Given the code:
class A{};
class B : public virtual A{};
class C : public virtual A{};
class D : public B,public C{};
int main(){
cout<<"sizeof(D)"<<sizeof(D);
return 0;
}
Output: sizeof(D) 8
Every class contains its own virtual pointer only not of any of its base class, So, why the Size of class(D) is 8?
Virtual base classes are used in virtual inheritance in a way of preventing multiple “instances” of a given class appearing in an inheritance hierarchy when using multiple inheritances.
It will make three levels of classes and two levels of inheritance. In some books, it is called multilevel inheritance. This type of inheritance is illustrated withFigure 10.4. Access specifier “protected” is very much useful in this type of inheritance.
Instead, if classes B and C inherit virtually from class A, then objects of class D will contain only one set of the member variables from class A. As you probably guessed, this technique is useful when you have to deal with multiple inheritance and it's a way to solve the infamous diamond inheritance.
Unlike languages that allow multiple inheritance, Visual Basic allows only single inheritance in classes; that is, derived classes can have only one base class. Although multiple inheritance is not allowed in classes, classes can implement multiple interfaces, which can effectively accomplish the same ends.
It depends on compiler implementation. My compiler is Visual Stdio C++ 2005.
Code like this:
int main(){
cout<<"sizeof(B):"<<sizeof(B) << endl;
cout<<"sizeof(C):"<<sizeof(C) << endl;
cout<<"sizeof(D):"<<sizeof(D) << endl;
return 0;
}
It will output
sizeof(B):4
sizeof(C):4
sizeof(D):8
class B has only one virtual pointer. So sizeof(B)=4
. And class C is also.
But D multiple inheritance the class B
and class C
. The compile don't merge the two virtual table.So class D
has two virtual pointer point to each virtual table.
If D only inheritance one class and not virtual inheritance. It will merge they virtual table.
It depends on compiler implementation so you should specify which compiler you're using. Anyway D derives from two classes so it contains pointers to B and C vtables base class pointers (I don't know a good name for this).
To test this you may declare a pointer to B and a pointer to C and cast the address of D to base class pointer. Dump that values and you'll see they're different!
EDIT
Test made with Visual C++ 10.0, 32 bit.
class Base
{
};
class Derived1 : public virtual Base
{
};
class Derived2 : public virtual Base
{
};
class Derived3 : public virtual Base
{
};
class ReallyDerived1 : public Derived1, public Derived2, public Derived3
{
};
class ReallyDerived2 : public Derived1, public Derived2
{
};
class ReallyDerived3 : public Derived2
{
};
void _tmain(int argc, _TCHAR* argv[])
{
std::cout << "Base: " << sizeof(Base) << std::endl;
std::cout << "Derived1: " << sizeof(Derived1) << std::endl;
std::cout << "ReallyDerived1: " << sizeof(ReallyDerived1) << std::endl;
std::cout << "ReallyDerived2: " << sizeof(ReallyDerived2) << std::endl;
std::cout << "ReallyDerived3: " << sizeof(ReallyDerived3) << std::endl;
}
Output, guess, is not surprising:
Adding a virtual method to the base you get 4 bytes more for each class. So probably extra bytes aren't vtable pointers but base class pointers used in multiple inheritance, this behavior does not change removing virtual inheritance (but if not virtual the size doesn't change adding more bases).
First: without virtual functions, it's probable that there isn't a
vptr
at all in the classes. The 8 bytes you're seeing are an artifact
of the way virtual inheritance is implemented.
It's often possible for several classes in a hierarchy to share the same
vptr
. For this to occur, it is necessary for their offset in the
final class to be the same, and for the list of vtable entries in the
base class to be an initial sequence the list of vtable entries in the
derived class.
Both conditions are met in almost all implementations for single
inheritance. No matter how deep the inheritance, there will usually be
only one vptr
, shared between all of the classes.
In the case of multiple inheritance, there will always be at least one class for which these requirements aren't met, since the two base classes can't have a common start address, and unless they have exactly the same virtual functions, only one's vtable could possibly be an initial sequence of the other.
Virtual inheritance adds another quirk, since the position of the virtual base relative to the class inheriting from it will vary depending on the rest of the hierarchy. Most implementations I've seen use a separate pointer for this, although it should be possible to put this information in the vtable as well.
If we take your hierarchy, adding virtual functions so that we are
certain of having a vptr
, we notice that B
and D
can still share a
vtable
, but both A
and C
need separate vtables
. This means that
if your classes had virtual functions, you would need at least three
vptr
. (From this I conclude that your implementation is using
separate pointers to the virtual base. With B
and D
sharing the
same pointer, and C
with its own pointer. And of course, A
doesn't
have a virtual base, and doesn't need a pointer to itself.)
If you're trying to analyse exactly what is going on, I'd suggest adding a new virtual function in each class, and adding a pointer sized integral type that you initial with a different known value for each class. (Use constructors to set the value.) Then create an instance of the class, take it's address, then output the address for each base class. And then dump the class: the known fixed values will help in identifying where the different elements lie. Something like:
struct VB
{
int vb;
VB() : vb( 1 ) {}
virtual ~VB() {}
virtual void fvb() {}
};
struct Left : virtual VB
{
int left;
Left() : left( 2 ) {}
virtual ~Left() {}
virtual void fvb() {}
virtual void fleft() {}
};
struct Right : virtual VB
{
int right;
Right() : right( 3 ) {}
virtual ~Right() {}
virtual void fvb() {}
virtual void fright() {}
};
struct Derived : Left, Right
{
int derived;
Derived() : derived( 5 ) {}
virtual ~Derived() {}
virtual void fvb() {}
virtual void fleft() {}
virtual void fright() {}
virtual void fderived() {}
};
You might want to add a Derived2
, which derives from Derived
and see
what happens to the relative addresses between e.g. Left
and VB
depending on whether the object has type Derived
or Derived2
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With