关注的问题集中在继承、派生、virtual函数等。如:
virtual non-virtual pure virtual
缺省参数值与virtual函数有什么交互影响
继承如何影响C++的名称查找规则
什么情况下有比virtual更好的选择
这些都是我们将要从这一章里学到的内容。
1 确定你的public继承可以塑模出is-a关系
谨记public继承的含义:
如果class D以public形式继承class B,则每一个类型D的对象同时也是一个类型B的对象,反之不成立。
即,B比D表现出更一般化的概念,而D比B表现出更特殊的概念。
如:
class Person { ... };
class Student : public Person { ... };
这个体系告诉我们:每个学生都是人,但并非每个人都是学生。
从C++的角度来看,任何函数,如果期望获得一个类型为Person(或指向Person对象的指针或引用),也都愿意接受一个Student对象(或指针或引用)。
需要留意的一点是:
以我们在生活中的直觉为基础来塑模is-a关系有时是错误的,可以说犯了“经验主义错误”。
如:
class Square应该以public形式继承class Rectangle吗
即正方形是一个(is-a)矩形吗
至少我们在学校里是这么学到的:正方形是一个矩形,但是矩形不一定是正方形。
那么我们来写一些这个继承
class Rectangle {
public:
virtual void setHeight(int newHeight);
virtual void setWidth(int newWidth);
virtual int height() const;
virtual int width() const;
......
};
void makeBigger (Rectangle& r) {
int oldHeght = r.height();
r.setWidth(r.width() + 10);
assert( r.heght() == oldHeght ); // 判断r的高度是否改变,永为真。
}
在这个矩形的基础上派生出一个正方形
class Square : public Rectangle { ... };
Square s;
...
assert( s.width() == s.height() );
makeBigger(s);
assert( s.widht() == s.height() );
显然makeBigger只改变矩形的宽度,而不改变矩形的长度。这和s是个正方形矛盾。
public所包含的含义为:能够使用在base class对象身上的每件事,应该同样可以使用在derived class对象身上。
由此可见,其他领域或者生活中,我们习得的直觉,在软件领域并不总是正确的。
因此,除了is-a关系,我们还要更多地思考和在适当的场合使用has-a和is-implemented-in-terms-of(根据某物实现出)
小结:
“public继承”意味着is-a。适用于base classes身上的每一件事情一定也适用于derived classes身上,每一个derived class对象也都是一个base class对象。