Earlier quoted context omitted.
You can explain is-a using examples that actually make sense to model using inheritance, like a set of game objects that have an interface like: class GameObject { public: // Called every frame to update the object's logical state. void Update(GameState* state); // Called to draw the object. Draw(GraphicsContext* context); } class EnemySpaceship : public GameObject { /* ... */ }; class SpaceDebris : public GameObject…
>rather than to make it a pointless ontological exercise of whether a Square is-a Rectangle or vice-versa it isn't pointless. It is the key point of the design : http://www.objectmentor.com/resources/articles/lsp.pdf
Humans have such a marvelous natural facility for attaching a meaning to a sentence that we don't feel like loopholes and contradictions within language are meaningful. Ask the average person "who shaves the barber" in a describing of Russel's paradox and they'll give you a "what was the problem" look rather than any answer at all. see http://en.wikipedia.org/wiki/Barber_paradox
So squares versus circles doesn't seem like a slightly important problem till you have a variation of it starting out of your debugger.
And the other side of this is ... since teasing out these loopholes is really hard and so many exist in potentia, it might really be just as well to leave things confused and correct them as they come up. If you a square class that's not a subclass of a rectangle and your rectangle class has an isSquare method and a toSquare method, well, your code will screwy but you'll have saved thousands of dollars in training fees...