C++中的const用法總結(jié)

const是修飾符,說明有只讀特性。
首先明確以下代碼:

int a=5;
const int a_const=a;//right
int b=a_const;//right
    
int * p=  &a_const;//error 
int * p=(int*) &a_const;//right
const int* p_const=&a;//right

說明只能從寬松到嚴格,反之不行。
const用法包括以下:

一.const變量

由于只讀不能修改的特性,因此const變量必須初始化
const全局變量可以替換常量宏定義,比宏定義的直接替換更嚴格一些(見第三)。
const結(jié)構(gòu)體變量,表示結(jié)構(gòu)體中的任何數(shù)據(jù)域均不允許改變,且需要另外一個結(jié)構(gòu)體變量進行初始化。

二.const類對象

不能改變?nèi)魏纬蓡T變量的值以及不能調(diào)用任何非const成員函數(shù)(見第九)。

三.指向const變量的指針

該指針指向的變量是const的。
那么 編譯器是如何判斷只讀呢?是通過指針的類型(const int *)還是指向變量的類型(const int)?

int a=5;
const int a_const=a;
    
int * p=  (int*)&a_const;
const int* p_const=&a;
    
*p=10;//right
*p_const=10;//error

從結(jié)果可以看出,如果指針類型是“const int*”即使其指向的內(nèi)容是非const,也無法通過指針改變數(shù)據(jù)內(nèi)容。反之,如果指針類型是普通的“int *”,即使其指向的變量是const,也可以修改這個指針指向的內(nèi)容。因此,編譯器是通過指針的類型來判斷是否只讀的。那么,一個新問題來了?。∩鲜龃a中的,*p=10執(zhí)行后,a_const的值是多少?看下面代碼:

const int volatile a_const=5;
int * p=  (int*)&a_const;
*p=10;
cout<<a_const<<endl;// 10
cout<<*p<<endl;//10
const int a_const=5;
int * p=  (int*)&a_const;
*p=10;
cout<<a_const<<endl;// 5
cout<<*p<<endl;//10

在本機上的結(jié)果如上所示。編譯器會將const變量放在符號表中,直接從表中獲的值,而不訪問實際的內(nèi)存。但是當在a_const前面加上volatile時,說明a_const是容易變化的,因此就修改了const值。 根據(jù)不同編譯器的優(yōu)化情況導致結(jié)果而不同(VC上,不管是否加violatile,都時直接從符號表中獲?。?。說明,const只是說明從道義上不會改變。
但是,我還發(fā)現(xiàn)了一個問題,上代碼:

int a=5;
const int a_const=a;
int * p=  (int*)&a_const;
*p=10;
cout<<a_const<<endl;// 10
cout<<*p<<endl;//10

const int a_const=a;猜測是這一句,因為a是可變的,所以使得編譯器認為a_const也是可變的,因此不會產(chǎn)生立即數(shù)。只是猜測,有機會再驗證吧。
同時,如果把const int a_const作為全局變量時,

int a=5;
const int a_const=a;
int main()
{
    int * p=  (int*)&a_const;
    *p=10;
    cout<<a_const<<endl; //10
    cout<<*p<<endl; //10
}
const int a_const=5;
int main()
{
    int * p=  (int*)&a_const;
    *p=10;   //段錯誤
    cout<<a_const<<endl;
    cout<<*p<<endl;    
}

不管怎樣,我們都可以使用const全局變量,來替代宏定義。根據(jù)上述可知,在實際執(zhí)行中,會直接去查找符號表,因此不會產(chǎn)生一次變量的內(nèi)存訪問,和宏有相同的執(zhí)行效率。同時,const全局變量可以通過編譯器進行類型檢查,來減少錯誤。

四.const指針

指針本身的地址值不能變,就是指針具體指向哪個變量是不能變的。

五.指向const變量的const指針

都不改變

六.const變量作為函數(shù)參數(shù)

在函數(shù)內(nèi)部不能修改這個參數(shù)的值。不關(guān)心在函數(shù)外部是否是const。
但是,注意int*可以隱式的轉(zhuǎn)換成const int*,反之,const int*不能隱式轉(zhuǎn)化為int*。因此,

void func(int* param){
    cout<<*param<<endl;
}
int main()
{
    int a=5;
    const int p=5;
    func(&p);//error: invalid conversion from 'const int*' to 'int*'
}

七.const返回值

指的是函數(shù)的返回值是一個const變量
函數(shù)返回const返回值,主要用于函數(shù)返回const引用。對于返回引用的函數(shù)來說,我們不希望通過修改返回的引用來對原值進行修改,否則代碼的健壯性太差。而通過將返回值寫成const引用,就可以很好的解決。和下面代碼一個道理:

int b=5;
const int &a=b;
a=10;//error assignment of read-only reference ?a?
int &a_=b;
a_=10; //right b=10

八.const成員變量

const成員變量必須初始化(在構(gòu)造函數(shù)的初始化列表中),初始化后,不能修改
靜態(tài)const成員變量需要在類外單獨定義并初始化。

類對象的構(gòu)造過程:首先,開辟整個類對象的內(nèi)存空間。根據(jù)類成員的情況,分配各個成員變量的內(nèi)存空間,并通過構(gòu)造函數(shù)的初始化列表進行初始化。最后,在執(zhí)行構(gòu)造函數(shù)中的代碼

靜態(tài)成員變量不屬于類,不依附于任何實例化對象。因此,靜態(tài)成員變量應該在任何實例化操作之前,就開辟好空間,又由于const成員變量必須初始化,因此在static const變量在定義時就完成初始化。

九.const成員函數(shù)

const成員函數(shù)不應該修改任何成員變量。
注:mutable關(guān)鍵字是為了突破const的。帶有mutable修飾的成員變量,即使在const成員函數(shù)中也可以修改。
傳給const成員函數(shù)的this指針,是指向const對象的const指針
而一般的非const成員函數(shù),需要傳入的this指針類型是指向一般對象的const指針。因此,需要將const int* const p 轉(zhuǎn)換成int* const p才能實現(xiàn)調(diào)用非const成員函數(shù),但是,很明顯,由嚴格到寬松是不現(xiàn)實的。所以,const對象不能調(diào)用非const成員函數(shù)。
那非const對象能調(diào)用const成員函數(shù)嗎?
答案是能。因為非const對象表示其可變,既能訪問const成員函數(shù),也能訪問非const成員函數(shù)。const對象只能訪問const成員函數(shù)。

總結(jié)

image.png

引用自:https://zhuanlan.zhihu.com/p/90720012

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

友情鏈接更多精彩內(nèi)容