Private Inheritance

You might not be surprised to learn that, in addition to the commonly used public inheritance C++ also supports private inheritance. What you might not know is how it works or what it means to privately inherit from another class. Before talking about what it does, let's figure out what it means to inherit privately from another class.



Private inheritance does not model an is-a relationship in the same way that public inheritance does. Instead, private inheritance refers to the idea of being "implemented in terms of a". The key difference is that whereas public inheritance provides a common interface between two classes, private inheritance does not--rather, it makes all of the public functions of the parent class private in the child class. This means that they can be used in order to implement the child class without being accessible to the outside world.

The syntax for private inheritance is almost exactly the same as for public inheritance:
class obj : private implementationDetailOfObj


This sort of thing might be useful for times when you want to disallow certain parts of a class's functionality. For instance, if you were creating a list of unique elements, you might want to implement it in terms of an STL list, but you wouldn't want to allow anyone to use the normal list add function, which might allow anyone to add non-unique elements to the list. You might think that you could override the method to accomplish the same thing. Unfortunately, this would only work if the method were virtual, and someone could still perform a cast to get around this attempt at preventing the use of the add function.

Of course, there is often another way to reuse code when your goal is to implement one class in terms of another class: inclusion. The idea of inclusion is that when you want to implement one class in terms of a second, you can often make the second class a private field of the first class and just make the appropriate method calls. This also solves the problem of preventing access to the functions of that class that you don't want to expose as part of your class's public interface (just as private inheritance does). Inclusion is also nice because it is conceptually simple to include multiple classes as members of another. In general, if you can, it is best to favor inclusion over private inheritance because of its simplicity.

So why would you ever want to use private inheritance? Sometimes it turns out that the class that you wish to implement your own class in terms of relies on overriding virtual functions for its implementation. For instance, you might have a class that provides a framework for a game and virtual functions that are called to draw the player sprites at appropriate locations and times. Unfortunately, to take advantage of this class, you need to overload those functions to build in your own features. You could do this by publicly inheriting the class, but then you expose all of those newly inherited functions as part of your own interface, probably not what you really wanted to do.

For instance, the following class provides some functionality that we might find useful, but it relies on virtual functions to determine parts of what it does:
class taxAdvisor
{
    public:
    int computeTaxes ()
    {
        // perform lots of fancy math using the getIncome and
        // computeDeductions functions
    }
    virtual int getIncome ();
    virtual computeDeductions ();
};
Any subclass of tax advisor that wishes to change the computations of taxes based on income of deductions would need to override the getIncome and computeDeductions functions. Unfortunately, we can't use inclusion in this case because that wouldn't let us override those functions. We actually need to inherit from taxAdvisor. But if our goal is just to implement a class in terms of taxAdvisor, then private inheritance is the right way to go. (Maybe we don't want getIncome to be public!)

If you need this kind of functionality, then private inheritance is the only solution to the problem!

Summary

  • Private inheritance models the "is implemented in terms of a" relationship, rather than the is-a relationship that is modeled by public inheritance.
  • Private inheritance results in all public functions of a class being inherited as private functions
  • Private inheritance should be used sparingly, but can be necessary when you need to override a virtual function