C++中的显式类型转换
| cast 类型 | 用途 | 安全性 | 常用程度 | 学起来一句话总结 |
|---|---|---|---|---|
static_cast |
编译期安全转换 | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ | 能编译过的正常类型转换基本用它 |
reinterpret_cast |
位级别重解释 | ⭐ | ⭐ | 允许你“把东西当成另一种东西看” |
const_cast |
去掉 / 添加 const | ⭐⭐⭐ | ⭐⭐⭐ | 唯一可以丢掉 const 的 cast |
dynamic_cast |
运行时检查 RTTI 的安全向下转型 | ⭐⭐⭐⭐⭐ | ⭐⭐ | 专为多态类型设计 |
1️⃣ static_cast —— 最常用、相对安全的转换
✔ 用途
-
基本类型转换(如 int → double)
-
有继承关系的向上转型(Child* → Parent*)
-
void* → T*(安全的 static 转)
-
调用显式构造函数
✔ 特性
-
编译期检查(不允许危险、不合理转换)
-
不能去 const
-
不能做不相关类型的指针互转(比如 int* → double*)
double d = static_cast<double>(5); // OK
Parent* p = static_cast<Parent*>(child_ptr); // 向上转换安全
void* vp = &d;
double* dp = static_cast<double*>(vp); // OK,static_cast可用于 void*
❌ 错误示例(会编译失败)
int* ip = static_cast<int*>(some_double_ptr); // 不允许,不安全
一句话总结:
能用
static_cast的地方,就不用别的 cast,它最“正统”。
2️⃣ reinterpret_cast —— 最危险但最强的转换
✔ 用途
-
任意指针之间互转(int* → double*)
-
指针 → 整数(uintptr_t) → 指针
-
将一块内存按另一种类型解释(“类型重解释”)
✔ 特性
-
底层二进制不变,只改变解释方式
-
没有安全检查
-
很容易造成未定义行为(UB)
-
多用于:
-
底层系统编程(驱动、内核代码)
-
内存池
-
自己写序列化
-
跨语言 / 跨库的 API
-
int i = 0x11223344;
char* p = reinterpret_cast<char*>(&i); // 获取字节级别内容
long addr = reinterpret_cast<long>(p); // 指针 <-> 整数
❌ 错误风险
double* dp = reinterpret_cast<double*>(p);
double x = *dp; // 未定义行为!因为内存不是 double 布局
一句话总结:
reinterpret_cast 是“霸王硬上弓”,能做任何转换,但你必须保证安全性。
3️⃣ const_cast —— 唯一能修改 const 属性的转换
✔ 用途
-
去掉 const
-
去掉 volatile
-
添加 const(极少用这个)
✔ 特性
-
只能改变对象的 const / volatile 修饰,不改变类型本身
-
必须非常小心:
移除 const 后修改对象 → 未定义行为(UB)
✔ 示例:去掉 const
void f(const int* p) {
int* q = const_cast<int*>(p);
*q = 10; // ⚠ 若 p originally 指向的是 const 对象,UB!
}
所以 const_cast 只有一个真正安全的用途:
当你知道对象原本不是 const,只是接口要求参数是 const 时。
比如 API:
void foo(const int* x) {
int* p = const_cast<int*>(x); // 只要你保证 x 指向的不是 const 对象
}
一句话总结:
const_cast 专门用来处理“去 const”的场景,不做类型转换。
4️⃣ dynamic_cast —— 多态体系中的安全向下转型
✔ 用途
-
子类 / 父类之间安全的类型转换
-
只能用于 带虚函数(有 RTTI) 的类层次结构
✔ 向下转型(Parent → Child)
Parent* p = new Child();
Child* c = dynamic_cast<Child*>(p); // OK
✔ 失败时会返回 nullptr(指针版本)
Parent* p = new Parent();
Child* c = dynamic_cast<Child*>(p); // c == nullptr,安全!
✔ 运行时检查(RTTI)
-
会查对象的实际类型
-
是唯一一个带“运行时成本”的 cast
✔ 引用版本失败会抛异常
Parent& p = Parent();
Child& c = dynamic_cast<Child&>(p); // throws std::bad_cast
一句话总结:
dynamic_cast 是唯一“真正安全”的向下转型方式,用于多态。
重点区分static_cast和reinterpret_cast
🟦 static_cast —— 语义转换,真正变成新的类型
✔ static_cast 会做“逻辑正确的”类型转换
-
int → double(改变值,类型变了)
-
Derived* → Base*(安全的向上转型)
-
void* → T*(但你保证原本就是 T)
✔ static_cast 会让变量成为目标类型(有意义的转换)
例如:
int i = 42;
double d = static_cast<double>(i); // d == 42.0
这里:
-
内存重新组织(int → double)
-
表示的数据类型改变
-
语义上是新值
再比如:
Derived* d;
Base* b = static_cast<Base*>(d);
这里:
-
类型系统认可
-
行为可预测
-
对象仍然属于 Derived,只是你看它“是个 Base 指针”
static_cast 永远不会破坏对象布局,是安全的语义转换。
🟥 reinterpret_cast —— 不改变内存,只改变解释方式
✔ 它不会“改变类型”,只是“改变阅读器”
想象你拿一本书(内存):
-
static_cast:把内容按照需求重新排版成新书
-
reinterpret_cast:不改内容,换一副不同的眼镜(把文字当成别的语言看)
int x = 0x11223344;
char* p = reinterpret_cast<char*>(&x);
内存布局:
44 33 22 11 (在小端序机器上)
你只是 用 char 的方式读它的内容*,而不是把 int 转成 char。
再看危险例子:
int* ip = new int(10);
double* dp = reinterpret_cast<double*>(ip);
double d = *dp; // ❌ 未定义行为
原因:
-
你告诉编译器:“这块 int 的内存,是 double!”
-
但布局完全不对,因此读取是错误的
✔ reinterpret_cast 的本质:
内存原样不动,只改变你访问它时使用的类型。
🧠 二者区别可以用一句话记住:
static_cast:转换 = 合理的,编译器帮你确保安全
reinterpret_cast:转换 = 你说了算,后果自负
更多推荐



所有评论(0)