Kundan Kumar
Kundan Kumar

Reputation: 2002

Size of the classes in case of virtual inheritance

Can someone please explain about the size of the classes in the case of virtual inheritance involving virtual functions.

   class A{
          char k[ 3 ];
          public:
          virtual void a(){};
          };

   class B : public  A{
          char j[ 3 ];
          public:
          virtual  void b(){};
          };

   class C : public virtual A{
          char i[ 3 ];
          public:
          virtual void c(){};
          };

   class D : public B, public C{
          char h[ 3 ];
          public:
          virtual void d(){};
          };

The output of the size of the classes is :

    sizeof(A): 8
    sizeof(B): 12
    sizeof(C): 16
    sizeof(D): 32

The compiler I am using is gcc version 4.6.1 (Ubuntu/Linaro 4.6.1-9ubuntu3)

Upvotes: 8

Views: 3455

Answers (4)

sizeof(A): 8

3 bytes in the array, 1 byte padding, 4 bytes for the vptr (pointer to the vtable)

sizeof(B): 12

A subobject: 8, 3 bytes for the extra array, 1 byte padding

sizeof(C): 16

This is probably the surprising one for you... A subobject: 8, 3 bytes for the extra array, 1 byte padding, 4 bytes pointer to A

Whenever you have virtual inheritance, the location of the virtual base subobject with respect to the start of the complete type is unknown, so an extra pointer is added to the original object to track where the virtual base is. Consider this example:

struct A {};
struct B : virtual A {};
struct C : virtual A {};
struct D : B, C {};

The location of A with respect to the start of the B object when the complete type is a B can be different than the location of the A subobject of B when it is part of the final object D. If this is not obvious, assume that the relative location is the same, and check whether the relative location of A with respect to C in a C final object or a C subobject in D can also be maintained.

As for the last example, I don't quite feel like analyzing it... but you can read the Itanium C++ ABI for a concrete implementation of the C++ object model. All other implementations don't differ much.


Last example:

sizeof(D): 32

D contains a B subobject (12), and a C subobject (16), plus an additional array of size 3 and one extra bit of padding 1.

In this particular case, the question that could come up is why are there two A subobjects if C inherits virtually from A, and the answer is that virtual base means that the object is willing to share this base with any other type in the hierarchy that is also willing to share it. But in this case B is not willing to share it's A subobject, so C needs it's own.

You should be able to track this by adding logs to the constructors at the different levels. In the case of A have it take a value in the compiler and pass different values from each extending class.

Upvotes: 10

Spo1ler
Spo1ler

Reputation: 4369

To know the real size of the data structure you can say the compliler not to align it in memory using #pragma pack(1). To save current packing settings and restore them later you also can use #pragma pack(push) and #pragma pack(pop).

Upvotes: 0

bisarch
bisarch

Reputation: 1398

sizeof(C) is more than sizeof(B) because an object of type C(because it is inheriting virtually from A) will contain a pointer(apart from a vptr which objects of type B will also contain) pointing for the part of itself that it inherited from A. Scott Meyers explains this in detail(about 10 pages) in the Item 24: 'Understand the costs of virtual functions, multiple inheritance, virtual base classes, and RTTI' of his book More Effective C++

Upvotes: 1

Edward Loper
Edward Loper

Reputation: 15944

Here's my best guess as to where all the bytes are being used:

              Avptr Bvptr CVptr DVptr k j i h k' j' i'  TOTAL
============= ========================================= =====
sizeof(A): 8    4                     4                   8
sizeof(B): 12        4                4 4                12
sizeof(C): 16              4          4 4 4              16
sizeof(D): 32                    4    4 4 4 4  4  4  4   32

Where:

  • the vptrs take 4 bytes each (64-bit pointers)
  • the char arrays take 4 bytes each (rounded up for alignment)
  • k', j', and i' are the copies of those variables that are inherited via C, rather than B.

Upvotes: -1

Related Questions