dynamic_cast只能用于多态类型,因为它依赖RTTI,而RTTI仅在含虚函数的类中生成;无虚函数的类使用会编译报错。

dynamic_cast 为什么只能用于多态类型
因为 dynamic_cast 依赖运行时类型信息(RTTI),而 RTTI 只在至少有一个虚函数的类中生成。如果你对一个普通 struct 或没有虚函数的 class 使用 dynamic_cast,编译器会直接报错:error: cannot dynamic_cast ... (source type is not polymorphic)。
常见错误场景:把基类指针指向子类对象,但基类没声明虚析构或任何虚函数,结果 dynamic_cast 编译不过。
- 必须确保基类有至少一个虚函数(最常用的是加个虚析构:
virtual ~Base() = default;) - 子类无需显式加
virtual,继承后自动多态 - 用
class而非struct不影响多态性,关键看有没有虚函数
向上转型(upcast)不需要 dynamic_cast
从派生类指针转到基类指针是安全、隐式的,dynamic_cast 完全多余,还可能掩盖设计问题。
比如:Derived* d = new Derived; → Base* b = d; 是合法且零开销的,不需要写成 Base* b = dynamic_cast<base>(d);。
立即学习“C++免费学习笔记(深入)”;
- 向上转型永远成功,
dynamic_cast不做任何检查,纯属冗余 - 强行使用反而让代码显得不熟悉 C++ 类型系统
- 如果编译器警告 “dynamic_cast used for upcast”,建议直接删掉
向下转型(downcast)怎么写才安全
这才是 dynamic_cast 的主战场:已知是基类指针,想尝试转成某个具体子类。它会在运行时检查实际类型,失败时返回 nullptr(指针)或抛出 std::bad_cast(引用)。
典型写法:
Base* ptr = get_some_base_ptr();
Derived* d = dynamic_cast<Derived*>(ptr);
if (d) {
d->specific_method(); // 安全调用
}- 永远先判空再用——这是最容易漏的一步,直接解引用可能 crash
- 对引用转换要包在
try/catch里:try { auto& r = dynamic_cast<Derived&>(*ptr); } catch (const std::bad_cast&) { ... } - 不要嵌套多个
dynamic_cast判断类型分支;考虑用虚函数或访问者模式替代
dynamic_cast 在 void* 和跨 DLL 边界时的限制
dynamic_cast 不能转成 void*,也不能从 void* 转回来——它只工作于类类型之间的指针/引用转换。另外,在 Windows 上若基类和子类分别定义在不同 DLL 中,且 RTTI 未统一启用(如链接时没加 /GR),dynamic_cast 可能静默失败或返回 nullptr。
- 别试图用
dynamic_cast<void*>(ptr),编译报错;该用static_cast<void*>就用那个 - 跨 DLL 场景下,确保所有模块都开启 RTTI(MSVC 对应
/GR,GCC/Clang 默认开启) - 调试时发现
dynamic_cast总是返回nullptr,先检查两个模块是否用了完全一致的类定义(包括头文件版本、模板实例化方式)
实际项目里,dynamic_cast 出现频率远低于初学者预期。真正难处理的,往往不是语法怎么写,而是“为什么我非得靠类型判断才能往下走”——这时候回头看看虚函数接口是不是没设计好。


















