1. 程式人生 > >C++:面向物件程式設計

C++:面向物件程式設計

面向物件程式設計(OOP)基於三個基本概念:資料抽象、繼承和動態繫結(即封裝、繼承、多型)。
通過使用資料抽象,我們可以將類的介面與實現分離;使用繼承,可以定義相似的型別並對其相似關係建模;使用動態繫結,可以在一定程度上忽略相似型別的區別,而以統一的方式使用它們的物件。

動態繫結

動態繫結是指在執行期間(非編譯期)判斷所引用物件的實際型別,根據其實際的型別呼叫其相應的方法(在C++語言中,當我們使用基類的引用或指標呼叫一個虛擬函式時將發生動態繫結)。

Note: 基類通常都應該定義一個虛解構函式,即使該函式不執行任何實際操作也是如此!
在派生類物件中含有與其基類對應的組成部分,這一事實是繼承的關鍵所在。派生類必須使用基類的建構函式來初始化他的基類部分。每個類控制它自己的成員初始化過程。首先初始化基類的部分,然後按照宣告的順序依次初始化派生類的成員。

關鍵概念:遵循基類的介面

必須明確一點:每個類負責定義各自的介面。要想與類的物件互動必須使用該類的介面,即使這個物件是派生類的基類部分也是如此。因此,派生類物件不能直接初始化基類成員。儘管從語法上說我們可以在派生類建構函式體內給它公有或受保護的基類成員賦值,但是最好不要這麼做。和使用基類的其他場合一樣,派生類應該遵循基類的介面,並且通過呼叫基類的建構函式來初始化那些從基類中繼承而來的成員。

Note:理解基類和派生類之間的型別轉換是理解C++語言面向物件程式設計的關鍵所在。和內建指標一樣,智慧指標也支援派生類向基類的型別轉換,這意味著我們可以將一個派生類物件的指標儲存在一個基類的智慧指標內。派生類向基類的自動型別轉換隻對指標或引用型別有用,在派生類型別和基類型別之間不存在這樣的轉換(在物件之間不存在型別轉換,有時派生物件看似能夠轉換為它的基類的原因是:拷貝建構函式是使用引用的)。當我們用一個派生類物件為一個基類物件初始化或賦值時, 只有該派生類物件中的基類部分會被拷貝,移動或賦值,它的派生類部分將被忽略掉。

關鍵概念:存在繼承關係的型別之間的轉換規則

(1)從派生類向基類的型別轉換隻對指標或引用型別有效。
(2)基類向派生類不存在隱式型別轉換。
(3)和任何其他型別一樣,派生類向基類型別的轉換也可能會由於訪問受限而變得不可行(例如,只有當D公有繼承B時,使用者程式碼才能使用派生類向基類的轉換;如果D繼承B的方式是受保護的或者私有的,則使用者程式碼不能使用該轉換)。

關鍵概念:C++的多型性

OOP的核心思想是多型性(polymorphism)。 我們把具有繼承關係的多個型別稱為多型型別,引用或指標的靜態型別與動態型別不同這一事實正是C++語言支援多型性的根本所在。

Note: 當且僅當通過指標或引用呼叫虛擬函式時,才會在執行時解析該呼叫,也只有在這種情況下物件的動態型別才有可能與靜態型別不同。基類中的虛擬函式在派生類中隱含地也是一個虛擬函式。當派生類覆蓋了某個虛擬函式時,該函式在基類中的形參必須與派生類中的形參嚴格匹配。虛擬函式也可以擁有預設實參,如果某次函式呼叫使用了預設實參,則該實參值由本次呼叫的靜態型別決定,換句話說,如果我們通過基類的引用或指標呼叫函式,則使用基類定義的預設實參,即使實際執行的是派生類中的函式版本也是如此。
Best Practices: 如果虛擬函式使用預設實參,則基類和派生類中定義的預設實參最好一致。

關鍵概念:重構

重構負責重新設計類的體系以便將操作和/或資料從一個類移動到另一個類中。 對於面向物件的應用程式來說,重構是一種很普遍的現象。