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.
- Effective C++ 3rd Edition has several items related to this:
- Item 32: Make sure public inheritance models "is-a."
- Item 34: Differentiate between inheritance of interface and inheritance of implementation
- Item 38: Model "has-a" or "is-implemented-in-terms-of" through composition