Search code examples
c++pointersthismultiple-inheritancethis-pointer

virtual method table for multiple-inheritance


I'm reading this article "Virtual method table"

Example in the above article:

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();

In the article, the author introduces that the memory layout of object d is like 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

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()

The question is about d->f2(). The call to d->f2() passes a B2 pointer as a this pointer so we have to do something like:

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

Why should we pass a B2 pointer as the this pointer not the original D pointer??? We are actually calling D::f2(). Based on my understanding, we should pass a D pointer as this to D::f2() function.

___update____

If passing a B2 pointer as this to D::f2(), What if we want to access the members of B1 class in D::f2()?? I believe the B2 pointer (this) is shown like 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

It already has a certain offset of the beginning address of this contiguous memory layout. For example, we want to access b1 inside D::f2(), I guess in runtime, it will do something like: *(this+4) (this points to the same address as b2) which would points b2 in B????


Solution

  • We cannot pass the D pointer to a virtual function overriding B2::f2(), because all overrides of the same virtual function must accept identical memory layout.

    Since B2::f2() function expects B2's memory layout of the object being passed to it as its this pointer, i.e.

    b2:
      +0: pointer to virtual method table of B2
      +4: value of int_in_b2
    

    the overriding function D::f2() must expect the same layout as well. Otherwise, the functions would no longer be interchangeable.

    To see why interchangeability matters consider this scenario:

    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
    

    B2::test() needs to make a call of f2() in both scenarios. It has no additional information to tell it how this pointer has to be adjusted when making these calls*. That is why the compiler passes the fixed-up pointer, so test()'s call of f2 would work both with D::f2() and B2::f2().

    * Other implementations may very well pass this information; however, multiple inheritance implementation discussed in the article does not do it.