dynamic_cast转换失败时对指针返回nullptr、对引用抛std::bad_cast;要求基类多态(含虚函数),且指针转换后必须判空,否则解引用崩溃。

dynamic_cast 转换失败时返回 nullptr,不是抛异常
很多人误以为 dynamic_cast 失败会抛 std::bad_cast,其实只对引用类型才抛异常;对指针类型,转换失败直接返回 nullptr。这是安全判断的前提——你必须显式检查指针是否为空,否则解引用会崩溃。
- 引用转换:
dynamic_cast<derived>(base)</derived>→ 失败抛std::bad_cast - 指针转换:
dynamic_cast<derived>(base_ptr)</derived>→ 失败返回nullptr - 必须确保源类型是多态的(至少含一个虚函数),否则编译报错:
error: cannot dynamic_cast
基类必须有虚函数,否则 dynamic_cast 编译不通过
dynamic_cast 依赖 RTTI(运行时类型信息),而 RTTI 只在类有虚函数表时才启用。哪怕只是声明一个空的虚析构函数,也足够激活它。
class Base {
public:
virtual ~Base() = default; // 关键:让 Base 成为多态类型
};
class Derived : public Base {};
- 没虚函数 →
dynamic_cast编译失败,不是运行时报错 - 虚析构函数最常用,既满足 RTTI 要求,又避免基类指针 delete 时未定义行为
- 纯虚函数(如
virtual void foo() = 0;)也行,但没必要为 cast 特意加业务无关接口
转换后必须判空,不能直接用
常见错误是拿到 dynamic_cast 结果就直接调用成员函数,忽略 nullptr 风险。尤其在继承链较深或条件分支复杂时,容易漏检。
Base* ptr = get_some_base_ptr();
Derived* d = dynamic_cast<derived>(ptr);
if (d) { // 必须这样判断
d->some_method(); // 安全
} else {
// 处理非 Derived 类型的情况
}
</derived>
- 写成
if (dynamic_cast<derived>(ptr))</derived>语法合法但可读性差,不推荐 - 不要和
static_cast混用:后者不检查类型,强制转换,出错更隐蔽 - 如果确定类型一定匹配(比如刚 new 出来就知道是 Derived),用
static_cast更轻量;但凡有一丝不确定性,就用dynamic_cast+ 判空
性能开销小但不可忽略,别在热循环里频繁调用
dynamic_cast 需要查虚函数表、遍历继承关系,比 static_cast 或直接访问慢一个数量级。在每帧调用数百次以上的渲染或物理循环中,它可能成为瓶颈。
- 典型耗时:一次
dynamic_cast约几十纳秒(取决于继承深度),static_cast是零开销 - 替代思路:用虚函数分发代替类型判断,例如把
handle()声明为虚函数,在派生类里各自实现 - 若必须保留类型判断逻辑,可缓存转换结果(如用
std::any或枚举标记类型),避免重复 cast
真正麻烦的不是语法怎么写,而是忘记基类没虚函数导致编译失败,或者转换后不判空直接解引用——这两个点卡住的人最多。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











