绝不重新定义继承而来的non-virtual函数
class B
{
public:
void mf();
...
};
class D : public B
{
...
}
有以下调用:
D x;
b
B* pB = &x;
pB->mf(); // line1
D* pD = &x;
pD->mf(); // line2
line1、line2都是调用的是=B::mf()
。
如果Class D重新定义了mf():
class D : public B
{
public:
void mf();
...
}
则line1调用B::mf()
, 而line2调用D::mf()
。原因是non-virtual函数B::mf()
、D::mf()
都是静态绑定。
另一方面,virtual函数却是动态绑定,所以它们不受这个问题之苦。如果mf是个virtual函数,不论是通过pB或者pD调用mf,都会导致调用D::mf
,因为pB和pD真正指的都是类型为D的对象。
如果正在编写的class D重新定义继承自class B的non-virtual函数mf,D对象很可能展现出精神分裂的不一致行为。更明确的说,任何一个D对象都可能表现出B或D的行为;决定因素不在对象自身,而在于"指向该对象之指针"当初的声明类型。References也会展现和指针一样难以理解的行径。
现在,如果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,并且它也不应该尝试这样做。
请记住:
决定不要重新定义继承而来的non-virtual函数。