【发布时间】:2017-11-10 00:44:36
【问题描述】:
我正在阅读 here 关于如何选择主要碱基:
"...2.如果C是动态类类型:
一个。识别所有直接或间接的虚拟基类,它们是某些其他直接或间接基类的主要基类。调用这些间接的主要基类。
b.如果 C 具有动态基类,则尝试选择主要基类 B。如果存在,它是第一个(按直接基类顺序)非虚拟动态基类。否则,它是一个几乎为空的虚拟基类,(预序)继承图顺序中的第一个,如果存在则不是间接主基类,或者如果它们都是间接主基类,则只是第一个......"
在进行了这个更正之后:
“上面的情况(2b)现在认为是设计上的错误。使用第一个间接主基类作为派生类的主基并没有节省对象的任何空间,而且会造成一些重复基类虚拟表的附加副本中的虚拟函数指针。
好处是使用派生类的虚指针作为基类的虚指针,往往会节省负载,调用它的虚函数也不需要调整this指针。
人们认为 2b 会允许编译器在某些情况下避免调整它,但这是不正确的,因为虚函数调用算法要求通过指向定义函数的类的指针来查找函数,而不是一个只是继承它。 删除该要求不是一个好主意,因为这样就不再有办法使用它们跳转到的函数发出所有 thunk。 例如,考虑这个例子:
struct A { virtual void f(); };
结构 B : 虚拟公共 A { int i; };
结构 C : 虚拟公共 A { int j; };
结构 D : 公共 B, 公共 C {};
当声明 B 和 C 时,A 在每种情况下都是主基,因此尽管在 A-in-B 和 A-in-C vtables 中分配了 vcall 偏移量,但不需要进行此调整,也不会生成 thunk .但是,在 D 对象内部,A 不再是 C 的主要基础,因此如果我们允许对 C::f() 的调用使用 C 子对象中 A 的 vtable 副本,我们需要将其从 C* 调整为B::A*,这需要第三方 thunk。因为我们要求对 C::f() 的调用首先转换为 A*,所以 C-in-D 的 A 的 vtable 副本永远不会被引用,所以这不是必需的。”
您能否举个例子解释一下这指的是什么:“删除该要求不是一个好主意,因为这样就没有办法用它们跳转到的函数发出所有thunk了强>”?
另外,什么是第三方thunk?
我也不明白引用的示例试图显示什么。
【问题讨论】:
-
我认为“主要基础”的想法太多:一个静态,这意味着对象和 vtable 的给定布局;一个动态的,它描述了一个动态类型的对象。这已经让我很困惑了!
标签: c++ vtable abi virtual-inheritance thunk