C++的显示类型转换和隐式类型转换
显示类型转换包括静态转换(static_cast)、动态转换(dynamic_cast)、常量转换(const_cast)、重新解释转换(reinterpret_cast)
1.静态转换(static_cast)
1.1一句话说清
static_cast 是 C++ 最常用、最安全、编译期完成的类型转换运算符,用于合法的、有意义的类型转换。
它是编译期检查,不会做运行时检查,比 C 语言强转 (type)val 更安全。
1.2 能做什么(最常用场景)
1.2.1 基本数据类型转换
int a = 10;
double b = static_cast<double>(a); // int → double
1.2.2 有继承关系的 向上转型(安全)
派生类 → 基类(指针 / 引用)
Derived* d = new Derived();
Base* b = static_cast<Base*>(d); // ✅ 安全
1.2.3 空指针转换
void* p = nullptr;
int* q = static_cast<int*>(p);
1.2.4 显式调用单参数构造函数 / 转换函数
string s = static_cast<string>("hello");
1.2.5 把表达式转为右值(配合移动语义)
int a = 10;
int&& b = static_cast<int&&>(a);
1.3 不能做什么(绝对不行)
1.3.1 不能用于 向下转型(不安全)
基类 → 派生类,static_cast 不检查是否真的是该对象
Base* b = new Base();
Derived* d = static_cast<Derived*>(b); // ❌ 编译过,但运行会炸
👉 向下转型必须用 dynamic_cast
1.3.2 不能去掉 const
const int a = 10;
int* p = static_cast<int*>(&a); // ❌ 编译错误
👉 去 const 必须用 const_cast
1.3.3 无关类型之间强转
int* p = static_cast<int*>(100); // ❌ 错误
👉 这种底层强转要用 reinterpret_cast
1.4 核心特点(必须记住)
- 编译期转换,没有运行时开销
- 只允许合法、有意义的转换
- 向上转型(派生→基类)非常安全
- 比 C 风格强转 (type) 更安全、更清晰
- 不能做动态检查、不能去 const、不能乱转指针
1.5 和其他转换的区别(超级好记)
| 转换 | 用途 |
|---|---|
| static_cast | 正常、安全、编译期转换 |
| dynamic_cast | 继承类向下转型(运行时检查) |
| const_cast | 去掉 / 添加 const |
| reinterpret_cast | 底层二进制强转(危险) |
1.6 最简单记忆口诀
- static_cast 最安全,
- 基本类型继承转
- 不能去 const 不能乱转
- 向下转型别用它
2.动态转换(dynamic_cast)
2.1 基本作用
dynamic_cast 是 C++ 专门用于多态类型转换的运算符,主要做:
- 基类指针 / 引用 → 派生类指针 / 引用(向下转型)
- 也可以做横向转换(同一继承树内的兄弟类)
它是唯一一个在运行时做检查的类型转换。
2.2 核心前提(必须满足)
要使用 dynamic_cast,基类必须包含至少一个虚函数(要有虚表、支持多态),否则编译报错。
2.3 两种用法 & 结果
2.3.1 指针转换
Base* base_ptr = new Derived();// 尝试转成 Derived*
Derived* der_ptr = dynamic_cast<Derived*>(base_ptr);
- 转换成功:返回有效指针
- 转换失败:返回
nullptr
2.3.2 引用转换
Base& base_ref = derived_obj;
Derived& der_ref = dynamic_cast<Derived&>(base_ref);
- 成功:返回派生类引用
- 失败:抛出
std::bad_cast异常
引用没有 “空引用”,所以失败只能抛异常。
2.4 安全 vs 不安全
-
static_cast 向下转型:
不检查,直接强转,错了也不知道 → 不安全
-
dynamic_cast 向下转型:
运行时查真实类型 → 安全
2.5 适用场景
- 你拿到一个基类指针 / 引用,但不确定它实际指向哪个子类
- 需要调用只有子类才有的成员函数
- 框架、插件、多态对象管理中大量使用
2.6 典型示例
class Base {
public:virtual ~Base() {} // 必须有虚函数
};class Derived : public Base {};int main() {Base* b = new Derived;Derived* d = dynamic_cast<Derived*>(b);if (d) {// 转换成功} else {// 不是 Derived 类型}
}
2.7 一句话总结
- dynamic_cast = 运行时安全向下转型
- 必须有多态(虚函数)
- 指针失败返回 nullptr,引用失败抛异常
3.常量转换(const_cast)
3.1 作用只有一个
用于增加或去除指针 / 引用上的 const、volatile 限定
它不能改变类型,只能改 “常量性”。
3.2 只能用于
- 指针
- 引用
- 指向对象的成员指针
不能用于普通变量。
3.3 最常见用法:去掉 const
const int a = 10;
const int* p = &a;// 去掉 const
int* q = const_cast<int*>(p);
void func(const int& x) {// 内部需要修改时int& m = const_cast<int&>(x);
}
3.4 也可以增加 const
int x = 10;
int* p = &x;const int* q = const_cast<const int*>(p);
3.5 重要危险规则
- const_cast 本身是安全的
- 但修改原本就是 const 的对象是未定义行为
const int a = 10;
int* p = const_cast<int*>(&a);
*p = 20; // ❌ 未定义行为!可能崩溃、可能不变
只有原本不是 const 的对象,去掉 const 再修改才安全:
int x = 10;
const int* pc = &x;
int* p = const_cast<int*>(pc);
*p = 20; // ✅ 安全
3.6 一句话记忆
const_cast 只改常量性,不改类型;
能加能去 const,只对指针引用;
改真 const 对象 = 未定义行为。
4.重新解释转换(reinterpret_cast)
reinterpret_cast = 重新解释二进制内存
它不做任何计算、不检查、不转换值,只把一段内存强行当成另一种类型看。
4.1 一句话核心
- 最暴力、最危险、最接近 C 语言强转
(type) - 只改变编译器怎么看待这段内存,不改变内存本身
- 用于底层、系统、硬件、网络、指针地址操作
4.2 典型用法
① 无关指针类型互转
int a = 0x12345678;
int* p = &a;// 把 int* 强行看成 char*
char* c = reinterpret_cast<char*>(p);
② 指针 ↔ 整数互转(地址操作)
int x = 10;
// 指针 → 整数(地址值)
uint64_t addr = reinterpret_cast<uint64_t>(&x);// 整数 → 指针
int* q = reinterpret_cast<int*>(addr);
③ 函数指针强转
void (*fp)() = nullptr;
// 强行看成另一种函数指针
using Func = int(*)(int);
Func f = reinterpret_cast<Func>(fp);
4.3 特点(必须记住)
- 编译期完成,无运行时开销
- 几乎不做安全检查,转错就炸
- 不修改二进制数据,只改 “解释方式”
- 不可用于:
- 直接转普通数值(如 int→double)
- 去掉 const(必须用 const_cast)
4.4 适用场景(正经用途)
- 操作系统、驱动、嵌入式开发
- 网络协议解析(字节流转结构体)
- 内存布局操作、hook、注入
- 与 C 接口、硬件寄存器交互
日常业务代码几乎不应该用。
4.5 一句话记忆
reinterpret_cast 不转值,只改内存解释;
指针随便转,地址转整数;
高效但危险,只用于底层。
