C++ 强制类型转换运算符
将类型名作为强制类型转换运算符的做法是 C 语言的老式做法,C++ 为保持兼容而予以保留。
C++ 引入了四种功能不同的强制类型转换运算符以进行强制类型转换:static_cast、reinterpret_cast、const_cast 和 dynamic_cast。
强制类型转换是有一定风险的,有的转换并不一定安全,如把整型数值转换成指针,把基类指针转换成派生类指针,把一种函数指针转换成另一种函数指针,把常量指针转换成非常量指针等。
C++ 强制类型转换运算符的用法如下:
1 | |
例如:
1 | |
一、static_cast
这是最常用的转换,用于“逻辑上相关的类型转换”。
- 特点:
- 用于基本数据类型转换(如
int转double) - 用于类层次结构中,将派生类指针/引用转换为基类指针/引用(向上转型,安全)
- 将基类指针转换为派生类指针(向下转型,不安全,因为不检查运行时类型)
- 将
void*转回具体的指针类型 - 没有运行时类型检查,如果转换不合理,结果通常是未定义行为
- 用于基本数据类型转换(如
1 | |
二、reinterpret_cast
这是“重新解释”位模式的转换,最危险且不可移植。reinterpret_cast 用于进行各种不同类型的指针之间、不同类型的引用之间以及指针和能容纳指针的整数类型之间的转换。转换时,执行的是逐个比特复制的操作。
- 特点:
- 它不进行任何值的转换,只是告诉编译器将这块内存空间看作另一种类型
- 常用于指针与整数之间的转换,或不同指针类型之间的直接强转
- 极易导致内存错误,除非你非常清楚自己在操作底层位数据,否则应尽可能避免使用
1 | |
第 2 行的代码不安全,因为在编译器看来,pa->j 的存放位置就是 n 后面的 4 个字节。 本条语句会向这 4 个字节中写入 500。但这 4 个字节不知道是用来存放什么的,贸然向其中写入可能会导致程序错误甚至崩溃。
上面程序中的各种转换都没有实际意义,只是为了演示 reinteipret_cast 的用法而已。在编写黑客程序、病毒或反病毒程序时,也许会用到这样怪异的转换。
reinterpret_cast 体现了 C++ 语言的设计思想:用户可以做任何操作,但要为自己的行为负责。
三、const_cast
专门用于移除或添加 const 或 volatile 属性。
- 特点:
- 它是唯一可以改变对象
const性质的转换运算符。 - 注意:移除
const后,尝试修改原本声明为const的原始变量是未定义行为。它通常用于调用第三方库中未标记const但实际上不会修改对象的函数。
- 它是唯一可以改变对象
1 | |
四、dynamic_cast
用 reinterpret_cast 可以将多态基类(包含虚函数的基类)的指针强制转换为派生类的指针,但是这种转换不检查安全性,即不检查转换后的指针是否确实指向一个派生类对象。dynamic_cast 专门用于将多态基类的指针或引用强制转换为派生类的指针或引用,而且能够检查转换的安全性。对于不安全的指针转换,转换结果返回 NULL 指针。
dynamic_cast 是通过“运行时类型检查”来保证安全性的。dynamic_cast 不能用于将非多态基类的指针或引用强制转换为派生类的指针或引用——这种转换没法保证安全性,只好用 reinterpret_cast 来完成。
这是唯一具备运行时类型检查的转换,专门用于多态场景。
- 特点:
- 要求目标类型必须是“多态类型”(即基类中至少包含一个虚函数)。
- 如果转换失败(例如向下转型到不正确的派生类):
- 若是指针转换,返回
nullptr。 - 若是引用转换,抛出
std::bad_cast异常。
- 若是指针转换,返回
- 主要用于安全的向下转型。
1 | |