Virtual inheritance in C++

坚强是说给别人听的谎言 提交于 2019-12-06 00:28:12

Sometimes, you just really need to see some code / diagrams :) Note that there is no mention of this implementation detail in the Standard.

First of all, let's see how to implement methods in C++:

struct Base
{
  void foo();
};

This is similar to:

struct Base {};

void Base_foo(Base& b);

And in fact, when you look at a method call within a debugger, you'll often see the this argument as the first parameter. It is sometimes called an implicit parameter.

Now, on to the virtual table. In C and C++ it is possible to have pointers to function. A vtable is essentially a table of pointers to functions:

struct Base
{
  int a;
};

void Base_set(Base& b, int i) { b.a = i; }
int Base_get(Base const& b) { return b.a; }

struct BaseVTable
{
  typedef void (*setter_t)(Base&, int);
  typedef int (*getter_t)(Base const&);

  setter_t mSetter;
  getter_t mGetter;

  BaseVTable(setter_t s, getter_t g): mSetter(s), mGetter(g) {}
} gBaseVTable(&Base_set, &Base_get);

Now I can do something like:

void func()
{
  Base b;
  (*gBaseVTable.mSetter)(b, 3);
  std::cout << (*gBaseVTable.mGetter)(b) << std::endl; // print 3
}

Now, on to the inheritance. Let's create another structure

struct Derived: Base {}; // yeah, Base does not have a virtual destructor... shh

void Derived_set(Derived& d, int i) { d.a = i+1; }

struct DerivedBaseVTable
{
  typedef void (*setter_t)(Derived&,int);
  typedef BaseVTable::getter_t getter_t;

  setter_t mSetter;
  getter_t mGetter;

  DerivedBaseVTable(setter_t s, getter_t g): mSetter(s), mGetter(g) {}
} gDerivedBaseVTable(&Derived_set, &Base_get);

And the use:

void func()
{
  Derived d;
  (*gDerivedBaseVTable.mSetter)(d, 3);
  std::cout << (*gDerivedBaseVTable.mGetter)(d) << std::endl; // print 4
}

But how to automate this ?

  • you only need one instance of a vtable per class having at least one virtual function
  • each instance of the class will contain a pointer to the vtable as its first attribute (even though you can't really access it by yourself)

Now, what happens in case of multi-inheritance ? Well, inheritance is very much like composition in term of memory layout:

|                                     Derived                                   |
|                 BaseA                 |                 BaseB                 |
| vpointer | field1 | field2 | padding? | vpointer | field1 | field2 | padding? |

There will thus be 2 virtual tables for MostDerived: one to change the methods from BaseA and one to change the methods from BaseB.

Pure virtual functions are generally represented as a null pointer (simply) in the corresponding field.

And finally, construction and destruction:

Construction

  • BaseA is constructed: first the vpointer is initialized, then the attributes, then the body of the constructor is executed
  • BaseB is constructed: vpointer, attributes, body
  • Derived is constructed: replace the vpointers (both), attributes, body

Destruction

  • Derived is destructed: body of the destructor, destroy attributes, put the base vpointers back
  • BaseB is destructed: body, attributes
  • BaseA is destructed: body, attributes

I think it's pretty comprehensive, I'd be glad if some C++ gurus around there could review this and check I haven't made any stupid mistake. Also, if something is missing, I'd be glad to add it.

I cannot, really. This section tries to describe what should be done in a C++ implementation using virtual method tables to provide dynamic binding (in case of multiple inheritance).

If you're not doing a compiler, my advice is: Don't bother. Read your favorite C++ book on inheritance, virtual methods, mulitple inheritance and virtual inheritance.

Plus, usage of a vtable is not required by the C++ standard (IIRC), it's an implementation detail. So really, don't bother.

As mkluwe suggested, vpointers are not really a part of the language. However, knowing about implementation techniques might be useful, especially in a low-level language like C++.

If you really want to learn this, I would recommend Inside the C++ Object Model, which explains this and a lot of other things in detail.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!