【c++】强制类型转化

server/2024/12/22 9:32:27/

一、前言

在C++语言中新增了四个关键字static_cast、const_cast、reinterpret_cast和dynamic_cast。这四个关键字都是用于强制类型转换的。

新类型的强制转换可以提供更好的控制强制转换过程,允许控制各种不同种类的强制转换。

C++中风格是static_cast<type>(content)。C++风格的强制转换其他的好处是,它们能更清晰的表明它们要干什么。程序员只要扫一眼这样的代码,就能立即知道一个强制转换的目的。

二、static_case

static_case:静态转换是最常用的一种类型转换,它可以在不同但相关的类型之间进行转换,如基本数据类型之间的转换、父类指针向子类指针的转换等。但是需要注意的是,静态转换没有运行时类型检查,因此在进行转换时需要确保类型之间是相关的,否则可能会导致错误。

int a = 10;
int b = 3;
double result = (double)a / (double)b;

它主要有如下几种用法:

  • 用于类层次结构中基类和派生类之间指针或引用的转换
  • 进行上行转换(把派生类的指针或引用转换成基类表示)是安全的
  • 进行下行转换(把基类的指针或引用转换为派生类表示),由于没有动态类型检查,所以是不安全的
  • 用于基本数据类型之间的转换,如把int转换成char。这种转换的安全也要开发人员来保证
  • 把空指针转换成目标类型的空指针
  • 把任何类型的表达式转换为void类型
  • 注意:static_cast不能转换掉expression的const、volitale或者__unaligned属性。

static_cast:可以实现C++中内置基本数据类型之间的相互转换。

如果涉及到类的话,static_cast只能在有相互联系的类型中进行相互转换,不一定包含虚函数。

三、const_cast

在C语言中,const限定符通常被用来限定变量,用于表示该变量的值不能被修改。

而const_cast则正是用于强制去掉这种不能被修改的常数特性,但需要特别注意的是const_cast不是用于去除变量的常量性,而是去除指向常数对象的指针或引用的常量性,其去除常量性的对象必须为指针或引用。

示例代码:

const int a = 100;
int* p = const_cast<int*>(&a);
*p = 200;cout << *p << endl;
cout << a << endl;

运行截图:

在上面的例子中,用p指向常量a,并且用const_cast去除p指针的常性,再对p指针解引用进行赋值,发现p中存放的值是被改变,但是a的值还是没有改变。

为什么相同的地址,*p的值改变了,但是a的值没有改变?

其实这是一件好事,我们要庆幸a变量最终的值没有变成200!变量a一开始就被声明为一个常量变量,不管后面的程序怎么处理,它就是一个常量,就是不会变化的。一旦一个项目工程非常庞大的时候,在程序某个地方出现了一个p这样的指针,它可以修改常量a,这是一件很可怕的事情的,可以说是一个程序的漏洞,毕竟将变量a声明为常量就是不希望修改它,如果后面能修改,这就太恐怖了。

如果加上volatile呢?

volatile const int a = 100;
int* p = const_cast<int*>(&a);
*p = 200;cout << *p << endl;
cout << a << endl;

如果不加volatile,a就没有被修改,因为编译器做出的优化,将const修饰的a的值直接存放到寄存器当中,或者直接将a替换成2,加了volatile就会去内存当中寻找a的值,就能修改。

四、reinterpret_cast

在C++语言中,reinterpret_cast主要有三种强制转换用途:改变指针或引用的类型、将指针或引用转换为一个足够长度的整形、将整型转换为指针或引用类型

//reinterpret_cast 不相近类型之间的转换
int main()
{double d = 12.34;int a = static_cast<int>(d);cout << a << endl;//12//int *p = static_cast<int*>(&a);这里使用static_cast会报错,应该使用reinterpret_castint* p = reinterpret_cast<int*>(&a);cout << *p << endl;//12return 0;
}

在使用reinterpret_cast强制转换过程仅仅只是比特位的拷贝,这种转换的结果会导致实际编程中的指针指向的内容是不明确的,因此需要开发者自行确保转换的安全性,谨慎使用。

五、dynamic_cast

  1. 以上三种强制类型转化都是编译时完成的,dynamic_cast是在运行时处理的,运行时要进行类型检查
  2. 不能用于基本数据类型的强制转换,一般是用于父类指针或者引用向子类指针或者引用进行类型转换。
  3. 如果转化成功的话,返回指向类的指针或者引用,如果转化失败的话,是返回NULL。
  4. 要使用dynamic_cast进行转化,基类一定要有虚函数,否则编译不通过。因为只有当类中存在虚函数,就说明它有想让基类指针或者引用指向派生类对象的情况,此时进行了类型转换才有意义。运行时类型检查需要运行时类型信息,这个信息保存在虚函数表当中。
  5. 相比static_cast,上行转换的效果一致,但下行转换时,dynamic_cast多了类型检查,比static_cast更加安全。
