C++ - TC++PL RTTI dynamic_cast 向下转型和虚拟表混淆(及其实现)

标签 c++ internal

我正在阅读 B. Stroustrup 的“The C++ Programming Language (4th Edition)”中的 RTTI。英语不是我的第一语言,我不确定我是否从它对使用 dynamic_cast<T*>(p) 的向下转换机制的解释中得出了正确的结论。 .我是引用书中的文字

Requiring the pointer’s type to be polymorphic simplifies the implementation of dynamic_cast because it makes it easy to find a place to hold the necessary information about the object’s type. A typical implementation will attach a ‘‘type information object’’ (§22.5) to an object by placing a pointer to the type information in the virtual function table for the object’s class (§3.2.3). For example: The image explaining the downcast The dashed arrow represents an offset that allows the start of the complete object to be found given only a pointer to a polymorphic subobject. It is clear that dynamic_cast can be efficiently implemented. All that is involved are a few comparisons of type_info objects representing base classes; no expensive lookups or string comparisons are needed.

我的困惑来自“虚线箭头代表一个偏移量,允许找到给定的完整对象的开始 只是一个指向多态子对象的指针。”

我从这一行中扣除的是:

  • vtbl(虚函数表)中存储了指向基(或子对象)的指针,虚线表示指向子对象的指针

  • 这与该行的第二部分相矛盾,即仅给出一个指向多态子对象的指针。但这会造成更多的困惑,我们如何将指针传递给子对象。向下转型时,我们在 > 括号中传递派生类名称 T,在 ()< 中传递指向基类对象 p 的指针/strong> dynamic_cast<T*>(p) 的括号语法。

作为一个完整的过程,如果我的第一点是合理的或被认为是正确的。 那么我们可以说我的以下假设成立吗?

假设::在向下转型时,虚函数表 (vtbl) 中存在的指针指向的类型信息对象 ( type_info ) 与基类的 type_id 相继进行比较.如果type_id在前面提到的比较中找到p(或p指向的对象),然后创建派生类的对象。由于指向子对象的指针存储在虚拟表中,我们将从 p (这是 dynamic_cast<T*>(p) 的输入参数)获得的基类对象 memcpy(或类似的东西)到驱动类的子对象(我们从虚函数表中的指针中找到)。

我用谷歌搜索了这个,但没有找到任何可能的解释。如果我跑题了,请引导我到正确的 StackExchange 模块。

P.S : 旁注,书中的topic 3.2.3 explain virtual table。以线条结尾。

This virtual call mechanism can be made almost as efficient as the ‘‘normal function call’’ mechanism (within 25%).

within 25% 是什么意思。同样,我对此有我的假设,但如果有人向我陈述他们的结论会更好。

最后,我们将不胜感激有关 dynamic_cast 如何识别或实现交叉转换的任何信息。

最佳答案

没有复制正在进行,因为所有对象(子对象)一直存在。可能有几个基类,其中一些可能具有虚拟继承。

vtable 中的指针(可能存储为偏移量,而不是固定地址)是帮助运行时找到整个对象中不同子对象开始位置的一种方法。或者从指向子对象的指针找到完整对象的开始。显然,只有第一个基类可以位于对象的开头,其他的都必须定位为 start + offset

虚拟调用几乎与直接函数调用一样高效。在机器代码级别,函数调用仅编码为 call address_of_function,地址存储在指令中。

虚拟调用可以实现为call *(vtable + offset)。如果 vtable 地址存储在寄存器中,许多 CPU 都支持在一条指令中执行这种间接寻址。成本是一次额外的内存访问,用于获取实函数地址。如果该函数做了任何重要的事情,那么这种额外的内存访问不会产生太大的影响。

关于C++ - TC++PL RTTI dynamic_cast 向下转型和虚拟表混淆(及其实现),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40947027/

相关文章:

android - 写入应用程序内部存储 - 频率限制?

c# - C Sharp 中的 'friend' 关键字等效于什么?

c++ - 允许移动和复制返回的类成员

C++ Opengl Gsl 着色器性能问题

php - 在 Android 中使用 PHP 和 MySQL 检测互联网并保存到内部存储

android - 关于从 Mediastore 获取数据的内部与外部 uri

c++ - 用于继承的模板便捷构造函数

c++ - 以下对象属性分配在哪里?

c++ - 如何找到 ROI 并检测内部标记?

Android 打开文本文件后读取 Intent.ACTION_GET_CONTENT