【C++ 面试 - 基础题】每日 3 题(十八)

✍个人博客:Pandaconda-CSDN博客

📣专栏地址:http://t.csdnimg.cn/fYaBd

📚专栏简介:在这个专栏中,我将会分享 C++ 面试中常见的面试题给大家~
❤️如果有收获的话,欢迎点赞👍收藏📁,您的支持就是我创作的最大动力💪

52. C++  的四种强制转换 reinterpret_cast、const_cast、static_cast、dynamic_cast

reinterpret_cast

reinterpret_cast <type-id> (expression)

type-id 必须是一个指针、引用、算术类型、函数指针或者成员指针。它可以用于类型之间进行强制转换。可以将指针值转换为一个整型数,但不能用于非指针类型的转换。

举个例子:

#include <iostream>
using namespace std;
int main(int argc, char** argv)
{int num = 0x00636261;//用16进制表示32位int,0x61是字符'a'的ASCII码int * pnum = &num;char * pstr = reinterpret_cast<char *>(pnum);cout<<"pnum指针的值: "<<pnum<<endl;cout<<"pstr指针的值: "<<static_cast<void *>(pstr)<<endl;//直接输出pstr会输出其指向的字符串,这里的类型转换是为了保证输出pstr的值cout<<"pnum指向的内容: "<<hex<<*pnum<<endl;cout<<"pstr指向的内容: "<<pstr<<endl;return 0;
}

在 Ubuntu 14.04 LTS 系统下,采用 g++ 4.8.4 版本编译器编译该源文件并执行,得到的输出结果如下:

  

第 6 行定义了一个整型变量 num,并初始化为 0x00636261(十六进制表示),然后取 num 的地址用来初始化整型指针变量 pnum。接着到了关键的地方,使用 reinterpret_cast 运算符把 pnum 从int*转变成char*类型并用于初始化 pstr。

将 pnum 和 pstr 两个指针的值输出,对比发现,两个指针的值是完全相同的,这是因为 “reinterpret_cast 运算符并不会改变括号中运算对象的值,而是对该对象从位模式上进行重新解释”。如何理解位模式上的重新解释呢?通过推敲代码 11 行和 12 行的输出内容,就可见一斑。

很显然,按照十六进制输出 pnum 指向的内容,得到 636261;但是输出 pstr 指向的内容,为什么会得到 ”abc” 呢?

在回答这个问题之前,先套用《深度探索 C++ 对象模型》中的一段话,“一个指向字符串的指针是如何地与一个指向整数的指针或一个指向其他自定义类型对象的指针有所不同呢?从内存需求的观点来说,没有什么不同!它们三个都需要足够的内存(并且是相同大小的内存)来放置一个机器地址。指向不同类型之各指针间的差异,既不在其指针表示法不同,也不在其内容(代表一个地址)不同,而是在其所寻址出来的对象类型不同。也就是说,指针类型会教导编译器如何解释某个特定地址中的内存内容及其大小。” 参考这段话和下面的内存示意图,答案已经呼之欲出了。

  

 const_cast

const_cast <type_id> (expression)

该运算符用来修改类型的 const 或 volatile 属性。除了 const 或 volatile 修饰之外, type_id 和 expression 的类型是一样的。用法如下(只能用于指针或者引用)

  • 常量指针被转化成非常量的指针,并且仍然指向原来的对象。

  • 常量引用被转换成非常量的引用,并且仍然指向原来的对象。

  • const_cast 一般用于修改底指针。如 const char *p 形式。

static_cast

static_cast <type-id> (expression)

该运算符把 expression 转换为 type-id 类型,但没有运行时类型检查来保证转换的安全性。它主要有如下几种用法:

  • 用于类层次结构中基类(父类)和派生类(子类)之间指针或引用的转换。

    • 进行上行转换(把派生类的指针或引用转换成基类表示)是安全的。

    • 进行下行转换(把基类指针或引用转换成派生类表示)时,由于没有动态类型检查,所以是不安全的。

  • 用于基本数据类型之间的转换,如把 int 转换成 char,把 int 转换成 enum。这种转换的安全性也要开发人员来保证。

  • 把空指针转换成目标类型的空指针。

  • 把任何类型的表达式转换成 void 类型。

注意:static_cast 不能转换掉 expression 的 const、volatile、或者 __unaligned 属性。

dynamic_cast

有类型检查,基类向派生类转换比较安全,但是派生类向基类转换则不太安全

dynamic_cast <type-id> (expression)

该运算符把 expression 转换成 type-id 类型的对象。type-id 必须是类的指针、类的引用或者 void*。

如果 type-id 是类指针类型,那么 expression 也必须是一个指针,如果 type-id 是一个引用,那么 expression 也必须是一个引用。

