简体   繁体   English

如何实现dynamic_cast

[英]How is dynamic_cast implemented

Consider this simple hierarchy: 考虑以下简单的层次结构:

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

Trying to downcast Base* p to Derived* is possible using dynamic_cast<Derived*>(p) . 可以使用dynamic_cast<Derived*>(p)Base* p转换为Derived* I used to think dynamic_cast works by comparing the vtable pointer in p to the one in a Derived object. 我以前认为dynamic_cast可以通过将p的vtable指针与Derived对象中的vtable指针进行比较来工作。

But what if we derive another class from Derived ? 但是,如果我们从Derived派生另一个类怎么办? We now have: 现在,我们有:

class Derived2 : public Derived { };

In this case: 在这种情况下:

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

We still get a successful downcast, even though the vtable pointer in Derived2 has nothing to do with a vtable pointer in Derived . 即使Derived2中的vtable指针与Derived的vtable指针无关,我们仍然可以成功地失败。

How does it actually work? 它实际上如何运作? How can the dynamic_cast know whether Derived2 was derived from Derived (what if Derived was declared in a different library)? dynamic_cast如何知道Derived2是否衍生自Derived (如果Derived在不同的库中声明)?

I am looking for specific details about how this actually works (preferably in GCC, but others are fine too). 正在寻找有关其实际工作方式的详细信息(最好在GCC中使用,但其他也可以)。 This question is not a duplicate of this question (which doesn't specify how it actually works). 这个问题不是一个重复这个问题 (没有指明它是如何工作)。

How can the dynamic_cast know whether Derived2 was derived from Derived (what if Derived was declared in a different library)? dynamic_cast如何知道Derived2是否衍生自Derived (如果Derived在不同的库中声明)?

The answer to that is surprisingly simple: dynamic_cast can know this by keeping this knowledge around. 答案非常简单: dynamic_cast可以通过保持这种了解来知道这一点。

When the compiler generates code it keeps around the data about the class hierarchies in some sort of table that dynamic_cast can look up later. 编译器生成代码时,它会将有关类层次结构的数据保存在某种表中,以便dynamic_cast稍后查找。 That table can be attached to the vtable pointer for easy lookup by the dynamic_cast implementation. 该表可以附加到vtable指针,以便dynamic_cast实现轻松查找。 The data neeeded for typeid for those classes can also be stored along with those. 那些类的typeid需要的数据也可以与它们一起存储。

If libraries are involved, this sort of thing usually requires these type information structures to be exposed in the libraries, just like with functions. 如果涉及到库,则这种情况通常需要这些类型的信息结构在函数库中公开。 It is possible, for example, to get a linker error that looks like "Undefined reference to 'vtable for XXX'" (and boy, are those annoying!), again, just like with functions. 例如,可能会出现链接器错误,就像函数一样,该错误看起来像是“对'vtable for XXX'的未定义引用”(而男孩,那些烦人!)。

Magic. 魔法。

Just kidding. 开玩笑。 If you really want to research this in detail, the code that implements it for GCC is in libsupc++, a part of libstdc++. 如果您真的想详细研究它,那么为GCC实现它的代码在libsupc ++(libstdc ++的一部分)中。

https://github.com/mirrors/gcc/tree/master/libstdc%2B%2B-v3/libsupc%2B%2B https://github.com/mirrors/gcc/tree/master/libstdc%2B%2B-v3/libsupc%2B%2B

Specifically, look for all files with tinfo or type_info in their name. 具体来说,查找名称中带有tinfo或type_info的所有文件。

Or read the description here, that's probably a lot more accessible: 或在此处阅读说明,可能更容易理解:

https://itanium-cxx-abi.github.io/cxx-abi/abi.html#rtti https://itanium-cxx-abi.github.io/cxx-abi/abi.html#rtti

This details the format of the type information the compiler generates and should give you clues how the runtime support then finds the right casting path. 这详细说明了编译器生成的类型信息的格式,并应为您提供线索,提示运行时支持如何找到正确的转换路径。

How can the dynamic_cast know whether Derived2 was derived from Derived (what if Derived was declared in a different library)? dynamic_cast如何知道Derived2是否衍生自Derived(如果Derived在不同的库中声明)?

The dynamic_cast itself does not know anything, its the compiler that knows those facts. dynamic_cast本身什么都不知道,它的编译器知道这些事实。 A vtable does not necessarily contain only pointers to virtual functions. vtable不一定只包含指向虚拟函数的指针。

Here's how I would (naively) do it: my vtable will contain pointer(s) to some type information (RTTI) used by dynamic_cast . 这是我(天真)的方法:我的vtable将包含指向dynamic_cast使用的某些类型信息(RTTI)的指针。 The RTTI for a type will contain pointers to base classes, so I can go up the class hierarchy. 类型的RTTI将包含指向基类的指针,因此我可以上层类层次结构。 Pseudocode for the cast would look like this: 转换的伪代码如下所示:

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;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM