我在这里阅读有关如何选择主要碱基的信息:
"...2。如果 C 是动态类类型:
一个。识别所有直接或间接的虚拟基类,它们是某些其他直接或间接基类的主要基类。调用这些间接主要基类。
湾。如果 C 有一个动态基类,则尝试选择一个主基类 B。它是第一个(按直接基类顺序)非虚拟动态基类(如果存在)。否则,它是一个几乎为空的虚拟基类,是(预排序)继承图顺序中的第一个,如果存在的话,它不是间接主基类,或者如果它们都是间接主基类,则只是第一个......”
在进行此更正之后:
“上面的情况(2b)现在被认为是设计上的错误。使用第一个间接主基类作为派生类的主基并没有节省对象的任何空间,并且会造成一些虚函数的重复基类虚拟表的附加副本中的指针。
好处是使用派生类的虚指针作为基类的虚指针通常会节省负载,并且调用它的虚函数不需要对this指针进行调整。
人们认为 2b 将允许编译器在某些情况下避免调整它,但这是不正确的,因为虚函数调用算法要求通过指向定义函数的类的指针来查找函数,而不是仅仅继承它。删除该要求并不是一个好主意,因为这样就不再有办法用它们跳转到的函数来发出所有 thunk。例如,考虑这个例子:
结构 A { 虚拟 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?
我也不明白引用的示例试图显示什么。