const

const 是constant 的縮寫,「恆定不變」的意思。被const 修飾的東西都受到強制保護,能夠預防意外的變更,能提升程序的健壯性。因此不少C++程序設計書籍建議:「Use const whenever you need」。數組

  1. const常量
  2. 修飾函數參數、返回值,甚至函數的定義體

 

一、用const 修飾函數的參數

(1)用函數參數進行返回值的:不用const修飾,不然「指針傳遞/引用傳遞」都不能正確返回參數值;函數

(2)函數參數做輸入:this

  • 輸入參數採用「指針傳遞」,加const 修飾能夠防止意外地改動該指針,起到保護做用。

例如StringCopy 函數:spa

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

其中strSource 是輸入參數,strDestination 是輸出參數。給strSource 加上const修飾後,若是函數體內的語句試圖改strSource 的內容,編譯器將指出錯誤。設計

  • 輸入參數採用「值傳遞」,因爲函數將自動產生臨時變量用於複製該參數,該輸入參數原本就無需保護,因此不要加const 修飾。

不要將函數void Func1(int x) 寫成void Func1(const int x)指針

不要將函數void Func2(A a) 寫成void Func2(const A a)code

 

關於內部和非內部數據類型參數傳遞:對象

  • 對於非內部數據類型的參數而言,void Func2(A a)效率低,由於調用時,須要產生對實參賦值,產生一個臨時對象,臨時對象構造、拷貝、析構耗時,可改爲void Func(A &a);而引用可能會修改a,故改爲void Func(const A &a)。
  • 對於內置數據類型,沒有必要寫成void Func(const int &x),由於內部數據類型的參數不存在構造、析構的過程,複製也很是快,「值傳遞」和「引用傳遞」的效率幾乎至關。

「const &」修飾輸入參數的用法:blog

  • 對於非內部數據類型的輸入參數,應該將「值傳遞」的方式改成「const 引用傳遞」,目的是提升效率。例如將void Func(A a) 改成void Func(const A &a)。
  • 對於內部數據類型的輸入參數,不要將「值傳遞」的方式改成「const 引用傳遞」。不然既達不到提升效率的目的,又下降了函數的可理解性。例如void Func(int x) 不該該改成void Func(const int &x)。

 

二、用const 修飾函數的返回值

(1)若是給以「指針傳遞」方式的函數返回值加const 修飾,那麼函數返回值(即指針)的內容不能被修改,該返回值只能被賦給加const 修飾的同類型指針。

例如函數:const char * GetString(void);

以下語句將出現編譯錯誤:char *str = GetString();

正確的用法是:const char *str = GetString();

(2)若是函數返回值採用「值傳遞方式」,因爲函數會把返回值複製到外部臨時的存儲單元中,加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; // 不正常的鏈式賦值,但合法

解答:

  1. 若是將賦值函數的返回值加const 修飾,那麼該返回值的內容不容許被改動。
  2. 上例中,語句 a = b = c 仍然正確,可是語句 (a = b) = c 則是非法的,由於a=b調用重載函數運算,a=b是成了const對象。

 

三、const 成員函數(const的做用:說明其不會修改數據成員)

任何不會修改數據成員的函數都應該聲明爲const 類型。若是在編寫const 成員函數時,不慎修改了數據成員,或者調用了其它非const 成員函數,編譯器將指出錯誤,這無疑會提升程序的健壯性。

示例:

如下程序中,類stack 的成員函數GetCount 僅用於計數,從邏輯上講GetCount 應當爲const 函數。編譯器將指出GetCount 函數中的錯誤。

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

const 成員函數的聲明看起來怪怪的:const 關鍵字只能放在函數聲明的尾部,大概是由於其它地方都已經被佔用了。

關於const函數的幾點規則:

  1. const對象只能訪問const成員函數,而非const對象能夠訪問任意的成員函數,包括const成員函數。
  2. (由於const對象不能被修改,與const成員函數一致;而非const對象能夠修改/不修改)
  3. const對象的成員是不可修改的,然而const對象經過指針維護的對象倒是能夠修改的。
  4. const成員函數不能夠修改對象的數據,無論對象是否具備const性質,它在編譯時,以是否修改爲員數據爲依據進行檢查。
  5. 加上mutable修飾符的數據成員,對於任何狀況下經過任何手段均可修改,天然此時的const成員函數是能夠修改它的。

 

const function使用實例:

