Diamond polymorphic inheritance: the size of most derived classes

I understand that diamond-based inheritance is ambiguous and can be avoided by using inheritance through virtual Base Classes , that’s not the point. The question is about the size of the most derived class in hierarchical form when the classes are polymorphic. The following is an example code and an output example:

 #include<iostream> using namespace std; class Base { public: virtual void doSomething(){} }; class Derived1:public virtual Base { public: virtual void doSomething(){} }; class Derived2:public virtual Base { public: virtual void doSomething(){} }; class Derived3:public Derived1,public Derived2 { public: virtual void doSomething(){} }; int main() { Base obj; Derived1 objDerived1; Derived2 objDerived2; Derived3 objDerived3; cout<<"\n Size of Base: "<<sizeof(obj); cout<<"\n Size of Derived1: "<<sizeof(objDerived1); cout<<"\n Size of Derived2: "<<sizeof(objDerived2); cout<<"\n Size of Derived3: "<<sizeof(objDerived3); return 0; } 

The output I get is:

  Size of Base: 4 Size of Derived1: 4 Size of Derived2: 4 Size of Derived3: 8 

As I understand it, Base contains a virtual member function and therefore sizeof Base = size vptr = 4 in this environment

The classes Derived1 and Derived2 .

Here are my questions related to the following scenario:
What about the size of an object of class Derived3 , does this mean that class Derived3 has 2 vptr?
How does the Derived3 class work with these 2 vptr, any ideas on the mechanism it uses?
The sizeof classes are left as a part of the compiler implementation and are not defined by the standard (since the virtual mechanism itself is a detail of the compiler implementation)?

+4
source share
4 answers

Yes, Derived3 has two vtable pointers. If you access it by value, it uses the Derived3 version or selects a function from the parent or means that it is ambiguous if it cannot solve.

In the case of a child, it uses a vtable corresponding to the 1/2 parent, which is used polymorphically.

Please note that you are not using virtual inheritance correctly, I believe that Derived1 and 2 must be inherited from virtually Base . sizeof(Derived3) still seems 8, because it still has two possible parents, which can be thought of as Derived3 . When you go to one of the parents, the compiler will actually set the pointer to the object to have the correct vtable.

I should also point out that something related to vtable is related to the implementation, because the standard does not mention the vtables standards.

+4
source

A small fix for your code: the virtual must be in the definition of derivative2 and derivative 3 to work.

http://www.parashift.com/c++-faq-lite/multiple-inheritance.html#faq-25.9

+3
source

I think you're interested in something completely concrete. You should not assume anything about class sizes.

Edit: although curiosity is a proven quality; -)

+1
source

Consider a slightly different case:

 struct B { virtual void f(); }; struct L : virtual B { virtual void g(); }; struct R : virtual B { virtual void h(); }; struct D : L, R {}; 

In a typical implementation, L :: g will be in the same position (for example, at index 0) in L vtable as R: h in R vtable. Now consider what happens with the following code:

 D* pd = new D; L* pl = pd; R* pr = pd; pl->g(); pr->h(); 

In the last two lines, the compiler will generate code to find the address of the function at the same position in table v. So, a vtable accessible via pl cannot be the same as one (or one prefix) accessed through etc. Thus, a complete object requires at least two vptr to point to two different vtable.

+1
source

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


All Articles