c++繼承筆記1
參考:C++ Primer 中文版第5版
1. 繼承
通過繼承(inerutance)聯絡其他在一起的類構成一種層次關係。通常在層次關係的根部有一個基類(base class),其他類直接或者間接從基類繼承而來,這些繼承得到的類稱為派生類(derived class)。
例子:首先定義一個名為Quote的類,將其作為層次關係中的基類。Quoto的物件表示按原價銷售的書籍。Quote派生出另一個名為Bulk_quote的類,表示可以打折銷售的書籍。
這些類包含以下兩個成員函式:
(1) isbn():返回書籍的ISBN編號。該操作不涉及派生類的特殊性,因此只定義在Quote類中。
(2) net_price(size_t),返回書籍的實際銷售價格,前提是使用者購買該書的數量達到一定標準,這個操作顯然是型別相關的,Quote和Bulk_quote都應該包含該函式。
在C++語言中,基類將型別相關的函式與派生類不做改變直接繼承的函式區分對待。對於某些函式,基類希望它的派生類各自定義適合自身的版本,此時基類就將這些函式宣告為虛擬函式(virtual function)。
我們將Quote類編寫為:
class Quote { public: std::string isbn() const; virutal double net_price(std::size_t n) const; //常成員函式 //常成員函式用來操作常量或者常物件。 };
派生類必須通過使用類派生列表(class derivative list)明確指明它從哪個基類繼承而來。
派生類列表形式:
class Bulk_quote :public Quote { //Bulk_quote繼承了Quote //由於使用了public關鍵字,因此我們完全可以把Bulk_quote的物件當成 //Quote的物件來使用。 public: double net_price(std::size_t) const override; };
派生類必須在其內部對所有重新定義的虛擬函式進行宣告。派生類可以在這樣的函式之前加上virtual關鍵字。
C++11新標準允許派生類顯式地註明它將使用哪個成員函式改寫基類的虛擬函式。 具體是在該函式的形參列表後增加一個override關鍵字。
2. 動態繫結
通過使用動態繫結,我們能用同一段程式碼分別處理Quote和Bulk_quote的物件。
例如:
double print_total(ostream &os, const Quote &item, size_t n ) //根據傳入item形參的物件型別呼叫Quote::net_price //或者Bulk_quote::net_price double ret = item.net_price(n); os << "ISBN: " <<item.isbn() //呼叫Quote::isbn << " # sold: "<< n << " total due: " << ret << endl; return ret; }
關於上述程式碼:
(1) 因為函式print_total的item形參是基類Quote的一個引用,我們既能使用基類的物件呼叫該函式,也能使用派生類的Bulk_quote的物件呼叫它。
(2)因為print_total是使用引用型別呼叫net_price函式,實際傳入print_total的物件型別將決定到底執行net_price的哪個版本。
//basic型別是Quote;bulk的型別是Bulk_quote print_total(cout,basic, 20); //呼叫Quote的net_price print_total(cout, bulk, 20); //呼叫Bulk_quote的net_price
上述過程中的函式執行版本由實參決定,即在執行時選擇函式的版本,所以動態繫結有時又被稱之為執行時繫結(run-time binding).
上述函式通過其名為item的引數來進一步呼叫net_price,其中item的型別是Quote&。因為item是引用而且net_price是虛擬函式,所以我們呼叫net_price的哪個版本完全依賴於執行時候
繫結到item的實參(動態)型別。
要注意: 動態繫結只有當我們通過指標或者引用呼叫虛擬函式時才會發生。