C++大体上有两种风格的类型转换,显式类型转换和隐式类型转换,而显式类型转换又分为两种,一种C风格的强制类型转换,另外一种使用类型转换运算符进行类型转换。
一、隐式类型转换
隐式类型转换通常出现在以下几种情况:
1.在不同类型的运算操作中
int intNum = 1;
double douNum = 1.1;
double addSum = intNum + douNum; //intNum类型被隐式提升为double类型
2.C++中内置的数据类型之间存在默认的隐式转换,例如char、int、short等;
3.在对象之间存在隐式的类型转换,此时可以通过explicit(只对构造函数起作用)关键字进行声明,以阻止不应该允许的构造函数的隐式类型转换。
二、C风格类型转换
1.示例 (T)expression T(expression)
int intNum = (int)douNum;
注:这可能造成数据丢失,同时C风格的的类型转换在程序中查找起来十分的困难
三、运算符类型转换
1.reinterpret_cast 低级转型,不可移植
该运算符的用法比较多。主要作用为重新解释类型,并不进行二进制的转换:
应用场景:
1)转换的类型必须是一个指针、引用、算术类型、函数指针或者成员指针,可用于任何指针向任何指针的转换,也可以用于将指针类型和整型类型相互转换,把一个指针转换成一个整数,把一个整数转换成一个指针
2)它不进行类型检查。reinterpret_cast转换是在类C转换的基础上,在编译期间约束了整型、浮点型和枚举类型的相互转换。
2.const_cast 常量性转除
该运算符只是负责给变量增加或者删除一些属性,以保证编译器可以编过。
应用场景:
1)常量指针被转化成非常量指针,并且仍然指向原来的对象;
2)常量引用被转换成非常量引用,并且仍然指向原来的对象;
3)常量对象被转换成非常量对象。
3.static_cast 强迫隐式转换
该运算符约束了指针和整型、无关系类型的指针以及具有继承关系的类之间的相互转换关系。
应用场景:
1)它用于在存在继承关系的类指针之间转换,用于类层次结构中基类和子类之间指针或引用的转换。
进行上行转换(把子类的指针或引用转换成基类表示)是安全的;
进行下行转换(把基类指针或引用转换成子类表示)时,由于没有动态类型检查,所以是不安全的;
2)可以用于基本数据类型之间的转换,如把int转换成char,把int转换成enum;
3)把空指针转换成目标类型的空指针;
4)它可以将void*型向任意指针类型转换,也可以把任何类型的表达式转换成void类型。
4.dynamic_cast
该运算符在底层并不像上面那几种转换运算符是使用简单的内存拷贝,而是使用了RTTI(运行时类型检查)技术,所以它要求操作的指针是多态的,否则每个转换操作都是失败的,返回Null。
应用场景:(必须要有虚函数)
1)只可以用于指针之间的转换,它还可以将任何类型指针转为无类型指针,甚至可以在两个无关系的类指针之间转换;
2)主要用于类层次间的上行转换和下行转换,还可以用于类之间的交叉转换。
3)在进行下行转换时,dynamic_cast具有类型检查的功能,比static_cast更安全。有条件转换,动态类型转换,运行时类型安全检查(转换失败返回NULL)。
dynamic_cast 最不安全,并且效率很慢,通常应用的场景是通过基类转换成派生类,来执行派生类特有的功能,替代方法
1)使用容器并在其中存储直接指向派生类对象的指针;
2)在基类内提供 virtual 函数做你想对各种派生类做的事。
应避免连串的dynamic_cast代码,见书《Effection C++ 中文版, 第三版》 中 122页.
5.qobject_cast (Qt 特有的)
T qobject_cast ( QObject * object )qobject_cast 函数原型。
本方法返回object向下的转型T,如果转型不成功则返回0,如果传入的object本身就是0则返回0。
应用场景:
1)QObject 及其派生类,且定义时使用了Q_OBJECT;
2)Q_DECLARE_INTERFACE 声明的接口类。
四、总结
1)reinterpret_cast主要用于不同类型的指针进行转换;
2)const_cast主要用于去const属性;
3)static_cast主要用于基础数据类型的转换,子类转基类;
4)dynamic_cast主要用于多态类之间的相互转换,基类转子类;
5)qobject_cast主要用于在槽中进行控件类型的转换。