3D graphics programmers, if there are any that read this blog, are familiar with gimbal lock. The Wikipedia article makes an analogy to compass directions. If you tell somebody at the north pole to face south, which direction are they facing? You have no way of knowing, because south loses its meaning at the north pole. At any other place on the planet, your location and direction are completely independent. At the poles, direction has no meaning in the cartographic coordinate system. Two previously independent variables have now become linked.
In programming, when you derive from a base class, the classes are in a state of gimbal lock. We can vary the subclass as much as we want without affecting the base class. However, a change to the base class will not only affect our subclass, but every other subclass out there. Suppose that our base class provides some core data processing functionality, and its various subclasses encapsulate different data sources. So far, so good. We've managed to avoid duplication. If we come up with a new data source, we can simply create a new subclass. However, what happens if we want an existing data source to send data to a different set of processing rules? A class would need to have more than one base class, except in a way different from normal multiple inheritance. No programming language that I've seen can support this scenario.
A hallmark of good object-oriented design is that classes have one and only one responsibility. Why is this important? It makes the code simple, it makes the code testable, it decreases coupling, it might increase cohesion, and it's just plain nicer to read. When you derive from a base class, your class has all of its explicit responsibilities, and the responsibilities of each of its ancestor classes. In our example, each subclass is itself responsible for knowing the ins and outs of a particular data source. Since they all derive from a common base class, they are also responsible for knowing how to process the data. This example only deals with 2 responsibilities, but real systems deal with hundreds.
Remember that inheritance is often used to represent taxonomies. You might have classes such as Animal > Mammal > Giraffe or Widget > Button > Pushbutton. You might say that things on the right are defined in terms of things on the left, but that's not exactly true. A giraffe doesn't have lungs because it's a mammal; we call it a mammal because it has lungs. Using inheritance to describe something (using, for example, interface inheritance) makes a lot of sense. Using inheritance to define something doesn't.