A few weeks ago I introudced private inheritance, and finished with a comment about a common excuse for using it. In this post I give an example of such usage, and discuss whether it is a good idea or not.
Say you are going to write a new class
CppInfo, which will print out some information about the C++ language. Here is an example:
Now we need some way to assess the quality of C++, to replace those question marks. Luckily, there exists a class that assesses the quality of a programming language:
As you can see, the only thing we need to do is to create a derived class from
LanguageQuality for C++, returning the number of characters required for a C++
Hello, World program.
This is where private inheritance can come in handy. We need access to
LanguageQuality::quality(), and we need to override
charsForHelloWorld(). If we chose to inherit privately from it in
CppQuality, we get both of these, yet none of the members of
LanguageQuality will be accessible by the users of that class (as shown in the last post).
Here is a version of
CppInfo that inherits privately from
I have to admit, this looks pretty neat. The alternative is to create a new class whose only responsibilty is overriding
And then have this as a member in
Now you have two classes instead of one, and 18 lines of code instead of 13. Which solution is best? I am not sure, so let’s have a look at the arguments:
The solution using inheritance is smaller. All the code is in one place, so it is easy to get an overview. We have however coupled our class
CppInfo very tightly to
LanguageQuality, even though their responsibilities aren’t directly related. Considering the single responsibility principle,
CppInfo is about printing general info about
LanguageQuality is about computing the quality of a programming language.
I think the principle that provides the tipping point for me in this example, is that every piece of your software should have a single reason to change. Say we want to change how we compute the quality of a language (the number of characters required for
Hello, World just doesn’t cut it anymore). This would require a change to
LanguageQuality. We would then probably need to update all its derived classes. And to change a class, you really should understand all its responsibilities, invariants and effects. All the other code in
CppInfo has nothing to do with the change we are making, so we shouldn’t have to worry about it. Also, if we want to change what information we print out about C++ (say we want to add the publication year of the latest language standard), we want to understand how info is printed, not how the quality is computed.
Again, in a small example like this, it might not matter much, but in a larger example it will. And what starts out small has a nasty tendency to grow, so you’d better care about design from the very start.
Just for fun, here is the result after adding
Language: C++ Creator : Bjarne Stroustrup Quality : 1.587302 Language: Java Creator : James Gosling Quality : 0.970874 Language: Python Creator : Guido van Rossum Quality : 5.263158
Unsurprisingly, we beat Java, but lose to Python.
Now I am interested to hear your thoughts, which solution would you choose, and why?
As usual, the code for this blog post is available on GitHub.