(一)首先有下面的继承体系:
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
对于同一个对象d,使用不同类型的指针指向它时,他表现得不尽相同。同理对于引用也是一样。
(1)造成这一行为的原因是,non-virtual函数都是静态绑定的。由于pB被声明为一个pointer-to-B,通过pB调用的non-virtual函数永远是B所定义的版本,即使pB指向一个类型为“B派生之Class”的对象。
(2)virtual函数是动态绑定的,如果mf是个virtual函数,不论通过pB还是通过pD调用mf,都会导致调用D::mf,因为pB和pD真正指的都是D的对象。
(三)
条款7“为多态基类声明虚析构函数”是本条款要求的特例:派生类可能有更多的成员变量和相应操作,因而析构函数必须与基类不同,采用虚析构函数的方法可以使用“动态绑定”从而产生安全的析构行为;反之,如果声明为非虚析构函数,必须重新定义,这和本条款的要求相违背。
请记住:
(1)绝对不要重新定义继承而来的 non-virtual 函数。