Reputation: 33
the environment is vs 2008
#include <iostream>
using namespace std;
class A {
public:
virtual ~A();
virtual void foo();
};
class B : public virtual A {
public:
virtual ~B();
virtual void foo();
};
class C : public virtual A {
public:
virtual ~C();
virtual void foo();
virtual void foobar();
};
class D : public B, public C {
public:
virtual ~D();
virtual void foo();
virtual void foobar();
};
int main()
{
cout<<"size of A "<<sizeof(A)<<endl;
cout<<"size of B "<<sizeof(B)<<endl;
cout<<"size of D "<<sizeof(D)<<endl;
cout<<"size of C "<<sizeof(C)<<endl;
}
the result is:
size of A 4
size of B 12
size of D 20
size of C 16
Upvotes: 0
Views: 431
Reputation: 73366
Only very few is defined in the standard about the memory layout of objects, as you can see in this SO question. Most of the layout is implementation defined. As you refer to MSVC implementation, let's have a look at these (non portable) implementation details for the sake of curiosity.
Simple inheritance:
I propose you to start with simple non virtual inheritance without virtual functions:
class X { }; // size of X 1
class Y : public X { }; // size of Y 1
All objects must have a non null size (that's still standard). This is why we see 1 despite X is completely empty. Remark that Y has the same size as X, because nothing is added in Y (and Y has therefore already a non null size).
Simple inheritance, with virtual functions:
When you start using virtual functions, MSVC adds a pointer to a vtable at the beginning of the object. This SO question show the principle of vtable in case of simple inheritance.
class XF // size of XF 4
{ public: virtual void foo(){} };
class YF : public XF // size of YF 4
{ public: virtual void bar(){} };
class YX : public X // size of YX 4
{ public: virtual void bar(){} };
You see here that the vtable pointer is of size 4. You can immediately deduct that I have compiled in 32 bit mode, because in x64 mode you'd have 8.
By the way, for the purpose of polymorphism, vtables of single inherited classes are merged (you've only one vtable pointer at the beginning of the derived object). More on vtables in signle an multiple inheritance in this very interesting DDJ article.
Multiple inheritance without virtual inheritance:
Multiple inheritance combines all the classes inherited, so its size is at least as big as the adding of the size of the inherited classes.
But it can be bigger because of alignement requirements, and in case virtual functions, an additional vtable pointer (merging is no longer possible as in single inheritance). This is also explained in the DDJ article.
Virtual inheritance:
Let's see the effect of virtual inheritance (which has nothing to do with virtual functions):
class ZX : public virtual X { }; // size of ZX 4
class ZF : public virtual XF { }; // size of ZF 8
class ZZF: public virtual ZF { }; // size of ZZF 12
So we see that whenever you make a virtual inheritance, a pointer is added. What's the purpose of this ?
Well without virtual inhertiance, upcasting from a derived object to its base is straightforward.
But with virtual inheritance, such upcasting is a nightmare, because several classes share the same base class. So the base class might no longer be contiguous to the derived class. This is why virtual inheritance needs a pointer to a virtual base table. For every virtual inheritance.
Upvotes: 1