[009] 不要用父子關係去理解 C++ Inheritance

[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();

惡霸趕走了,雨也停了,收傘。