c++ const修飾符用法整理

1、什麼是const?

常類型是指使用類型修飾符const說明的類型,常類型的變量或對象的值是不能被更新的。(當然,我們可以偷樑換柱進行更新:)
修改常量:加mutable

mutable class A { 
public: 
    A(int i=0):test(i) { } 
    void SetValue(int i)const { test=i; } 
private: 
    mutable int test;//這裏處理! 
};

2、cons有什麼主要的作用?

(1)可以定義const常量,具有不可變性。 例如: const int Max=100; int Array[Max];

(2)便於進行類型檢查,使編譯器對處理內容有更多瞭解,消除了一些隱患。

例如: void f(const int i) { …} 編譯器就會知道i是一個常量,不允許修改。

(3)可以避免意義模糊的數字出現,同樣可以很方便地進行參數的調整和修改。 同宏定義一樣,可以做到不變則已,一變都變!如(1)中,如果想修改Max的內容,只需要:const int Max=you want;即可!

(4)可以保護被修飾的東西,防止意外的修改,增強程序的健壯性。 還是上面的例子,如果在函數體內修改了i,編譯器就會報錯; 例如:
void f(const int i) { i=10;//error! }

(5) 爲函數重載提供了一個參考。

class A { ...... 
void f(int i) {......} //一個函數 
void f(int i) const {......} //上一個函數的重載 ...... 
}; 

(6)提高了效率。 編譯器通常不爲普通const常量分配存儲空間,而是將它們保存在符號表中,這使得它成爲一個編譯期間的常量,沒有了存儲與讀內存的操作,使得它的效率也很高。

3、如何使用const?

(1)修飾一般常量 一般常量是指簡單類型的常量。這種常量在定義時,修飾符const可以用在類型說明符前,也可以用在類型說明符後。
例如: int const x=2; 或 const int x=2;

(2)修飾常數組 定義或說明一個常數組可採用如下格式:
int const a[5]={1, 2, 3, 4, 5};
const int a[5]={1, 2, 3, 4, 5};

(3)修飾常對象 常對象是指對象常量,定義格式如下:
class A;
const A a;
A const a;
定義常對象時,同樣要進行初始化,並且該對象不能再被更新,修飾符const可以放在類名後面,也可以放在類名前面。

(4)修飾常指針
const int *A; //const修飾指向的對象,A可變,A指向的對象不可變
int const *A; //const修飾指向的對象,A可變,A指向的對象不可變
int *const A; //const修飾指針A, A不可變,A指向的對象可變
const int *const A;//指針A和A指向的對象都不可變

(5)修飾常引用 使用const修飾符也可以說明引用,被說明的引用爲常引用,該引用所引用的對象不能被更新。
其定義格式如下:
const double & v;

(6)修飾函數的常參數 const修飾符也可以修飾函數的傳遞參數,格式如下:
void Fun(const int Var); 告訴編譯器Var在函數體中的無法改變,從而防止了使用者的一些無意的或錯誤的修改。

(7)修飾函數的返回值: const修飾符也可以修飾函數的返回值,是返回值不可被改變,格式如下:
const int Fun1(); const MyClass Fun2();

(8)修飾類的成員函數: const修飾符也可以修飾類的成員函數,格式如下:

class ClassName { 
public: 
int Fun() const; ..... 
}; 

(9)在另一連接文件中引用const常量
extern const int i;//正確的引用
extern const int j=10;//錯誤!常量不可以被再次賦值 另外,還要注意,常量必須初始化! 例如: const int i=5;

1>用const 修飾函數的參數

如果參數作輸出用,不論它是什麼數據類型,也不論它採用“指針傳遞”還是“引用傳遞”,都不能加const 修飾,否則該參數將失去輸出功能。const 只能修飾輸入參數:
如果輸入參數採用“指針傳遞”,那麼加const 修飾可以防止意外地改動該指針,起到保護作用。
例如StringCopy 函數:

void StringCopy(char *strDestination, const char *strSource);

其中strSource 是輸入參數,strDestination 是輸出參數。給strSource 加上const修飾後,如果函數體內的語句試圖改動strSource 的內容,編譯器將指出錯誤。
如果輸入參數採用“值傳遞”,由於函數將自動產生臨時變量用於複製該參數,該輸入參數本來就無需保護,所以不要加const 修飾。
例如不要將函數void Func1(int x) 寫成void Func1(const int x)。同理不要將函數void Func2(A a) 寫成void Func2(const A a)。其中A 爲用戶自定義的數據類型。
對於非內部數據類型的參數而言,象void Func(A a) 這樣聲明的函數註定效率比較底。因爲函數體內將產生A 類型的臨時對象用於複製參數a,而臨時對象的構造、複製、析構過程都將消耗時間。
爲了提高效率,可以將函數聲明改爲void Func(A &a),因爲“引用傳遞”僅借用一下參數的別名而已,不需要產生臨時對象。但是函數void Func(A &a) 存在一個缺點:
“引用傳遞”有可能改變參數a,這是我們不期望的。解決這個問題很容易,加const修飾即可,因此函數最終成爲void Func(const A &a)。
以此類推,是否應將void Func(int x) 改寫爲void Func(const int &x),以便提高效率?完全沒有必要,因爲內部數據類型的參數不存在構造、析構的過程,而複製也非常快,“值傳遞”和“引用傳遞”的效率幾乎相當。
問題是如此的纏綿,我只好將“const &”修飾輸入參數的用法總結一下。
對於非內部數據類型的輸入參數,應該將“值傳遞”的方式改爲“const 引用傳遞”,目的是提高效率。例如將void Func(A a) 改爲void Func(const A &a)。
對於內部數據類型的輸入參數,不要將“值傳遞”的方式改爲“const 引用傳遞”。否則既達不到提高效率的目的,又降低了函數的可理解性。例如void Func(int x) 不應該改爲void Func(const int &x)。

2>用const 修飾函數的返回值

如果給以“指針傳遞”方式的函數返回值加const 修飾,那麼函數返回值(即指針)的內容不能被修改,該返回值只能被賦給加const 修飾的同類型指針。
例如函數:
const char * GetString(void);
如下語句將出現編譯錯誤:
char *str = GetString();
正確的用法是
const char *str = GetString();
如果函數返回值採用“值傳遞方式”,由於函數會把返回值複製到外部臨時的存儲單元中,加const 修飾沒有任何價值。
例如不要把函數int GetInt(void) 寫成const int GetInt(void)。
同理不要把函數A GetA(void) 寫成const A GetA(void),其中A 爲用戶自定義的數據類型。
如果返回值不是內部數據類型,將函數A GetA(void) 改寫爲const A & GetA(void)的確能提高效率。但此時千萬千萬要小心,一定要搞清楚函數究竟是想返回一個對象的“拷貝”還是僅返回“別名”就可以了,否則程序會出錯。
函數返回值採用“引用傳遞”的場合並不多,這種方式一般只出現在類的賦值函數中,目的是爲了實現鏈式表達。
列如:

class A
{
   A & operate = (const A &other); // 賦值函數
};
A a, b, c; // a, b, c 爲A 的對象
 
a = b = c; // 正常的鏈式賦值
(a = b) = c; // 不正常的鏈式賦值,但合法

如果將賦值函數的返回值加const 修飾,那麼該返回值的內容不允許被改動。上例中,語句 a = b = c 仍然正確,但是語句 (a = b) = c 則是非法的。

3>const 成員函數(const的作用:說明其不會修改數據成員)

任何不會修改數據成員的函數都應該聲明爲const 類型。如果在編寫const 成員函數時,不慎修改了數據成員,或者調用了其它非const 成員函數,編譯器將指出錯誤,這無疑會提高程序的健壯性。以下程序中,類stack 的成員函數GetCount 僅用於計數,從邏輯上講GetCount 應當爲const 函數。編譯器將指出GetCount 函數中的錯誤。

class Stack
{
public:
 void Push(int elem);
 int Pop(void);
 int GetCount(void) const; // const 成員函數
private:
 int m_num;
 int m_data[100];
};
int Stack::GetCount(void) const
{
 ++m_num; // 編譯錯誤,企圖修改數據成員m_num
 Pop(); // 編譯錯誤,企圖調用非const 函數
 return m_num;
}

const 成員函數的聲明看起來怪怪的:const 關鍵字只能放在函數聲明的尾部,大概是因爲其它地方都已經被佔用了。
關於Const函數的幾點規則:
a. const對象只能訪問const成員函數,而非const對象可以訪問任意的成員函數,包括const成員函數.
b. const對象的成員是不可修改的,然而const對象通過指針維護的對象卻是可以修改的.
c. const成員函數不可以修改對象的數據,不管對象是否具有const性質.它在編譯時,以是否修改成員數據爲依據,進行檢查.
e. 然而加上mutable修飾符的數據成員,對於任何情況下通過任何手段都可修改,自然此時的const成員函數是可以修改它的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章