Jiahonzheng's Blog

C++ 不重写公有继承得到的非虚函数

字数统计: 357阅读时长: 1 min
2018/04/08 Share

Item 36: Never redefine an inherited non-virtual function.

在公有继承下,例如 Derived 继承自 Base ,若 Base 有一个非虚函数 func ,那么客户会倾向认为下面两种调用结果是一样的:

1
2
3
4
5
6
Derived d;
Base* pb = &d;
Derived* pd = &d;
// 以下两种调用应当等效
pb->func();
pd->func();

为什么两种调用应当等效?因为公有继承表示着 “is-a” 的关系,每个 Derived 对象都是一个 Base 对象(见此处)。

然而重写(override)非虚函数 func ,将会造成上述调用结果不一致:

1
2
3
4
5
6
7
8
class Base{
public:
void func(){}
};
class Derived: public Base{
// 隐藏从父类继承得到的非虚函数
void func(){}
};

因为 pb 类型是 Base*pd 类型是 Derived* ,对于普通函数 func 的调用是静态绑定(在编译期便决定了调用地址偏移量),即 pb->func() 调用的是 Base::func()pd->func() 调用的是 Derived::func()

在子类中重写父类的非虚函数在设计上是矛盾的:

  • 一方面,父类定义了普通函数 func ,意味着它反映了父类的不变式,子类重写后,父类的不变式不再成立,因此子类和父类不再是 “is-a” 的关系。
  • 另一方面,如果 func 应当在子类中提供不同的实现,那么它就不再反映父类的不变式,它就应该声明为 virtual 函数。
CATALOG