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

class B {
public:
    void mf();
    ...
};
class D : public B {...};

D x;

如果一下行为:

B* pB = &x;

pB->mf();

异于以下行为:

D* pD = &x;

pD->mf();

你可能相当惊讶。两者的行为确实应该相同,但是如果mf是个non-virtual函数而D定义有自己的mf版本:

class D : public B {
public:
    void mf();
    ...
};
pB->mf();//调用B::mf
pD->mf();//调用D::mf

造成这一行为的原因是,non-virtual函数都是静态绑定的。由于pB被声明为一个pointer-to-B,通过pB调用的non-virtual函数永远是B所定义的版本,即使pB指向一个类型为“B派生之Class”的对象。

virtual函数是动态绑定的,如果mf是个virtual函数,不论通过pB还是通过pD调用mf,都会导致调用D::mf,因为pB和pD真正指的都是D的对象。

reference也会展现和指针一样难以理解的这中精神分裂的不一致行为。

public继承意味着is-a关系。

如果有non-virtual函数mf,B的derived class一定会继承mf的接口和实现。

现在,如果D重新定义mf,你的设计就出现矛盾。如果D真有必要实现出与B不同的mf,并且如果每一个B对象--不管多么特化--真的必须使用B所提供的mf实现码,那么“每个D都是一个B”就不为真。既然如此,D就不应该以public形式继承B。

另一方面,如果D真的必须以public方式继承B,并且D真有需要实现出与B不同的mf,那么mf就无法为B反应出“不变性凌驾特异性”的性质。既然这样mf应该声明为virtual函数。

最后,如果D真的是个B,并且如果mf真的为B反应出“不变性凌驾特异性”的性质,那么D便不需要重新定义mf,而且也不应该尝试这样做。

原文链接: https://www.cnblogs.com/lidan/archive/2012/02/11/2346845.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍

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

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/41384

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年2月8日 下午6:15
下一篇 2023年2月8日 下午6:15

相关推荐