Types of inheritance in C++
C++ standard supports three types of inheritance: public, protected and private. One of the main differences is the accessibility of the public and protected members – their accessibility is narrowed to the type of inheritance. Private members are always not accessible from derived class. The code below presents the members scope depending on the inheritance type.
The public and protected members’ scope doesn’t change when the inheritance is public. Private members can’t be accessed from derived class.
For protected inheritance, the public members become protected and protected members stay protected. This type of inheritance is rarely useful.
Both public and protected members are private in derived class.
Public inheritance
Usage of public inheritance is pretty common and means is-a relationship. The derived class can be always used when the base class is needed. In the example below, the DerivedPublic class object is passed to the function which awaits Base class and everything is fine.
Private inheritance
Would you be able to do the same trick when the derived class inherits privately from Base? Unfortunately not. Such piece of code will not compile:
The compiler will complain about error: ‘Base’ is an inaccessible base of ‘Derived’ doSmthOnBase(d). That means that, unlike public inheritance, private inheritance is not an “is-a” relationship.
So what’s the use of private inheritance?
Private inheritance means “has-a” relationship (or: “is implemented in terms of”). Similar to composition, you should use private inheritance when you want to make use of the implementation details of base class, but you do not want to inherit the interface.
When private inheritance is better than composition?
You will have to use private inheritance when you need to have access to protected members/member functions of base class. In other cases almost always you should use composition. Private inheritance will make your code harder to maintain and increase the compilation dependencies (in case of composition, you can use forward declaration and a member-pointer to object).
Empty Base Optimization (EBO)
There is one more specific case when private inheritance can be reasonable: so called Empty Base Optimization. Imagine EmptyClass with zero non-static members and zero virtual functions nor base classes. Composition of EmptyClas will increase the size of OtherClass_composition.
But if you use private inheritance you will save some space.
In this case, the size of OtherClass_inheritance should not increase (but it’s dependant on the compiler). With the use of MinGW 4.9.1 the size of OtherClass_composition was 8, while the size of OtherClass_inheritance was 4.
Further readings: