在C语言中,只有强制类型转换
int i = 1;
double j = 1.1;
int a = (int)j;
double b = (double)i;
这种方式简单粗暴,并且不安全,因此,C++提供了四种类型转换操作符
static_cast
在编译期进行转换,不成功则报错,成本较低。
static_cast可以完全代替C风格的类型转换,实现基本类型转换。在对象指针之间进行转换时,可以将父类指针转换成子类指针,也可以将子类指针转换成父类指针,但是如果两个类是不相关的,则无法完成转换。
需要注意的是,如果父类指针指向一个父类对象,此时将父类指针转换成子类指针虽然可以通过static_cast实现,但是这种转换很可能是不安全的;如果父类指针本身就指向一个子类对象,则不存在安全问题。
class Base{};
class Derived :public Base {};
Base* b1 = new Base;
Base* b2 = new Derived;
Derived* d1 = static_cast<Derived*>(b1); //转换成功(不安全)
Derived* d2 = static_cast<Derived*>(b2); //转换成功(安全)
int i = 1;
double d = 1.5;
int a = static_cast<int>(d);
double b = static_cast<double>(i);
dynamic_cast
在运行期进行转换,成本较高。实际开发中用得最多的一种转换,需要重点关注。
dynamic_cast只能用于对象指针之间的类型转换,可以将父类指针转换为子类指针,也可以将子类指针转换为父类指针,此外转换结果可以是引用,但是dynamic_cast并不等同于static_cast。
将子类转换成父类总会转换成功。
dynamic_cast在将父类指针转换为子类指针的过程中,需要对其背后的对象类型进行检查以保证类型完全匹配,而static_cast不会这样做。只有当父类指针指向一个子类对象,并且父类中包含虚函数时,使用dynamic_cast将父类指针转换成子类指针才会成功,否则返回空指针,如果是引用则抛出异常。
class Base { virtual void func() {} };
class Derived :public Base {};
Base* b1 = new Base;
Base* b2 = new Derived;
Derived* d1 = dynamic_cast<Derived*>(b1); //转换成功,返回NULL
Derived* d2 = dynamic_cast<Derived*>(b2); //转换成功
Derived& d3 = dynamic_cast<Derived&>(*b1); //转换失败,抛出异常
Derived& d4 = dynamic_cast<Derived&>(*b2); //转换成功
const_cast
const_cast可以在转换过程中增加或删除const属性,一般情况下,无法将常量指针直接赋值给普通指针,但是可以通过const_cast移除常量指针的const属性,实现const指针到非const指针的转换。
class Test {};
const Test* t1 = new Test;
Test* t2 = const_cast<Test*>(t1); //转换成功
reinterpret_cast
reinterpret_cast可以将一种类型的指针直接转换为另一种类型的指针,不论两个类型之间是否有继承关系,此外reinterpret_cast可以把一个指针转换为一个整数,也可以把一个证书转换成一个指针,reinterpret_cast还经常用在不同函数指针之间的转换。
class A {};
class B {};
A* a = new A;
B* b = reinterpret_cast<B*>(a); //转换成功