考虑这个简单的层次
class Base { public: virtual ~Base() { } };
class Derived : public Base { };
试图向下转换Base* p到Derived*可能使用dynamic_cast<Derived*>(p).我曾经dynamic_cast通过将vtable指针p与Derived对象中的指针进行比较来思考作品.
但是,如果我们从中衍生出另一个类Derived呢?我们现在有:
class Derived2 : public Derived { };
在这种情况下:
Base* base = new Derived2;
Derived* derived = dynamic_cast<Derived*>(base);
我们仍然得到一个成功的向下转换,即使vtable指针in Derived2与vtable指针无关Derived.
它是如何实际工作的?如何dynamic_cast知道是否Derived2派生自Derived(如果Derived在不同的库中声明的话)?
我正在寻找关于它如何实际工作的具体细节(最好是在海湾合作委员会,但其他人也很好).这个问题是不是一个重复这个问题(没有指明它是如何工作).
R. *_*des 25
如何
dynamic_cast知道是否Derived2派生自Derived(如果Derived在不同的库中声明的话)?
答案非常简单:dynamic_cast通过保持这些知识可以了解这一点.
当编译器生成代码时,它会保留某些表中有关类层次结构的数据,这些表dynamic_cast可以在以后查找.该表可以附加到vtable指针,以便于dynamic_cast实现查找.typeid这些类所需的数据也可以与那些一起存储.
如果涉及到库,这类事情通常要求这些类型信息结构在库中公开,就像函数一样.例如,有可能获得一个链接器错误,看起来像"未定义引用'vtable for XXX'"(和男孩,那些令人讨厌!),再次,就像功能一样.
Seb*_*edl 14
魔法.
开玩笑.如果你真的想详细研究它,那么为GCC实现它的代码就是libsupc ++,这是libstdc ++的一部分.
https://github.com/mirrors/gcc/tree/master/libstdc%2B%2B-v3/libsupc%2B%2B
具体来说,查找名称中包含tinfo或type_info的所有文件.
或者阅读这里的描述,这可能更容易获得:
https://itanium-cxx-abi.github.io/cxx-abi/abi.html#rtti
这详细说明了编译器生成的类型信息的格式,并且应该为您提供线索,然后运行时支持如何找到正确的转换路径.
Dynamic_cast 如何知道 Derived2 是否派生自 Derived(如果 Derived 是在不同的库中声明的怎么办)?
它dynamic_cast本身什么都不知道,编译器知道这些事实。vtable 不一定只包含指向虚拟函数的指针。
我会(天真地)这样做:我的 vtable 将包含指向 . 使用的某些类型信息(RTTI)的指针dynamic_cast。类型的 RTTI 将包含指向基类的指针,因此我可以向上查找类层次结构。强制转换的伪代码如下所示:
Base* base = new Derived2; //base->vptr[RTTI_index] points to RTTI_of(Derived2)
//dynamic_cast<Derived*>(base):
RTTI* pRTTI = base->vptr[RTTI_index];
while (pRTTI && *pRTTI != RTTI_of(Derived))
{
  pRTTI = pRTTI->ParentRTTI;
}
if (pRTTI) return (Derived*)(base);
return NULL;