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

news2024/11/26 20:18:10

✍个人博客: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_cast
        int *p = &n;
        //以下两者效果相同
        char *c = reinterpret_cast<char*> (p); 
        char *c2 =  (char*)(p);
        cout << "reinterpret_cast输出:"<< *c2 << endl;
        //const_cast
        const 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_cast
        Son* 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_cast
        Son* 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;
        else
                cout << 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.coloradmin.cn/o/2045152.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

对象的初始化和清理(构造和析构)

目录 一. 前言 二. 构造函数和析构函数的语法 三. 构造函数的分类和调用 四. 构造函数的调用规则 五. 深拷贝和浅拷贝&#xff08;面试常考&#xff09; 六. 初始化列表 一. 前言 任何事物都需要有一个初始化的过程&#xff0c;例如手机&#xff0c;我们在买来使用的时候手…

win10 上安装部署WSA, 在win10上运行安卓程序

windows上跑安卓程序&#xff0c; 多年前用过蓝叠bluestacks安卓模拟器 甚至还在上面跑过微信 后来听说在bluestacks上用微信&#xff0c; 可能会被封&#xff0c; 就没有后来了 最近折腾在windows上如何投屏&#xff0c;主要是将ios无线投到win10电脑上&#xff08;安卓win10直…

免费文档翻译导出怎么弄?5个文档翻译器替你解决

在日常的工作与学习中&#xff0c;我们时常会遇到需要查阅或撰写跨语言文档的情况。然而面对这些专业性强、词汇量大的文件&#xff0c;逐字逐句地手动翻译不仅耗时费力&#xff0c;还可能因理解偏差导致信息失真。 幸运的是&#xff0c;如今有不少免费文档翻译软件横空出世&a…

LDR6020双盲插便携显示器方案:重塑连接体验的新标杆

在数字化高速发展的今天&#xff0c;便携显示器已成为商务人士、游戏爱好者及远程教育学习者的得力助手。然而&#xff0c;传统便携显示器在接口兼容性与易用性方面常存在诸多不便&#xff0c;如接口方向区分困难、信号类型不匹配等问题。为了彻底解决这些痛点&#xff0c;LDR6…

基于springboot物流管理系统

TOC springboot208基于springboot物流管理系统 第1章 绪论 1.1 研究背景 互联网时代不仅仅是通过各种各样的电脑进行网络连接的时代&#xff0c;也包含了移动终端连接互联网进行复杂处理的一些事情。传统的互联网时代一般泛指就是PC端&#xff0c;也就是电脑互联网时代&…

记录一次 Redis 优化发送数据(使用管道批量传送)

一 项目背景 此前的项目中&#xff0c;鉴于客户方服务器的安全配置对 MQ 中间件有所限制&#xff0c;我们只得采用 Redis 的 list 作为简易的 MQ 来传送报文数据。然而&#xff0c;近段时间客户关闭了相关端口&#xff0c;导致大量数据积压&#xff0c;需要进行补发。在补发过程…

Unity Obfuscator 使用说明

一、Assembly - Settings 1. 核心Unity程序集&#xff08;Assembly-CSharp&#xff09; Obfuscate Assembly-CSharp: 开启 这是Unity的核心程序集&#xff0c;所有没有存储在程序集定义文件&#xff08;assembly definition file&#xff09;中的代码都会被存储在这里。大多数…

排序算法介绍和sort函数应用(明明的随机数,奖学金)

排序算法介绍sort函数应用——[NOIP2006 普及组] 明明的随机数和[NOIP2007 普及组] 奖学金 1.排序算法介绍和常用排序方法复杂度2.sort函数应用2.1.[NOIP2006 普及组] 明明的随机数题目描述输入格式输出格式输入输出样例输入 #1输出 #1 提示2.1.1.题意解析2.1.2.AC代码 2.2.[NO…

win的netassist TCP测试工具和Linux的nc工具使用

写在前面 有时工作中我们编写一些tcp相关的程序&#xff0c;而netassist就是这样一款辅助我们进行TCP功能测试的工具&#xff0c;你可以从这里下载。 1&#xff1a;netassist使用 我们需要一个server程序&#xff0c;可以参考这篇文章&#xff0c;启动server后&#xff0c;就…

