1、分类
在C++的编程中,我们常使用的类型转换有以下几种:
C风格或函数风格的强转,比如 int a = (int)d;或 int a = int(d); ,C++的四种类型转换,包括 static_cast,dynamic_cast,const_cast,reinterpret_cast;
2、用途/异同
(1)C风格或函数风格的强转,这种方式几乎允许你将任何类型转换成任何其他类型,使用起来简单粗暴,不能精确的指明转换意图或者说转换方式,安全性和可读性都较差,对于C++代码,不推荐这种转换方式(见More Effecttice C++的第二条准则);
(2)静态类型转换 static_cast,非多态的类型转换,这种转换方式和C风格的强转一样暴力和限制,比如同样无法将一个自定义类型Class转换为int,可以理解为C风格强转的升级版。除了拥有同样暴力的转换能力外,static_cast 还会在编译阶段就做一些检查限制,提高安全性。比如有两个独立的自定义类型A和B,
A * pA = new A;
B * pB1 = (B *)pA; //可以编译通过
B * pB2 = static_cast<B *>(pA); //编译错误
(3)动态类型转换 dynamic_cast,可执行多态的类型转换,这个在C++代码中使用还是比较广泛的,用于继承体系中的类型转换。在有些专业的参考书中解释为“安全的向下转型或跨系转型动作”,简单解释就是可以将指向基类对象的指针或应用转换成子类对象的指针或应用。这种类型转换比较安全,对于指针,转换失败会返回
nullptr,对于引用,转换失败会抛出 exception 异常,所以使用 dynamic_cast 转换时一定要注意,对于指针,需要判定转换结果,对于引用,需要对转换过程进行try--Catch;
(4)去常转换 const_cast,这个没啥可说的,使用此转换可以移除表达式的常量性,使其变为非常量;
(5)重解释类型转换 reinterpret_cast,顾名思义,重新解释对象的类型,比较专业的说法是“为操作数的位模式提供较低层的重新解释,也就是说将数据以二进制存在形式的重新解释。比如当我们需要用一个数组来存储好几种类型的对象时,可以定义数组为void*类型,使用时再用 reinterpret_cast 将其转换为对应的类型。这种转换方式多用于函数指针,因为所定义的函数指针容器一般不会只严格匹配存储一种函数,比如
typedef void(*FUNCPtr)();
FUNCPtr funcPtrArray[10];
上面我们定义了一个函数指针数组,如果我们要存入一个返回类型为 int 的函数,比如 int playGame() 就需要先使用重解释类型转换,否则无法填入数组;
忘了说,由于reinterpret_cast 是对对象进行二进制形式的重新解释,实际动作(及结果)可能取决于编译器,所以此转换类型不具备可移植性;
3、总结
鉴于C++提供的四种转换类型有着更为严谨的风格,可对应处理不同的转换问题并且有着很好的可辨识性(对机器)和可读性(对人),所以C风格的强制转换一般不推荐使用。static_cast 一般用于基本类型的转换,dynamic_cast 用于继承体系内的转换,const_cast 用于去掉常属性,reinterpret_cast 用于跨类型的转换;