dynamic_cast失败时对指针返回nullptr,对引用抛出std::bad_cast异常;仅适用于多态类型,基类析构函数须为虚函数,RTTI禁用时行为退化或编译失败。

dynamic_cast 失败时返回什么
对指针使用 dynamic_cast,转换失败时**返回 nullptr**;对引用使用则**抛出 std::bad_cast 异常**。这是最根本的分水岭,不区分用法直接判断返回值会踩坑。
常见错误现象:if (ptr == nullptr) 检查对引用类型无效,编译都过不去;而忘了检查指针是否为空,直接解引用就会崩溃。
- 只对多态类型(含至少一个虚函数)的指针/引用有效,否则编译报错
error: cannot dynamic_cast ... (source type is not polymorphic) - 基类析构函数必须是虚函数,否则
dynamic_cast行为未定义(尤其涉及继承链中间类时) - 转换目标类型不能是 cv 限定更严格的类型(如从
Base*转const Derived*合法,反过来不行)
怎么安全地检查 dynamic_cast 是否成功
优先用指针 + 空指针检查,比 try/catch 更轻量、更符合 C++ 惯例。引用场景较少,通常出现在明确预期成功、失败即逻辑错误的场合。
实操建议:
立即学习“C++免费学习笔记(深入)”;
- 对指针:始终先赋值再判空,避免重复 cast
Derived* d = dynamic_cast(base_ptr); if (d) { /* 安全使用 d */ } - 对引用:仅在能合理处理异常且调用方已声明
noexcept(false)时使用,例如:try {
Derived& d = dynamic_cast(base_ref);
} catch (const std::bad_cast&) {
// 处理错误分支
} - 不要写
if (dynamic_cast这种“一次调用两次转换”的写法——编译器未必优化掉第二次 cast,且可读性差(p)) { ... }
RTTI 被禁用时 dynamic_cast 会怎样
如果编译时加了 -fno-rtti(GCC/Clang)或 /GR-(MSVC),dynamic_cast 对指针会退化为 static_cast(不检查类型,静默失败),对引用则直接编译失败。
这意味着:程序可能在 RTTI 关闭后看似运行正常,实则类型检查完全失效,隐患极深。
- 检查是否启用 RTTI:GCC/Clang 下看宏
__GXX_RTTI是否定义;MSVC 下看_CPPRTTI - 跨模块(如插件、动态库)使用
dynamic_cast时,所有模块必须用相同 RTTI 设置链接,否则行为不可预测 - 嵌入式或性能敏感场景禁用 RTTI 是合理的,但此时应改用其他机制(如类型 ID 枚举 +
switch)替代运行时类型判断
为什么有时 dynamic_cast 明明类型对却返回 nullptr
最常见原因是对象内存布局不匹配——比如通过 malloc 分配、未调用构造函数,或对象已被析构但指针仍被使用。
另一个隐蔽原因是多重继承下的指针偏移问题:若 Base* 实际指向的是派生类中某个非首字段的基类子对象,而该基类不是虚继承,dynamic_cast 可能无法正确调整地址。
- 确保对象是完整构造的:不要对
placement new未完成初始化的对象做dynamic_cast - 避免在虚析构函数执行过程中(即析构函数体内部)对
this做dynamic_cast,此时 RTTI 信息可能已部分销毁 - 虚继承可解决菱形继承中的指针一致性问题,但会带来额外开销;非虚继承下,务必保证
dynamic_cast的源指针指向的是完整对象的起始地址(即原始new返回值)
C++ 的 dynamic_cast 不是万能钥匙,它依赖完整的对象生命周期、正确的继承定义和开启的 RTTI 支持。最容易被忽略的是:空指针检查只适用于指针,而引用的异常路径往往在测试中被绕过,上线后才暴露。










