In addition to the answers already given, here’s a link to an article I think is relevant.
Excerpts:
In the object-oriented framework, inheritance is usually presented as a feature that goes hand in hand with subtyping when one organizes abstract datatypes in a hierarchy of classes. However, the two are orthogonal ideas.
- Subtyping refers to compatibility of interfaces. A type
Bis a subtype ofAif every function that can be invoked on an object of typeAcan also be invoked on an object of typeB.- Inheritance refers to reuse of implementations. A type
Binherits from another typeAif some functions forBare written in terms of functions ofA.However, subtyping and inheritance need not go hand in hand. Consider the data structure deque, a double-ended queue. A deque supports insertion and deletion at both ends, so it has four functions
insert-front,delete-front,insert-rearanddelete-rear. If we use justinsert-rearanddelete-frontwe get a normal queue. On the other hand, if we use justinsert-frontanddelete-front, we get a stack. In other words, we can implement queues and stacks in terms of deques, so as datatypes,StackandQueueinherit fromDeque. On the other hand, neitherStacknorQueueare subtypes ofDequesince they do not support all the functions provided byDeque. In fact, in this case,Dequeis a subtype of bothStackandQueue!
I think that Java, C++, C# and their ilk have contributed to the confusion, as already noted, by the fact that they consolidate both ideas into a single class hierarchy. However, I think the example given above does justice to the ideas in a rather language-agnostic way. I’m sure others can give more examples.