C语言中,类型强转一般就是这样:
int a = (int)b;//把右边的类型强转成左边的类型,不安全,根据强转的类型造成内存大小会扩大的可能,访问不安全
const_cast : 去掉(指针或者引用)常量属性的一个类型转换 static_cast : 提供编译器认为安全的类型转换(没有任何联系的类型之间的转换就被否定了,就编译不通过) reinterpret_cast : 类似于C风格的强制类型转换,谈不上什么安全 dynamic_cast : 主要用在继承结构中,可以支持RTTI类型识别的上下转换
去掉(指针或者引用)常量属性的一个类型转换
可以看成模板。
底层的汇编指令是一模一样的。
但是在转换变成汇编指令之前,编译阶段,就有所不同了。
编译是没有问题的。
但是如果是这样:
C++中把一个整型常量的地址转成一个指针类型不匹配的另一个类型的指针。
编译报错了。
const_cast在进行类型强转的时候,地址a的类型是和左边的类型和<>里面的去掉常量的类型是要保持一致的
这样const_cast才能答应
强转,是语言级别的,不产生任何额外的指令代码,这两句在汇编指令上没有区别。
我们再举一个例子:
提供编译器认为安全的类型转换(没有任何联系的类型之间的转换就被否定了,就编译不通过)
int和char是有关联有联系的,所以转换没问题。
但是
这2个指针之间是没有任何联系的,就被否决了。
如果说让你转成功了,double类型的指针b指向了一个整型的内存,这个b一解引用,就是8个字节的内存,而实际上只有4个字节的整数内存,不安全。
C底层的类型强转不管你类型之间有没有联系
因为基类类型和派生类类型是继承结构上从上到下的类型。
类型强转的时候,它们类型之间是有关系联系的。
static_cast可以通过它们之间的互相转换,但是转换之后,代码到底安不安全是由开发者来保证,而不是由static_cast保证。
reinterpret_cast : 类似于C风格的强制类型转换,就是随意转了,没有任何安全可言
指针解引用8个字节,而原本内存只有4字节,造成了不安全。
主要用在继承结构中,可以支持RTTI类型识别的上下转换
但是,有可能,随着项目的进行,软件开发的需求改变了,我们要增加新的需求:
class Base//抽象类 { public: virtual void func() = 0; }; class Derive1 : public Base { public: void func() { cout << "call Derive1::func" << endl; } }; class Derive2 : public Base { public: void func() { cout << "call Derive2::func" << endl; } //Derive2实现新功能的API接口函数 void derive02func() { cout << "call Derive2::derive02func" << endl; } };
那么在下面这个函数,要进行判断:
如果指向的是其他派生类的对象,那么调用这个func就可以了,但是,如果指向的是Derive2这个对象,就不要调用这个func方法,应该调用derive02func这个方法。
我们现在的软件设计就要去实现这个功能。我们有什么办法呢?
现在就要识别*p的类型,到底指向的是哪个对象,如果是Derive这个对象, 就要重新调用函数
1、我们可以通过typeid(*p).name() == "Derive"比较,判断类型
p指针是Base类型的指针,Base里面是虚函数,识别的是运行时的动态绑定,就是指针指向的对象,进而访问其虚函数表,取的是RTTI的类型。
2、但是我们现在是用dynamic_cast进行RTTI类型的转换
class Base//抽象类 { public: virtual void func() = 0; }; class Derive1 : public Base { public: void func() { cout << "call Derive1::func" << endl; } }; class Derive2 : public Base { public: void func() { cout << "call Derive2::func" << endl; } //Derive2实现新功能的API接口函数 void derive02func() { cout << "call Derive2::derive02func" << endl; } }; /* typeid(*p).name() == "Derive" */ void showFunc(Base *p) { //dynamic_cast会检查p指针是否指向的是一个Derive2类型的对象? //通过p访问->vfptr访问->vftable RTTI信息 如果是,dynamic_cast转换类型成功, //返回Derive2对象的地址,给pd2;否则返回nullptr //static_cast是编译时期的类型转换 dynamic_cast是运行时期的类型转换,是支持RTTI信息识别的 Derive2 *pd2 = dynamic_cast<Derive2*>(p); if (pd2 != nullptr) { pd2->derive02func(); } else { p->func();//动态绑定 *p的类型 Derive2 derive02func } } int main() { Derive1 d1; Derive2 d2; showFunc(&d1); showFunc(&d2); return 0; }
使用static_cast也是可以类型转换成功的,因为Base和Derive是有关联的,有继承关系,但是是永远都可以转换成功,所以无法识别出Derive2,看起来是Derive2对象了,实际上有可能是其他派生类对象,这就非常不安全了。