There are different types of inheritance depending on the mode of inheritance we use. Like public, protected and private inheritance. There is also concept of interface inheritance and implementation inheritance. When you are deriving your class from a base class publicly, then user of the Derived class will get access to all public interfaces of Base class, which is called as interface implementation. Where in, when your are inheriting privately, then user of the Derived class cant access Base class public interfaces. But Derived class will get access to public interfaces of Base class. That is, implementation of those interfaces is inherited. And this type of inheritance is implementation inheritance.
Again, we can inherit a Base virtually, but there is some additional cost apart from cost of normal inheritance. Every class that inherits a Base class virtually will have a virtual base pointer.
We all know that, when we instantiate an object of a class in an inheritance hierarchy, each constructer will call its immediate Base class's constructer. But this rule does not hold good when we have virtual inheritance in our hierarchy.
class BaseMost {
public:
BaseMost(int aMem = 0) : iMem(aMem) {
cout<<"BaseMost::BaseMost --> iMem is "<<iMem<<endl;
}
private:
int iMem;
};
class Base : public BaseMost {
public:
Base(int aMem = 0) : BaseMost(aMem+1), iMem(aMem) {
cout<<"Base::Base --> iMem is "<<iMem<<endl;
}
private:
int iMem;
};
class DerivedA : virtual public Base {
public:
DerivedA(int aMem = 0) : Base(aMem+1), iMem(aMem) {
cout<<"DerivedA::DerivedA --> iMem is "<<iMem<<endl;
}
private:
int iMem;
};
class DerivedB : virtual public Base {
public:
DerivedB(int aMem = 0) : Base(aMem+1), iMem(aMem) {
cout<<"DerivedB::DerivedB --> iMem is "<<iMem<<endl;
}
private:
int iMem;
};
class DerivedAB : public DerivedA, public DerivedB {
public:
DerivedAB(int aMem = 0) : /*Base(aMem+3),*/ DerivedA(aMem+2), DerivedB(aMem+1), iMem(aMem) {
cout<<"DerivedAB::DerivedAB --> iMem is "<<iMem<<endl;
}
private:
int iMem;
};
class Derived : public DerivedAB {
public:
Derived(int aMem = 0) : /*Base(aMem+4), */ DerivedAB(aMem+1), iMem(aMem) {
cout<<"Derived::Derived --> iMem is "<<iMem<<endl;
}
private:
int iMem;
};
If you were going to create an object of class DerivedAB (either using DerivedAB object; or Derived* pDerievdAB = new DerivedAB;), then your output will be like this.
BaseMost::BaseMost --> iMem is 1
Base::Base --> iMem is 0
DerivedA::DerivedA --> iMem is 2
DerivedB::DerivedB --> iMem is 1
DerivedAB::DerivedAB --> iMem is 0
But you might have expected something else atlest for this output Base::Base --> iMem is 0 and Base::Base --> iMem is 1 !!. I have the explanation for this behavior below:
When you instantiate an object, constructer of that class will take care of calling the constructer of virtual base class (if it sits above in the hierarchy from this class) and other constructers will be called as usual. So, it's the responsibility of the programmer to make sure that virtual base class is initialized with proper values when an object of that hierarchy is created. This can be achieved by calling explicitly the virtual base constructer in the initialization list.
In the above code, DerivedAB will take care of calling constructer of Base (which is virtual Base) rather than calling its immediate bases (which is DerivedA). Which inturn invokes constructer of its base, that is BaseMost's constructer. So the sequence will be as shown in below diagram,

So, it's the responsibility of Derived class to initialize virtual Base with proper value by calling the Constructer explicitly with proper input. Now try the same program with uncommenting red-colored commented codes in Derived and DerivedAB's constructer initialization list. Try to create object of Derived and see what happens with that with out those commented code. Try to see how the sequence of constructer invoking happens.
After uncommenting those code and if you try to create an object of Derived, then output will be
BaseMost::BaseMost --> iMem is 5
Base::Base --> iMem is 4
DerivedA::DerivedA --> iMem is 3
DerivedB::DerivedB --> iMem is 2
DerivedAB::DerivedAB --> iMem is 1
Derived::Derived --> iMem is 0
And see what is the size of each class in this hierarchy. For your reference, it will be:
Size of BaseMost is : 4 bytes
Size of Base is : 8 bytes
Size of DerivedA is : 16 bytes
Size of DerivedB is : 16 bytes
Size of DerivedAB is : 28 bytes
Size of Derived is : 32 bytes
Notice that, size of DerivedA and DeriveB will be 16 bytes because, they are having one extra virtual base class pointer, which will add up to 16 bytes. All the classes below this will have additional overhead of extra 4 byte because of this virtual inheritance.
Now, what is that we can achieve by using virtual inheritance? Answer will be, we can achieve some patters in C++ using virtual inheritance which would have been impossible with out virtual inheritance. And the classic example will be Final Class Pattern.
Those who are familiar with Java must be knowing that, Java provides a keyword final, using which we can put an end to inheritance hierarchy. If a class is declared as final, then nobody can inherit from this class. That is, none can use this final class in “is-a” relation. It will be the bottom most class in the hierarchy. But, in case of C++, there is no language specific keyword for supporting this final class. But there is a way of achieving this concept, so that developer of a class can make sure that nobody can extend his class by using it in inheritance hierarchy (relationship).
The implementation goes like this:
//Forward declaration of your Class, which you don't want, others to extend or inherit
class MyClass;
class LockClass {
friend class MyClass;
private:
LockClass() {}
LockClass(const LockClass& aLockClass) {}
};
class MyClass : public virtual LockClass {
public:
MyClass() {}
MyClass(const MyClass& aMyClass) { }
/* All ur implementation of MyClass class Comes here*/
};
// Its a compiler Error, if u try to inherit from MyClass!!!
class ExtendMyClass: public MyClass {
public:
ExtendMyClass() { }
};
And the compiler error is:
'LockClass::LockClass' : cannot access private member declared in class 'LockClass'
Suppose MyClass inherits LockClass non-virtually, then there wont be any error, which means that others can make use of MyClass for inheritance. So, it's the only way of achieving Final Class in C++.
This can also be achieved by making your all constructers as private. But the cost is, you have to provide one new function (which should be static) for creating an object of your class in heap and it also avoids others from having a stack variable (automatic variable) which means user of your class has to do some different mechanism for using your class.