Recently we discussed a defect mentioned here and one of the parties said something like "yes, that's why books say that inheritance should be avoided.
I've been using inheritance for years and find it very useful and convenient in many design cases. Also I'm sure that the person arguing at the very least misunderstood what those "books say".
Is there really an idea that inheritance is kind of bad and should be avoided? Where does it originate and where can I learn more?
I think what he might have meant is that inheritance can be overused, even in cases where composition would be a better solution. This is discussed in several books, e.g.
Inheritance is a powerful way to achieve code reuse, but it is not always the best tool for the job. Used inappropriately, it leads to fragile software. It is safe to use inheritance within a package, where the subclass and the superclass implementations are under the control of the same programmers. It is also safe to use inheritance when extending classes specifically designed and documented for extension (Item 17). Inheriting from ordinary concrete classes across package boundaries, however, is dangerous. As a reminder, this book uses the word “inheritance” to mean implementation inheritance (when one class extends another). The problems discussed in this item do not apply to interface inheritance (when a class implements an interface or where one interface extends another).
Unlike method invocation, inheritance violates encapsulation [Snyder86]. In other words, a subclass depends on the implementation details of its superclass for its proper function. The superclass’s implementation may change from release to release, and if it does, the subclass may break, even though its code has not been touched. As a consequence, a subclass must evolve in tandem with its superclass, unless the superclass’s authors have designed and documented it specifically for the purpose of being extended.
Not to be avoided every time, but it hinders flexibility wherever you are stuck with a defined set of operations from a superclass. The basic design idea is "leave to inheritance the fixed parts and inject the parts subject to change".
In Head First Desing Patterns there is a good example.
Say you decide to model ducks with a base class which implements fly(). Say that you have a RubberDuck, who can't fly, of course. You override fly() with a method that does nothing. But then some day you add DecoyDuck and forget to override fly() and you get a mess. It would have been better to build the DecoyDuck injecting the desired behaviour (composition over inheritance).
Good coding practice in C++ prefers composition through aggregation. cf. "C++ Coding Standards: 101 Rules, Guidelines, And Best Practices" by Sutter/Alexandrescu
Inheritance should not be avoided 'as is'.
Inheritance should be used (and only used) when you want to define / describe an 'is a' relationship.
When an entity 'is not' anotherentity, entity should not inherit from anotherentity. In such cases, composition should be used.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With