第7章 類
1. 引入const成員函數(C++ Primer P231⑵32)
C++類的常量對象是沒法調用非const成員函數的,如果想讓常量對象調用某個成員函數,必須聲明成const:
2. 1個類的尾后const成員函數如果返回*this,那末其返回類型必定是const 類名 & 前面這個const是不能少的.否則沒法通過編譯.
3. 默許構造函數P235⑵36
編譯器只有在發現類中不包括任何構造函數的情況下,才會為我們合成1個默許的構造函數,且該函數對類中的成員履行默許初始化(如果類成員具有類內初始值就不履行默許初始化了).
對內置類型成員,局部對象默許初始化賦予隨機值,全局對象默許初始化賦予0.
對類類型成員,默許初始化調用該類的默許構造函數.
編譯器有可能不能給沒有構造函數的類合成1個的.假設A類沒有默許構造函數,但是A類中包括1個B類的對象成員b,且B類沒有默許構造函數,此時編譯器將沒法用合成的構造函數初始化A類對象中的成員b,所以此時A類將不存在合成的默許構造函數:
如果1個類的構造函數只給部份成員賦予了初值,那末剩下的成員將取得1個默許值(如果有類內初始值,則直接初始化,否則履行默許初始化).
4. 拷貝與賦值的區分 P239
對象在幾種情況下會被拷貝:初始化變量,以值的方式傳遞或返回1個對象.
我們使用了賦值運算符時,會產生對象的賦值操作.
5. 友元P241
類A定義了兩個友元,分別是函數print() 和類B,所以在函數print()內部或在類B的內部可以訪問類A的私有成員x.
注意:如果你想直接cout<<b.a.x<<endl;的話 還是錯的,由于x是私有的,就算類A是B的友元,你也不能直接訪問a的私有成員. 友元的含義不過是指在類或函數的內部你可以訪問其他類的私有成員.
友元再探:
假定有A類和B類,現在想在B類中把A類的1個函數print()定義成友元,應當怎樣定義前后順序?
應遵守上面的順序:先聲明B類,然后再定義A類,但是A類的print函數只能聲明,不能定義.
可以這樣理解:
A類定義先于B類定義(但此時print()僅聲明不定義): 既然B類要把1個A類的成員函數print()作為友元,那末明顯A類的定義要先于B類,由于這樣你才能在定義B類的時候能援用A類的print()成員函數.
B類聲明先于A類定義: B類其次由于print()成員函數有B類的形參,所以你需要在定義A類之前,把class B聲明1下,才行.
B類定義先于print()函數定義: 由于print()函數的定義中用到了B類的成員,所以在你定義print()函數時,B類必須已完全定義了.
友元函數聲明:
假定類A用friend聲明了友元函數print(). 此時print()可以先不聲明,但是任何類A的代碼也不可以調用print(). 只有等print()函數在全局聲明以后,類A才能調用print()函數使用. 也就是說print()函數什么時候能被使用,只與它是不是被正常聲明有關.
6. 可變數據成員(mutable關鍵字)P245 就算是const對象,mutable成員也能夠被改變.
a是1個常量對象, a只能調用const成員函數.
7. 假定class A有1個set方法和1個print()方法,我們甚么情況下能以下使用: a.set(10).set(100).print(); 當set()返回 *this的援用時!
由于點運算符是左結合的,所以左側先計算. 此時set返回*this的援用,所以可以繼續調用其他成員函數.
注意:如果set()函數是const的,那末它返回的*this 就是1個const對象,那末a.set()就不能調用非const的print()函數. 關于這點可見P247⑵48頁.
8. 不完全類型:1個類只有聲明,但是卻還沒有定義.P250
可以定義指向該類型的指針或援用,也能夠聲明把以不完全類型為參數或返回值的函數. 但是不可以定義不完全類型的對象.所以:
1個類可以包括指向它本身類型的指針或援用
但是不能包括本身類型的對象.
9. 類型名作用域:P255
類中定義的類型名可以覆蓋類外定義的類型名,條件是當前定義語句之前沒有使用過類外的類型名:
由于定義val時,已用了money定義,所以接著定義新money類型是錯的. 如果money新類型放在第4行的話,那末就是正確的.
10. 某些類的構造函數必須初始化: const成員, 援用, 或某些未提供默許構造函數的類類型.由于如果不初始化,那末這些成員就沒成心義.
上面的類A構造函數沒有對v2和v3履行初始化,所以是錯的.A的構造函數應當對v2和v3履行初始值列表初始化.而不應當在構造函數中直接賦值(賦值不是初始化).
11. 構造函數中成員的初始化順序是依照它們在類中定義的前后順序的,而不是依照初始值列表中的成員順序:
v1先初始化,所以v1(v2)后,v1將是1個隨機值.v2后初始化,所以v2將是500.
12. 拜托構造函數用法(P261,經測試 非C++11編譯器也能用)
注意:假定構造函數1拜托了構造函數2構造對象,那末構造函數1就算定義在構造函數2之前,1函數照樣能調用2函數,
13. 類對象被默許初始化或值初始化時自動履行默許構造函數,所以盡可能給每一個類都寫1個默許構造函數,否則容易出現毛病.
14. 轉換構造函數->隱式的類類型轉換(P295)
如果構造函數只接受1個參數,那末它實際上定義了轉換為此類類型的隱式轉換機制. 即在需要該類對象的地方,我們可使用那個參數替換.
上面A類中,分別用100和cin替換了A類的對象.
只允許1步類類型轉換! 但是內置類型的轉換支持多步.即上面的語句可以寫成 a1=a1+100.3; 先將100.3轉成int(內置轉換),然后將int轉成類A對象(類類型轉換).
上面代碼想將100轉成B的對象,然再轉成A的對象將出錯.
抑制轉換構造函數的隱式轉換:explicit關鍵字
用了explicit關鍵字的單參數構造函數不會自動履行了(explicit對多參數構造函數無任何影響).且初始化的時候,explicit的構造函數只能直接初始化,不能賦值初始化了.
explicit關鍵字只能出現在類內部構造函數聲明處.
15. 類的靜態成員變量與靜態成員函數
類的靜態成員變量必須在類的外部定義和初始化1次,否則沒法正確使用.
上一篇 3D塔防游戲實現 4.2 3D怪物連續刷新(Feekood語言)
下一篇 第2章3節《MonkeyRunner源碼剖析》了解你的測試對象: NotePad窗口Activity之NoteEditor簡介(原創)