我正在阅读multiple inheritance for c++
本文的一个例子:(第377页)

class A {virtual void f();};
class B {virtual void f(); virtual void g();};
class C: A, B {void f();};
A* pa = new C;
B* pb = new C;
C* pc = new C;
pa->f();
pb->f();
pc->f();
pc->g()


(1)Bjarne写道:在进入C::f时,this指针必须指向C对象的开头(而不是B部分)。但是,通常在编译时并不知道B指向的pbC的一部分,因此编译器无法减去常数delta(B)。因此,我们必须为运行时存储delta(B),它实际上是与vtbl存储在一起的。因此,vtbl条目现在看起来像:

struct vtbl_entry {
    void (*fct)();
    int  delta;
}


类c的对象如下所示:

----------             vtbl:
   vptr -------------->-----------------------
   A part                C::f   | 0
----------             -----------------------
   vptr -------------->-----------------------
   B part                C::f   | -delta(B)
----------               B::g   | 0
   C part              -----------------------
----------


Bjarne写道:

pb->f() // call of C::f:
register vtbl_entry* vt = &pb->vtbl[index(f)];
(*vt->fct)((B*)((char*)pb+vt->delta)) //vt->delta is a negative number I guess


我在这里完全感到困惑。为什么(*vt->fct)((B*)((char*)pb+vt->delta))中的(B *)不是(C *)????根据我的理解和Bjarne在377页的5.1节第一句话的介绍,我们应该在此处将C *作为this传递!

紧接着上面的代码片段,Bjarne继续写:
请注意,可能必须将对象指针调整为po
在找到指向vtbl的成员之前,将int转换为正确的子对象。

天啊!!!我完全不知道Bjarne想要说什么?你能帮我解释一下吗?

最佳答案

它是一个C*,只是没有这样输入。

坦白说,这是一个非常糟糕的解释,而不是真正的完成方式。在vtable中存储函数指针要好很多,也很容易。

struct vtbl {
    void(*f)(B* b);
};
struct B {
   vtbl* vtable;
};
// Invoke function:
B* p = init();
p->vtable->f(p);
// Function pointer points to:
void f_thunk(B* b) {
    C* c = (char*)b - delta(B);
    C::f(c);
}


当编译器生成thunk时,它知道它们要thunk到的派生对象,因此它们不需要将偏移量存储在vtable中。编译器可以简单地将指针偏移到thunk中,然后使用指针委托给适当的方法。当然,该重击仅在没有任何C ++表示的情况下才是生成的程序集,因此声明其中的指针具有任何特定的C ++类型将是无效的。

关于c++ - 对C++的多重继承的理解,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/30768589/

10-10 06:43