C++ FAQ Celebrating Twenty-One Years of the C++ FAQ!!!
(Click here for a personal note from Marshall Cline.)
Section 21:
[21.12] If SortedList has exactly the same public interface as List, is SortedList a kind-of List?

Probably not.

The most important insight is that the answer depends on the details of the base class's contract. It is not enough to know that the public interfaces / method signatures are compatible; one also needs to know if the contracts / behaviors are compatible.

The important part of the previous sentence are the words "contracts / behaviors." That phrase goes well beyond the public interface = method signatures = method names and parameter types and constness. A method's contract means its advertised behavior = advertised requirements and promises = advertised preconditions and postconditions. So if the base class has a method void insert(Foo const& x), the contract of that method includes the signature (meaning the name insert and the parameter Foo const&), but goes well beyond that to include the method's advertised preconditions and postconditions.

The other important word is advertised. The intention here is to differentiate between the code inside the method (assuming the base class's method has code; i.e., assuming it's not an unimplemented pure virtual function) and the promises made outside the method. This is where things get tricky. Suppose List::insert(Foo const& x) inserts a copy of x at the end of this List, and the override of that method in SortedList inserts x in the proper sort-order. Even though the override behaves in a way that is incompatible with the base class's code, the inheritance might still be proper if the base class makes a "weak" or "adaptable" promise. For example, if the advertised promise of List::insert(Foo const& x) is something vague like, "Promises a copy of x will be inserted somewhere within this List," then the inheritance is probably okay since the override abides by the advertised behavior even though it is incompatible with the implemented behavior.

The derived class must do what the base class promises, not what it actually does.

The key is that we've separated the advertised behavior ("specification") from implemented behavior ("implementation"), and we rely on the specification rather than the implementation. This is very important because in a large percentage of the cases the base class's method is an unimplemented pure virtual — the only thing that can be relied on is the specification — there simply is no implementation on which to rely.

Back to SortedList and List: it seems likely that List has one or more methods that have contracts which guarantee order, and therefore SortedList is probably not a kind-of List. For example, if List has a method that lets you reorder things, prepend things, append things, or change the ith element, and if those methods make the typical advertised promise, then SortedList would need to violate that advertised behavior and the inheritance would be improper. But it all depends on what the base class advertises — on the base class's contract.