[21.8] But I have a Ph.D. in Mathematics, and I'm sure a Circle is a kind of an Ellipse! Does this mean Marshall Cline is stupid? Or that C++ is stupid? Or that OO is stupid?
Actually, it doesn't mean any of these things. But I'll tell you what it does mean — you may not like what I'm about to say: it means your intuitive notion of "kind of" is leading you to make bad inheritance decisions. Your tummy is lying to you about what good inheritance really means — stop believing those lies.
Look, I have received and answered dozens of passionate e-mail messages about this subject. I have taught it hundreds of times to thousands of software professionals all over the place. I know it goes against your intuition. But trust me; your intuition is wrong, where "wrong" means "will cause you to make bad inheritance decisions in OO design/programming."
Here's how to make good inheritance decisions in OO design/programming: recognize that the derived class objects must be substitutable for the base class objects. That means objects of the derived class must behave in a manner consistent with the promises made in the base class' contract. Once you believe this, and I fully recognize that you might not yet but you will if you work at it with an open mind, you'll see that setSize(x,y) violates this substitutability.
There are three ways to fix this problem:
Sorry, but there simply are no other choices.
You must make the base class weaker (weaken Ellipse to the point that it no longer guarantees you can set its width and height to different values), make the derived class stronger (empower a Circle with the ability to be both symmetric and, ahem, asymmetric), or admit that a Circle is not substitutable for Ellipse.
Important: there really are no other choices than the above three. In particular:
(Note: this FAQ has to do with public inheritance; private and protected inheritance are different.)
(Note: some people correctly point out that a constant Circle is substitutable for a constant Ellipse. That's true, but it's really not a fourth option: it's really just a special case of option #1, since it works precisely because a constant Ellipse doesn't have a setSize(x,y) method.)