dynamic_cast 运算符可以在执行期决定真正的类型,也就是说 expression 必须是多态类型。如果下行转换是安全的(也就说,如果基类指针或者引用确实指向一个派生类对象)这个运算符会传回适当转型过的指针。如果下行转换不安全,这个运算符会传回空指针(也就是说,基类指针或者引用没有指向一个派生类对象)。

dynamic_cast 主要用于类层次间的上行转换和下行转换,还可以用于类之间的交叉转换。

向下类型转换

在类层次间进行上行转换时,dynamic_cast 和 static_cast 的效果是一样的。

在进行下行转换时,dynamic_cast 具有类型检查的功能,比 static_cast 更安全。

举个例子:

#include <bits/stdc++.h>
using namespace std;class Base
{
public:Base() :b(1) {}virtual void fun() {};int b;
};class Son : public Base
{
public:Son() :d(2) {}int d;
};int main()
{int n = 97;//reinterpret_castint *p = &n;//以下两者效果相同char *c = reinterpret_cast<char*> (p); char *c2 =  (char*)(p);cout << "reinterpret_cast输出:"<< *c2 << endl;//const_castconst int *p2 = &n;int *p3 = const_cast<int*>(p2);*p3 = 100;cout << "const_cast输出:" << *p3 << endl;Base* b1 = new Son;Base* b2 = new Base;//static_castSon* s1 = static_cast<Son*>(b1); //同类型转换Son* s2 = static_cast<Son*>(b2); //下行转换,不安全cout << "static_cast输出:"<< endl;cout << s1->d << endl;cout << s2->d << endl; //下行转换,原先父对象没有d成员,输出垃圾值//dynamic_castSon* s3 = dynamic_cast<Son*>(b1); //同类型转换Son* s4 = dynamic_cast<Son*>(b2); //下行转换,安全cout << "dynamic_cast输出:" << endl;cout << s3->d << endl;if(s4 == nullptr)cout << "s4指针为nullptr" << endl;elsecout << s4->d << endl;return 0;
}
//输出结果
//reinterpret_cast输出:a
//const_cast输出:100
//static_cast输出:
//2
//-33686019
//dynamic_cast输出:
//2
//s4指针为nullptr

从输出结果可以看出,在进行下行转换时,dynamic_cast 安全的,如果下行转换不安全的话其会返回空指针,这样在进行操作的时候可以预先判断。而使用 static_cast 下行转换存在不安全的情况也可以转换成功,但是直接使用转换后的对象进行操作容易造成错误。

用于多态类型检查

  

dynamic_cast 底层原理

dynamic_cast 的底层原理依赖于运行时类型信息 (RTTI, Runtime Type lnformation) C++ 编译器在编译时为支持多态的类生成 RTTI,它包含了类的类型信息和类层次结构。我们都知道当使用虚函数时,编译器会为每个类生成一个虚函数表 (vtable) ,并在其中存储指向虚函数的指针。

伴随虚函数表的还有 RTTI (运行时类型信息),这些辅助的信息可以用来帮助我们运行时识别对象的类型信息。

《深度探索 C++ 对象模型》中有个例子:

  

  

首先,每个多态对象都有一个指向其 vtable 的指针,称为 vptr。

RTTI (就是上面图中的 type_info 结构) 通常与 vtable 关联。dynamic_cast 就是利用 RTTI 来执行运行时类型检查和安全类型转换。以下是 dynamic cast 的工作原理的简化描述:

  1. 首先,dynamic_cast 通过查询对象的 vptr 来获取其 RTTI (这也是为什么 dynamic_cast 要求对象有虚函数)。

  2. 然后,dynamic_cast 比较请求的目标类型与从 RTTI 获得的实际类型。如果目标类型是实际类型或其基类,则转换成功。

  3. 如果目标类型是派生类,dynamic_cast 会检查类层次结构,以确定转换是否合法。如果在类层次结构中找到了目标类型,则转换成功;否则,转换失败。

  4. 当转换成功时,dynamic_cast 返回转换后的指针或引用。

  5. 如果转换失败,对于指针类型,dynamic_cast 返回空指针;对于引用类型,它会抛出个 std::bad_cast 异常。

因为 dynamic_cast 依赖于运行时类型信息,它的性能可能低于其他类型转换操作 (如,static 是编译器静态转换,编译时期就完成了 static_cast)。

 53. RTTI 是什么?其原理是什么?

RTTI是 C++ 中的一种运行时类型识别机制,它允许程序在运行时查询一个对象的实际类型信息。RTTI 主要用于多态场景中,例如,当一个基类指针指向一个派生类对象时,通过 RTTI 可以判断出该指针所指向的对象的实际类型。

