The Benefit of Private Inheritance
(Yes the title is accurate. As you will see by the end of this piece, there is exactly one benefit of private inheritance.)
One of the (few) useful aspects unique to OO is inheritance. In general, inheritance allows you to expand an existing class to change or increase it’s functionality. Inheritance as known by Java and .NET programmers (and beginning C++ programmers) simply pulls down all the functions from a single base/super class and exposes them from your derived/sub class.
In the C++ world, though, inheritance is more complicated. The contents of more than one class may be used to construct a new class, and the accessibility of the imported members may be modified. The ‘standard’ inheritance is known in C++ as public inheritance. All imported members have the same accessibility as they did in the base class.
class MyBaseClass { public: void doSomething(); protected: int aNumber; }; class MyDerivedClass : public MyBaseClass { public: int getTheNumber() { return aNumber; } };
Could have been written as follows:
class MyDerivedClass { public: void doSomething(); int getTheNumber() { return aNumber; } protected: int aNumber; };
Private inheritance limits the accessibility of the imported members allowing only the immediate derived class access.
class MyBaseClass { public: void doSomething(); protected: int aNumber; }; class MyDerivedClass : private MyBaseClass { public: int getTheNumber() { return aNumber; } };
Is effectively the same as:
class MyDerivedClass { public: int getTheNumber() { return aNumber; } private: void doSomething(); int aNumber; };
Protected inheritance exists but is basically never used. The same can be said for private inheritance, since it provides very little benefit over a second option. The example of private inheritance directly above could also have been written like this:
class MyDerivedClass2 { private: MyBaseClass myClass; public: int getTheNumber() { return myClass.aNumber; } };
These snippets are actually examples of the Adapter pattern.
An adapter allows classes to work together … by wrapping its own interface around that of an already existing class.
To be more specific, the example using inheritance is an example of a class adapter, while the second is an example of an object adapter. Private inheritance is preferred for class adapters, since clients are prevented from modifying the underlying data structure. Programming languages that don’t support private inheritance must use an object adapter to achieve this.
So private inheritance may be used to allow the class you are writing to use a particular object without allowing the client or subclasses to also use it. Obviously (hopefully), this provides absolutely no benefit over simply declaring a private instance variable.
In fact, private inheritance is at a distinct disadvantage to an instance variable. How many other programmers will notice and understand the ‘private’ specification? Composing two concrete or partially implemented classes becomes mind-bendingly confusing and the risk of namespace collisions should turn even the most masochistic developer off private inheritance.
So what’s left? “Performance,” somebody yells. “Accessing a function attached to a member variable requires an extra lookup over accessing a function on the caller.” This is correct, under certain conditions.
Firstly, the function being called must have been marked virtual. A non-virtual function doesn’t appear in the virtual function table (duh) but is called directly.
Secondly, the instance variable must be a pointer to an instance, rather than the instance itself. Why? Because an actual instance must be a fully defined class. The following snippet shows both a valid and invalid example.
class LaunchableOutOfACannon { public: virtual void launch() = 0; }; class PussyCat : public LaunchableOutOfACannon { public: void launch() { cout << "Meowwwwwwww!"; } }; // A valid example class MyObjectAdapterThatWorks { private: PussyCat obj; public: void fireMe() { obj.launch(); } }; // An invalid example class MyObjectAdapterThatDoesntWork { private: LaunchableOutOfACannon obj; public: void fireMe() { obj.launch(); } };
Spot the difference? An abstract class cannot be instantiated, and so the type of an object that is specified in this manner (that is, not a pointer) must be fully known at compile time. As a result, the exact function call is known at compile time and a virtual function table lookup is not necessary. The other side of the same coin is that if a virtual function table lookup is required for the object adapter, it will also be required for the class adapter.
class MyClassAdapter : private PussyCat { public: void fireMe() { launch(); } }; |
class MyObjectAdapter { private: PussyCat obj; public: void fireMe() { obj.launch(); } }; |
; void fireMe() { launch(); } mov eax, [ecx] mov edx, [eax] jmp edx |
; void fireMe(); { obj.launch(); } mov eax, [ecx] mov edx, [eax] jmp edx |
The optimised VC++ 9.0 output is identical for both the object adapter and the class adapter (as is the unoptimised output, but the optimised one is considerably neater). The virtual function table lookup occurs in both cases with the final function pointer ending up in edx. (Removing the pure virtual function from LaunchableOutOfACannon results in direct jumps to the function, as expected. Apparently VC++ 9.0 will not optimise out virtual function lookups.)
So private inheritance doesn’t have the benefit of speed or code size over a private instance variable. It doesn’t have the benefit of readability and can require incredible feats of mental gymnastics to follow code using it. The one and only advantage of private inheritance is that Java developers don’t get to use it. Nya nya nya nya nya nya!
