前一篇,是《封裝》的尾巴(點我),這一篇,是《派生》的前奏……(突然有一種七八月份的感覺)
8.1.派生
型別和型別之間可以有很多關係,其中「派生」是最重要和最基礎的一種關係。這裡有一道小學語文題。
〖輕鬆一刻〗:做小學題,學型別的派生關係
請照著1和
2中三個詞語的關係,從a、
b、c、
d中選出乙個你認為合適的詞填在劃線處:
1) 人類、白種人、黃種人;
2) 交通工具、小汽車、飛機;
3) 電腦、台式電腦、
_____
備選答案:
a)樟腦;b)
硬碟、c
)拖拉機、
d)筆記本。
除非你堅決認為我說的「筆記本」是紙簿,否則你應該不會選錯。這就是「派生」的基本概念:
b型別是一種特定的
a型別。比如:「白種人是一種特定的人類」,或者「飛機是一種特定的交通工具」。此時可稱
b為「派生類」,
a為「基類」,描述為:
a類派生出
b類,或者
b類繼承自a類。
你需要能夠看得懂以下關係圖:
請注意箭頭的方向:由派生類指向基類,這是當前軟體設計界流行的表示法。用
c++的語法,可以表達為:
code:
class transportation //交通工具類
; class car : public transportation //小汽車是交通工具的派生類
; class airplane : public transportation //飛機是交通工具的派生類
;
先不必太關心語法,只要能看出上面有三個,而不是乙個
class
即可。但有讀者馬上要問了:真的需要把「
car」和「
airplane
」全部設計為
class
嗎?為什麼它們不可以就是「交通工具」這個類的兩個變數?示意為如下**:
code:
class transportation //交通工具類
; transportation acar; //一輛小汽車
transportation aplane; //一架飛機
這種思路是:我設計了乙個超強的「交通工具類」,它同時具備小汽車和飛機應用的功能,然後當需要時,我希望它是小汽車,它就是小汽車,希望它是飛機,它就是飛機。必須承認,前幾年我坐某航空公司的飛機到北京,飛機降落機場時找不到停機位,於是龐大的鐵鳥在首都機場上四處亂逛,當時我是感覺自己正坐在大巴士上……但這是錯覺!現實中要設計生產一種既可以在市區像qq車一樣四處鑽,又可以騰空而飛的玩意兒,怎麼可能呢?
(有同學不服氣:人家美國的變型金剛就是這樣子的……)
這就是學習「派生」之後,你經常要向自己問的乙個重要問題:你真的需要乙個派生類嗎?比如足球有真皮做的,也有塑膠做的,那麼我們需要「足球(基類)」、「皮足球」和「塑膠足球」三個類嗎?
別輕易說「要」或「不要」……複習一下「什麼是封裝」?封裝乙個類,既需要考慮事物內部的本質不變式,還需要考慮它的使用者是誰。
對於賣體育用品的商店,或者對於買家,通常是不需要將「皮足球」和「塑膠足球」分別定義成乙個類。「皮」或「塑膠」只是足球乙個屬性:材料,我們可以用乙個列舉來作簡單區分。
code:
enum material ;
class football//乙個為買賣設計的足球類
double getprice() const
void setprice(double price);
private:
meterial _meterial;
double _price;
};
足球當然還有其它屬性,比如尺寸或顏色等等,都非常適於像這裡的「**」及「材料」一樣,被僅僅當成足球的屬性看待(設計為乙個類的不同成員)。
對於足球的產家就不同了,他需要關心乙個足球如何生產出來,所以可能會為
football
類新增「製作」、「質檢」等等和生產相關函式,而「皮球」和「塑膠球」在這些操作上,可能天差地別,這時分拆成三個類就非常自然:
code:
class football
; class leatherfootball : public football
; class plasticfootball : public football
;
這就回到了「飛機」與「小汽車」無法合二為一的情況了,工廠無法在同一條生產線同時生產真皮球和塑膠球,負責塑膠球的質檢員,最好不要同時也負責真皮球的質檢(當然,當然,我知道資本家可能不這麼想)。當使用者是廠家時,足球
class
就和前面為買賣過程所做的設計大有不同:此時我們希望不同材質的球可以擁有自己的
make
函式,從而可以避免去寫乙個超強的,必然也是超複雜的,無所不能的
make
或qualitytest
函式。
〖危險〗:
不要迷戀「變形金剛」,那只是童年乙個夢…… 每個
c++程式設計師懂得「類」是要設計的……於是乎有些人設計設計再設計,**裡就出現乙個「變形金剛」類。原來他們把所有邏輯全寫到乙個函式或乙個類裡面(變形金剛),然後通過各種開關,各種複雜的邏輯,去區分這個類什麼時候是乙個機械人,什麼時候又是乙隻汽車……
其實,真正的設計,首先是懂得「拆分
」,派生是拆分的方法之一。
當然,也要反覆不管三七二十一,物件稍有區別,就被設計成兩個類,這是一種「過度設計」。但對於初學者,有時候只是懶惰造就了乙個個龐然大物——卻振振有辭:我在設計乙個偉大的變形金剛,請不要拿那種無趣的規則制約我的創造力!
醒醒噢,我們寫的是**,而不是科幻**,請不要把**寫成乙份無人理解的寂寞。
最後提乙個問題:足球的尺寸,通常只需要做為乙個屬性設計,請讀者思考什麼情況下,足球的尺寸也會造成專門設計乙個派生類才更合適?
如果您想與我交流,如下鏈結成為我的好友:
C 繼承與派生(公有派生和私有派生)的概念
層次概念是計算機的重要概念。通過繼承 inheritance 的機制可對類 class 分層,提供型別 子型別的關係。c 通過類派生 class derivation 機制來支援繼承。被繼承的型別稱為基類 base class 或超類 superclass 新產生的類為派生類 derived cla...
派生與繼承 多重派生
1 理解下面的程式,並在 vc 6.0 下執行檢視結果,回答程式後面的問題。class cbase1 cbase1 void print protected int a class cbase2 cbase2 void print protected int b class cderive publ...
Advanced Puppet 系列的前言
在網路上,你能找到大量關於puppet的安裝,配置以及基礎用法的文章和部落格。你在通過一段時間的實戰後,熟練掌握了puppet基礎用法,隨著你管理的集群日益擴大,你的部署邏輯越來越複雜,當你打算使用到一些puppet高階用法時,當你想要對puppet 寫測試用例時,當你希望對puppet進行效能調優...