可以通过使用两个关键字 typeiddynamic_cast 来实现 RTTI:

  • typeid 运算符,用于返回表达式的类型,可以通过基类的指针获取派生类的数据类型。

  • dynamic_cast 运算符,具有类型检查的功能,用于将基类的指针或引用安全地转换成派生类的指针或引用。

虚函数表中起始部分存放 RTTI 指针标识动态类型,从而能实现多态。

RTTI 是一种运行时机制,需要在程序运行时才能进行类型信息的查询和转换。由于这种机制会增加程序的运行时开销。使用虚函数实现多态,而不是手动进行类型转换是一种避免额外 RTTI 开销的方法。

54. 系统 崩溃的原因有哪些?

  1. 分段错误:这是程序崩溃的主要原因。这些可能是造成这种原因的原因:尝试访问系统中不存在的内存位置、试图在只读存储器位置上进行写操作。

  2. 堆栈溢出:在某些情况下,可能无法终止内存位置的递归。

  3. 缓冲区溢出:这是一种异常,程序在将数据写入缓冲区时会溢出缓冲区的边界并覆盖相邻的内存位置。

  4. 内存泄漏:如果我们通过某个程序分配一些内存,并保持原样。一段时间后,将分配但未使用巨大的内存,因此一段时间后将缺少内存。然后程序开始崩溃。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/401190.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Web开发-CSS篇-上

CSS的发展历史 CSS&#xff08;层叠样式表&#xff09;最初由万维网联盟&#xff08;W3C&#xff09;于1996年发布。CSS1是最早的版本&#xff0c;它为网页设计提供了基本的样式功能&#xff0c;如字体、颜色和间距。随着互联网的发展&#xff0c;CSS也不断演进&#xff1a; C…

【低代码开发】

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

谷粒商城实战笔记-175~177-商城业务-检索服务-检索查询接口开发

文章目录 一&#xff0c;175-商城业务-检索服务-检索查询参数模型分析抽取二&#xff0c;176-商城业务-检索服务-检索返回结果模型分析抽取三&#xff0c;177-商城业务-检索服务-检索DSL测试-查询部分四&#xff0c;178-商城业务-检索服务-检索DSL测试-聚合部分问题记录解决方案…

RCE之无参数读取文件总结

RCE漏洞(Remote Code|Command Execute)&#xff1a; 是指由于程序中预留了执行代码或者命令的接口&#xff0c;并且提供了给用户使用的界面&#xff0c;导致被黑客利用&#xff0c; 控制服务器。 代码执行漏洞原理&#xff1a; 传入php代码到执行函数的变量&#xff0c;客户端…

IIC 通信协议详解

目录 一、概述二、I2C 详解1、I2C 总线简介2、I2C 协议相关知识2.1 起始位2.2 停止位2.3 数据传输2.4 应答信号2.5 I2C 设备地址格式2.5 I2C 时序图2.5.1 I2C 写时序2.5.2 I2C 读时序2.5.3 单个/多个字节的写入/读取 3、时钟同步和仲裁3.1 时钟同步3.2 时钟仲裁 一、概述 IIC …

Fal.ai Flux 1-Pro/Viva.ai/哩布哩布AI:AI绘图部分免费工具+原图提示词Prompt

目录 #1 找软件 #2 懂提示词 #3 更难的一步&#xff0c;会英文 我个人认为&#xff0c;想要玩文生图&#xff0c;你要会3个步骤&#xff1a; #1 找软件 主流文生图软件&#xff1a;Midjourney、Stable Diffusion、Dall-E 3 巧了&#xff0c;我用的都是小众、免费的画笔工…

【Linux】守护进程:containerd的使用教程

这里写目录标题 前言一. ctr1.1 ctr CLI1.2 ctr 调试 二、 创建 container2.1 进入 NewContainer2.2 ContainerService().Create 前言 介绍了 kubelet 通过 cri 接口和 containerd 交互的过程&#xff0c;containerd 源码分析&#xff1a;启动注册流程 介绍了 containerd 作为…

赶快收藏!全网最佳Set集合详解:HashSet、TreeSet!

先赞后看&#xff0c;Java进阶马上一大半 海外geeksforgeeks网站画了这么一张Set集合的层次结构图&#xff0c;基本把Set集合涉及的常用类关系给标明了。 大家好&#xff0c;我是南哥。 一个Java学习与进阶的领路人&#xff0c;相信对你通关面试、拿下Offer进入心心念念的公司…

arthas使用

1.安装arthas 我的是windows #打开cmd&#xff0c;执行以下命令 &#xff0c;下载jar curl -O https://arthas.aliyun.com/arthas-boot.jar2.启动本地的idea项目 3.进入到jdk的bin文件夹 jdk的配置在“高级系统设置” 进入jdk的bin目录 4.启动arthas 5.arthas使用 trace 类…

