static_cast适用于编译期可确认的类型转换,如数值转换、向上转型或自定义转换函数;dynamic_cast依赖RTTI和虚函数表,仅用于多态类型的运行时安全向下转型,失败时指针返回nullptr、引用抛bad_cast。

static_cast 适合什么场景
它做的是编译期能确认的类型转换,不涉及运行时类型检查。常见于数值类型转换、有明确继承关系的指针/引用向上转型(派生类 → 基类),或调用自定义的 operator T() 转换函数。
容易踩的坑:static_cast 允许向下转型(基类 → 派生类),但**不验证实际对象类型**,如果对象不是目标派生类实例,行为是未定义的。
- 把
int转成double:安全,编译器直接生成转换指令 - 把
Derived*转成Base*:安全,向上转型天然合法 - 把
Base*转成Derived*:危险,编译通过但可能崩溃
dynamic_cast 为什么需要虚函数表
dynamic_cast 依赖 RTTI(Run-Time Type Information),而 RTTI 只在至少有一个虚函数的类中才被编译器生成。它会在运行时检查对象的实际类型是否支持转换,只对多态类型(带虚函数的类)有效。
常见错误现象:dynamic_cast 对非多态类型(比如没有虚函数的 struct)编译失败,报错类似 cannot dynamic_cast ... (source type is not polymorphic)。
立即学习“C++免费学习笔记(深入)”;
- 向下转型成功时返回目标类型的合法指针或引用
- 向下转型失败时,对指针返回
nullptr,对引用抛出std::bad_cast - 跨继承体系(如从一个基类转到另一个无关基类)也会失败
指针和引用的 behavior 差异
二者在失败处理上完全不同,这是最常被忽略的设计细节。
Base* b = new Base(); Derived* d1 = static_cast(b); // 编译通过,d1 指向非法内存 Derived* d2 = dynamic_cast (b); // 运行时检查,d2 == nullptr Base& b_ref = *new Base(); try { Derived& d3 = dynamic_cast
(b_ref); // 抛 std::bad_cast } catch (const std::bad_cast&) { // 必须捕获,否则程序终止 }
- 用指针做
dynamic_cast:失败返回nullptr,可安全判空 - 用引用做
dynamic_cast:失败直接抛异常,不提供“检查失败”的机会 -
static_cast对两者都不做运行时检查,失败后果由程序员承担
性能与设计意图的取舍
static_cast 零开销,dynamic_cast 有明显运行时成本:查虚函数表、遍历继承链、比较 type_info。它不是“更高级的 static_cast”,而是解决不同问题的工具。
- 已知对象确切类型?用
static_cast,比如工厂返回Base*但你 100% 知道它是Derived - 不确定运行时类型,且必须安全向下转型?只能用
dynamic_cast - 想避免
dynamic_cast的开销又需要类型分发?考虑 Visitor 模式或std::variant+std::visit
真正容易被忽略的是:哪怕开了 RTTI,dynamic_cast 在多重继承或虚继承下仍可能因偏移计算变慢;而关闭 RTTI(如 GCC 的 -fno-rtti)会让所有 dynamic_cast 编译失败——这点在嵌入式或游戏引擎中常被遗忘。









