1. static_cast —— 最常用的“本分”转换

什么时候用?

基本类型之间转换(int ↔ double,char ↔ int)

父子类指针/引用之间的向上转型(子类 → 父类,绝对安全)

父子类指针/引用之间的向下转型(父类 → 子类,不安全,但语法允许)

任何“有明确定义”的类型转换,比如 void* → 具体类型*

特点:

编译时检查(不检查运行时类型)

不做安全保证,你自己要确保转换合理

例子:

double d = 3.14;
int i = static_cast<int>(d);   // 3,可以

class Base {};
class Derived : public Base {};
Derived d;
Base* b = static_cast<Base*>(&d);  // ✅ 向上转型,安全

Base* b2 = new Base;
Derived* d2 = static_cast<Derived*>(b2); // ⚠️ 编译通过,但危险!b2实际不是Derived

2. dynamic_cast —— 安全的“多态”转换

什么时候用?

把父类指针/引用转成子类指针/引用(向下转型),并且你需要知道转换是否成功

前提: 父类至少有一个虚函数(多态类型)

特点:

运行时检查类型

转换失败:指针 → nullptr,引用 → 抛出 std::bad_cast

比 static_cast 慢一点点,但安全

例子:

class Animal { virtual void speak(){} }; // 有虚函数
class Dog : public Animal {};

Animal* a = new Dog;
Dog* d = dynamic_cast<Dog*>(a);  // ✅ 成功,d不为空

Animal* a2 = new Animal;
Dog* d2 = dynamic_cast<Dog*>(a2); // ❌ 失败,d2 == nullptr

3. reinterpret_cast —— 危险的“瞎转”

什么时候用?

完全不相干的类型之间的转换,比如 int* ↔ double*

指针 ↔ 整数(底层位模式重解释)

几乎只在底层编程、序列化、硬件访问时使用

特点:

编译时直接重解释比特位,不做任何检查

几乎不保证可移植性

能用别的就别用它

例子:

int x = 65;
int* p = &x;
char* c = reinterpret_cast<char*>(p); // 把int*当char*用,危险
std::cout << *c; // 可能输出 'A'(小端机器),但非常容易出错

4. const_cast —— 去掉 const 的“后悔药”

什么时候用?

需要一个“只在这个函数里”修改原本不是 const 的对象(比如函数参数是 const,但你知道它本来不是 const)

调用一个非 const 成员函数,但你手里只有 const 引用

特点:

只能添加或移除 const/volatile

绝对不能用来修改一个原本就是 const 的对象(后果是未定义行为)

例子:

void print(char* p) { std::cout << p; }

const char* msg = "hello";
// print(msg); // 错误,不能传const char*给char*
print(const_cast<char*>(msg)); // 去掉const,但msg本身是const char*,修改它会导致未定义行为

⚠️ 除非你100%确认原对象不是 const,否则不要用 const_cast 去修改内容。

一句话总结

在这里插入图片描述

实际开发建议

大部分情况 static_cast 够用

多态向下转型时,优先用 dynamic_cast

尽量避免 reinterpret_cast 和 const_cast,它们往往是代码设计有问题的信号

C 风格转换 (int)x 在 C++ 中不推荐,因为它实际上就是 reinterpret_cast + const_cast 的混合体,容易被误用

更多推荐