关于dynamic_cast检查逻辑及向下转型特殊场景的技术咨询
dynamic_cast 工作机制相关问题解答 一、dynamic_cast 执行类型转换的具体检查步骤
- 编译期基础校验:首先会校验源类型是否为多态类型(即至少包含一个虚函数),如果源类型不满足多态要求,直接编译报错。同时会检查目标类型和源类型是否属于同一继承体系下的相关类型,完全无关的类型转换也会在编译阶段被拦截。
- 运行时RTTI校验:如果编译期校验通过,运行时会读取对象虚表中存储的运行时类型信息(RTTI),匹配实际对象类型和目标类型的继承关系:
- 向上转型(转为实际对象的基类类型):校验永远通过,直接返回调整后的正确地址。
- 向下转型(转为实际对象的派生类类型):如果实际对象类型是目标类型本身,或是目标类型的公开派生类,校验通过返回对应地址;否则指针转换返回
nullptr,引用转换抛出std::bad_cast异常。 - 交叉转型(多继承场景下转为另一分支的基类类型):如果实际对象确实继承了目标基类,校验通过,否则转换失败。
二、非钻石继承下向下转孙子类成功、转儿子类失败的场景
这种场景确实存在,核心是你持有的基类指针指向的是孙子类独有的基类子对象,和儿子类没有继承关联,示例场景如下:
场景复现结构
非钻石多继承结构,孙子类同时继承儿子类和基类,存在两个独立的基类子对象:
#include <iostream> class Base { public: virtual ~Base() = default; // 保证是多态类型 }; // 儿子类,公有继承Base class Derived : public Base {}; // 孙子类:同时公有继承Derived和Base,非钻石结构(无虚继承),存在两个独立的Base子对象 class GrandDerived : public Derived, public Base {}; int main() { GrandDerived gd; // 取孙子类直接继承的Base子对象的指针,这个子对象不属于Derived的继承链 Base* base_ptr = static_cast<GrandDerived::Base*>(&gd); // 向下转儿子类Derived:失败,当前Base子对象和Derived无继承关系 Derived* d_ptr = dynamic_cast<Derived*>(base_ptr); std::cout << "转型到儿子类结果:" << (d_ptr ? "成功" : "失败") << "\n"; // 向下转孙子类GrandDerived:成功,当前Base子对象属于GrandDerived的一部分 GrandDerived* gd_ptr = dynamic_cast<GrandDerived*>(base_ptr); std::cout << "转型到孙子类结果:" << (gd_ptr ? "成功" : "失败") << "\n"; return 0; }
运行结果
转型到儿子类结果:失败 转型到孙子类结果:成功
原理说明
因为没有使用虚继承,该结构属于普通非钻石继承,GrandDerived会生成两个完全独立的Base子对象:一个从Derived继承而来,另一个是自身直接继承的。当你持有的Base*指向的是GrandDerived直接继承的那个Base子对象时,这个子对象和Derived类没有任何继承关联,所以转型到Derived会失败;但它本身属于GrandDerived的一部分,所以转型到GrandDerived会成功。
内容的提问来源于stack exchange,提问作者Mohammed Kiwan
相关产品推荐
相关产品推荐

