In OO design you have two common ways of dealing with duplication and reuse: composition and inheritance.
Composition: Assembling objects. "Has a" relationships. Black box reuse (No internals visible)
Inheritance: Defined in terms of the parents implementation. "Is a" relationships. (Don't forget Liskov) White-box reuse (Access to parent internals).
As stated in the definition above, you use inheritance for "is a" relationships (that are substitutable).
The are several problems with using inheritance for anything else
- You're not supposed to use inheritance for code reuse.
- You can (sort of) break encapsulation since the sub-class is so tightly coupled to the parent's implementation.
- Inheritance is set in stone at runtime, so no dynamic fun.
- A subclass can easily make assumptions about the context the method it overrides is called.
Composition has other strengths than inheritance
- Any object with the same type can be replaced at runtime. This is important for many things, for instance testing - as we want to test in isolation.
- You can "just plug in behavior" with composition. A small object can help decide how a bigger object works.
- It is the better approach when you want to reuse functionality.
It is also erroneous that composition does not use inheritance. It is typically done through implementing smaller interfaces rather than inheriting from a big class.
If you want to have a look at what Grady Booch defines as the "prototypical example of the flexibility of composition over inheritance", take a look at the strategy pattern.
To sum up a short text: This is really a no-brainer. Think for a couple of seconds before choosing an approach, and just use your gut feeling.