Virtual Inheritance in C ++

I read a Wikipedia article on virtual inheritance. I followed the entire article, but I could not follow the last paragraph

This is done by providing the Mammal and WingedAnimal with a vtable pointer (or "vpointer"), because, for example, the memory shift between the beginning of the mammal and its Part of the animals is unknown before execution. Thus, Bat becomes (Vpointer, Mammal, vpointer, WingedAnimal, Bat, animal). There are two vtable pointers, one for each inheritance hierarchy that actually inherits Animal. In this example, one for mammals and one for WingedAnimal. Therefore, the size of the object is increased by two pointers, but now there is only one Animal and there is no ambiguity. All objects of type Bat will have the same pointers, but each Bat object will contain its own unique Animal Object. If another class is inherited from mammals such as Squirrel,then the vpointer in the mammalian object in the protein will be different from the vpointer in the mammalian object in the bat, although they can still be essentially the same in the special case when the protein part of the object is the same size as the bat part, because then the distance from the mammal to the animal part is the same. Vtables are not really the same, but all the essential information in them (distance).

Can someone shed extra light on this.

+3
source share
3 answers

Sometimes you just need to see some codes / diagrams :) Please note that the standard does not mention this implementation detail.

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

struct Base
{
  void foo();
};

It looks like:

struct Base {};

void Base_foo(Base& b);

And in fact, when you look at the method call inside the debugger, you often see the argument thisas the first parameter. It is sometimes called an implicit parameter.

Now, to the virtual table. In C and C ++, there may be pointers to work with. Vtable is essentially a table of function pointers:

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, to inheritance. Let me 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 use:

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

?

  • vtable ,
  • vtable ( )

, ? , :

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

, MostDerived 2 : BaseA BaseB.

() .

, , :

  • BaseA: vpointer, ,
  • BaseB: vpointer, attributes, body
  • Derived: vpointers (), ,

  • Derived is destructed: , , vpointers
  • BaseB : ,
  • BaseA : ,

, , , ++ , - . , - , .

+6

, . , ++ ( ).

, : . ++ , , mulitple .

, vtable ++ (IIRC), . , .

+6

As suggested, vpointers are not really part of the language. However, knowing about implementation methods can be useful, especially in a low-level language such as C ++.

If you really want to know this, I would recommend Inside the C ++ Object Model , which explains this and much more in detail.

+1
source

Source: https://habr.com/ru/post/1753057/


All Articles