Everything that applies to base classes must also apply to derived classes in public inheritance, for every derived class object is a base class object.
There are multiple relationships that can exist between classes:
- “is-a” is talked about in this item.
- “has-a” is discussed about in item 38.
- “is-implemented-in-terms-of” is introduced in item 39.
We should understand the differencea among these relationships.
For “is-a”, we should understand it in this way: if the class D (“derived”) publicly inherits from class B (“base), C++ compilers will assume that every object of type D is also an object of type B, but not vice versa. That is, every D is-a B, but not vice versa 1.
The concept of is-a sounds simple, but sometimes our intuition may mislead us. Say we want to create class Square
and class Rectangle
. I hear you say:
Everybody knows that a square is a rectangle, but generally not vice versa
Then consider this code:
|
|
|
|
Now we face a big problem: how can we reconcile the following assertion:
- before calling
makeBigger
,s
’s height is the same as its width; - inside
makeBigger
,s
’s width is changed, but its height is not; - after returning from
makeBigger
,s
’s height is again the same as its width
Here, the instincts we’ve develped in mathematics does not serve well. In this case, something applies to a rectangle is not applicable to a square, but public inheritance asserts that everthing that applies to base class object also applies to derived class objects. Thus using public inheritance to model the relationship between Rectangle
and Square
is incorrect.
With the knowledge of inheritance added into our arsenal of design, we’ll have to augment our intuition with new insights to guide us in inheritance’s proper application.
-
This is true only for public inheritance. Private inheritance means somethign entirely different (item 39), and protected inheritance is something beyond understanding. ↩︎