1. 程式人生 > >C++ Primer學習總結 第7章 類

C++ 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.  類的靜態成員變數與靜態成員函式

類的靜態成員變數必須在類的外部定義和初始化一次,否則無法正確使用.