C++ Primer學習總結 第7章 類,primer第7章
第7章 類
1. 引入const成員函數(C++ Primer P231-232)
C++類的常量對象是無法調用非const成員函數的,如果想讓常量對象調用某個成員函數,必須聲明成const:
2. 一個類的尾後const成員函數如果返回*this,那麼其傳回型別必然是const類名 & 前面這個const是不能少的.否則無法通過編譯.
3. 預設建構函式P235-236
編譯器只有在發現類中不包含任何建構函式的情況下,才會為我們合成一個預設的建構函式,且該函數對於類中的成員執行預設初始化(如果類成員具有類內初始值就不執行預設初始化了).
對於內建類型成員,局部對象預設初始化賦予隨機值,全域對象預設初始化賦予0.
對於類類型成員,預設初始化調用該類的預設建構函式.
編譯器有可能不能給沒有建構函式的類合成一個的.假如A類沒有預設建構函式,但是A類中包含一個B類的對象成員b,且B類沒有預設建構函式,此時編譯器將無法用合成的建構函式初始化A類對象中的成員b,所以此時A類將不存在合成的預設建構函式:
如果一個類的建構函式只給部分成員賦予了初值,那麼剩下的成員將獲得一個預設值(如果有類內初始值,則直接初始化,否則執行預設初始化).
4. 拷貝與賦值的區別 P239
對象在幾種情況下會被拷貝:初始設定變數,以值的方式傳遞或返回一個對象.
我們使用了賦值運算子時,會發生對象的賦值操作.
5. 友元P241
類A定義了兩個友元,分別是函數print() 和類B,所以在函數print()內部或在類B的內部可以訪問類A的私人成員x.
注意:如果你想直接cout<<b.a.x<<endl;的話 還是錯的,因為x是私人的,就算類A是B的友元,你也不能直接存取a的私人成員. 友元的含義不過是指在類或函數的內部你可以訪問其他類的私人成員.
友元再探:
假設有A類和B類,現在想在B類中把A類的一個函數print()定義成友元,應該怎麼定義先後順序?
應遵循上面的順序:先聲明B類,然後再定義A類,但是A類的print函數只能聲明,不能定義.
可以這樣理解:
A類定義先於B類定義(但此時print()僅聲明不定義):既然B類要把一個A類的成員函數print()作為友元,那麼明顯A類的定義要先於B類,因為這樣你才能在定義B類的時候能引用A類的print()成員函數.
B類聲明先於A類定義:B類其次由於print()成員函數有B類的形參,所以你需要在定義A類之前,把class B聲明一下,才行.
B類定義先於print()函數定義:由於print()函數的定義中用到了B類的成員,所以在你定義print()函數時,B類必須已經完全定義了.
友元函式宣告:
假設類A用friend聲明了友元函數print(). 此時print()可以先不聲明,但是任何類A的代碼也不可以調用print(). 只有等print()函數在全域聲明之後,類A才能調用print()函數使用. 也就是說print()函數何時能被使用,只與它是否被正常聲明有關.
6. 可變資料成員(mutable關鍵字)P245 就算是const對象,mutable成員也可以被改變.
a是一個常量對象, a只能調用const成員函數.
7. 假設class A有一個set方法和一個print()方法,我們什麼情況下能如下使用:a.set(10).set(100).print(); 當set()返回 *this的引用時!
因為點運算子是左結合的,所以左邊先計算. 此時set返回*this的引用,所以可以繼續調用其他成員函數.
注意:如果set()函數是const的,那麼它返回的*this 就是一個const對象,那麼a.set()就不能調用非const的print()函數. 關於這點可見P247-248頁.
8. 不完全類型:一個類只有聲明,但是卻還沒有定義.P250
可以定義指向該類型的指標或引用,也可以聲明把以不完全類型為參數或返回值的函數. 但是不可以定義不完全類型的對象.所以:
一個類可以包含指向它自身類型的指標或引用
但是不能包含自身類型的對象.
9. 類型名範圍:P255
類中定義的類型名可以覆蓋類外定義的類型名,前提是當前定義語句之前沒有使用過類外的類型名:
由於定義val時,已經用了money定義,所以接著定義新money類型是錯的. 如果money新類型放在第4行的話,那麼就是正確的.
10. 某些類的建構函式必須初始化: const成員, 引用, 或某些未提供預設建構函式的類類型.因為如果不初始化,那麼這些成員就沒有意義.
上面的類A建構函式沒有對v2和v3執行初始化,所以是錯的.A的建構函式應該對v2和v3執行初始值列表初始化.而不應該在建構函式中直接賦值(賦值不是初始化).
11. 建構函式中成員的初始化順序是按照它們在類中定義的先後順序的,而不是按照初始值列表中的成員順序:
v1先初始化,所以v1(v2)後,v1將是一個隨機值.v2後初始化,所以v2將是500.
12. 委託建構函式用法(P261,經測試 非C++11編譯器也能用)
注意:假設建構函式1委託了建構函式2構造對象,那麼建構函式1就算定義在建構函式2之前,1函數照樣能調用2函數,
13. 類對象被預設初始化或值初始化時自動執行預設建構函式,所以盡量給每個類都寫一個預設建構函式,否則容易出現錯誤.
14. 轉換建構函式->隱式的類類型轉換(P295)
如果建構函式只接受一個參數,那麼它實際上定義了轉換為此類類型的隱式轉換機制. 即在需要該類對象的地方,我們可以使用那個參數替代.
上面A類中,分別用100和cin替代了A類的對象.
只允許一步類類型轉換!但是內建類型的轉換支援多步.即上面的語句可以寫成 a1=a1+100.3; 先將100.3轉成int(內建轉換),然後將int轉成類A對象(類類型轉換).
上面代碼想將100轉成B的對象,然再轉成A的對象將出錯.
抑制轉換建構函式的隱式轉換:explicit關鍵字
用了explicit關鍵字的單參數建構函式不會自動執行了(explicit對多參數建構函式無任何影響).且初始化的時候,explicit的建構函式只能直接初始化,不能賦值初始化了.
explicit關鍵字只能出現在類內部建構函式聲明處.
15. 類的靜態成員變數與靜態成員函數
類的靜態成員變數必須在類的外部定義和初始化一次,否則無法正確使用.