C++类型转换

时间:2024-01-26 21:15:35

目录

一、C语言的类型转换

二、C++四种类型转换

①static_cast

②reinterpret_cast

③const_cast

④dynamic_cast

RTTI(了解内容)


一、C语言的类型转换

C语言中有隐式类型转换和显式的强制类型转换,如下所示:

隐式类型转换意义相近类型之间的转换
显示的强制类型转换则是意义不相近类型之间的转换(值转换后有意义)

但是并不是所有的意义不相近类型都能转换的,例如结构体类型怎么转换也不能够转换为一个int类型的数

C语言中的显示类型转换还好说,隐式类型转换有些情况就会出现问题:

如上所示,我们有两个size_t类型的变量分别是a、b,当进入while循环时,a从5不断的--,直到减到0,按理说下一次a--到-1时就不满足条件了,但是运行结果却是一直死循环

原因就是size_t是无符号整数,a减到-1并不是负数,而是整数的最大值,所以会持续死循环

那这时,如果将a改为int类型,a--到-1是不是就能够解决这个问题呢,也并不是我们所想的那样:

程序依然死循环,这就是C语言中的隐式类型转换可能带来的问题
原因是:a变为了int类型,但是在while循环的判断条件中,int类型的a在与size_t类型的b比较时,会自动将int类型的a隐式提升为size_t类型,依然是第一次出现的问题

所以上述情况是C语言隐式类型转换的缺陷,转换的可视性较差,类型转换的情况不够清晰
也会有精度丢失的缺点


二、C++四种类型转换

由于C语言的类型转换由上面的一些缺陷,所以C++也提出了自己的类型转换,当然C++也还是会兼容C的类型转换(不会舍弃旧的语法)

C++为了加强类型转换的可视性,引入了四种命名的强制类型转换操作符:

static_cast、reinterpret_cast、const_cast、dynamic_cast

①static_cast

编译器隐式执行的任何类型转换都可用 static_cast(意义相近类型),但它不能用于两个不相关的类型进行转换(隐式类型转换)

用法如下:

static_cast后面的<>里放的就是转换后的类型


②reinterpret_cast

reinterpret_cast用于将一种类型转换为另一种不同的类型,即意义不相近类型(强制类型转换)

用法如下:


③const_cast

const_cast最常用的用途就是删除变量的const属性,方便赋值(强制类型转换)

如上图即删除了变量a的const属性,并将它的地址给了ptr指针,从而可以赋值

但是我们可以观察到,a的值和*ptr的值却是不同的,为什么const_cast将a的const属性删除了,且将a的地址赋值给了ptr,接着改变*ptr的值,a的值却没有变化呢?

原因是编译器对于const类型的一个优化,编译器认为const类型的a不会被改,所以就不用每次访问时都从内存中去读取a的数值,于是直接将a加载到一个寄存器中,所以虽然a在内存中被改了,但是编译器并不知道,编译器依然是从寄存器中读取的,而*ptr是从内存中取的,所以*ptr的值改变了,因此打印出来的a和*ptr的值是不同的

那么如何解决这个问题呢,有个关键字volatile就是专门解决这里的优化问题的

在const int a前面加上关键字volatile,就是在告诉编译器,不要优化a,每次访问时都去内存中取,优化后如下:

成功解决问题


④dynamic_cast

dynamic_cast是用于将一个父类对象的指针/引用转换为子类对象的指针/引用(动态转换)

向上转换子类对象指针/引用->父类指针/引用(不需要转换,赋值兼容规则)

向下转换父类对象指针/引用->子类指针/引用(用dynamic_cast转型是安全的)

例如父类A类,子类是B类,则子类对象是可以转换成父类对象的,赋值兼容,可以切片处理,而父类对象是不能转换成子类对象的:


 在test函数中:参数A*类型的指针pa有可能指向父类A,也有可能指向子类B:

如果是test(&pb)传入的pb原本就是指向子类的指针,此时将test函数中的父类指针pa强制转换后赋值给pb,pb是可以指向子类的成员_b并使用的

但是如果是test(&pa)传入的pa原本就是指向父类的指针,即使在test函数中将父类指针强制转换后赋值给pb,由于本身就是父类指针,无法使用子类的_b成员,若使用子类成员_b是会发生越界的

所以这时C++引入了dynamic_cast,使用dynamic_cast是安全的

如果pa是指向子类,那么可以转换,转换表达式返回正确的地址
如果pa是指向
父类,那么不能转换,转换表达式返回nullptr

这时使用方法如下:

main函数中先传入父类指针pa,进入test函数后使用dynamic_cast进行转换,因为指向父类,所以返回值为nullptr,因此进入else语句,打印转换失败

第二个传入子类指针pb,因为指向子类,所以返回正确的地址,因此进入if语句,打印转换成功

之所以说使用dynamic_cast是安全的,是因为如果不使用dynamic_cast,而是直接执行语句B* pb = (B*)pa的话,那么不论是传入父类还是子类指针都会进入if语句,然后就会发生越界错误,所以是不安全的

需要注意的是:

dynamic_cast只能用于父类含有虚函数的类(可以注意到上面所举例子的父类A里有虚函数f(),若没有虚函数则会语法报错)


RTTI(了解内容)

RTTI就是Run-time Type identification,即运行时类型识别。

C++通过以下方式来支持RTTI:

①、 typeid运算符:获取对象类型字符串

②、dynamic_cast运算符:可以识别父类的指针指向父类对象,还是子类对象

③、 decltype:可以推导一个对象的类型