Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/156.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 动态_cast是如何实现的_C++_Dynamic Cast - Fatal编程技术网

C++ 动态_cast是如何实现的

C++ 动态_cast是如何实现的,c++,dynamic-cast,C++,Dynamic Cast,考虑一下这个简单的层次结构: class Base { public: virtual ~Base() { } }; class Derived : public Base { }; 使用dynamic\u cast(p)可以尝试将Base*p向下转换为Derived*。我过去认为dynamic_cast的工作原理是将p中的vtable指针与派生的对象中的指针进行比较 但是如果我们从派生的派生另一个类呢?我们现在有: class Derived2 : public Derived { };

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

class Base { public: virtual ~Base() { } };
class Derived : public Base { };
使用
dynamic\u cast(p)
可以尝试将
Base*p
向下转换为
Derived*
。我过去认为
dynamic_cast
的工作原理是将
p
中的vtable指针与
派生的
对象中的指针进行比较

但是如果我们从派生的派生另一个类呢?我们现在有:

class Derived2 : public Derived { };
在这种情况下:

Base* base = new Derived2;
Derived* derived = dynamic_cast<Derived*>(base);
Base*Base=new-Derived2;
派生*派生=动态_铸造(基础);
尽管
Derived2
中的vtable指针与
Derived
中的vtable指针无关,但我们仍然成功地进行了向下转换

它实际上是如何工作的?
dynamic\u cast
如何知道
Derived2
是否派生自
derived
(如果
derived
是在其他库中声明的呢)

am正在寻找关于这实际上是如何工作的具体细节(最好是在GCC中,但其他的也可以)。这个问题不是重复的(没有具体说明它是如何工作的)。

Magic

只是开玩笑。如果您真的想详细研究这一点,那么为GCC实现它的代码在libsupc++中,它是libstdc++的一部分

具体来说,查找名称中包含tinfo或type_info的所有文件

或者阅读这里的描述,这可能更容易理解:

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

dynamic\u cast
如何知道
Derived2
是否派生自
derived
(如果
derived
是在其他库中声明的呢)

答案出人意料地简单:
dynamic\u cast
可以通过保留这些知识来了解这一点

当编译器生成代码时,它将类层次结构的数据保存在某种表中,
dynamic\u cast
可以稍后查找。该表可以附加到vtable指针,以便通过
dynamic\u cast
实现轻松查找。这些类的
typeid
所需的数据也可以与这些类一起存储

如果涉及到库,这类事情通常需要在库中公开这些类型信息结构,就像函数一样。例如,可能会得到一个链接器错误,看起来像“未定义对'vtable for XXX'的引用”(男孩,这些都很烦人!),就像函数一样

动态_cast如何知道Derived2是否派生自派生(如果在不同的库中声明了派生会怎么样)

dynamic\u cast
本身什么都不知道,编译器知道这些事实。vtable不一定只包含指向虚拟函数的指针

我(天真地)会这样做:我的vtable将包含指向
dynamic\u 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;
Base*Base=new-Derived2//base->vptr[RTTI_索引]指向(Derived2)的RTTI_
//动态投影(基本):
RTTI*pRTTI=base->vptr[RTTI_index];
while(pRTTI&&*pRTTI!=RTTI_of(派生))
{
pRTTI=pRTTI->ParentRTTI;
}
如果(pRTTI)返回(派生*)(基本);
返回NULL;

它可能在不同的编译器中以不同的方式实现,以确保您可能希望阅读它们的源代码……事实上,这是非常幼稚的,因为它无法考虑多个基类、虚拟基类(那些不是有趣的)和偏移量适配。不过基本思想是好的:对象拓扑编码在它的V表中。@MatthieuM。这就是我想要的:描述基本的想法。我想到了其他东西(除了虚拟基类,去他们的吧!),但没有费心编写大量无用的伪代码;-)对于一个参考实现,我在中发现了一个非常可读的实现,尤其是与安腾ABI第2.9.5节中RTTI结构布局的链接相结合。也很聪明。这个想法实际上与这里介绍的想法类似,但是使用多态递归来实现,以支持从u类_类型_信息派生的不同类型的类。谢谢你的链接!谢谢特别令人感兴趣的是第2.9.5节,其中包含RTTI结构(又名v表)的描述以及层次结构的编码方式(当然还有描述算法本身的第2.9.7节)。当涉及多重继承时,会有一些复杂情况。例如,见。