《Effective C++》條款3:const問題
本章節主要講解了const的一些應用問題,並且通過例子系統的講解了const的使用場景和方法;
針對於指標和函式來說:
首先注意的是變數、指標和函式返回時使用const修飾時的場景;
char greeting[] = "hello"; const char* a=greeting; char* const b=greeting;
如上的例子,分別有const char* 和 char* const兩種形式;
這裡給出一個判斷法則:對於指標const修飾,指標是const還是資料是const,由星號*和const的位置而定;
如果const在*左邊,則指代指標為const;
如果const在*右邊,則指代指標指向資料為const;
其中值得注意的是,如果採用容器中的iterator作為指標模擬,則最好使用const_iterator,防止引起混淆;
如果使用const iterator(),則代表該迭代器指標是const,不得指向別的物件;
如果使用const_iteraotr(),則代表該迭代器指向的資料是const,不得修改;
對於函式來說,除了const 引用,比較少見的是返回值const;
返回值const通常常見於類內的過載運算子函式上;
例如:
class ration { const ration operator*(const ration& a, const ration& b); };
初次見可能不太明白加上const的意義是什麼;
其實考慮一下if((a*b)=c),其中a,b,c都為ration類,所以可以看到,根據運算結果,存在錯誤賦值的情況;
所以使用const返回可以有效地避免相關錯誤的出現;
針對於類內成員函式來說:
對於常見的成員函式,有兩種典型的const使用:
1.宣告該成員函式為const;
2.傳參或者返回值為const,一般為reference-to-const或者pointer-to-const;
其中針對於成員函式是否為const,可以進行過載;
#include<iostream> #include<string> using namespace std; class test { private: string s; public: test(string a) :s(a) {}; const char& operator[](std::size_t position) { cout << "this is non-const version" << endl; return s[position]; } const char& operator[](std::size_t position) const{ cout << "this is const version" << endl; return s[position]; } }; int main() { const test a("123"); test b("123"); a[0]; b[0]; system("pause"); return 0; }
從上述[]運算子可以看出來,類內對於[]進行了過載;
對於const類,會呼叫const版本的過載函式,非const類呼叫普通版本的過載函式;
對於const函式(也就是函式後是否加上const),本質上取決於是否想通過該函式對相關的涉及內容進行修改;
關於const的看法,書中提到了兩派:
1.bitwise-constness流派:const函式不能進行更改資料的操作;
2.logical-constness流派:const函式可以修改資料,但是不能讓編譯器發現;
其實現行編譯器依據的規則就是第一派,但是可以使用其他關鍵字和方法實現第二派的思想;
例如,如果對const函式中進行賦值,則有以下的報錯資訊:
從而說明編譯器現階段const函式仍然以不能顯式修改操作為主;
對於第二流派,可以顯式使用mutable關鍵字進行修改,這樣可以在const函式中進行修改;
存在問題:
對於不同const物件實現過載,可能會導致程式碼膨脹等後果,導致維護工作上升;
所以常見的方法是使用轉型呼叫,即進行const和non-const的互相呼叫;
常見的操作時進行呼叫,使用const版本來進行函式主體實現;
non-const進行const版本的呼叫,但是需要進行const和non-const的型別轉換;
如下所示:
class test { private: mutable string s; public: test(string a) :s(a) {}; char& operator[](std::size_t position) { return const_cast<char&>(static_cast<const test&>(*this)[position]); } const char& operator[](std::size_t position) const{ return s[position]; } };
上述程式碼進行了兩次型別轉換:
1.將non-const test物件轉化為const test物件,使用static_cast進行轉型;
2.使用const_cast對const的返回值進行去const處理;
通過上述兩步操作可以使用const函式為non-const函式進行操作服務,從而無需大段的進行復制;
但是注意一點:不能通過const呼叫non-const,因為non-const不能保障是否進行修改操作,從而不能使安全性得到保證;
個人存在疑惑:
1.關於const的相關應用場景;
2.關於轉型問題的補充;
3.關於*this的詳細的呼叫場景;