以后有新的发现时还会在下面补充。
static_cast
- 任何public的非虚继承关系链上的类型转换,上下行转换均支持。但程序不对下行转换做完整性检查,这是很危险的,因此通常只使用上行转换。
- 可以完成任何隐式类型转换,可以在有歧义的时候为编译器指明语义;
- 可以完成显式类型转换,此时会显式调用已定义的构造函数、类型转换重载操作符函数等。它可以替代
(Type)var这种写法。事实上,这种C风格的强制类型转换本质上就是先使用static_cast,在发现该途径不可行时则使用reinterpret_cast,然而后者一般会导致意料之外的后果,所以直接使用static_cast来规避潜在的风险;
dynamic_cast
- 仅能进行类的指针或引用的转换(通用指针类型
void*除外); - 仅能用于public继承方式的基类和子类间的转换,否则会导致封装性的破坏。当然
static_cast也是如此; - 一般只用于虚基类到派生类的下行转换,因为上行转换本身是安全的,可以使用
static_cast,它的开销较小。
const_cast
- 可以为一个变量添加或移除
const属性; - 如果要让一个常量对象调用非
const成员函数,但我们确实能保证这个成员函数没有修改对象的属性,那么用const_cast解除限制。但如果该接口是自己写的,最好为成员函数添加const属性; - 如果要向一个函数的非
const参数传入const类型的变量(一般都是引用或指针),但我们确实能保证这个函数没有修改非const对象的属性,那么用const_cast解除限制。但如果该接口是自己写的,最好为参数添加const属性; - 如果想要修改一个
const变量的属性,且能确保该变量指向的对象最初被分配内存时是非const的,那可以把它转换成非const指针或引用然后修改,否则会导致未定义行为。一般来说,非得改变一个常量实在是不合适;但如果需要以非常复杂的逻辑初始化某对象的const成员变量,以至于不能在初始化列表中完成,可以单独把这部分逻辑抽出来放到一个静态成员函数中; - 我能想到的以上三条都是对
const属性的移除,均为不好的编码习惯导致的后果;而添加const属性其实不需要由const_cast来完成。所以得出的结论是:const_cast只用于不得不违背语义的场合,例如调用一个不规范的API。
reinterpret_cast
- 对于语句
A *a = reinterpret_cast<A *>(&b),它仅仅简单地把&b指向的内存解释为A类型,因而试图将int*转换为double*不能得到正确的结果; - 但如果确实需要“重新解释”某块内存,例如将数据存储到一个字符型缓冲区并写入二进制文件,此时由于目标类型不是
void*,隐式类型转换会失败,故应当使用reinterpret_cast; - 如在
static_cast中所言,应当避免强制类型转换,但仅在明确知道程序需要做什么时使用reinterpret_cast。
参考资料:
https://zhuanlan.zhihu.com/p/151744661
https://www.cnblogs.com/ider/archive/2011/07/22/cpp_cast_operator_part2.html