1.1 類與物件
物件(object)是類(class)的乙個例項(instance)。如果將物件比作房子,那麼類就是房子的設計圖紙。所以物件導向程式設計的重點是類的設計,而不是物件的設計。類可以將資料和函式封裝在一起,其中函式表示了類的行為(或稱服務)。類提供關鍵字public、protected 和private 用於宣告哪些資料和函式是公有的、受保護的或者是私有的。
這樣可以達到資訊隱藏的目的,即讓類僅僅公開必須要讓外界知道的內容,而隱藏其它一切內容。我們不可以濫用類的封裝功能,不要把它當成火鍋,什麼東西都往裡扔。
類的設計是以資料為中心,還是以行為為中心?
主張「以資料為中心」的那一派人關注類的內部資料結構,他們習慣上將private 型別的資料寫在前面,而將public 型別的函式寫在後面,如表8.1(a)所示。
主張「以行為為中心」的那一派人關注類應該提供什麼樣的服務和介面,他們習慣上將public 型別的函式寫在前面,而將private 型別的資料寫在後面,如表8.1(b)所示。
很多c++教課書主張在設計類時「以資料為中心」。我堅持並且建議讀者在設計類時「以行為為中心」,即首先考慮類應該提供什麼樣的函式。microsoft 公司的com 規範的核心是介面設計,com 的介面就相當於類的公有函式[rogerson 1999]。在程式設計方面,咱們不要懷疑microsoft 公司的風格。
設計孤立的類是比較容易的,難的是正確設計基類及其派生類。因為有些程式設計師搞不清楚「繼承」(inheritance)、「組合」(composition)、「多型」( polymorphi**)這些概念。
1.2 繼承與組合
如果a 是基類,b 是a 的派生類,那麼b 將繼承a 的資料和函式。示例程式如下:
class a
;class b : public a
;// example
main()
這個簡單的示例程式說明了乙個事實:c++的「繼承」特性可以提高程式的可復用性。正因為「繼承」太有用、太容易用,才要防止亂用「繼承」。我們要給「繼承」立一些使用規則:
不要覺得「不吃白不吃」,讓乙個好端端的健壯青年無緣無故地吃人參補身體。
二、如果類b 有必要使用a 的功能,則要分兩種情況考慮:
(1)若在邏輯上b 是a 的「一種」(a kind of ),則允許b 繼承a 的功能。如男人(man)是人(human)的一種,男孩(boy)是男人的一種。那麼類man 可以從類human 派生,類boy 可以從類man 派生。示例程式如下:
class human
;class man : public human
;class boy : public man
;(2)若在邏輯上a 是b 的「一部分」(a part of),則不允許b 繼承a 的功能,而是要用a和其它東西組合出b。例如眼(eye)、鼻(nose)、口(mouth)、耳(ear)是頭(head)的一部分,所以類head 應該由類eye、nose、mouth、ear 組合而成,不是派生而成。示例程式如下:
class eye
;class nose
;class mouth
;class ear
;// 正確的設計,冗長的程式
class head
void **ell(void)
void eat(void)
void listen(void)
private:
eye m_eye;
nose m_nose;
mouth m_mouth;
ear m_ear;
};如果允許head 從eye、nose、mouth、ear 派生而成,那麼head 將自動具有look、**ell、eat、listen 這些功能:
// 錯誤的設計
class head : public eye, public nose, public mouth, public ear
;上述程式十分簡短並且執行正確,但是這種設計卻是錯誤的。很多程式設計師經不起「繼承」的**而犯下設計錯誤。
乙隻公雞使勁地追打乙隻剛下了蛋的母雞,你知道為什麼嗎?
因為母雞下了鴨蛋。
1.3 虛函式與多型
除了繼承外,c++的另乙個優良特性是支援多型,即允許將派生類的物件當作基類的物件使用。如果a 是基類,b 和c 是a 的派生類,多態函式test 的引數是a 的 指標。那麼test 函式可以引用a、b、c 的物件。示例程式如下:
class a
;void test(a *a)
class b : public a
;class c : public a
;// example
main()
;以上程式看不出「多型」有什麼價值,加上虛函式和抽象基類後,「多型」的威力就顯示出來了。
c++用關鍵字virtual 來宣告乙個函式為虛函式,派生類的虛函式將(override)基類對應的虛函式的功能。示例程式如下:
class a
};void test(a *a)
class b : public a
};class c : public a
};// example
main()
;如果基類a 定義如下:
class a
;那麼函式func1 叫作純虛函式,含有純虛函式的類叫作抽象基類。抽象基類只管定義純虛函式的形式,具體的功能由派生類實現。
結合「抽象基類」和「多型」有如下突出優點:
(1)應用程式不必為每乙個派生類編寫功能呼叫,只需要對抽象基類進行處理即可。這一
招叫「以不變應萬變」,可以大大提高程式的可復用性(這是介面設計的復用,而不是**實現的復用)。
(2)派生類的功能可以被基類指標引用,這叫向後相容,可以提高程式的可擴充性和可維護性。以前寫的程式可以被將來寫的程式呼叫不足為奇,但是將來寫的程式可以被以前寫的程式呼叫那可了不起。
物件導向程式設計的概念
物件和物件導向的概念 萬物皆物件 物件導向指以屬性和行為的觀點去分析現實生活中的事物 物件導向程式設計指先以物件導向的思想進行分析,然後使用物件導向的程式語言進行表達的過程 物件導向程式設計是軟體產業化發展的需要 理解物件導向的思想精髓 封裝 繼承 多型 至少掌握一種程式語言 類和物件的概念 物件主...
C 物件導向程式設計基本概念
繼承與派生 都是針對同一種技術現象的不同角度說法 子類繼承父類,父類派生出子類 繼承 乙個新類從已有的類那裡獲得其已有特性,這種現象稱為類的繼承。派生 從已有的類產生乙個新的子類 或稱為基類和派生類 多重繼承 乙個派生類有兩個或多個基類。派生類是基類的具體化,而基類是派生類的抽象。注 多重繼承的構造...
C 物件導向程式設計 複習重點概念
內聯函式 乙個函式,前面加有關鍵字inline。系統在編譯時,凡遇到呼叫內聯函式,則在實參替代形參後,用該函式中的全部 來代替被呼叫函式。語句較少,且被頻繁呼叫的函式可被定義為內聯函式。函式過載 指在同乙個命名空間內,多個函式可以擁有相同的名字。要求過載的函式至少在引數個數或引數型別上與已定義的函式...