dynamic_cast是如何实现的

Avi*_*sov 35 c++ dynamic-cast

考虑这个简单的层次

class Base { public: virtual ~Base() { } };
class Derived : public Base { };
Run Code Online (Sandbox Code Playgroud)

试图向下转换Base* pDerived*可能使用dynamic_cast<Derived*>(p).我曾经dynamic_cast通过将vtable指针pDerived对象中的指针进行比较来思考作品.

但是,如果我们从中衍生出另一个类Derived呢?我们现在有:

class Derived2 : public Derived { };
Run Code Online (Sandbox Code Playgroud)

在这种情况下:

Base* base = new Derived2;
Derived* derived = dynamic_cast<Derived*>(base);
Run Code Online (Sandbox Code Playgroud)

我们仍然得到一个成功的向下转换,即使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

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

  • 谢谢!特别有趣的是 *2.9.5* 部分,它包含 RTTI 结构(又名 v-table)的描述以及层次结构的编码方式(当然还有描述算法本身的 *2.9.7*)。 (2认同)

Arn*_*rtz 5

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;
Run Code Online (Sandbox Code Playgroud)

  • 事实上,相当天真,因为它无法考虑多个基类、虚拟基类(那些并不有趣)和偏移量适应。不过基本的想法是好的:对象拓扑被编码在它的 V 表中。 (4认同)