1. 程式人生 > 實用技巧 >《Effective C++》條款3:const問題

《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的詳細的呼叫場景;