The rule of thumb is, never use private inheritance unless you absolutely have to, and you almost never have to. Let’s see why.
Private inheritance is completely different than public inheritance, in many aspect. One is how compiler treat those differently.
1 | class Person { ... }; |
In contrast to public inheritance, compilers will generally not convert a derived class object (such as Student
) into a base class object (such as Person
) if the inheritance relationship between the classes is private. That’s why the call to eat
fails for the object s
.
Private inheritance means is-implemented-in-terms-of. If you make a class D
privately inherit from a class B
, you do so because you are interested in taking advantage of some of the features available in class B
, not because there is any conceptual relationship between objects of types B
and D
. As such, private inheritance is purely an implementation technique. Private inheritance means nothing during software design, only during software implementation.
So what’s the situation private inheritance is suitable? Let’s see and example. In this example, we want to write a Timer
for our Widget
class, and we find a Timer
we can reuse all interfaces but need to change one function onTick
. One way is to let Widget
inherit from Timer
privately, and redefine the virtual function onTick
.
1 | class Timer { |
An alternative, is to create a public inheritance WidgetTimer
and use it as composition.
1 | class WidgetTimer: public Timer { |
So why public inheritance plus composition is preferred over private inheritance? Here are two reasons.
- You might want to design Widget to allow for derived classes, but you might also want to prevent derived classes from redefining
onTick
. If Widget inherits fromTimer
, that’s not possible, not even if the inheritance is private. - You might want to minimize
Widget
‘s compilation dependencies. IfWidget
inherits fromTimer
,Timer
‘s definition must be available whenWidget
is compiled, so the file definingWidget
probably has to#include "Timer.h"
.
Private inheritance is most likely to be a legitimate design strategy when you’re dealing with two classes not related by is-a where one either needs access to the protected members of another or needs to redefine one or more of its virtual functions. Even in that case, we’ve seen that a mixture of public inheritance and containment can often yield the behavior you want, albeit with greater design complexity. Using private inheritance judiciously means employing it when, having considered all the alternatives, it’s the best way to express the relationship between two classes in your software.