C++显式类型转换

本文主要分析C++的4种显式类型转换

文章目录

  • static_cast
    • 基本数据类型转换
    • const
    • 用于类层次结构
    • void*
  • dynamic_cast
    • 继承中的转换
  • const_cast
  • reinterpret_cast
  • 参考资料


我们使用显示类型转换,就是在告诉编译器要怎么解释这块内存。

在早期C/C++中,显式的类型转换有如下两种形式

type(expr); // 函数形式的显式类型转换
(type)expr; // C语言风格 

C++的新式显式类型转换

cast-name<type>(expression);
  • cast-namestatic_castdynamic_castconst_castreinterpret_cast 四种,表示转换的方式
  • type表示转换的目标类型
  • expression 是被转换的值

下面详细讲解下这四种显式类型转换


static_cast

格式为 static_cast<type>(expression)

任何在编写程序时能够明确的类型转换都可以使用 static_cast

基本数据类型转换

基本数据类型转换,比如将int转换为double,反之亦然,需要编写程序时确认安全性

将 `int` 转换为 `double` 编译器可能的操作如下(VS2022 x64),比如有如下代码
int x = 0;
double y = static_cast<double>(x);

其汇编码为,cvtsi2sd 指令把源地址1个双字有符号整数变成1个双精度浮点数,xmm0 为英特尔处理器中的一个128位寄存器,movsd mmword ptr [y],xmm0 指令表示从 xmm0 寄存器中移动低64位到 y 地址

const

将非const对象转换为const对象 (但不能将const对象转换为非const对象,这个只有const_cast才能做到)
如果转换底层 const 对象到非 const 对象,编译器会报表达式必须是可修改的左值错误

顶层 const 也不可以被 static_cast 转换

用于类层次结构

父类和子类之间指针和引用的转换
假设我们现在有两个类,父类 A 和其派生类 B

class A {
public:virtual void foo() {std::cout << "A::foo()" << std::endl;}int m_a = 0;
};class B : public A
{
public:virtual void foo() {std::cout << "B::foo()" << std::endl;}int m_b = 0;
};
  • 进行上行转换,即把子类对象的指针/引用转换为父类指针/引用,这种转换是安全的
B b;
static_cast<A>(b).foo();
B* bptr = new B;
static_cast<A*>(bptr)->foo();

输出如下

  • 进行下行转换,即把父类对象的指针/引用转换成子类指针/引用,这种转换是不安全的,因为没有运行时检查,所以需要在编写程序时确认安全性
A* a = new A;
std::cout << static_cast<B*>(a)->m_b << std::endl; // 不安全的,访问了申请外的内存

输出如下

void*

void* 转换为目标类型的指针(这是极其不安全的),类似于上面父类指针转子类指针,可能会访问申请外的内存

void* a = new A;
std::cout << static_cast<B*>(a)->m_b << std::endl; // 不安全的,访问了申请外的内存

输出如下


dynamic_cast

格式为 dynamic_cast<type>(expression)

相比static_castdynamic_cast 会在运行时检查类型转换是否合法,具有一定的安全性。由于运行时的检查,所以会额外消耗一些性能。需要注意的是 dynamic_cast 转换仅适用于指针或引用

继承中的转换

  1. 上行转换

由子类指针/引用转换到父类指针/引用,与 static_cast 和隐式转换一样,都是安全的

B* b = new B;
A* a = dynamic_cast<A*>(b);
std::cout << a->m_a << std::endl;

可以看到下面的汇编代码中,只是把指针的值给到了 [a] 地址

  1. 下行转换

由父类指针/引用转换到子类指针/引用,使用 dynamic_cast 进行下行转换有个条件,就是其操作数必须含有多态类类型,简单理解,父类得有虚函数。

如果我们将之前 类A 和 类B 中的虚函数去掉,则会报错

如果和之前一样,类 A 中有虚函数 foo(),那么执行 dynamic_cast 会发生什么

A* a = new A;
B* b = dynamic_cast<B*>(a);
std::cout << b->m_b << std::endl;

可以看到把类 B 和类 A 的运行时类型描述符放到了 r9r8 寄存器中

之后运行时动态类型转换,这里的实现原理简单描述为,我们在虚函数表 vtbl[-1] 的位置存放着指向类型信息的 tpye_info*,那么由于我们实际指向的对象的类是 A 其取出的 RTTI Type Descriptor 应该是类 A 我们和需要转换的类 B 的 RTTI Type Descriptor 比较,然后发现不匹配,此时转换失败,会返回一个 nullptr。

如果 a 实际指向的是类 B 的对象,那么运行时转换成功。

注意转换的是引用,转换失败会抛出 bad_cast 异常


const_cast

格式为 const_cast<type>(expression)

const_cast 用于移除类型的 constvolatile_unaligned 属性

const A* const a = new A;
A* aa = const_cast<A*>(a);
aa->m_a = 2;

当然也可以用于添加 const


reinterpret_cast

格式为 reinterpret_cast<type>(expression)

