dynamic_cast是如何实现的

时间:2013-08-21 14:11:03

标签: c++ dynamic-cast

考虑这个简单的层次结构:

class Base { public: virtual ~Base() { } };
class Derived : public Base { };

使用Base* p可以尝试将Derived*转发给dynamic_cast<Derived*>(p)。我曾经认为dynamic_cast的作用是将p中的vtable指针与Derived对象中的vtable指针进行比较。

但是如果我们从Derived推导出另一个类呢?我们现在有:

class Derived2 : public Derived { };

在这种情况下:

Base* base = new Derived2;
Derived* derived = dynamic_cast<Derived*>(base);

即使Derived2中的vtable指针与Derived中的vtable指针无关,我们仍然可以获得成功的向下转换。

它是如何实际运作的? dynamic_cast如何知道Derived2是否来自Derived(如果Derived在另一个库中声明了怎么办?)

正在寻找有关其实际工作方式的具体细节(最好是在海湾合作委员会,但其他人也很好)。此问题this question的副本(未指定其实际工作方式)。

3 个答案:

答案 0 :(得分:25)

  

dynamic_cast如何知道Derived2是否来自Derived(如果Derived在另一个库中声明了怎么办?)

答案非常简单:dynamic_cast可以通过掌握这些知识来了解这一点。

当编译器生成代码时,它会保留dynamic_cast稍后可以查找的某种表格中有关类层次结构的数据。该表可以附加到vtable指针,以便dynamic_cast实现轻松查找。这些类的typeid所需的数据也可以与那些一起存储。

如果涉及到库,这类事情通常需要在库中公开这些类型信息结构,就像使用函数一样。例如,有可能获得一个链接器错误,看起来像“未定义引用'vtable for XXX'”(和男孩,那些令人讨厌的!),再次,就像功能一样。

答案 1 :(得分:13)

魔术。

开玩笑吧。如果你真的想详细研究它,那么为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

这详细说明了编译器生成的类型信息的格式,并且应该为您提供线索,然后运行时支持如何找到正确的转换路径。

答案 2 :(得分:2)

  

dynamic_cast如何知道Derived2是否派生自Derived(如果Derived是在另一个库中声明的话)?

dynamic_cast本身并不知道任何东西,它是知道这些事实的编译器。 vtable不一定只包含指向虚函数的指针。

以下是我(天真地)这样做的方法:我的vtable将包含dynamic_cast使用的某些类型信息(RTTI)的指针。类型的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;