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,而且也不应该尝试这样做。

相关文章:

  • 2022-12-23
  • 2021-12-15
  • 2021-12-01
  • 2021-06-16
  • 2021-08-29
  • 2021-06-03
  • 2021-09-17
  • 2021-07-08
猜你喜欢
  • 2022-01-31
  • 2021-10-25
  • 2021-08-13
  • 2021-07-03
  • 2021-07-21
  • 2021-08-12
  • 2021-10-02
相关资源
相似解决方案