標籤:effective c++ 學習筆記 條款03
***************************************轉載請註明出處:http://blog.csdn.net/lttree********************************************
一、 Accustoming Yourself to C++
Rule 03: Use const whenever possible.
條款03:儘可能的使用const
const就是常量,它允許你指定一個語義約束,編譯器會強制實施這項約束。
多才多藝的關鍵字const 有多種用途:
① 在classes 外部修飾global 或 namespace 範圍中的常量
② 修飾檔案、函數 或 區塊範圍(block scope )中被聲明為static的對象
③ 用它修飾classes內部的 static 和 non-static 成員變數
幾個重要的作用
1.對於指標
對於指標,可以設定 指標自身 、 指標所指物 或 兩者都是(或都不是) const
分辨方法也很簡單:如果const出現在星號(*)左面,表示被指標所指的物是常量,如果出現在右面,表示指標自身是常量。
自此,也可以擴充到 迭代器 ( iterator )
如果你想表示這個迭代器不得指向不同的東西,但它所指的東西的內容是可以改動的:
const std::vector<int>::iterator iter
反之,迭代器可以指向不同的東西,但所指的內容不可改動:
std::vector<int>::const_iterator iter
2.最具威力的用法——對於函式宣告時的應用
在一個函式宣告中,const 可以和 函數返回值、各參數、函數自身 產生關聯。
①函數的返回值
令函數返回一個常量值,往往可以降低因客戶錯誤而造成的意外,而又不至於放棄安全性和高效性。
②函數的參數
除非你有需要改動參數或local const對象,否則請將它們聲明為const。僅僅幾個字元,可以幫你省下很多的煩惱。
③函數自身(const成員函數)
const實施於成員函數的理由有兩個:
<1> 它們使classes介面比較容易理解(可以明確知道哪個函數可以改動對象內容,而哪個不能)
<2> 它們使“操作const對象”成為可能。 這個是 "pass by reference to const 方式傳遞對象"技術的基礎。
而且,在重載方面,還有一個很重要的特性。
對於一個類,兩個函數:
class TextBlock{public: .... const char& operator[](std::size_t position) const { return text[position]; } char& operator[] ( std::size_t position ) { return text[position]; }private: std::string text;};
只要重載 operator[] 並對不同的版本給予不同的傳回型別,就可以令 const 和 non-const TextBlocks 獲得不同的處理:
std::cout<<tb[0]; // 沒問題,讀一個non-consttb[0] = ' x '; // 沒問題,寫一個non-conststd::cout<<ctb[0]; // 沒問題,讀一個constctb[0] = ' x '; // 錯誤,寫一個const
錯誤的原因是 企圖對一個“由const版之operator[]返回”的const char& 施行賦值動作。
此處要注意一下 non-const operator[] 的傳回型別是個 reference to char (引用char型),不是char,
否則 tb[0] = ‘ x ‘將無法通過編譯。
對於 成員函數如果是const意味性 有兩個流派:bitwise 和 logical
——bitwise const 陣營
奉行: 成員函數只有在不更改對象之任何成員變數(static除外)時才可以說是const。也就是說它不更改對象內的任何一個bit(位)。
優點:很容易偵測違反點,編譯器只需要尋找成員變數的賦值動作即可。
不足:不幸的是許多成員函數雖然不十足具備const性質卻能通過bitwise測試。
可以看下面這個例子:
const CTextBlock cctb("Hello");char* pc = &cctb[0];*pc = 'J';
這樣cctb現在儲存的是 "Jello"這個內容,顯然不符合const的定義
——logical const 陣營
奉行:一個const成員函數可以修改它所處理的對象內的某些bits,但只有在用戶端監測不出的情況下才如此。
例如 你的CTextBlock class 有可能快取(cache)文本區塊的長度以便詢問:
class CTextBlock{public: ... std::size_t length() const;private: char* pText; std::size_t textLength;<span style="white-space:pre"></span>// 最近一次計算的文本區塊長度。 bool lengthIsValid;<span style="white-space:pre"></span>// 目前長度是否有效};std::size_t CTextBlock::length() const{ if( !lengthIsValid) { textLength = std::strlen( pText );<span style="white-space:pre"></span>// 錯誤!在const 成員函數內不能賦值給這倆者 lengthIsValid = true; } return textLength;}
length實現肯定不是 bitwise const ,因為textLength 和 lengthIsValid都可能被修改。它們兩者被修改對const CTextBlock 對象而言雖然可以接受,但編譯器不同意。
所以就用一個mutable(可變的)來解決,用mutable來釋放掉non-static 成員變數的bitwise constness約束
class CTextBlock{public: ... std::size_t length() const;private: char* pText; mutable std::size_t textLength;// 這些成員變數即使在 mutable bool lengthIsValid;// const成員函數內也可更改};std::size_t CTextBlock::length() const{ if( !lengthIsValid) { textLength = std::strlen( pText );// 現在可以這樣 lengthIsValid = true; } return textLength;}
So 在const 和 non-const成員函數中避免重複
這個問題是由上面問題產生的,mutable固然可以解決變數的問題,但是如果這個東西很長,
我們則需要些兩份很長很長的怪物,so scary!
這就需要non-const來調用const的東西來避免重複,這樣改動也方便一些,
{
為什麼不讓const調用non-const的?
拜託,const成員函數承諾絕不改變其對象的邏輯狀態,non-const沒有
}
這樣就需要 調用 轉型 這個概念,看下面的例子:
class TextBlock{public:...const char& operator[](std::size_t position) const{.........return text[position];}char& operator[](std::size_t position){returnconst_cast<char&>(static_cast<const TextBlock&>(*this) [position]);}...};
這裡用到了兩個轉型:
static_cast 將non-const對象轉換成const對象
const_cast 移除const
結束語:
const是一個非常奇妙的且非比尋常的東西,
它可以用在 指標和迭代器上;
在指標、迭代器及reference指涉的對象身上;
在函數參數和傳回型別上;
在local變數身上;
在成員函數身上,
等等。。。。
Please remember:
<1> 將某些東西聲明為 const 可協助編譯器偵測出錯誤用法。const可被施加於任何範圍內的對象、函數參數、函數傳回型別、成員函數本體。
<2> 編譯器強制實施bitwise constness,但你編寫程式時應該使用 conceptual constness(概念上的常量性)。
<3> 當const和non-const 成員函數有著實質等價的實現時,令non-const版本用const版本可避免代碼重複。
***************************************轉載請註明出處:http://blog.csdn.net/lttree********************************************
《Effective C++ 》學習筆記——條款03