[009] 不要用父子關係去理解 C++ Inheritance
昨天跟同事討論到 C++ 繼承,主要是從「用何種方式去描述或理解 C++ Inheritance 比較精確」來切入。他說繼承像是「父子關係」,我卻覺得這樣不夠精確。本篇旨在描述我的想法。
C++ Inheritance 讓兩個物件成為 is-a 關係,若 Object Q 繼承了 Object Y,那麼我們可以說 Q is-a Y——因為 Q 俱備了 Y 的所有介面,故可被當做 Y,但 Q 卻不是 Y。
Q 看起來就像 Y,對外人說 Q 就是 Y,外人絕對認不出來。把 Q 當做 Y,一點不違和。
為什麼用父子關係描述繼承不夠精確?因為兒子跟老爸長得肯定不同,老爸會的兒子不一定會。對外人說兒子就是老爸,肯定是笑破大牙。
太過生硬的解釋較難理解,「父子關係」試圖用生活化的譬喻來說明 C++ Inheritance ,立意雖好,卻可能造成初學者日後理解困難。
如果許多技術名詞,我主張保留原文不要刻意翻成中文。那麼繼承就是描述兩物件為 is-a 關係。真要翻成中文,我認為「Object Q 是一種 Y」比較恰當。
以程式來說明的話,我想到一種武器——雨傘劍。一把普通雨傘的介面如下:
class Umbrella
virtual void Open();
virtual void Close();
};
而雨傘劍也是一種(is-a)傘,它繼承了普通傘的介面:
class UmbrellaSword : public Umbrella {
virtual void Close() override;
virtual void Attack();
};
用故事來使用上述的普通傘與雨傘劍。一位不懂武功的書生到店裡買傘,老闆店內沒普通傘,於是給了一把雨傘劍:
Umbrella* u = new UmbrellaSword();
u->Open();
書生接過傘,不疑有他,「開」傘遮雨往山上走去...。山腳下遇見惡霸,書生打電話跟傘店老闆求救,老闆告訴他那把傘其實是一支劍,並告訴書生雨傘劍的使用法,書生於是:
UmbrellaSword* sword = dynamic_cast<UmbrellaSword*>(u);
sword->Attack();
sword->Close();
惡霸趕走了,雨也停了,收傘。