1. 程式人生 > >c++: 繼承的詳解(理解)

c++: 繼承的詳解(理解)

目錄

【面試題】

繼承的相關概念:

複用:重複性的程式碼肯定是越少越好,隨著組織越來越複雜,單純在main()中寫程式碼會變的越來越難以維護。而函式則更像是一個小的程式。

          可以從主函式中脫離出來,使我們可以將任務劃分的跟更小,大大降低了我們的程式整體複雜性,函式讓我們實現了一定程度的程式碼複用。

繼承:繼承的機制是面向物件程式設計使程式碼可以複用的一種手段,它允許程式設計師在保持原有類特性的基礎上繼承擴充套件,增加功能。這樣產生的類

          成為派生類!

繼承的格式:

繼承許可權&訪問限定符

三種類成員訪問限定符:

  1. public公有
  2. protected保護
  3. private私有

三種繼承關係

  1. public公有繼承
  2. protected保護繼承
  3. private私有繼承

繼承方式及繼承許可權對應表:

總結:

  1. 基類private成員在派生類中不可訪問(如果基類成員不想在類外被直接訪問,但需要在派生類中訪問就定義為protected,保護成員限定符因繼承才出現
  2. public繼承是一個介面繼承,保持is-a的原則,每個父類可用成員對子類也可用,因為每個子類物件也都是一個父類物件
  3. protected/private是一個實現繼承,基類的部分成員並非完全成為子類介面的一部分,是has-a原則
  4. 不管是那種繼承方式,派生類內部都可以訪問基類的公有和保護成員,私有成員則不可見(編譯器語法檢測無法通過,所以不能訪問)
  5. class預設private,struct預設public
  6. 一般使用public,極少場景才會使用其他

賦值相容規則(public繼承)

  1. 子類物件可以賦值給父類物件(切割或切片:僅把父類含有的物件進行賦值)
  2. 父類物件不能賦值給子類物件
  3. 父類的指標或引用可以指向子類物件
  4. 子類的指標或引用不能指向父類物件(可以通過強制型別轉換完成,但是不能呼叫成員函式,會崩潰)

繼承中的作用域:

  1. 在繼承體系中基類和派生類都有獨立的作用域
  2. 子類和父類中有同名成員,子類將遮蔽對同名成員的直接訪問(在子類成員中:可以使用基類::基類成員 訪問)--(隱藏或重定義)
  3. 在實際體系中最好不要定義同名成員

派生類的預設成員函式:

派生類如果沒有顯示定義這六個預設成員函式,編譯器則會合成

合成:必須依賴與基類,根據基類的相應成員的行為來合成派生類的預設成員函式

生成:不依賴於任何東西,只是編譯器根據類的定義簡單生成基於基礎型別的成員函式

  1. 基類沒有預設建構函式,派生類必須要在初始化類表中顯式給出基類名和引數列表
  2. 基類沒有定義建構函式,則派生類也可以不用定義,全部使用預設建構函式
  3. 基類定義了帶有形參表建構函式,派生類就一定定義建構函式

【面試題】

系統自動呼叫析構原因:保證先析構子類在析構父類(子類隱藏了父類的解構函式)棧結構規則

                                     同理:子類初始化時呼叫父類的預設成員函式初始化父類,呼叫自己的預設成員函式初始化自己

棧結構:先初始化父類在子類,先析構子類在析構父類

實現一個不能被繼承的類:將父類的建構函式定義成私有!

                                       子類合成時先呼叫父類建構函式,因為私有所有失敗!

繼承與友元:

友元關係不能繼承,也就是說基類友元不能訪問子類私有和保護成員(父親的朋友,不一定是孩子的朋友)

繼承與static靜態成員:

基類定義了static靜態成員,則整個繼承體系中只有一個這樣的成員,無論派生出多少子類都只有static

繼承體系下派生類的物件模型:

                物件模型為物件中非靜態成員變數在記憶體中的佈局形式,與成員函式無關

  1. 單繼承:一個子類只有一個直接父類
  2. 多繼承:一個子類有兩個或以上直接父類 
  3.       菱形繼承                  我們發現Assistant類中存在兩份Person物件,因此在訪問繼承於基類的成
    員變數時,會存在資料冗餘及二義性的問題                                                                                                                                二義性:兩邊都有(選擇困難) 解決方式:1》指定訪問那個父類2》虛繼承
  4. 虛擬繼承——  解決菱形繼承的二義性和資料冗餘的問題

虛擬繼承在程序許可權前面加上virtual關鍵字即可構成虛擬繼承

特點:在任何派生類中的virtual基類總共用同一個(共享)物件表示

【注意】:儘量不要設計菱形繼承的類
虛繼承和直接繼承有什麼區別
1.時間:在通過繼承類物件訪問虛基類物件中的成員(包括資料成員和函式成員)時,都必須通過某種間接引用來
完成,這樣會增加引用定址時間(就和虛擬函式一樣),其實就是調整this指標以指向虛基類物件,只不過這個調整
是執行時間接完成的。
2.空間:由於共享所以不必要在物件記憶體中儲存多份虛基類子物件的拷貝,這樣較之 多繼承節省空間。虛擬繼承與
普通繼承不同的是,虛擬繼承可以防止出現菱形繼承時,一個派生類中同時出現了兩個基類的子物件。也就是說,
為了保證 這一點,在虛擬繼承情況下,基類子物件的佈局是不同於普通繼承的。因此,它需要多出一個指向基類子
物件的指標