在这四种类型转换符包括static_cast、dynamic_cast、reinterpret_cast、const_cast
其中使用比较多的是dynamic_cast
和static_cast
。我们就从这两种类型转换符开始谈起。
一、static_cast
该类型转换符主要应用于普通数据类型和具有继承关系的类的指针和引用的转换,不能进行两个完全不相干的类型或者两个不同类型指针或引用的转换。
int * ptr_a = &a;
double* ptr_db = &bd;
//编译器报错
double* test = static_cast<double*>(ptr_a);
普通类型的数据之间进行转换,有可能转换后的数据会将原本的数据截断,导致数据不完全,这就要程序员自己去发现这种风险,编译器不会报错。
而对于具有继承关系类指针和引用的转换需要注意几点:
- 使用
static_cast
向上转换,即将派生类指针、引用转换成基类的指针或者引用是安全的,以为派生类始终包含着基类。 - 使用
static_cast
向下转换是不安全的,但是编译器是允许的,不进行错误检查。之所以不安全是因为不能确保转换后的指针和引用确实是指向一个派生类对象的。有可能这个指针和引用实际指向的就是基类对象,强制转换成指向派生类的对象后,这个指针或引用也不具备派生的数据和成员,也不能调用派生类的方法。(转换后指针包含的增加的内存存储的东西是未知的),dynamic_cast
在继承关系的类指针引用转换的时候就会进行安全检查。
二、dynamic_cast
dynamic_cast
最主要的作用就是将基类指针引用转换成派生类指针引用去调用专属于派生类的非虚方法,或者是专有的虚方法。
dynamic_cast
只能用于具有继承关系的类的指针和引用的转换。
- 当向上转换时,是完全安全的。
- 在向下转换时(必须确保具有多态继承关系,即基类必须具有虚函数),且要确保被转换的指针或者引用确实是指向一个被转换类型的对象。
首先考察继承关系的类之间没有多态关系:
class Base {
public:
};
class Derived:public Base {
};
int main() {
Base a;
Derived d;
Base* ptr1 = &a;
Base* ptr2 = &d;
Derived* ptr3 = &d;
Base& ref = d;
Base& ref2 = d;
Derived& ref3 = d;
Base* temp = dynamic_cast<Base*> (&d);//向上转换,安全
//不具备多态类继承关系,也就是基类并没有虚函数,将基类指针
//转换成派生类指针是没有意义的
Derived* temp2 = dynamic_cast<Derived*> (ptr2);
Derived& temp3 = dynamic_cast<Derived&>(ref2);
//将基类中增加一个虚函数dynamic_cast就不会报错了,
//因为别转换的类型具备多态属性了
}
上述结论表明:dynamic_cast
是要进行运行时安全检查的,将不具备多态继承关系的基类指针或引用向下转换成派生类指针或引用,dynamic_cast
会报错,表明它向下转换的类型必须具有多态属性。
在来考察基类和派生类具有多态属性的情况:
class Base {
public:
virtual void test(){}
};
class Derived:public Base {
void test(){}
};
class Derived2 :public Base {
};
int main() {
Base a;
Derived d;
Base* ptr1 = &a;
Base* ptr2 = &d;
Derived* ptr3 = &d;
Base& ref = d;
Base& ref2 = d;
Derived& ref3 = d;
Base* temp = dynamic_cast<Base*> (ptr3);
//这两句将不会再报错
Derived* temp2 = static_cast<Derived*> (ptr2);
Derived& temp3 = dynamic_cast<Derived&>(ref2);
Derived2* temp4=dynamic_cast<Derived2*>(ptr2);
//这个转换会失败,因为ptr2实际指向的是一个Derived对象
//而不是Derived2对象,这样的转换不安全,编译器
//会报错
}
根据上述情况我们又可以得出结论:dynamic_cast
向下转换,必须转换成被转换指针或引用实际指向的对象的指针或引用才行。
dynamic_cast<type_id>(expression)
中expression实际指向的对象要与type_id指向的对象类型相同
所以、结合上述两点的情况。
dynamic_cast
会执行运行时检错,如果继承类中没有多态属性,则在向上转换时可以使用dynamic_cast
,也可以使用static_cast
,这两个类型转换在向上转换时都是安全的。在向下转换时,则要考虑dynamic_cast
会报错,被转换的指针或引用只想的对象必须具有多态性才能向下转换,而使用static_cast
是不会报错的,但不安全。- 在具有多态属性的继承类中,向上转换都是安全的。但是在向下转换时,如果没有转换到
dynamic_cast<type_id>(expression)
中expression实际指向的类型的指针或引用时,会转换失败,指针的话会返回空指针,引用的话会抛出异常。
三、reinterpret_cast
reinterpret_cast
常用于将两个不相关类型的转换、或是两个指针类型之间的转换、或是整型和指针之间的转换。
这种类型的转换就是重新对内存的存储形式进行改变,例如将整型转换为指针,就是将整型的四个字节重新解释为一个指针, 指向一个内存。
或是将一个指针转换为另外一个指针,对指针指向的内存做重新解释(或是切割,或是增长)。
四、const_cast
主要用于对常指针或常引用来取出const限定符。