C++ const用法小結


C++const 關鍵字小結

constconstant的縮寫,本意是不變的,不易改變的意思。

const 在C++中是用來修飾內置類型變量,自定義對象,成員函數,返回值,函數參數

short conclusion

// for variable
const int a = 8;
int *p = (int *)&a;
*p =7;      // wrong, it's unpredictable

// for pointer, 左定值,右定向
int a = 8;
const int *p = &a;
*p = 7;     // wrong

int * const p2 = &a;
int b = 10;
p2 = &b;    // wrong

// for func param
class A {};

void func(const A *a){}     // equal to void func(const A& a){}, improve performance for copy constructor comparing to void func(A a)

void func(A * const a){}    // equal to void func(A& a){}

// for class method, indicate 'the method can't modify the instance data', (mutable修飾的變量除外)
// 不能調用非const成員函數
class B{
    private:
        int count;
    public:
        int GetCount() const {
            count ++; // wrong
            return count;
        }
}

// for return value, no practical value

一、const修飾普通類型的變量。

如下:

const int  a = 7; 

int  b = a; //it's right

a = 8;       // it's wrong,

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

接着看如下的操作:

#include<iostream>
using namespace std;

int main(void)
{

    const int  a = 7;
    int  *p = (int*)&a;

    *p = 8;

    cout<<a;
    system("pause");
    return 0;
}

對於const變量a,我們取變量的地址並轉換賦值給 指向int的指針,然后利用*p = 8;重新對變量a地址內的值賦值,然后輸出查看a的值。

從下面的調試窗口看到a的值被改變為8,但是輸出的結果仍然是7。

img

img

從結果中我們可以看到,編譯器然后認為a的值為一開始定義的7,所以對const a的操作就會產生上面的情況。所以千萬不要輕易對const變量設法賦值,這會產生意想不到的行為。

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

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

#include<iostream>

using namespace std;

int main(void)
{

    volatile const int  a = 7;
    int  *p = (int*)&a;

    *p = 8;

    cout<<a;

    system("pause");
    return 0;
}

輸出結果如我們期望的是8

img

二、const 修飾指針變量。

const 修飾指針變量有以下三種情況。

  • A:const 修飾指針指向的內容,則內容為不可變量。
  • B:const 修飾指針,則指針為不可變量。
  • C:const 修飾指針和指針指向的內容,則指針和指針指向的內容都為不可變量。

對於A:

const int *p = 8;

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

對於B:

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

 *p = 9; //it’s right

 int  b = 7;
 p = &b; //it’s wrong

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

對於C:

則是A和B的合並,

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

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

const修飾指針Conclusion

對於A,B,C三種情況,根據const位於*號的位置不同,我總結三句話便於記憶的話,

左定值,右定向,const修飾不變量

三、const in function參數傳遞

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

值傳遞的const修飾傳遞

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

#include<iostream>

using namespace std;

void Cpf(const int a)
{
    cout<<a; 
    // ++a;  it's wrong, a can't is changed
}

int main(void)
{
    Cpf(8);

    system("pause"); 
    return 0;
}

const參數為指針

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

#include<iostream>

using namespace std;

void Cpf(int *const a) 
{ 
    cout<<*a<<" ";
    *a = 9;
}

int main(void)
{ 
    int a = 8; 
    Cpf(&a);

    cout<<a; // a is 9 
    system("pause");
    return 0;
}

self definded type, const reference

C:自定義類型的參數傳遞,需要臨時對象復制參數,對於臨時對象的構造,需要調用構造函數,比較浪費時間,因此我們采取const外加引用傳遞的方法。

並且對於一般的int ,double等內置類型,我們不采用引用的傳遞方式。

#include<iostream>

using 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修飾內置類型的返回值,修飾與不修飾返回值作用一樣。

#include<iostream>

using 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成員函數

#include<iostream>

using 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關鍵字修飾的成員可以處於不斷變化中,如下面的例子。

#include<iostream>
using namespace std;

class Test
{
public:
    Test(int _m,int _t):_cm(_m),_ct(_t){}
    void Kf() const
    {
        ++_cm; //it's wrong
        ++_ct; //it's right
    }
private:
    int _cm;
    mutable int _ct;
};

int main(void)
{
    Test t(8,7);
    return 0;
}

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

轉載:

C++ const用法 盡可能使用const https://www.cnblogs.com/xudong-bupt/p/3509567.html

C++const 關鍵字小結 https://www.cnblogs.com/Forever-Kenlen-Ja/p/3776991.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM