文章目录
C语言中的强制类型转换通常不安全,根据强转的类型造成变量内存扩大或缩小,访问不安全
- const_cast : 去掉(指针或者引用)const属性的一个类型转换,只能转换指针或引用类型
- static_cast : 提供编译器认为安全的类型转换(没有任何联系的类型之间的转换无法通过编译)
- reinterpret_cast : 类似于C风格的强制类型转换,谈不上什么安全
- dynamic_cast : 主要用在继承结构中,可以支持RTTI类型识别的上下转换。基类指针转成相应的派生类对象指针的时候,会识别该指针是否能够进行转换
一、const_cast
首先写一段代码,将const int*
转换为int*
我们来看一下汇编指令
可以看到,由于const_cast是语言级别的,不产生任何额外的指令代码,这两句在汇编指令上没有区别,两行代码转换的汇编指令是完全一样的,但是在编译阶段会有所差别我们再看,这时我们直接将const int*
转换为double*
,p1指向的内存空间是const int a的空间,但是p1解引用后访问的范围是4字节,这就不安全了,然而编译依然通过
我们使用const_cast将const int*
转换为char*
试试
这就不被允许了,因为指针解引用后范文的范围和指针指向的变量不一致,这会不安全
只要是指针访问的范围和实际指向的变量空间不一致,就不允许转换再举一个例子:
const_cast的参数必须是指针或引用类型
二、static_cast
static_cast静态类型转换应该是我们用的最多的,提供编译器认为安全的类型转换,没有任何联系的类型之间的转换就被否定了,编译不通过
这样转换是没有问题的,因为int和char是有联系的,在ASCII码表中97对应字符a我们试试将int*
转换为double*
编译不通过,因为int*
和double*
是没有任何联系的,所以static_cast不允许转换。如果static_cast允许转换了,指针访问的范围就变了,用指向8字节空间的指针访问4字节内存,会导致内存访问不安全
而我们用C风格的写法,是可以编译通过的
此外,static_cast还支持基类和派生类类型的转换,因为基类类型和派生类类型是继承结构上从上到下的类型,它们类型之间是有关系联系的
static_cast可以通过它们之间的互相转换,但是转换之后,代码到底安不安全是由开发者来保证,而不是由static_cast保证。
使用static_cast:
- 有联系的类型之间可以互相转换
- 没有任何联系的类型之间无法转换
- 基类类型与派生类类型进行转换,可以用static_cast,它们类型之间有关系,但不一定安全
三、reinterpret_cast
类似于C风格的强制类型转换,和内存访问安全就没有什么关系了
编译通过,但使用起来不安全
四、dynamic_cast
Base里面是虚函数,是运行时的动态绑定,取的是RTTI的类型,就是指针指向的对象,进而访问其虚函数表,执行派生类的同名覆盖方法
但是随着项目的进行,软件开发的需求改变了,我们要增加新的需求:如果Base指针指向其他的Derive对象,就调用func方法,如果指向Derive2对象,就调用new_func方法
如果现在的软件设计就要去实现这个功能,我们应该怎么做?
现在需要识别*p
的类型,到底指向的是哪个对象,如果是Derive2的对象, 就要调用new_func方法
我们可以通过typeid(*p).name() == "Derive2"
比较,判断p指向的对象,进而调用不同的函数,dynamic_cast就是通过这种方式进行RTTI类型的转换
使用static_cast,是编译时期的类型转换,不会判断运行时期的RTTI类型,由于这是上下继承关系,是一定可以转换成功的,这就导致我们无法判断Base指针指向的到底是哪个派生类对象
这种写法是肯定可以转换成功的,所以pd2不为空,无论Base指针导致指向的是哪个派生类对象,最后调用的肯定是Derive2::new_func。然而第一次调用showFunc传入的是Derive1对象的地址,还是调用了Derive2::new_func,这就很不安全