最近好像很久沒有更新過關于c++ primer 的讀書筆記了,一來自己最近遇到了煩心事,中斷了一段時間的讀書。第二個是因為我有點想寫點随筆之類的東西了,中間更新了兩篇随筆《關于讀書》、《我的五年計劃》。第三個是因為關于類這部分的内容确實有點多了,要讀完也需要花費一定時間。是以更新就慢了起來。我發現我已經忘記了如何給這類文章取名字了,還是看着以前的項目想起來的。既然我定下來了未來5年的發展計劃,那麼從現在開始就應該堅持下來了。
定義抽象資料類型
這裡定義抽象資料類型就是定義一個類,隻要學過c++的對定義一個類并并不陌生,這裡就不再詳細的說明該如何定義一個類了。這部分主要需要注意:1
- 類的const成員函數:一般類的成員函數會隐式的傳入目前對象的位址即
const型的成員函數傳入的是一個const型的this指針,ClassExample::func(ClassExample* this);
從這個角度上說不允許在常函數裡面修改對象的值。同時由于const類型無法自動轉化為非const類型,是以const型對象隻能調用const成員函數。ClassExample::func(const ClassExample* this);
- 類的作用域:類本身就是一個作用域,類中的所有成員定義在類這個作用域中。編譯器在編譯類的時候分兩步,首先編譯成員的聲明,然後編譯成員函數,是以在成員函數中可以随意使用類的其他成員而不用關心這些成員出現的順序。
- 如果一個函數在概念上屬于這個類,但是不定義為類的成員函數,一般将這個類定義在類聲明的頭檔案中
通路控制與封裝
一般來說定義類的時候應該将類中的資料成員定義為私有或者保護類型,通過成員函數來通路類的資料成員,這樣有兩個好處:
- 當我們發現資料成員的值不正常的時候,由于類外部是無法通路到資料成員的,是以在調試時隻用關注改變了該資料成員的函數即可
- 使用者在使用時隻需要關注類提供的功能,不需要知道它裡面具體的實作。隻用調用類方法就好了,不用關注該如何設定資料成員
到此為止,書中提到了兩種通路權限,public和private:
public: 後定義的成員可以在整個程式内被通路
private: 後定義的成員隻能在類的成員函數中被通路
每個通路說明符指定了接下來的成員的通路級别,其有效範圍直到出現下一個通路說明符或者達到類的結尾為止
使用class或者struct關鍵字定義的唯一差別是預設的通路控制符,class預設是private、而struct預設的是public
友元
在某些時候,可能必須要在類外部使用類的私有成員,這個時候可以将對應的函數或者類聲明為類的友元函數或者友元類,友元函數或者友元類可以随意使用類的私有成員。
如果類想把一個函數作為它的友元,隻需要增加一條以friend 關鍵字開始的函數聲明語句即可
友元聲明隻能出現在類内部,但是在類内出現的具體位置不限,友元不是類的成員也不受它所在區域通路控制級别的限制。
需要注意在設計時盡量考慮清楚是不是一定要用到友元,畢竟友元已經在一定程度上破壞了類的封裝性
類的其他特性
除了一些基本的使用和通路權限控制外,書中還提到了類的其他特性:
- 在類中,常有一些規模較小的函數合适于被聲明成内聯函數。定義在類内部的成員是自動inline的,當然也可以顯式的聲明為inline函數,這樣就可以在類外部定義
- 我們可以僅僅隻聲明而暫時不定義它,這種聲明有時候被稱作前向聲明。這個類在聲明之後,定義之前是一個不完全類型。不完全類型可以用于定義該類型的指針或者引用,也可以聲明以該類型作為參數或者傳回該類型的函數。
- 對一個類來說,在建立它的對象之前必須被定義。因為編譯器在建立對象的時候必須知道類對象占多少存儲空間
- 如果一個類指定了友元類,那麼這個友元類的成員函數可以通路此類包括非公有成員在内的所有成員
- 友元關系不具備傳遞性,每個類單獨控制自己的友元類或者友元函數
- 除了令整個類作為友元之外,還可以隻為某個成員函數單獨提供通路權限。當把成員函數聲明為友元的時候,我們必須明确指出該成員屬于哪個類
- 如果一個類想把一組重載函數聲明為友元,它需要對這組函數中的每一個分别聲明
類的作用域
一個類就是一個作用域,在類的外部類成員都被隐藏起來了。
在c++ 中,内層作用域中的同名成員會覆寫外層,當函數内部或者類内部定義了與全局作用域相同的變量時,要使用全局作用域中的變量可以使用::
類構造函數相關
- 在構造函數中初始化清單相當于先定義再指派,而要做到對成員變量定義的同時初始化,可以使用初始值清單的形式
- 在某些場合下初始值清單必不可少:初始化const成員或者引用成員
- 構造函數初始值清單隻說明用于初始化成員的值,而不限定初始化的具體執行順序
- 成員的初始化順序與他們在類中定義的順序一緻。構造函數初始值清單中初始值的前後位置關系不會影響實際的初始化順序
- 最好令構造函數初始值的順序與成員聲明的順序保持一緻。而且如果可能的話,盡量避免使用某些成員初始化其他成員
類的靜态成員
類的靜态資料成員存在于任何對象之外,對象中不包含任何與靜态資料成員有關的資料。
類似的類的靜态函數成員也不與任何對象綁定在一起。它們不包含this指針,靜态函數成員不能被聲明成const類型,也不能在靜态函數成員中調用非類的靜态成員
不能在類的内部初始化類的靜态成員,static關鍵字隻能出現在類内部聲明語句中,定義的時候不能加static關鍵字
針對constexpr類型的static成員,可以在類内定義類内初始值
由于靜态資料成員不與類綁定,是以在計算類大小的時候可以不用考慮靜态成員。這樣就可以在類内定義該類型的靜态資料成員,而非靜态資料成員隻能定義為該類型的指針或者引用
+BEGIN_SRC c++
class Menu
{
private:
static Menu me1;
Menu* me2;
Menu& me3;
};
+END_SRC
另外我們可是用靜态成員做成員函數的預設實參