Unlike protected inheritance, C++ private inheritance found its way into mainstream C++ development. However, I still haven't found a good use for it.
When do you guys use it?
Unlike protected inheritance, C++ private inheritance found its way into mainstream C++ development. However, I still haven't found a good use for it.
When do you guys use it?
I found a nice application for private inheritance, although it has a limited usage.
Problem to solve
Suppose you are given the following C API:
Now your job is to implement this API using C++.
C-ish approach
Of course we could choose a C-ish implementation style like so:
But there are several disadvantages:
struct
wrongstruct
C++ Approach
We are allowed to use C++, so why not use its full powers?
Introducing automated resource management
The above problems are basically all tied to the manual resource management. The solution that comes to mind is to inherit from
Widget
and add a resource managing instance to the derived classWidgetImpl
for each variable:This simplifies the implementation to the following:
Like this we remedied all the above problems. But a client can still forget about the setters of
WidgetImpl
and assign to theWidget
members directly.Private inheritance enters the stage
To encapsulate the
Widget
members we use private inheritance. Sadly we now need two extra functions to cast between both classes:This makes the following adaptions necessary:
This solution solves all the problems. No manual memory management and
Widget
is nicely encapsulated so thatWidgetImpl
does not have any public data members anymore. It makes the implementation easy to use correctly and hard (impossible?) to use wrong.The code snippets form a compiling example on Coliru.
I use it all the time. A few examples off the top of my head:
A typical example is deriving privately from an STL container:
Sometimes I find it useful to use private inheritance when I want to expose a smaller interface (e.g. a collection) in the interface of another, where the collection implementation requires access to the state of the exposing class, in a similar manner to inner classes in Java.
Then if SomeCollection needs to access BigClass, it can
static_cast<BigClass *>(this)
. No need to have an extra data member taking up space.Private Inheritance to be used when relation is not "is a", But New class can be "implemented in term of existing class" or new class "work like" existing class.
example from "C++ coding standards by Andrei Alexandrescu, Herb Sutter" :- Consider that two classes Square and Rectangle each have virtual functions for setting their height and width. Then Square cannot correctly inherit from Rectangle, because code that uses a modifiable Rectangle will assume that SetWidth does not change the height (whether Rectangle explicitly documents that contract or not), whereas Square::SetWidth cannot preserve that contract and its own squareness invariant at the same time. But Rectangle cannot correctly inherit from Square either, if clients of Square assume for example that a Square's area is its width squared, or if they rely on some other property that doesn't hold for Rectangles.
A square "is-a" rectangle (mathematically) but a Square is not a Rectangle (behaviorally). Consequently, instead of "is-a," we prefer to say "works-like-a" (or, if you prefer, "usable-as-a") to make the description less prone to misunderstanding.
If derived class - needs to reuse code and - you can't change base class and - is protecting its methods using base's members under a lock.
then you should use private inheritance, otherwise you have danger of unlocked base methods exported via this derived class.
I find it useful for interfaces (viz. abstract classes) that I'm inheriting where I don't want other code to touch the interface (only the inheriting class).
[edited in an example]
Take the example linked to above. Saying that
is to say that Wilma is requiring Fred to be able to invoke certain member functions, or, rather it is saying that Wilma is an interface. Hence, as mentioned in the example
comments on the desired effect of programmers needing to meet our interface requirements, or breaking the code. And, since fredCallsWilma() is protected only friends and derived classes can touch it i.e. an inherited interface (abstract class) that only the inheriting class can touch (and friends).
[edited in another example]
This page briefly discusses private interfaces (from yet another angle).