Avoiding Inheritance Dependency
You read it right. The traditional Object Oriented principle of inheritance can (and IMO, should) be avoided especially when trying to build maintainable and extensible frameworks. Although it works in some instances, modern C++ allows us to leave out this pillar of the Object Oriented Paradigm with the use of function pointer wrappers and functional programming (with some template metaprogramming on the side).
Why Avoid Inheritance
Because Inheritance causes too close a coupling between the base class and the derived class (or type, which can be pretty much interchangeable in C++). The close dependency between the base class and the derived class leads you to write a lot of code that assumes some behavior or functionality -- which can (and will most probably break) when something from the base class changes.
Inheritance alone (without polimorphism) is pretty much useless if not to just become like something else. Extending a class by inheritance is pretty much moot especially if the goal was to add functionality to the class -- which always begs the question: why don't you just either change the class or do composition? It's always a good question, and if the goal was adding functionality and adding to the existing interface then we see that composition is a good choice; while in other cases just adding a function to the class itself will make a lot of sense.
Then why do we even entertain Inharitance?
Sometimes it's because some (or a lot of) frameworks rely on inheritance (even multiple inheritance) to be able to work with it. Most of these frameworks already have some hard-coded assumptions and closely coupled components where the application specific parts need to conform to.
In other cases, it's because most of the designers have been preconditioned to think that inheritance is a good thing -- and it certainly is very easy to just inherit behavior from a base class. In even more cases, that's the only way developers in the trenches can claim that their code is object oriented.
In a lot of cases, it's because the (earlier) books on object oriented design and patterns have come up with elaborate UML diagrams of how a pattern can be implemented using the basic tenets of OOP. That's not bad at all, until you start trying to maintain (C++) code which relied heavily on inheritance and polimorphism.
So what are my options in C++?
You can reverse the relationship: still use inheritance but instead of the derived class implementing the specifics, you have the base class implementing the specifics. This is somewhat called the Parametric Base Class Pattern (PBCP) as used by the Phoenix framework.
Another way is to let the base class know about the derived class, and still have the base class implement the specifics, though during compile time. This is called the Curiously Recurring Template Pattern (CRTP).
Yet another way is to do something called "duck typing" ala Python, where the code just requires that a type implements a certain function. People use traits for specialization or policies for (compile time) decision making. And there's an even more flexible means by requiring that a function pointer of a certain interface be stored and passed around.
There are certainly a lot of ways to go around the runtime penalty hit of inheritance+polimorphism with RTTI by using modern C++ concepts and techniques. Now if people only knew about how to stop using inheritance for the wrong reasons...
Good stuff!



2 comments:
Looks cool . But can you give a simple example and tell That Inheritance is not good here without being biased against Inheritance ..
Hi Mukesh!
I can certainly do that, and I'll put it in my list of next blog posts. :)
Revisiting Inheritance with examples is definitely a good idea and I hope to write about it soon. Adjusting to a new work environment is taking some time.
Thanks for dropping a line!
Post a Comment