非常激进的指针类型转换,在编译期完成,可以转换任何类型的指针,所以极不安全。非极端情况不要使用


参考资料

C++笔记 · C++类型转换 —— 默默默默默
C++对象模型之RTTI的实现原理 —— linux

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

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

相关文章

使用python给图片加上文字水印

使用python给图片加上文字水印 作用效果代码 作用 给图片加上文字水印文字水印的字体&#xff0c;颜色&#xff0c;位置可自定义 效果 原图&#xff1a; 加水印后的图&#xff1a; 代码 from PIL import Image, ImageDraw, ImageFontdef add_text_watermark(input_image…

ThreadLocal,一次到位

一、定义 ThreadLocal是线程私有变量&#xff0c;用于保存每个线程的私有数据。 那么什么情况下需要进行线程隔离 二、源码分析 public class ThreadLocalTest01 {ThreadLocal<Integer> t new ThreadLocal<>();public void test() {t.set(1);Integer integer…

iOS plist文件增删改查

一. plist简介 plist文件&#xff0c;即属性列表文件&#xff0c;全名是Property List&#xff0c;这种文件的扩展名为.plist&#xff0c;因此&#xff0c;通常被叫做plist文件。它是一种用来存储串行化后的对象的文件&#xff0c;在iOS开发中通常用来存储用户设置&#xff0c…

记笔记从学Typora开始--------------------(1)下载、安装、购买、激活

一、登录Typora官网 官网地址&#xff1a;Typora 二、鼠标往下滑&#xff0c;点击下载按钮 三、下载得到安装包&#xff0c;双击 四、一直点击下一步&#xff0c;进行安装 五、安装完成 六、启动Typoera 七、针对欢迎界面点击下一页 八、一直点击直到弹出以下软件激活界面 九…

wefaf

c语言中的小小白-CSDN博客c语言中的小小白关注算法,c,c语言,贪心算法,链表,mysql,动态规划,后端,线性回归,数据结构,排序算法领域.https://blog.csdn.net/bhbcdxb123?spm1001.2014.3001.5343 给大家分享一句我很喜欢我话&#xff1a; 知不足而奋进&#xff0c;望远山而前行&am…

NAT技术总结与双向NAT配置案例

NAT的转换方式&#xff1a; 1.静态转换&#xff1a;固定的一对一IP地址映射。 interface GigabitEthernet0/0/1 ip address 122.1.2.24 nat static global 122.1.2.1 inside 192.168.1.1 #在路由器出接口 公网地址 私网地址。 2.动态转换&#xff1a;Basic NAT nat address-gr…

Shell脚本 <<EOF ... EOF语法(Here Document)(特殊的输入重定向方式)(定界符)

文章目录 Here Document语法Here Document 的基本语法使用场景 关于定界符定界符不是变量定界符在 Here Document 中只是一个字符串&#xff0c;主要功能是标记输入文本的开始和结束&#xff0c;使用时应遵循最佳实践格式要求例子和说明如何使用定界符定界符可重复使用&#xf…

如何在云电脑实现虚拟应用—数据分层(应用分层)技术简介

数据分层&#xff08;应用分层&#xff09;技术简介 近几年虚拟化市场实现了非常大的发展&#xff0c;桌面虚拟化在企业中应用越来越广泛&#xff0c;其拥有的如下优点得到大量企业的青睐&#xff1a; 数据安全不落地。在虚拟化环境下面数据保存在中心服务器上面&#xff0c;…

想做好抖店?新手、老玩家切勿掉进这些坑,操作要慎重!

大家好&#xff0c;我是电商花花。 很多人都说做抖音小店不需要脑子&#xff0c;会抄就行&#xff0c;难道做店真的就是这样吗&#xff1f; 真的就是会抄&#xff0c;会简单选品&#xff0c;找一些达人就能出单&#xff0c;就能实现睡后收入了吗&#xff1f; 其实并不见得&a…

Day_5

1. Apache ECharts Apache ECharts 是一款基于 Javascript 的数据可视化图表库&#xff0c;提供直观&#xff0c;生动&#xff0c;可交互&#xff0c;可个性化定制的数据可视化图表 官网地址&#xff1a;https://echarts.apache.org/zh/index.html 入门案例 快速入门&#x…

K210开发板MicroPython开发环境搭建

一、安装CanMV IDE开发软件 1、进入如下连接 https://developer.canaan-creative.com/resource 2、点击下载 3、下一步 4、修改安装路径&#xff0c;下一步 5、接受许可下一步 6、下一步 7、安装 8、完成 9、区域①菜单栏&#xff1a;操作文件&#xff0c;使用工具等。…

短视频素材该去哪里找?分享8个短视频剪辑必备的素材大全

在短视频创作与运营中&#xff0c;素材的找寻常常成为创作者的最头疼的事&#xff0c;因为它既要求不侵犯版权&#xff0c;又追求内容的优质性。然而&#xff0c;今天我要为大家揭晓一些剪辑短视频素材库的宝藏网站&#xff0c;它们将成为你创作旅程中的得力帮手&#xff0c;让…