dynamic_cast只对多态类型有效,因其依赖rtti,而rtti仅在含虚函数的类中生成;无虚函数则编译失败或运行时返回nullptr/抛bad_cast。

dynamic_cast 为什么只对多态类型有效
因为 dynamic_cast 依赖运行时类型信息(RTTI),而 RTTI 只在有虚函数的类中生成。没虚函数的类,哪怕有继承关系,dynamic_cast 也会编译失败或返回 nullptr(指针)/抛出 std::bad_cast(引用)。
常见错误现象:dynamic_cast 返回 nullptr 却没检查,直接解引用导致崩溃;或对非多态类型强制转换,编译器报错 error: cannot dynamic_cast。
- 必须至少有一个虚函数(哪怕只是
virtual ~Base() = default;) - 基类析构函数建议声明为
virtual,否则用dynamic_cast转回派生类后 delete 基类指针会未定义行为 - 转换失败时:指针转为
nullptr,引用转为抛异常 —— 别忘了加try/catch或空指针检查
指针转换和引用转换的区别在哪
行为差异直接决定你该用哪个:指针转换安全、可判空;引用转换简洁但必须确保成功,否则程序终止。
使用场景举例:向下转型(父类指针 → 子类指针)适合用指针版;已知对象一定属于某子类型(比如事件处理回调里明确传入的是 KeyDownEvent&),才考虑引用版。
立即学习“C++免费学习笔记(深入)”;
- 指针转换:
Derived* d = dynamic_cast<derived>(base_ptr);</derived>—— 检查d != nullptr再用 - 引用转换:
Derived& d = dynamic_cast<derived>(*base_ptr);</derived>—— 必须配try { ... } catch (const std::bad_cast&) { ... } - 性能上:两者开销基本一致,都查 vtable 和 type_info,别指望引用版更快
dynamic_cast 在 void* 上完全不能用
dynamic_cast 不支持转到 void*,也不支持从 void* 转出 —— 这是语言硬性限制,不是编译器 bug。
常见错误现象:想“先转成通用指针再转回来”,写 dynamic_cast<void>(ptr)</void>,结果编译直接报错 error: cannot dynamic_cast 'ptr' (of type 'X*') to type 'void*' (source is not a pointer to class)。
- 要获取对象地址,直接用
static_cast<void>(ptr)</void>或更安全的reinterpret_cast<:uintptr_t>(ptr)</:uintptr_t> - 从裸地址恢复类型,只能靠你自己记录类型信息,
dynamic_cast帮不上忙 - 如果真需要运行时类型擦除,考虑
std::any或std::variant,而不是硬塞void*
替代方案比 dynamic_cast 更快也更安全的场合
不是所有向下转型都得靠 dynamic_cast。它慢(查 RTTI)、依赖开启 RTTI(某些嵌入式环境禁用)、且掩盖设计问题。
典型可替代场景:同一组派生类处理逻辑高度相似,但行为略有不同 —— 这正是虚函数的本职工作。
- 优先用虚函数 + 纯虚接口,把差异行为封装进类内部,避免外部频繁转型
- 若需区分类型做分支处理(如日志、序列化),考虑用
typeid(*ptr) == typeid(Derived),它比dynamic_cast略快但不提供安全转型能力 - 现代 C++ 中,
std::visit配合std::variant可彻底消除运行时转型需求,类型安全且零开销
RTTI 是开关,不是默认打开的工具。关掉它时 dynamic_cast 就失效了,而很多团队在发布构建里确实会关 —— 这时候代码还能不能跑,得提前想清楚。








