六、继承与面向对象设计
条款36、绝不重新定义继承而来的 non-virtual 函数
Rule 36. Never redefine an inherited non-virtual function.
如果在基类中有一个public函数,创建一个派生类指针指向基类对象调用这个函数,然后再创建一个基类指针指向这个对象调用这个函数,结果应该是一样的吗?
不一样! 因为在派生类中,如果重新定义基类的函数,将会遮掩基类的相应函数,通过派生类调用该函数,永远是派生类的版本,而非基类的版本。
class B {
public:
void mf();
...
};
class D : public B {
public:
void mf(); // 遮掩了基类B的mf函数(可详见条款33)
...
};
D x;
B* pB = &x;
D* pD = &x;
pB->mf(); // 调用 B::mf
pD->mf(); // 调用 D::mf
造成这样现象的原因是,non-virtual函数如B::mf 和 D::mf 都是静态绑定。
但,virtual函数就是 动态绑定,所以,它们不会出现这个问题。
在之前的条款32中,也已经说过,public继承 意味着 is-a 关系。条款34中也描述了为什么在 class 内声明一个 non-virtual 函数会为该class建立起一个不变性。施之于此例,则表现为:
- 适用于B对象的每一件事,也适用于D对象,因为每个D对象都是一个B对象。
- B类的派生类一定会继承mf的接口和实现,因为mf是B的一个non-virtual函数。
所以,据上所述,任何情况下都不该重新定义一个继承而来的non-virtual函数。