C风格的强制转换(Type Cast)容易理解,不管什么类型的转换都可以使用使用下面的方式。
Type a = (NewType)b;
当然,C++也是支持C风格的强制转换,但是C风格的强制转换可能带来一些隐患,让一些问题难以察觉。所以C++提供了一组可以用在不同场合的强制转换的函数。
在C++中,我们可以使用四种强制类型转换操作符来进行类型转换。
1. 静态转换(static_cast): 静态转换是最常用的强制类型转换方式,用于一般类型的隐式转换。它可以用于类层次结构中基类和派生类之间的相互转换,也可以用于不同类型之间的转换(例如数字类型之间的转换)。
- 用于类层次结构中基类(父类)和派生类(子类)之间指针或引用的转换。不管是否发生多态,父子之间互转时,编译器都不会报错。
进行上行转换(把派生类的指针或引用转换成基类表示)是安全的;
进行下行转换(把基类指针或引用转换成派生类表示)时,由于没有动态类型检查,所以是不安全的,但是编译器不会报错。
- 用于基本数据类型之间的转换,如把int转换成char,把int转换成enum。这种转换的安全性也要开发人员来保证。
- 把空指针转换成目标类型的空指针。
- 把任何指针类型转换成空指针类型。
- 可以对普通数据的const和non_const进行转换,但不能对普通数据取地址后的指针进行const添加和消去。
- 无继承关系的自定义类型,不可转换,不支持类间交叉转换。
代码示例:
int num1 = 10;
double num2 = static_cast<double>(num1); // 将int类型num1转换为double类型
2. 动态转换(dynamic_cast): 动态转换主要用于类层次结构中基类和派生类之间的转换。它在运行时检查转换的有效性,如果无效则返回null指针(对于指针类型)或抛出std::bad_cast异常(对于引用类型)。
动态转换的类型和操作数必须是完整类类型或空指针、空引用,只能用于类间转换,支持类间交叉转换,不能操作普通数据。
主要用于类层次结构中基类(父类)和派生类(子类)之间指针或引用的转换,
- 进行上行转换(把派生类的指针或引用转换成基类表示)是安全的,允许转换;
- 进行下行转换(把基类指针或引用转换成派生类表示)时,由于没有动态类型检查,所以是不安全的,不允许转化,编译器会报错;
- 发生多态时,允许互相转换。
- 无继承关系的类之间也可以相互转换,类之间的交叉转换。
- 如果dynamic_cast语句的转换目标是指针类型并且失败了,则结果为0。如果转换目标是引用类型并且失败了,则dynamic_cast运算符将抛出一个std::bad_cast异常
代码示例:
class Animal { ... };
class Dog : public Animal { ... };
Animal* animalPtr = new Dog();
Dog* dogPtr = dynamic_cast<Dog*>(animalPtr); // 将基类指针转换为派生类指针
3. (reinterpret_cast): reinterpret_cast可以将一个指针转换为任意其他类型的指针,也可以将一个整数类型转换为任意其他类型的指针。这种转换是非常危险的,因为它完全依赖于底层的硬件和编译器的实现。 代码示例:
int* numPtr = new int(10);
char* charPtr = reinterpret_cast<char*>(numPtr); // 将int指针转换为char指针
4. 常量转换(const_cast): 常量转换主要用于去除指针或引用的const属性,或者用于添加const属性。它在进行类型转换时并不会进行运行时检查。 const_cast用于强制去掉不能被修改的常数特性,其去除常量性的对象一般为指针或引用。
用法:const_cast<new type>(exp)
该运算符用来修改类型的const或volatile属性。除了const 或volatile修饰之外, new_type和expression的类型是一样的。
常量指针被转化成非常量指针,并且仍然指向原来的对象;
常量引用被转换成非常量引用,并且仍然指向原来的对象。
代码示例:
const int num = 10;
int* mutableNumPtr = const_cast<int*>(&num); // 去除指针的const属性
*mutableNumPtr = 20; // 修改num的值
PS:需要注意的是,在进行类型转换时要尽量避免使用reinterpret_cast,因为它的安全性较低并且不可移植。始终确保转换的合法性,并在可能的情况下优先选择静态转换和动态转换。