假設我告訴你 class(類)D 從 class(類)B publicly derived(公有繼續),而且在 class(類)B 中定義了一個 public member function(公有成員函數)mf。mf 的參數和返回值類型是無關緊要的,所以我們就假設它們都是 void。換句話說,我的意思是:
class B { public: void mf(); ... }; class D: public B { ... }; 甚至不必知道關于 B,D,或 mf 的任何事情,給定一個類型為 D 的 object(對象)x,
D x; // x is an object of type D 對此你或許非常吃驚,
B *pB = &x; // get pointer to x pB->mf(); // call mf through pointer 的行為不同于以下代碼:
D *pD = &x; // get pointer to x pD->mf(); // call mf through pointer 因為在兩種情況中,你都調用了 object(對象)x 中的 member function(成員函數)mf。因為兩種情況中都是同樣的 function(函數)和同樣的 object(對象),它們的行為應該有相同的方式,對嗎?
是的,應該。但是也可能不,非凡地,假如 mf 是 non-virtual(非虛擬)而 D 定義了它自己的版本的 mf:
class D: public B { public: void mf(); // hides B::mf; see Item33 ... };
假如你在編寫 class D 而且你重定義了一個你從 class B 繼續到的 non-virtual function(非虛擬函數)mf,D 的 objects(對象)將很可能表現出不協調的行為。非凡是,當 mf 被調用時,任何給定的 D object(對象)的行為既可能像 B 也可能像 D,而且決定因素與 object(對象)本身無關,但是和指向它的 pointer(指針)的聲明類型有關。references(引用)也會像 pointers(指針)一樣表現出莫名其妙的行為。
前文解釋了 public inheritance(公有繼續)意味著 is-a,在《C++箴言:接口繼續和實現繼續》一文中記述了為什么在一個 class(類)中聲明一個 non-virtual function(非虛擬函數)是為這個 class(類)設定一個 invariant over specialization(超越非凡化的不變量),假如你將這些經驗應用于 classes(類)B 和 D 以及 non-virtual member function(非虛擬函數)B::mf,那么:
每一件適用于 B objects(對象)的事情也適用于 D objects(對象),因為每一個 D objects 都 is-a(是一個)D objects(對象);
從 B 繼續的 classes(類)必須同時繼續 mf 的 interface(接口)和 implementation(實現),因為 mf 在 B 中是 non-virtual(非虛擬)的。
現在,假如 D 重定義 mf,你的設計中就有了一處矛盾。假如 D 真的需要實現不同于 B 的 mf,而且假如每一個 B objects(對象)——無論如何非凡——都必須使用 B 對 mf 的實現,那么每一個 D 都 is-a(是一個)B 就完全不成立。在那種情況下,D 就不應該從 B publicly inherit(公有繼續)。另一方面,假如 D 真的必須從 B publicly inherit(公有繼續),而且假如 D 真的需要實現不同于 B 的 mf,那么 mf 反映了一個 B 的 invariant over specialization(超越非凡化的不變量)就不會成立。在那種情況下,mf 應該是 virtual(虛擬)的。最后,假如每一個 D 真的都 is-a(是一個)B,而且假如 mf 真的相當于一個 B 的 invariant over specialization(超越非凡化的不變量),那么 D 就不會真的需要重定義 mf,而且想都不能想。