c++primer第十五章面向對象設計小結-15

第十五章------面向對象設計

1、面向對象程序設計(object-oriented programming)的核心思想是數據抽象、繼承和動態綁定。數據抽象技術使實現和接口分離,繼承可以很快捷方便的定義相似的關係類,動態綁定(因爲基類指針和引用可以指向或綁定到派生類的對象,所以只有程序運行到調用的函數處纔會因爲參數類型不同而決定到底指向的是基類還是派生類,編譯時就知道的類型,比如內置數據類型,那是屬於靜態綁定),可以使得程序以一種統一的方式調用函數。

2、.C++ 中的函數調用默認不使用動態綁定。要觸發動態綁定,滿足兩個條件:第一,只有指定爲虛函數的成員函數才能進行動態綁定,成員函數默認爲非虛函數,非虛函數不進行動態綁定;第二,必須通過基類類型的引用或指針進行函數調用。要理解這一要求,需要理解在使用繼承層次中某一類型的對象的引用或指針時會發生什麼。

3、派生類的構造函數必須重新寫過,不能繼承。(因爲畢竟兩個類的類名都不一樣,不可能構造函數繼承)只繼承其他的成員函數和成員變量。派生類可以覆蓋基類的虛函數,但是也可以選擇不覆蓋(即直接使用父類的函數版本),基類的靜態成員:如果基類有一個靜態成員,那麼基類和所有派生類都共同擁有這僅有的一個靜態成員。所以只有構造函數和靜態成員函數不能爲virtual函數如果子類不顯式調用父類的構造函數,編譯器會自動調用父類的【無參構造函數】;

4、 繼承構造函數(Inheriting constructors)

(1) C++11 才支持;

(2) 實質是編譯器自動生成代碼,通過調用父類構造函數來實現,不是真正意義上的【繼承】,僅僅是爲了減少代碼書寫量(參考 《C++ Primer》)

5、繼承的權限:
    1.如果是公用繼承,基類成員保持自己的訪問級別:基類的 public 成員爲派生類的 public 成員,基類的 protected 成員爲派生類的 protected成員。
    2.如果是受保護繼承,基類的 public 和 protected 成員在派生類中爲protected 成員。
    3.如果是私有繼承,基類的的所有成員在派生類中爲 private 成員。

6、接口繼承與實現繼承
    1.public 派生類繼承基類的接口,它具有與基類相同的接口。設計良好的類層次中,public 派生類的對象可以用在任何需要基類對象的地方。
    2.使用 private 或 protected 派生的類不繼承基類的接口,相反,這些派生通常被稱爲實現繼承。派生類在實現中使用被繼承但繼承基類的部分並未成爲其接口的一部分

7、友元關係不能繼承。
8、如果基類定義 static 成員,則整個繼承層次中只有一個這樣的成員。
9、派生類構造函數通過將基類包含在構造函數初始化列表中來間接初始化繼承成員。
10、一個類只能初始化自己的直接基類。
11、在函數形參表後面寫上 = 0 以指定純虛函數:
    將函數定義爲純虛能夠說明,該函數爲後代類型提供了可以覆蓋的接口,但是這個類中的版本決不會調用。重要的是,用戶將不能創建 Disc_item 類型的對象。
12、將派生類對象複製到基類對象時,派生類對象多出的部分將被切掉

