Admit that you can't have it all. Despite its intuitive appeal, and regardless of how many other member functions are inheritable, deriving Circle from Ellipse causes problems. The problems stem from the inherent incompatibility of the following statements.
At least one of those statements must be false. The options are exactly the same as with the Ostrich / Bird dilemma. Hmmm. Is there a pattern here? The three options follow.
The basic problem is that Ellipse is too strong. Ellipse has such powerful member functions that Circle can't be substituted. The options are to weaken Ellipse, strengthen Circle, or admit that a Circle isn't substitutable for an Ellipse. The situation occurred as a result of an inadequate domain analysis. Either the requirements for class Ellipse were not understood or the consequences of trying to define Circle as substitutable for Ellipse were overlooked. Remember: do not confuse substitutability with specialization. Because a circle is a specialized ellipse (circles are ellipses that have an extra symmetry constraint) does not imply that Circle is substitutable for Ellipse. The substitutability relation has to do with behaviors, not specialization. When evaluating a potential inheritance relationship, the only criterion should be substitutability. The derived class should never surprise code that expects a properly functioning base class. Note that if Circle::setSize(x,y) is redefined so that it throws an exception, it would break user code unless the specification of Ellipse::setSize(x,y) allows exceptions to be thrown. If Circle::setSize(x,y) is redefined to be a no-op, it would break user code unless the specification of Ellipse::setSize(x,y) says, "This member function might do nothing." There are other ways to illustrate this basic issue. Integer is not substitutable for RationalNumber if RationalNumber has a divide-self-by-two member function (unless the divide-self-by-two member function has a weak specification, such as "Multiplying the result by two might not give the original number"). This issue is important because it comes up so often in real-life situations. This is not about ellipses or birds or integers. This is about wasted money and failed projects. Unfortunately, the projects that are most vulnerable to improper inheritance are the larger ones with bigger budgets and more to lose. |