C++引入了四种更加安全的强制类型转换运算符,分别是const_cast
、static_cast
、reinterpret_cast
和dynamic_cast
,作用和区别如下:
const_cast:
去除const(volatile)属性, 只针对指针、引用和this指针有效,其他情况会报错
示例
int main() { const int a = 0; // int *p = &a; // 这样会报错 int *p = const_cast<int*>(&a); // 去除了 const 属性 // int c = const_cast<int>(a); // 报错,因为只针对指针、引用和this指针有效 return 0; }
static_cast:
用于各种隐式转换例如
void*
转换为任意类型的指针- 任意类型的指针转换为
void*
- 编译器允许的跨类型转换,比如
char
类型转换为int
类型,double
转int
型
static_cast
不做类型检查, 允许子类类型的指针安全转换为父类类型的指针,相反也能转换能成功但是不安全,结果未知,只能在拥有继承关系的类之间进行转换示例
class Base { }; class Derived : public Base { }; int main() { Derived* d = new Derived(); Base* b = static_cast<Base*>(d); // 子类转换为父类, 是安全的 Base* b1 = new Base(); Derived* d1 = static_cast<Derived*>(b1); // 父类转换为子类,不安全 return 0; }
dynamic_cast:
动态类型转换,只能用于含有虚函数的类, 不然会报错,
dynamic_cast
会做类型检查, 检测在运行时进行。如果是非法的,对于指针返回NULL,对于引用抛bad_cast异常。将子类类型的指针转换为父类类型的指针与static_cast
是一样的示例
class Base { virtual void dummy() {} // 如果没有虚函数dynamic_cast会编译报错}; class Derived : public Base {}; int main() { //指针 Base* b1 = new Derived; Base* b2 = new Base; Derived* d1 = dynamic_cast<Derived *>(b1); // 成功 Derived* d2 = dynamic_cast<Derived *>(b2); // 失败返回空指针 //引用 Base& b3 = *b1; Base& b4 = *b2; try { Derived& d3 = dynamic_cast<Derived&>(b3); // 成功 Derived& d4 = dynamic_cast<Derived&>(b4); // 失败抛出异常 } catch (bad_cast& e) { cout << e.what() << endl; } }
reinterpret_cast
就像传统的强制类型转换一样对待所有指针的类型转换。几乎什么都可以转,比如将int转指针,可能会出问题, 它不进行检查,只是进行强制的复制
示例
int main() { int a = 10; int* p = &a; int* c = reinterpret_cast<int*>(a); // 可以把整数转成指针 char* p1 = reinterpret_cast<char*>(p); // 可以把指针转成另一种指针 }
相比于 c 的强制类型转换的优点
- 语义更加明确,类型转换更容易在代码里被发现。
- C++编译器在编译阶段就会针对错误的转换报错,而C风格不会
- C 的强制转换表面上看起来功能强大什么都能转,但是转化语义不够明确,不能进行错误检查,容易出错。