13、C++11 標準允許派生類顯示地註明它將使用哪個成員函數改寫基類的虛函數,具體措施是在該函數的形參列表之後增加一個 override 關鍵字。
14、在C++語言中,當我們使用基類的引用或指針調用一個虛函數時將發生動態綁定。
15、基類通常都應該定義一個虛析構函數,即使該函數不執行任何實際操作也是如此。
16、任何構造函數以外的非靜態函數都可以是虛函數。關鍵字 virtual 只能出現在類內部的生命語句之前而不能用於類外部的函數定義。如果基類把一個函數聲明成虛函數,則該函數在派生類中隱式地也是虛函數。
17、成員函數如果沒有被聲明成虛函數,則其解析過程發生在編譯時而非運行時。
18、C++11 新標準提供了一種防止繼承發生的方法,即在類名後跟一個關鍵字 final 。
19、理解基類和派生類之間的類型轉換是理解C++語言面向對象編程的關鍵所在。當我們用一個派生類對象爲一個基類對象初始化或賦值時,只有該派生類對象中的基類部分會被拷貝、移動或賦值,它的派生類部分將被忽略掉。要理解在具有繼承關係的類之間發生的類型轉換,有三點非常重要:
    ① 從派生類向基類的類型轉換隻對指針或引用類型有效;
    ② 基類向派生類不存在隱式類型轉換;
    ③ 和任何其他成員一樣,派生類向基類的類型轉換也可能會由於訪問受限而變得不可行。
    (儘管自動類型轉換隻對指針或引用類型有效,但是繼承體系中的大多數類仍然(顯示或隱式地)定義了拷貝控制成員。因此,我們通常能夠將一個派生類對象拷貝、移動或賦值給一個基類對象)
20、動態綁定只有當我們通過指針或引用調用虛函數時纔會發生。
21、基類中的虛函數在派生類中隱含地也是一個虛函數。當派生類覆蓋了某個虛函數時,該函數在基類中的形參必須與派生類中的形參嚴格匹配。
22、如果我們希望對虛函數的調用不要進行動態綁定,而是強迫其執行虛函數的某個特定版本。使用作用於運算符可以實現這一目的。通常情況下,只有成員函數(或友元)中的代碼需要使用作用域運算符來回避虛函數的機制。
23、含有(或者未經覆蓋直接繼承)純虛函數的類時抽象基類(abstract base class)。我們不能創建抽象基類的對象。
24、派生類的成員或友元只能通過派生類對象來訪問基類的受保護成員。
25、對於代碼中的某個給定節點來說,如果基類的公有成員是可訪問的,則派生類向基類的類型轉換也是可訪問的;反之則不行。
26、不能繼承友元關係;每個類負責控制各自成員的訪問權限,控制自己成員初始化。
27、派生類只能爲那些它可以訪問的名字提供 using 聲明。
28、人們常常有一種錯覺,認爲在使用 struct 關鍵字和 class 關鍵字定義的類之間還有更深層次的差別。事實上,唯一的差別就是默認成員訪問說明符及默認派生訪問說明符;除此之外,再無其他不同之處。
29、派生類的成員將隱藏同名的基類成員。我們可以通過作用於運算符來使用一個被隱藏的基類成員。(除了覆蓋繼承而來的虛函數之外,派生類最好不要重用其他定義在基類中的名字。)
30、和其他作用域一樣,如果派生類(即內層作用域)的成員與基類(即外層作用域)的某個成員同名,則派生類將在其作用域內隱藏該基類的成員。即使派生類成員和基類成員的形參列表不一樣,基類成員也仍然會被隱藏掉。
31、如果基類的析構函數不是虛函數,則 delete 一個指向派生類的基類指針將產生未定義的行爲。(動態綁定析構函數)
32、如果一個類定義了析構函數,即使它通過 =default 的形式使用了合成的版本,編譯器也不會爲這個類合成移動操作。
33、當派生類定義了拷貝或移動操作時,該操作負責拷貝或移動包括基類部分成員在內的整個對象。
34、在默認情況下,基類默認構造函數初始化派生類對象的基類部分。如果我們想拷貝(或移動)基類部分,則必須在派生類的構造函數初始值列表中顯示地使用基類的拷貝(或移動)構造函數。
35、與拷貝和移動構造函數一樣,派生類的賦值運算符也必須顯示地爲其基類部分賦值。
36、如果構造函數或析構函數調用了某個虛函數,則我們應該執行與構造函數或析構函數所屬類型相對應的虛函數版本。
37、如果基類含有幾個構造函數,則除了兩個例外情況,大多數時候派生類會繼承所有這些構造函數:
    ① 如果派生類定義的構造函數與基類的構造函數具有相同的參數列表,則該構造函數將不會被繼承。
    ② 默認、拷貝和移動構造函數不會被繼承。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章