The virtual base object is somewhere in the memory block that belongs to the object (the memory with size = sizeof(object)). Because several sub objects of different types can be combined in various ways but must share the same base object, a offset pointer is needed for each sub object to find out the virtual base object. Without virtual inheritance, the offset to find out the corresponding base object is fixed at compile time for each class type.
The sizeof values depend on your compiler and machine, but the following assumptions are very common:
assumption: pointer size is 4 bytes
assumption: class size is rounded up to multiple of 4 bytes
sizeof(A): 8 -> 1 pointer to vtable (virtual method)
+ 3 chars -> 4+3=7
-> round up to 8
sizeof(B): 20 -> 8 + 1 pointer to vtable (virtual method)
+ 1 offset pointer to virtual base
+ 3 chars -> 8 + 4 + 4 + 3 = 19
-> round up to 20
sizeof(C): 32 -> 20 + 1 pointer to vtable (virtual method)
+ 1 offset pointer to virtual base
+ 3 chars
-> 20 + 4 + 4 + 3 = 31 // this calculation refers to an older
-> round up to 32 // version of the question's example
// where C had B as base class
The calculations are guessed because the real calculation must exactly know how the compiler works.
Regards,
Oliver
More details why an extra offset pointer is needed:
Example:
class B : virtual public A {...};
class C : virtual public A {...};
class D1 : public B {...};
class D2 : public B, C {...};
possible memory layout for D1:
A
B
D1
possible memory layout for D2:
A
C
B
D2
in the second case sub object B needs another offset to find its base A
An object of type D2 consists of a memory block, where all the parent object parts are contained, i.e. the memory block for an object of type D2 has a section for the A member variables, the C member variables, the B member variables and the D2 member variables. The order of these sections is compiler dependent, but the example shows, that for multiple virtual inheritance a offset pointer is needed, that points within the object's total memory block to the virtual base object. This is needed because the methods of class B know only one this pointer to B and must somehow calculate where the A memory part is relative to the this pointer.
Calculation sizeof(D):
sizeof(D): 36 -> A:3 chars + A:vtable
+ B:3 chars + B:vtable + B:virtual base pointer
+ C:3 chars + C:vtable + C:virtual base pointer
+ D:3 chars + D:vtable
= 3 + 4
+ 3 + 4 + 4
+ 3 + 4 + 4
+ 3 + 4
= 36
The above calculation is probably wrong ;-) ...
I'm not sure whether the D part has its own vtable pointer or not (this is all highly compiler dependent).
I now think that it could be that the D part use the vtable pointer entry of its parent classes and that the 4 extra bytes are used for alignment each part (multiple of 8 bytes):
So this calculation is probably more correct:
sizeof(D): 36 -> A:3 chars + A:vtable + A:alignment
+ B:3 chars + B:vtable + B:virtual base pointer + B:alignment
+ C:3 chars + C:vtable + C:virtual base pointer + C:alignment
+ D:3 chars + D:alignment
= 3 + 4 + 1
+ 3 + 4 + 4 + 1
+ 3 + 4 + 4 + 1
+ 3 + 1
= 36