Boolan 第三周筆記
首先反思一下第二周作業。我在Rectangle類中對Point類的數據成員進行賦值,而沒有為Point寫構造函數再通過構造函數初始化Point的成員,這樣是不好的。“每個類負責定義各自的接口”,“要想與對象交互必須使用該類的接口(C++ Primer中文第五版 P532)”,這樣的準則在原書中是描述基類和派生類的,我覺得同樣適用於委托。因此第二周作業中Point和Rectangle應該負責定義各自的接口。
這一周老師舉了很多設計模式的例子,我覺得這種方式的確可以使我理解復合,委托和繼承,但是距離理解並應用這些設計模式還差得非常遠。因此這篇筆記只記錄繼承相關的內容,設計模式後面還有課,到那時再深入吧。
派生類與基類之間是一種“is a”的關系,即派生類是一種基類(派生類中的一部分是基類)。基類的所有成員都會被派生類繼承,繼承的是調用權,即子類可以像父類一樣工作,調用父類的成員(函數和數據)。
派生類不繼承的函數包括:基類的析構函數,友元函數和賦值運算符。
派生類構造函數必須調用基類的構造函數。在創建派生類對象時會調用基類的構造函數,派生類的實例會按照從基類到派生類的順序沿著繼承鏈調用所有的基類構造函數。若基類的構造函數沒有被顯式地調用,則基類的無參構造函數會被調用(如果基類沒有無參構造函數,編譯器會報錯,因此為類寫一個=default構造函數是一個好習慣)。如果想用除基類無參構造函數之外的其他構造函數,需要進行顯式調用。
在一個繼承鏈中,析構函數的調用順序與構造函數的調用順序相反。
多態
廣義的多態:不同對象對相同的消息有不同的響應。截至目前,多態表現為重載和重定義。
//重載
class C
{
int f() {};
int f(int i) {};
};
//重定義
class Base
{
public:
int f() {};
};
class Derived : public Base
{
public:
int f() {};
};
重載函數與重定義函數的區別:
重載函數:只在參數上有區別(類型,數量,順序)。
重定義函數:在基類和派生類中分別定義,同名,同參數(類型,數量,順序都一致),同返回類型。派生類中的重定義函數會覆蓋掉基類中的同名函數。
訪問控制(Accessibility)
1.基類中的訪問說明符:
private:只能由類內函數訪問
public:被任意其他類訪問
protected:可被派生類成員(註意,不是派生類對象)訪問
2.派生類中的訪問說明符:
(1).公有繼承
基類成員在派生類中的訪問屬性不變。
派生類的成員函數可以訪問基類的公有成員和受保護成員。
(2).私有繼承
基類成員在派生類中的訪問屬性都變成私有的。
派生類的成員函數可以訪問基類的公有成員和受保護成員。
派生類之外的其他函數不可以通過派生類對象訪問從基類繼承來的任何成員。
(3).受保護繼承
基類中的公有成員和受保護成員在派生類中的訪問屬性都變成受保護的。基類的私有成員仍是私有的。
派生類的成員函數可以訪問基類的公有成員和受保護成員。
派生類之外的其他函數不可以通過派生類對象訪問從基類繼承來的任何成員。
私有繼承與受保護繼承的區別在於:私有繼承中,孫類(派生類的派生類)的成員函數無法訪問子類從父類繼承來的所有成員;而受保護繼承中,孫類(派生類的派生類)的成員函數可以訪問子類從父類繼承來的公有成員和受保護成員,因為它們在子類中都是受保護的。
抽象基類與虛函數
繼承鏈越往上就越抽象,越往下越具體。因為過於抽象而無法實例化(為之創建對象)的類就是抽象類。含有純虛函數的基類就是抽象基類。
Boolan 第三周筆記