(1)const 函數只能調用 const 函數,即便某個函數本質上沒有修改任何數據,但沒有聲明爲const,也是不能被const函數調用的。

示例1

class my {  
public:  
    string& operator[](const string& s) const
    { return table[s]; }  //編譯錯誤
private:  
    map table;  
};  

解答:

當本重載函數聲明爲const後,就只能調用其餘的一樣也聲明爲const的函數;而table[s]實際上調用的是map的下標重載運算函數,該函數並無聲明爲const。因此去掉本函數的const聲明,就能夠順利經過編譯了。

 

示例2

class A{  
public:  
    A(int n) { num = n; }  
    void incr() { num += 5; }  
void disp() const { cout << numspan> int times(int m) { return num * m; } int f() const {   incr();//passing `const A' as `this' argument of `void A::incr()' discards qualifiers   disp();// ok   times(2);//passing `const A' as `this' argument of `int A::times(int)' discards qualifiers   return num; }
private: int num; }; int main(int argc, char *argv[]) { A a(5); a.f(); system("PAUSE"); return EXIT_SUCCESS; }

示例3:

DateTime類是自定義的,isvalidDateTime類的方法。

bool DateTime::earlier(const DateTime &dt){
    if(!isvalid()) return true;
    if(!dt.isvalid()) return false;
    //出錯,提示 The non-const member function "DateTime::isvalid()" is called for "const DateTime"

解答:

  1. 每一個非staticconst成員函數都有一個隱含的this指針,是非const型的,不能接受const型實參;
  2. 在你的函數裏,dtconst DateTime &型的,dt.isvalid()至關於將const對象傳給非constthis指針,因此出錯。
  3. 若是isvalid不改變對象狀態,能夠將earlier成員函數定義爲const型。

 

若是用const來修飾函數,那麼函數必定是類的成員函數。

const 類型的成員函數不能返回非const類型的引用。

示例:

class Test  
{  
public :  
    int & GetValue()const;  
    private:  
    int value;  
};  

int &Test::GetValue() const
{  
    return value; //value此時具備const屬性,與返回值類型int &的非const屬性不匹配
}  

解答:

  1. 這樣的代碼在vs2003中提示的錯誤:error C2440: return: 沒法從「const int」轉換爲「int &」。
  2. const函數中傳遞this的時候把this變成了const T* const this,因此一個非const的引用指向一個const類型的變量,就會error

修改:

  1. int value 改爲mutable int valuemutable修飾的變量使之在const函數中能夠被改變的。
  2. return value 改爲。 return const_cast(value)const_cast去掉了const性質。
  3. 把函數寫成const int &Test::GetValue() const ,.這樣作的目的是使引用的變量也是const類型的,就至關於const int & b
  4. 把引用去掉,寫成返回值類型的。
  5. 把函數後面的const去掉。
  6. 返回值不是類的成員變量。
int &Test::GetValue() const
{  
    int temp = value;  
    return temp;  
}  

 

cosnt函數(const放在函數後面):

在調用成員函數時,對象的傳遞是經過this隱藏的,const實際上修飾了this指向的對象,假如定義了:

int &Test::GetValue() const
{  
    int temp = value;  
    return temp;  
}  

 

  1. f函數其實有兩個參數,第一個是A * const thisthis指向的對象是不能改變的) 另外一個纔是int類型的參數。
  2. 若是咱們不想f函數改變參數的值,能夠把函數原型改成f(const int),但若是咱們不容許f改變this指向的對象呢?由於this是隱含參數,const無法直接修飾它,就加在函數的後面了,表示this的類型是const A *const this
  3. const修飾*this是本質,至於說「表示該成員函數不會修改類的數據,不然會編譯報錯」之類的說法只是一個現象,根源就是由於*thisconst類型的。

 

在C中,常量只的是字面值,如0x1,1L等,const稱爲只讀常量。
const聲明的變量在棧裏面,只是其內容不能在代碼中改變,它不是在靜態內存中的,訪問它的時候彈棧。
訪問cosnt變量時,不能像真正的常量同樣從一個已知的固定內存地址中取得,這對早期的C語言編譯器是不可能的。
因爲const是定義在棧裏面的,它在程序運行時才能肯定裏面的值是多少,因此在編譯的時候不能用它來定義數組大小了 。

 

轉載自:http://blog.csdn.net/zcf1002797280/article/details/7816977(侵權即刪)

相關文章
相關標籤/搜索