C++ const 總結

安全劍客發表於2020-08-30
const 是 constant 的縮寫,本意是不變的,不易改變的意思。在 C++ 中是用來修飾內建型別變數,自定義物件,成員函式,返回值,函式引數。

C++ const 允許指定一個語義約束,編譯器會強制實施這個約束,允許程式設計師告訴編譯器某值是保持不變的。如果在程式設計中確實有某個值保持不變,就應該明確使用const,這樣可以獲得編譯器的幫助。

一、const修飾普通型別的變數
const int  a = 7; 
int  b = a; // 正確
a = 8;       // 錯誤,不能改變

a 被定義為一個常量,並且可以將 a 賦值給 b,但是不能給 a 再次賦值。對一個常量賦值是違法的事情,因為 a 被編譯器認為是一個常量,其值不允許修改。

接著看如下的操作:

例項

#includeusing namespace std;
 
int main(void)
{
    const int  a = 7;
    int  *p = (int*)&a;
    *p = 8;
    cout<<1a; system("pause");="" return="" 0;="" }

對於 const 變數 a,我們取變數的地址並轉換賦值給 指向 int 的指標,然後利用 *p = 8; 重新對變數 a 地址內的值賦值,然後輸出檢視 a 的值。

從下面的除錯視窗看到 a 的值被改變為 8,但是輸出的結果仍然是 7。
C++ const 總結C++ const 總結
C++ const 總結C++ const 總結
從結果中我們可以看到,編譯器然後認為 a 的值為一開始定義的 7,所以對 const a 的操作就會產生上面的情況。所以千萬不要輕易對 const 變數設法賦值,這會產生意想不到的行為。

如果不想讓編譯器察覺到上面到對 const 的操作,我們可以在 const 前面加上 volatile 關鍵字。

Volatile 關鍵字跟 const 對應相反,是易變的,容易改變的意思。所以不會被編譯器最佳化,編譯器也就不會改變對 a 變數的操作。

例項

#includeusing namespace std;
 
int main(void)
{
    volatile const int  a = 7;
    int  *p = (int*)&a;
    *p = 8;
    cout<<1a; system("pause");="" return="" 0;="" }

輸出結果如我們期望的是 8。
C++ const 總結C++ const 總結

二、const 修飾指標變數

const 修飾指標變數有以下三種情況。

  1. A: const 修飾指標指向的內容,則內容為不可變數。

  2. B: const 修飾指標,則指標為不可變數。

  3. C: const 修飾指標和指標指向的內容,則指標和指標指向的內容都為不可變數。

對於 A:

const int *p = 8;

則指標指向的內容 8 不可改變。簡稱左定值,因為 const 位於 * 號的左邊。

對於 B:

int a = 8;
int* const p = &a;
*p = 9; // 正確
int  b = 7;
p = &b; // 錯誤

對於 const 指標 p 其指向的記憶體地址不能夠被改變,但其內容可以改變。簡稱,右定向。因為 const 位於 * 號的右邊。

對於 C: 則是 A 和 B的合併

int a = 8;
const int * const  p = &a;

這時,const p 的指向的內容和指向的記憶體地址都已固定,不可改變。

對於 A,B,C 三種情況,根據 const 位於 * 號的位置不同,我總結三句話便於記憶的話:"左定值,右定向,const修飾不變數"。

三、const引數傳遞和函式返回值

對於 const 修飾函式引數可以分為三種情況。

A:值傳遞的 const 修飾傳遞,一般這種情況不需要 const 修飾,因為函式會自動產生臨時變數複製實參值。

例項

#includeusing namespace std;
 
void Cpf(const int a)
{
    cout<<1a; ++a;="" 是錯誤的,a="" 不能被改變="" }="" int="" main(void)="" {="" cpf(8);="" system("pause");="" return="" 0;="" }

B:當 const 引數為指標時,可以防止指標被意外篡改。

例項

