贝利信息

C++中static_cast和dynamic_cast的区别?(静态转型与动态安全检查)

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

static_cast 适合什么场景

它做的是编译期能确认的类型转换,不涉及运行时类型检查。常见于数值类型转换、有明确继承关系的指针/引用向上转型(派生类 → 基类),或调用自定义的 operator T() 转换函数。

容易踩的坑:static_cast 允许向下转型(基类 → 派生类),但**不验证实际对象类型**,如果对象不是目标派生类实例,行为是未定义的。

dynamic_cast 为什么需要虚函数表

dynamic_cast 依赖 RTTI(Run-Time Type Information),而 RTTI 只在至少有一个虚函数的类中才被编译器生成。它会在运行时检查对象的实际类型是否支持转换,只对多态类型(带虚函数的类)有效。

常见错误现象:dynamic_cast 对非多态类型(比如没有虚函数的 struct)编译失败,报错类似 cannot dynamic_cast ... (source type is not polymorphic)

指针和引用的 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&) { // 必须捕获,否则程序终止 }

性能与设计意图的取舍

static_cast 零开销,dynamic_cast 有明显运行时成本:查虚函数表、遍历继承链、比较 type_info。它不是“更高级的 static_cast”,而是解决不同问题的工具。

真正容易被忽略的是:哪怕开了 RTTI,dynamic_cast 在多重继承或虚继承下仍可能因偏移计算变慢;而关闭 RTTI(如 GCC 的 -fno-rtti)会让所有 dynamic_cast 编译失败——这点在嵌入式或游戏引擎中常被遗忘。