用于多继承的虚方法表

Fih*_*hop 7 c++ pointers this multiple-inheritance this-pointer

我正在读这篇文章" 虚方法表 "

上面的文章中的示例:

class B1 {
public:
  void f0() {}
  virtual void f1() {}
  int int_in_b1;
};

class B2 {
public:
  virtual void f2() {}
  int int_in_b2;
};

class D : public B1, public B2 {
public:
  void d() {}
  void f2() {}  // override B2::f2()
  int int_in_d;
};

B2 *b2 = new B2();
D  *d  = new D();
Run Code Online (Sandbox Code Playgroud)

在文章中,作者介绍了对象的内存布局d是这样的:

          d:
D* d-->      +0: pointer to virtual method table of D (for B1)
             +4: value of int_in_b1
B2* b2-->    +8: pointer to virtual method table of D (for B2)
             +12: value of int_in_b2
             +16: value of int_in_d

Total size: 20 Bytes.

virtual method table of D (for B1):
  +0: B1::f1()  // B1::f1() is not overridden

virtual method table of D (for B2):
  +0: D::f2()   // B2::f2() is overridden by D::f2()
Run Code Online (Sandbox Code Playgroud)

问题是关于d->f2().调用d->f2()B2指针作为this指针传递,因此我们必须执行以下操作:

(*(*(d[+8]/*pointer to virtual method table of D (for B2)*/)[0]))(d+8) /* Call d->f2() */
Run Code Online (Sandbox Code Playgroud)

我们为什么要传递B2指针作为this指针而不是原始D指针??? 我们实际上是在调用D :: f2().根据我的理解,我们应该传递一个关于D :: f2()函数的D指针this.

___update____

如果将B2指针传递this给D :: f2(),如果我们想要访问B1D :: f2()中的类成员怎么办?我相信B2指针(this)显示如下:

          d:
D* d-->      +0: pointer to virtual method table of D (for B1)
             +4: value of int_in_b1
B2* b2-->    +8: pointer to virtual method table of D (for B2)
             +12: value of int_in_b2
             +16: value of int_in_d
Run Code Online (Sandbox Code Playgroud)

它已经具有该连续存储器布局的起始地址的某个偏移量.例如,我们要访问b1内部d :: F2(),我想在运行时,它会做这样的事情:*(this+4)(this指向同一地址B2),这将分b2B????

das*_*ght 4

我们不能将D指针传递给虚函数重写B2::f2(),因为同一虚函数的所有重写都必须接受相同的内存布局。

由于B2::f2()函数期望将B2对象的内存布局作为其this指针传递给它,即

b2:
  +0: pointer to virtual method table of B2
  +4: value of int_in_b2
Run Code Online (Sandbox Code Playgroud)

重写函数D::f2()也必须具有相同的布局。否则,这些功能将不再可以互换。

要了解为什么互换性很重要,请考虑以下场景:

class B2 {
public:
  void test() { f2(); }
  virtual void f2() {}
  int int_in_b2;
};
...
B2 b2;
b2.test(); // Scenario 1
D d;
d.test(); // Scenario 2
Run Code Online (Sandbox Code Playgroud)

B2::test()在这两种情况下都需要进行调用f2()。它没有额外的信息来告诉它this在进行这些调用时如何调整指针*。这就是编译器传递固定指针的原因,因此test()的调用f2适用于D::f2()B2::f2()

*其他实现很可能会传递此信息;然而,本文中讨论的多重继承实现并没有做到这一点。