#include <iostream>class Base {
public:virtual ~Base() {}
};class Derived : public Base {
public:void DerivedMethod() {std::cout << "Derived method called." << std::endl;}
};int main() {Base* da = new Derived;Derived* db = dynamic_cast<Derived*>(da);if (db) {db->DerivedMethod();}else {std::cout << "dynamic_cast failed." << std::endl;}delete da;return 0;
}

结果:

Derived method called.

如果父类指针本来指向父类对象,被类型转化为子类指针,如果强制转换,那么会存在越界访问的问题,此时如果用dynamic_cast进行转换,那么会得到一个空指针,如果这个父类指针指向子类对象,转化为子类指针,不存在安全问题,所以此时用dynamic_cast转换就是安全的。

注意:父类必须包含虚函数,要不然dynamic_cast就不能用了。


http://www.ppmy.cn/server/104931.html

相关文章

ARM/Linux嵌入式面经(二六):韶音

面试体验很好,流程规范,HR细心热情,目前秋招体验最好的一家公司。 一面HR面30min: 1.自我介绍 2.课题组主要做的什么方向 3.聊一聊项目,内容,团队,分工 4.课题组多少人等等。。 5.唠家常 6.其他公司进度 7.意向薪资 二面技术面20min 1.自我介绍 2.OTA 在嵌入式…

linux tomcat jenkins 迁移

最近由于我们的测试和生产环境jenkins频频发生错误&#xff0c;索性尝试了一把在阿里云上做jenkins迁移 在阿里云jenkins安装模式是用tomcat安装部署的 [rootk8s-master local]# ls aegis bin cloudmonitor etc games go ilogtail include lib lib64 libexec sbin…

高性能Web服务器

Nginx的架构和安装Nginx的概述 Nginx &#xff1a; engine X &#xff0c; 2002 年开发&#xff0c;分为社区版和商业版 (nginx plus ) 2019 年 3 月 11 日 F5 Networks 6.7 亿美元的价格收购 Nginx 是免费的、开源的、高性能的 HTTP 和反向代理服务器、邮件代理服务器、以及 T…

【Qt笔记】QPushButton控件详解

目录 一、概述 二、属性 三、方法 四、信号与槽 五、QPushButton的主要功能 六、QPushButton的常用函数方法 1. 构造函数 2. 设置与获取文本 3. 设置与获取图标 4. 设置与获取快捷键 5. 连接信号和槽 6. 启用和禁用按钮 7. 设置默认按钮和自动默认按钮 七、QPush…

DM8守护集群部署、数据同步验证、主备切换

1. 环境描述 实例详情 端口详情 2. 部署步骤 2.1 数据准备 2.1.1主库初始化 [dmdbaray1 ~]$ cd /dmdba/dmdbms/bin [dmdbaray1 bin]$ ./dminit path/dmdba/data PAGE_SIZE32 EXTENT_SIZE32 CASE_SENSITIVEy CHARSET1 DB_NAMEGRP1_RT_01 INSTANCE_NAMEGRP1_RT_01 PORT_NU…

Robot Operating System——自定义Service/Client通信消息结构

大纲 初始化环境生成自定义服务的工程创建包自定义消息package.xml完整文件 CMakeLists.txt完整文件 编译注册 使用自定义服务的工程创建包代码CMakeLists.txt编译运行 工程地址参考资料 在《Robot Operating System——自定义订阅/发布的消息结构》一文中&#xff0c;我们讲解…

USB分析仪USB3.2日志分析

1.简介 USB2.0总线采用轮询模式&#xff0c;即总线事务开始时&#xff0c;都要先发送IN或者OUT令牌包&#xff0c;以通知端点或者查询端点是否准备好。而USB3.2采用了异步通知模式&#xff0c;若端点没有准备好&#xff0c;则主机无需轮询&#xff0c;端点准备好后会通知主机&…

坚持绿色发展的上海智算中心,稳步推进中

自今年年初正式封顶以来&#xff0c;云端股份上海智算中心在外墙及内部的建设进展顺利。这座智算中心地理位置优越&#xff0c;正逐步成为推动数字经济发展的重要力量。 位置优势 云端股份上海智算中心毗邻智慧岛数据产业园&#xff0c;是崇明区目前建设的唯一一座智算中心&am…