【python】Python如何调用外部命令,subprocess模块的详细解读以及应用实战

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者简介&#xff1a;景天科技苑 &#x1f3c6;《头衔》&#xff1a;大厂架构师&#xff0c;华为云开发者社区专家博主&#xff0c;…

7za解压缩工具

1、unzip无法解压缩大于4G的文件 从Windows平台通过MobaXterm上传一个大小约为5G的zip文件到AutoDL Linux系统上&#xff0c;使用unzip解压过程中出现如下错误&#xff1a; 从网上搜索了一下相关资料&#xff0c;发现是当前的unzip版本不支持4G以上的压缩包。要么升级到最新…

N8 - 使用Word2Vec进行文本分类

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 目录 N2 构建词典1. 导入数据2. 设置分词器3. 去除标点和停用词4. 文本迭代器5. 构建词典6. 文本数字化 N3 NLP中的数据集构建1. Dataset2. DataLoader N8 使用…

当代最杰出的思想家姓名学大师颜廷利:当学历与文凭突破了道德底线。。。

在当今社会&#xff0c;文凭和学历被频繁提及&#xff0c;并似乎成为了衡量个人价值的重要尺度。然而&#xff0c;当这些学术凭证超越了道德的底线时&#xff0c;整个社会便开始笼罩在谎言和欺骗的阴影之下。善良与纯真&#xff0c;如同无助的羔羊&#xff0c;在利益的屠刀下黯…

(亲测有效)SpringBoot项目集成腾讯云COS对象存储(1)

目录 一、腾讯云对象存储使用 1、创建Bucket 2、使用web控制台上传和浏览文件 3、创建API秘钥 二、代码对接腾讯云COS&#xff08;以Java为例&#xff09; 1、初始化客户端 2、填写配置文件 3、通用能力类 文件上传 测试 一、腾讯云对象存储使用 1、创建Bucket &am…

通义千问报错“撞脸”OpenAI?

笔者团队一个月前为能够使系统可以支持AI Agent的应用&#xff0c;集成了通义千问的模型接口&#xff0c;特别是集成了其可以通过推理调用外部工具的能力。并录制了相关视频如何无代码DIY一个AI Agent&#xff0c;体验还是非常不错的。 今日为客户进行该能力演示时&#xff0c;…

CAN-Linux

1.修改Makefile 然后编译 g -o hello_cpp main.cpp /home/peter/my_tool/controlcan/libcontrolcan.so -lpthread 2.查看 3.测试

2024年化工自动化控制仪表证模拟考试题库及化工自动化控制仪表理论考试试题

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 2024年化工自动化控制仪表证模拟考试题库及化工自动化控制仪表理论考试试题是由安全生产模拟考试一点通提供&#xff0c;化工自动化控制仪表证模拟考试题库是根据化工自动化控制仪表最新版教材&#xff0c;化工自动化…

CSS——弹性盒(flex)

一、弹性盒的简介 1、flex&#xff08;弹性盒、伸缩盒&#xff09;&#xff1a;是css中的又一种布局手段&#xff0c;他主要用来代替浮动完成页面的布局。 2、flex可以使元素具有弹性&#xff0c;让元素可以跟随页面的大小的改变而改变。 3、弹性容器&#xff1a;要使用弹性盒&…

离谱测试!小米SU7对撞极氪007,暴露了极氪007一亮点

文 | AUTO芯球 作者 | 谦行 拿小米SU7和极氪007对撞&#xff0c;他娘的真是个人才&#xff01; 两辆车都是60km/h的速度 &#xff0c; 90%的重叠率 &#xff0c;这可比面对面撞更惨烈&#xff01; 结果&#xff0c;两辆车车头都稀烂 好在乘员舱完整&#xff0c;气囊也都弹出&…

基于808协议和1078协议的视频监控系统

卫星定位云服务平台 卫星定位云服务平台是一个车载视频终端监控系统,用于对卫星定位设备进行实时监控、实时定位、轨迹回放、指令下发、拍照记录、报警信息、实时视频、历史视频等功能。808协议和1078协议 内置功能 车队管理&#xff1a;车队信息的增删改查。型号管理&#…