爲了支持代碼的複用,繼承與派生在C++中就顯得十分重要。
繼承與派生:
當定義一個新的類 B 時,如果發現類 B 擁有某個已寫好的類 A 的全部特點,此外還有類 A 沒有的特點,那麼就不必從頭重寫類 B,而是可以把類 A 作爲一個“基類”(也稱“父類”),把類 B 寫爲基類 A 的一個“派生類”(也稱“子類”)。這樣,就可以說從類 A “派生”出了類 B,也可以說類 B “繼承”了類 A。
基類的所有成員都自動稱爲派生類的成員。派生類可以在其基礎上添加和修改
舉個栗子:學生類作爲基類,成員函數中打印函數可以打印姓名、性別。本科生類作爲派生類,成員函數中要多打印一個專業。那麼可以在本科生類中寫一個與學生類中打印函數同名的函數,先調用學生類中的打印函數,在單獨打印專業這一信息。通過派生類對象訪問同名成員,除非特別指明,否則訪問的就是派生類的成員,這種情況叫“覆蓋”,即派生類的成員覆蓋基類的同名成員。
派生類對象佔用的存儲空間大小 = 基類對象佔用存儲空間大小 + 派生類對象自身成員變量佔用存儲空間大小。
類與類之間的關係有兩種:組合和繼承。組合指的是A是B的一部分。繼承指的是A是B的一種。
protected:
之前一直使用的是public與private。protected修飾的是保護成員,它的可訪問範圍介於public與private之間。
設置protected的目的:無論派生類是用何種方式繼承的基類,基類中的私有成員在派生類中都是無法訪問的。但是派生類的成員函數又確實需要經常訪問基類成員。所以我們將它設置爲保護成員,既可以起到隱藏的目的,又可是讓派生類訪問它。(保護成員可以在派生類訪問,但不能在其他地方訪問。)
如果不寫繼承方式:最好還是寫上!
派生類用struct定義,默認繼承方式就是public。派生類用class定義,默認繼承方式就是private。
派生類的構造函數和析構函數:
由於派生類中包含基類成員,所以在執行派生類構造函數的時候,都會先執行基類的構造函數(在構造函數的參數列表中,如果不在初始化列表中,寫在內部,它的意思就先構造派生類了,肯定是錯的)。如果對此不做說明,編譯器會調用基類的無參構造函數,如果沒有無參構造函數,就會報錯。
析構函數的調用依舊滿足:先構造的後析構,後構造的先析構的特點。
多層次的派生:
A類 派生 B類,B類 派生 C類。
則 A類 是 B類 的直接基類,B類 是 C類 的直接基類,A類 是 C類 的間接基類。
在 C類 寫派生關係的時候,只寫直接基類 B類,不寫間接基類 A類。
調用構造函數的時候會先構造最上面的基類,之後依次往下。
當組合與派生同時使用:
先調用基類的構造函數,再按照成員對象的定義順序執行各自的構造函數。
基類與派生類賦值(初始化)規則:
- 派生類對象可以賦值給基類對象。
- 派生類對象可以用來初始化基類引用。
- 派生類的指針可以賦值給基類的指針。
結論:繼承結構中,默認支持從下到上的轉換,反過來不行的。
理解一下:派生類包含基類,派生類是個大圈裏面有個小圈是基類。大的(派生類)給小的(基類)賦值可以,你小的(基類)給大的(派生類)只能賦一部分,剩下的就浪費了所以不合適。 雖然說大的(派生類指針)可以給小的(基類指針)賦值,但不屬於小的(基類指針)那一部分,小的(基類指針)也是無法訪問的。(也就是說不能通過基類指針訪問基類沒有而派生類中有的成員。)
還有一點:雖然小的(基類指針)不能賦值給大的(派生類指針),但你要強制類型轉換,編譯器當然也會認可。但這種情況下需要保證那個基類指針本身就指向一個派生類對象。不然會出錯。慎用!!!!
基類與派生類同名成員的訪問:
同名成員方法的關係:重載、隱藏、覆蓋
重載
在基類或者派生類同一個類作用域當中的,函數名相同,參數列表不同。
隱藏
方法分佈在基類和派生類中
只要方法名字相同(無論參數個數或參數類型是否相同),就說派生類的同名方法把基類的同名方法給隱藏了。
覆蓋
方法分佈在基類和派生類中
基類的方法是虛函數,派生類的方法和基類的虛函數,返回值相同,函數名相同,參數列表也相同。那麼就會用派生類的函數覆蓋掉基類的虛函數。在虛函數表中進行覆蓋!