When there is a virtual base object, the location of the base object relative to the address of the derived object is not statically predictable. It is noteworthy that if you expand the class hierarchy a bit, it becomes clear that there may be several subobjects D that still need to reference only one base object B :
class I1: public D {}; class I2: public D {}; class Most: public I1, public I2 {};
You can get D* from the Most object by converting it first to I1 or first to I2 :
Most m; D* d1 = static_cast<I1*>(&m); D* d2 = static_cast<I2*>(&m);
You will have d1 != d2 , i.e. there really are two subobjects D , but static_cast<B*>(d1) == static_cast<B*>(d2) , i.e. there is only one subobject B To determine how to adjust d1 and d2 to find a pointer to subobject B , dynamic offset is required. Information on how to determine this offset must be stored somewhere. Storage for this information is a likely source of an additional 8 bytes.
I do not think that the layout of the object for types in MSVC ++ is [publicly] documented, i.e. it’s impossible to say exactly what they are doing. In appearance, they implement a 64-bit object in order to be able to indicate where the base object is relative to the address of the derived object (a pointer to some type information, a pointer to the base, the base offset, something like this). The other 8 bytes, most likely, come from the need to store char plus some addition so that the object is aligned on a suitable border. This is similar to what the other two compilers do, except that they used 16 bytes for a long double to start with (perhaps just 10 bytes, complemented by suitable alignment).
To understand how the C ++ object model can work, you can take a look at Stan Lippman's "Inside the C ++ Object Model" . It is a bit outdated, but describes possible implementation methods. Is MSVC ++ any of these, I don’t know, but it gives ideas that can be used.
For the object model used by gcc and clang, you can take a look at Itanium ABI : they essentially use Itanium ABI with little tweaks to the actual CPU used.