(一)首先有下面的繼承體系:
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
(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 函數。