对C++中static_cast、dynamic_cast、const_cast和reinterpret_cast作用和相互之间关系、区别的一点理解

以后有新的发现时还会在下面补充。

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://stackoverflow.com/questions/332030/when-should-static-cast-dynamic-cast-const-cast-and-reinterpret-cast-be-used

https://zhuanlan.zhihu.com/p/151744661

https://www.cnblogs.com/ider/archive/2011/07/22/cpp_cast_operator_part2.html

发表评论

您的电子邮箱地址不会被公开。