Elasticsearch自动补全功能实践与Java API应用

Elasticsearch是一个强大的搜索引擎&#xff0c;它不仅支持全文搜索&#xff0c;还提供了自动补全功能&#xff0c;可以显著提升用户体验。自动补全功能允许用户在输入查询时实时显示建议项&#xff0c;帮助用户快速找到所需信息。本文将介绍如何使用Elasticsearch的RestHighLe…

探索Java Stream API:高效处理集合的利器

文章目录 一、Stream API简介1.1 什么是Stream&#xff1f;1.2 Stream的特点 二、Stream API的基本操作2.1 创建Stream2.2 中间操作2.3 终端操作 三、Stream API的高级应用3.1 并行Stream3.2 复杂数据处理3.3 Stream与Optional 四、最佳实践例子 1: 筛选和映射例子 2: 排序和收…

什么是流批一体?怎样理解流批一体?

目录 一、流式处理与批量处理概述 1.流式处理 2.批量处理 3.流批一体的定义 二、流批一体的关键特点 三、流批一体的技术实现 四、应用场景 五、实施流批一体的考虑因素 流批一体听起来很简单&#xff0c;但内涵却十分复杂。它包含了计算语义、编程模型、API、调度、执行、shuf…

html+css+js网页制作 京东首页官网 ui还原度100%

htmlcssjs网页制作 京东首页官网 ui还原度100% 网页作品代码简单&#xff0c;可使用任意HTML编辑软件&#xff08;如&#xff1a;Dreamweaver、HBuilder、Vscode 、Sublime 、Webstorm、Text 、Notepad 等任意html编辑软件进行运行及修改编辑等操作&#xff09;。 获取源码 …

微服务系列:Spring Cloud 之 Feign、Ribbon、Hystrix 三者超时时间配置

Feign 自身有超时时间配置 Feign 默认集成的 Ribbon 中也有超时时间配置 假如我们又使用了 Hystrix 来实现熔断降级&#xff0c;Hystrix 自身也有一个超时时间配置 注: spring-cloud-starter-openfeign 低一点的版本中默认集成的有 Hystrix&#xff0c;高版本中又移除了。 …

x264 编码器 SSIM 算法源码分析

SSIM SSIM(Structural Similarity Index)是一种用于衡量两幅图像之间视觉相似度的指标。它不仅考虑了图像的亮度、对比度和饱和度,还考虑了图像的结构信息。SSIM的值介于-1到1之间,值越接近1表示两幅图像越相似。 SSIM是基于以下三个方面来计算的: 亮度(Luminance):比…

MLM之GPT-4o:在GPT-4o的806版本的 API 中引入结构化输出—可以可靠地遵循开发人员提供的 JSON 模式

MLM之GPT-4o&#xff1a;在GPT-4o的806版本的 API 中引入结构化输出—可以可靠地遵循开发人员提供的 JSON 模式 导读&#xff1a;2024年8月6日&#xff0c;OpenAI推出了新的API功能"结构化输出"&#xff0c;旨在更好地帮助人们理解和与大型语言模型的输出进行交互。这…

Linux系统编程(10)线程资源回收和互斥锁

一、pthread_cancel函数 pthread_cancel 函数用于请求取消一个线程。当调用 pthread_cancel 时&#xff0c;它会向指定的线程发送一个取消请求。 #include <pthread.h>int pthread_cancel(pthread_t thread);thread&#xff1a;要发送取消请求的线程标识符。 成功时&a…

Dify 开源大语言模型(LLM) 应用开发平台如何使用Docker部署与远程访问

目录 ⛳️推荐 前言 1. Docker部署Dify 2. 本地访问Dify 3. Ubuntu安装Cpolar 4. 配置公网地址 5. 远程访问 6. 固定Cpolar公网地址 7. 固定地址访问 ⛳️推荐 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享…

Javascript反调试实现判断用户是否打开了浏览器控制台

前言 晓杰最近在研究如何防止用户恶意调试前端网页代码&#xff0c;防止打开控制台进行调试&#xff0c;首先禁用了浏览器页面右键事件和F12等快捷键&#xff01;然后利用了创建元素是否成功方式进行校验,具体实现代码如下。 代码 document.addEventListener(keydown, functi…

(贪心) LeetCode 376. 摆动序列

原题链接 一. 题目描述 如果连续数字之间的差严格地在正数和负数之间交替&#xff0c;则数字序列称为 摆动序列 。第一个差&#xff08;如果存在的话&#xff09;可能是正数或负数。仅有一个元素或者含两个不等元素的序列也视作摆动序列。 例如&#xff0c; [1, 7, 4, 9, 2,…