第一章 基础议题
2.最好使用C++转型操作符
1.static_cast
static_cast基本上拥有与C旧式转换相同的威力与意义,以及相同的限制
,它是与C-style最接近的一个转换;
使用情况概述:通常是数值数据类型转换(比如float->int);不执行运行时类型检查(安全性不如dynamic_cast);能用于多态向上转换
,向下则不一定能保证真确;
补充:任何编写程序时能够明确的类型转换都可以使用static_cast(static_cast不能转换掉底层const,volatile和__unaligned属性)。由于不提供运行时的检查,所以叫static_cast
,因此,需要在编写程序时确认转换的安全性。
2.const_cast
const_cast用于改变表达式中的常量性(const)或易变性(volatile),以及__unaligned属性。
使用情况概述:最常用的是将const转换为非const;当然它其实还能去掉volatile性质
、改变__unaligned的心性质;
疑问:旧式的C转换如何做到const_cast同样效果呢?
3.dynamic_cast
dynamic_cast用于多态的安全向下转型
以及向上转型。
使用情况概述:用于多态类型向上/向下转型;会执行运行时检查;
4.reinterpret_cast
reinterpret_cast就是bit的简单重新解释
,几乎什么都可以转。
使用情况概述:尽量少使用
注:static_cast与const_cast的区别
在多重继承上可以体现二者的区别:
class A {
public:
int m_a;
};
class B {
public:
int m_b;
};
class C : public A, public B {};
int main(){
C c;
printf("%p, %p, %p", &c, reinterpret_cast<B*>(&c), static_cast <B*>(&c));
}
//打印结果: 0x7fff17de3820, 0x7fff17de3820, 0x7fff17de3824
C++通过指针来访问成员的过程,实际上是根据指针的类型,找到改类定义,并从中找到要访问的成员的地址偏移,然后从对象指针开始加上偏移,便得到了成员的地址,然后进行访问操作。所以类定义的作用之一在于,确定成员的内存偏移。
static_cast会在编译期将指针在类的内存空间内移动,并最终指向到你转换到的内存上
。在上面的例子中,当将C的指针转型为B型指针时,实际上将指针的数值修改了,指向了内存中B类的开头位置。当使用转换后的指针访问B的成员时,先到B类定义查到B的内存分布,然后进行指针便宜,访问。一切都是正确的。
reinterpret_cast并不会在转型是修改指针的值,而是告诉编译器,这个指针是某个类型的指针,仅此而已
。所以当使用此转型方式转换C的指针到B类型时,指针仍然指向原来的位置,即C的开头,也是A的开头。这时如果访问B*的成员m_b,那么先到B上查到m_b的地址偏移为一个整型的字节大小(一般是4),那么你实际是将指针偏移到了A类的m_a成员处,访问的是m_a的内容。这种错误是编译器不明白的,你的程序即将崩溃。