#includeusing namespace std;
 
void Cpf(int *const a)
{
    cout<<*a<<" ";
    *a = 9;
}
 
int main(void)
{
    int a = 8;
    Cpf(&a);
    cout<<1a; a="" 為="" 9="" system("pause");="" return="" 0;="" }

C:自定義型別的引數傳遞,需要臨時物件複製引數,對於臨時物件的構造,需要呼叫建構函式,比較浪費時間,因此我們採取 const 外加引用傳遞的方法。

並且對於一般的 int、double 等內建型別,我們不採用引用的傳遞方式。

例項

#includeusing namespace std;
 
class Test
{
public:
    Test(){}
    Test(int _m):_cm(_m){}
    int get_cm()const
    {
       return _cm;
    }
 
private:
    int _cm;
};
 
 
 
void Cmf(const Test& _tt)
{
    cout<<_tt.get_cm();
}
 
int main(void)
{
    Test t(8);
    Cmf(t);
    system("pause");
    return 0;
}

結果輸出 8。

對於 const 修飾函式的返回值。

Const 修飾返回值分三種情況。

A:const 修飾內建型別的返回值,修飾與不修飾返回值作用一樣。

例項

#includeusing namespace std;
 
const int Cmf()
{
    return 1;
}
 
int Cpf()
{
    return 0;
}
 
int main(void)
{
    int _m = Cmf();
    int _n = Cpf();
 
    cout<<_m<<" "<<_n;
    system("pause");
    return 0;
}

B: const 修飾自定義型別的作為返回值,此時返回的值不能作為左值使用,既不能被賦值,也不能被修改。

C: const 修飾返回的指標或者引用,是否返回一個指向 const 的指標,取決於我們想讓使用者幹什麼。

四、const修飾類成員函式

const 修飾類成員函式,其目的是防止成員函式修改被呼叫物件的值,如果我們不想修改一個呼叫物件的值,所有的成員函式都應當宣告為 const 成員函式。

注意:const 關鍵字不能與 static 關鍵字同時使用,因為 static 關鍵字修飾靜態成員函式,靜態成員函式不含有 this 指標,即不能例項化,const 成員函式必須具體到某一例項。

下面的 get_cm()const; 函式用到了 const 成員函式:

例項

#includeusing namespace std;
 
class Test
{
public:
    Test(){}
    Test(int _m):_cm(_m){}
    int get_cm()const
    {
       return _cm;
    }
 
private:
    int _cm;
};
 
 
 
void Cmf(const Test& _tt)
{
    cout<<_tt.get_cm();
}
 
int main(void)
{
    Test t(8);
    Cmf(t);
    system("pause");
    return 0;
}

如果 get_cm() 去掉 const 修飾,則 Cmf 傳遞的 const _tt 即使沒有改變物件的值,編譯器也認為函式會改變物件的值,所以我們儘量按照要求將所有的不需要改變物件內容的函式都作為 const 成員函式。

如果有個成員函式想修改物件中的某一個成員怎麼辦?這時我們可以使用 mutable 關鍵字修飾這個成員,mutable 的意思也是易變的,容易改變的意思,被 mutable 關鍵字修飾的成員可以處於不斷變化中,如下面的例子。

例項

#includeusing namespace std;
class Test
{
public:
    Test(int _m,int _t):_cm(_m),_ct(_t){}
    void Kf()const
    {
        ++_cm; // 錯誤
        ++_ct; // 正確
    }
private:
    int _cm;
    mutable int _ct;
};
 
int main(void)
{
    Test t(8,7);
    return 0;
}

這裡我們在 Kf()const 中透過 ++_ct; 修改 _ct 的值,但是透過 ++_cm 修改 _cm 則會報錯。因為 ++_cm 沒有用 mutable 修飾。

原文地址:

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/31559985/viewspace-2715843/,如需轉載,請註明出處,否則將追究法律責任。

相關文章