Effective C++——条款36(第6章)

条款36: 绝不重新定义继承而来的non-virtual 函数

Never redefine an inherited non-virtual function

    假设 class D系由 class B以 public 形式派生出来,class B定义有一个 public 成员函数mf.由于mf的参数和返回值都不重要,所以假设两者皆为 void .
class B {
public:
    void mf();
};
class B : public B { ... };
    虽然对B,D和mf一无所知,但面对一个类型为D的对象 x:
D x;        // x是一个类型为D的对象
    如果以下行为:
B *pB = &x; // 获得一个指针指向x
pB->mf();   // 经由该指针调用mf
    异于以下行为:
D *pD = &x;
pD->mf();
    两者都通过对象 x 调用成员函数 mf,由于两者所调用的函数都相同,所以行为应该相同,是吗?
    是的,一般如此.更明确地说,如果mf是个non-virtual 函数而D定义有自己的mf,那就不是如此:
class D : public B {
public:
    void mf();      // 遮掩了B::mf
    ...
};
pB->mf();           // 调用B::mf
pD->mf();           // 调用D::mf
    造成此一两面行为的原因是, non-virtual 函数如B::mf和D::mf都是静态绑定(staticlly bound,详见条款37).这意思是说, 由于pB被声明为一个pointer-to-B,通过pB调用的non-virtual 函数永远是B所定义的版本,即使pB指向一个类型为"D派生的class"的对象.
    但另一方面,virtual 函数却是动态绑定(dynamically bound,详见条款37),所以它们不受这个问题困扰.如果mf是个 virtual 函数,不论是通过pB或pD调用mf,都会导致调用D::mf, 因为pB和pD真正指的都是一个类型为D的对象.
    如果正在 编写 class D并重新定义继承自 class B的non-virtual 函数mf,D对象很 可能展现出不一致的行为.更明确地说,当mf被调用, 任何一个D对象都可能展现出B或D的行为:决定因素不在对象自身,而在于"指向该对象的指针"当初的声明类型.
    但那只是实务面上的讨论,真正的理论层面的理由,接下来讨论.
    条款32已经说过,所谓 public 继承意味is-a的关系. 条款34则描述为什么在 class 内声明一个non-virtual 函数会为该 class 建立起一个不变性,凌驾其特异性.如果将这两个观点施行于两个 class B和D以及non-virtual 成员函数B::mf身上,那么:
    适用于B对象的每一件事,也适用于D对象,因为每个D对象都是一个B对象.
    B的derived class 一定会继承mf的接口和实现,因为mf是B的一个non-virtual 函数.
    现在, 如果D重新定义mf,设计便出现矛盾.既然D以 public 形式继承B,并且mf是B的一个non-virtual 函数, 那么D的mf行为和B的mf行为必须是一致的.但D又重新定义mf,这就发生了矛盾.
    因此,任何情况下都不应该重新定义一个继承而来的non-virtual 函数.
    同时这个条款也 解释了为什么多态性base class 内的析构函数应该是 virtual.如果违反了这个准则,在base class 内声明一个non-virtual 析构函数,那么在derived class 就不能重新定义一个派生类的non-virtual 析构函数.但即使没有重新定义non-virtual 析构函数,编译器也会为derived class 定义一个默认的析构函数,仍然发生矛盾.
    注意:
    绝对不要重新定义继承而来的non-virtual 函数.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值