c++中const關鍵字使用

一、c和c++區別

c語言const的特點:

1.c語言中const變量是隻讀的,本質還是變量
2.const修飾的變量在棧上分配空間
3.const修飾的全局變量在只讀存儲區分配空間
4.const只在編譯期有用,運行期無用

總結:const修飾的變量不是真的常量,只是告訴編譯器該變量不能出現在賦值符號的左邊

c++中const在c的基礎上進行了升級

1.當碰到const聲明時,將常量納入符號表
2.編譯期如果發現使用常量,直接用符號表中的值進行替換
3.編譯器若發現一下情況則給對應的常量分配存儲空間
    ·對const使用extern
    ·對const使用&操作符

c++中const與宏的區別

1.const常量由編譯器處理
2.編譯器對const常量進行類型檢查和作用域檢查
3.宏由預處理處理,只是單純的文本替換

關於c++中const&分配存儲空間的代碼

void test_const(){
    const int a = 3;
    int *p = (int *)&a;
    *p = 5;
    cout << "a = " << a << endl;
    cout << "*p = " << *p << endl;
    cout << "&a = " << &a << endl;
    cout << "p = " << p << endl;
}
輸出:
a = 3
*p = 5
&a = 0x7ffeec3a8a3c
p = 0x7ffeec3a8a3c

發現a的值爲3,但是*p的值是5,驗證了之前說的符號表中的值進行替換,而第二行用到了&a對a又分配了空間,*p則是改變了分配的空間的值

二、const修飾符的使用

1.const與指針的搭配

int a = 2, b = 3;

int * const p1 = &a;
const int *  p2 = &a;

*p1 = 3; // 正常賦值
p1 = &b; // 報錯,指針指向不能改變

*p2 = 3; // 報錯,指針指向的值不能改變
p2 = &b; // 正常修改指針指向

2.const成員函數

·const對象調用
·不允許修改任何non-static成員變量
·常量性不同,可以進行重載

下面引用effective C++裏面的例子

class TextBlock{
public:
    TextBlock(string text):text(text){

    }
    const char& operator[](std::size_t pos) const{  // operator[] for const對象
        return text[pos];
    }

    char& operator[](std::size_t pos) {  // operator[] for non-const對象
        return text[pos];
    }
    
    void setText(std::string text) const{
        this->text = text;
    }

private:
    std::string text;
};

int main(){
    TextBlock tb("hello");
    const TextBlock tcb("world");
    std::cout << tb[0];
    std::cout << tcb[0];

    tb[0]='x'; // 正常賦值
    tcb[0]='x'; // 編譯錯誤,返回的是const
    
    tb.setText("abc"); // 編譯錯誤,no viable overloaded '=' 將const去掉正常賦值
    return 0;
}

1.const對象調用的是const聲明的成員函數,

2.這裏面兩個函數都返回都是char&,如果返回都是char,那麼也同樣無法通過編譯(原因是如果函數返回值是內置類型,那麼改動返回值不合法,即使合法,也是一個副本,也不是你想要的結果)

3.setText方法設置成const則該成員函數不能修改任何non-static成員變量

有些時候,必須使用const成員避免一些莫名其妙的問題如:(a*b) = c;

class Complex{
public:
    Complex(int real, int imag):real(real),imag(imag){

    }
    const Complex operator*(const Complex& comp1){
        Complex c(0,0);
        c.real = this->real * comp1.real - this->imag*comp1.imag;
        c.imag = this->real * comp1.imag + this->imag * comp1.real;
        return c;
    }
    void show(){
        cout << this->real << " + " << this->imag << "i" << endl;
    }
private:
    int real;
    int imag;
};


int main(){
    Complex c1(2,3);
    Complex c2(3,2);
    Complex c3 = c1*c2;
    c3.show();

    Complex c4(1,1);
    (c1*c2) = c4;
    return 0;
}

(c1*c2) = c4這種代碼不應該出現,但是編譯器如果重載操作符opertor*不返回一個const的話,那麼這種不合理現象只能在運行期發現,加上const則在編譯器就能發現

3.const修飾函數參數

當函數參數爲const的引用的時候,會創建臨時變量:
·實參類型正確,但是不是左值
·實參類型不正確,但是可以轉換成正確的類型

借用c++ primer plus例子

    double refcube(const double &ra){
        return ra*ra*ra;
    }
    
    double side = 3.0;
    double * pd = &side;
    double & rd = side;
    long edge = 5l;
    double lens[4] = {2.0,5.0,10.0,2.2};
    
    double c1 = refcube(side);  // 類型正確,左值
    double c2 = refcube(lens[2]); // 類型正確,左值
    double c3 = refcube(rd); // 類型正確,左值
    double c4 = refcube(*pd); // 類型正確,左值
    double c5 = refcube(edge); // 類型不正確,ra是一個臨時變量
    double c6 = refcube(7.0); // 類型正確,不是左值,ra是一個臨時變量
    double c7 = refcube(side+7.0); // 類型正確,不是左值,ra是一個臨時變量

解釋下,左值是可以被引用的值,例如:變量,數組,結構成員,引用,解除引用的指針都是左值,非左值包括字面量,和包含多項的表達式

正常情況下,接受引用參數的函數的意圖是修改作爲參數傳遞的變量,如果創建臨時變量,則在函數體內修改,並不能改變原來的變量,顯然這不是開發者的意圖,c++在沒有const的情況下就是這麼做的,去掉const發現編譯器報錯。但是現在refcube函數傳遞的變量只是使用值,所以臨時變量並不影響

引用參數聲明爲const理由有三個:

·避免無意中修改數據的編程錯誤
·使用const能處理const和non-const參數,否則只能接受non-const參數
·是函數能正確生成並使用臨時變量
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章