C++ Inheritance easily grows out of control

Interface inheritance is good.

Inheritance
Parts of your behaviour are inherited from your parents. That is  “sub-typing” kind of a inheritance. The interface of your parents defines the part of  your behavior. Just like yours defines the parts of the behaviour of your children.

Update

Just stumbled upon this excellent and succinct short text on how not to use inheritance. In C++ in particular, and I am adding: in general.

The purpose of inheritance in C++ is to express interface compliance (subtyping), not to get code reuse.

That text is precisely about differences v.s. the Objective-C, but it is priceless if and when you spot the growth of the weed of inheritance.

Original post

I always have bright ideas in the morning. This morning I thought of ATL. And its usage of templates and inheritance. I figured it is a typical inheritance for implementation case. Which is bad. Make no mistake: for when it was concieved ATL was ahead of its time.

Inheritance of interfaces is an implementation of the ‘behavior extension’ concept aka “sub-typing”. Which is good. Interface inheritance is used to re-use the behaviour of the base interface. Just the behaviour.

The interface defines only the behaviour of the class which implements it. Very good indeed. Especially if you do not have one root interface in your design. Surprisingly present inside some key OO designs and implementations in widespread use today. W3C DOM objects are the typical example of bad inheritance design.

In DOM every object has properties and methods of an invisible root DOM object. A single root interface. So we have dozens or more, methods and properties, on each and every DOM object. Regardless of its required behaviour. Same on each and every DOM object. This is in many cases, much, much more than we need on a particular object.

Example : DOM element “XML” is represented with a DOM object which has all the visual properties and methods as (for example) DIV element has.  That is because they both inherit from the same object. And they are mostly totally unusable and are seriously getting in the way, especially when you are new to the DOM scripting/programming, and its zillions of objects, methods, events and properties. A sure recipe for making many mistakes and introducing many bugs.

Another example of evil inheritance is MFC. A naive, single rooted, and elaborate hierarchy of classes (not interfaces), which makes for an sea of very heavy classes with hundreds of methods and those crazy “Hungarian notation” named variables. While working in your favorite IDE they are ALL there even if you do not need them and do not have a clue what are they all for. Again, a sure sign you are bound to make bugs. If you use MFC, that is.

Information Hiding

This is the KEY problem with class inheritance: parent information is not hidden. A total opposite of the first law of OO: Information must be hidden as much as possible. So-called ‘information hiding’. A foundation corner stone of OO. Sadly broken by the likes of MFC, DOM ….. and somewhat by ATL.

Yes, I like ATL because it has used early C++ to the full and shows (same as ISO C++ std lib) very clearly, why C++ is very elegant and complete. Of course, if you know how to make it to be that way.

Sadly, the ATL team, I suppose somewhat under the dark and large shadow of MFC, adopted class inheritance approach, too. Although much better variety of inheritance than MFC. But (sadly) ATL classes, at the end of the day, inherit from template instances which are nothing else but classes, again. Only the code looks more snazzy.

ATL implementation inheritance pattern is this (deliberately simplistic but still canonical code) :

Some of you might have recognized this as a so-called “Curiously Recurring Template Pattern“. But that is basically  “inheritance for implementation” idiom. Looks pretty snazzy, does it not? But you basically inherit from template definition which actually is a type.

More detail

Well, the first problem (with any kind of inheritance) shows particularly in modern IDE’s. Imagine now some Base class has many methods. Dozens or more.  You want to inherit it and use only a sinle one. But, due to the IDE “intellisense”, all the other functions and members are immediately and readily available and very close as soon as you start typing inside your derived class. Too close for comfort. Your Visual Studio editor IntelliSense will show ALL of them. Many of them. But you need only one. Found it yet, why not? And this is just for a single one class inherited.

To make matter worse, in MFC and ATL you can (and will) inherit several base classes. And each one has many methods and properties. And they are all available to you at the same time. Providing all the methods visible from all of them all the time; through the IntelliSense feature. Hundreds of them. And still, you want only one.

All of this is directly opposite of the foundation corder stone of the OO: information hiding. Much better and dare I say proper way is delegation:

That concept is called Delegation. We delegate the job to the instance of the  Log_Service. Delegation gives total encapsulation of App2 and its implementation.

A template instance Log_Service<App2> is now totally hidden. Information hiding is achieved: Users of App2 do not know what doesLog_Service<App2> do internally. They just use it. They are even unaware of its existence. This also means that replacing Log_Service<App2> with e.g. Rest_Log_Service<App2>  is completely painless. Provided they both have the same interface. This does not break existing App2 usage in any way. Clients of App2 are completely isolated from this change.

Of course, both Log_Service<App2> and Rest_Log_Service<App2> have both to conform to same, clean and simple and narrow interface.  Just like every other class should be. Narrow interface? Ok, this is another key concept. I shall stop here, this is all that I thought off, this morning …