C++中const用法小結。本站提示廣大學習愛好者:(C++中const用法小結)文章只能為提供參考,不一定能成為您想要的結果。以下是C++中const用法小結正文
const在C++中應用非常普遍,分歧地位應用的意義也不盡雷同,所以想寫篇文章對其做一個總結。
起首,明白const是“不變”這個根本意義,然則不變不料味著甚麼都不變,上面將會看到。
1. const與變量
根本准繩:const變量(對象)不克不及被修正
const在變量中的引入和魔數有關,所謂“魔數”指的是忽然湧現的一個常量值(也叫字面值常量)。
for(int i = 0; i < 512; i++) { // todo }
上例中,512即為魔數,512忽然湧現在輪回中,使人不克不及得知其意義,所以引入const。
const int length = 512; for(int i = 0; i < length; i++) { // todo }
如許就曉得輪回是在長度規模內。
1.1 const潤飾一個變量(或許說對象),使其釀成一個常量,表現該變量的值沒法再被修正,正由於如斯,所以界說一個常量的時刻,必需初始化。
1.2 const常量的感化域:
我們曉得,在全局感化域內聲明一個變量(此處特指非const潤飾的變量),其感化於全部法式,在其他文件中也能被援用,緣由是在全局感化域聲明一個變量,默許是extern潤飾的。
在全局感化域內聲明一個const變量,默許不是extern潤飾,所以其只能感化於本文件內,若要在其他文件中拜訪,須要顯式聲明為extern
2. const與援用
根本准繩:const援用是指向const變量(對象)的援用
const int ival = 1024; const int &refVal = ival;
2.1 const援用可以指向一個相干類型(不是本類型)的const變量
double dval = 3.14; const int &refVal = dval;
編譯器將double轉換成一個暫時的int對象,然後讓const援用綁定到這個暫時對象,所以轉變dval的值不會轉變refVal,也就是說dval依然長短const變量,refVal依然是常量援用。
primer第四版是下面的說法,但我在VS2012中,const也能夠指向一個本類型的非const變量,查找材料的緣由年夜概是知足reference-campatible前提。
實際上,我們應當嚴厲遵照,常量援用指向常量對象,異常量援用指向異常量對象,防止失足。
3. const與指針
const與指針的關系分為兩種:const潤飾的指針和指向const對象的指針,兩者const的地位不雷同
3.1 指向const對象的指針(const位於指針符號*後面)
關於一個const對象,必需用一個指向const的指針來指向它。緣由在於,const潤飾使得對象沒法被轉變,而指針假如不是指向const的指針,則可以經由過程指針來修正對象,這是不被許可的。
const int ival = 1; const int *ptrVal = &ival;
反過去,關於一個指向const對象的指針,可以指向隨意率性一個對象,這個該怎樣懂得呢?我們起首看看指針賦值的進程:
int *ptr = &val;
將val的地址賦值給ptr,由於賦值的只是地址,所以不曉得ptr所指向的對象能否為const。
假如我們把一個地址賦值給一個指向const的指針,那末指針以為這是一個const的對象,也就是說,ptr指針指向了一個“自以為”是const的對象。
int ival = 1; const int *ptrVal = &ival;
下面的法式是准確的,我們須要明白,ival長短const變量,所以我們可以經由過程給ival賦值更改ival的值。ptrVal指向了一個自以為是const的對象,所以我們沒法經由過程*ptrVal來更改ival的值。
3.2 const潤飾的指針(const位於指針符號*前面)
int *const ptr;
上式聲清楚明了一個const類型的指針,表現的意思是指針自己是一個常量,不克不及被修正。
若何懂得?指針自己的值是一個地址,假如指針自己是一個常量,則這個地址值不克不及被修正,也就是說指針只能指向這個地址,不克不及指向其他處所。但指針所指向的地址的內容不屬於指針自己的值,所以其所指向的內容可以轉變。
int ival = 1; int *const ptr = &ival; *ptr = 2; // ok int ivalTwo = 11; ptr = &ivalTwo // error
綜上,可以界說一個指向const對象的const指針
const int *const ptr = &ival;
3.3 typedef中易失足的const指針
typedef string *ptr; const ptr s_ptr;
上式不克不及直代替換懂得為const string *s_prt; 從而以為s_ptr是一個指向const string的指針。
起首,ptr是一個指針,const潤飾的是一個指針,所以應當是string *const s_ptr; s_ptr是一個指向string的const指針。
4. const與數組
const與數組的點在於const在界說時必需初始化這個准繩,所以應用靜態分派數組時,假如數組存儲的是const類型的對象,必需停止初始化(應用初始化符號())。
5. const與函數前往值
潤飾函數的前往值,用於前往一個常量。
const int foo();
5.1 前往經由過程值傳遞
假如函數前往時采取值傳遞,好比前往一個int類型,那末函數會把前往的值(好比47)復制到內部暫時存儲單位中(發生暫時正本),所以加const潤飾毫有意義
int foo(); const int foo();
兩者完整雷同。須要留意的是,值傳遞發生暫時正本,效力低(上面const與函數參數有講),所以平日采取援用傳遞來前往。
5.2 前往經由過程援用傳遞(其實不多見)
假如前往值不是外部類型,平日應用援用傳遞來前往成果,由於援用傳遞的是自己,不須要發生暫時正本。但須要留意的是,此時僅僅前往一個體名。
ClassType &foo(); const ClassType &foo();
const潤飾的前往援用值,表現函數挪用的成果只能賦值給一個同類型的const援用。
5.3 前往經由過程指針傳遞
const ClassType *foo();
表現函數前往一個ClassType類型的指針,這個指針指向一個const對象,指針所指的內容不克不及被修正,所以函數的前往值只能賦值給指向一個const的同類型的指針。
const ClassType *ptr = foo(); //ok ClassType *ptr = foo(); //error
6. const與函數參數
起首須要明白,const潤飾的目標就在於掩護所潤飾的內容不被轉變。
在C++中,函數參數分為值傳遞,指針傳遞和援用傳遞。
6.1 值傳遞
值傳遞在函數挪用時發生一個暫時正本,函數中對傳入參數的修正和操作是對正本的操作,不轉變實參自己的值,所以無需const來掩護。
值傳遞的掩護很好,但值傳遞存在缺陷,須要發生暫時正本,假如傳入的是對象,那末須要停止結構、復制、和析構等操作,效力不高。這時候候可以斟酌援用傳遞
void foo1(int x); void foo2(ClassType instance); //開支較年夜
上面這類掩護有意義:
void foo1(const int x); void foo2(const ClassType instance);
6.2 援用傳遞
經由過程傳入實參的援用,下降開支。由於援用即自己,不須要去發生一個暫時正本。
void foo1(int &x); void foo2(ClassType &ref);
關於上述兩個函數,函數挪用和值傳遞的情勢完整一樣,分歧的是函數外部獲得的x和ref是挪用傳入實參的援用。也正由於如斯,援用可以經由過程函數轉變傳入的參數來轉變實參。這對與實參來講,比擬風險,這時候候須要經由過程const潤飾來掩護傳入的援用不被修正。
void foo1(const int &x); void foo2(const ClassType &ref);
平日來講,關於根本外部類型,不存在對象的結構等操作,所以上面兩種掩護參數不被修正的方法效力根本一樣。
void foo1(int x); void foo1(const int &x);
6.3 指針傳遞
指針傳遞在掩護參數不被修正上和援用傳遞是一樣的,指針傳遞還有一個功效是可以擴展吸收參數的規模:
void foo1(const ClassType *ptr);
聯合下面const與指針,我們曉得,ptr指向一個自以為是const類型的對象,所以!傳入的對象紛歧定是const潤飾的對象,可所以const對象,也能夠非const對象。反過去,假如沒有const潤飾函數的形參,則只能傳入非const對象。
須要明白,不管傳入的能否是const對象,都沒法經由過程指針來修正這個對象,這和下面指針與const的關系是分歧的。
最初須要曉得:const只能潤飾一個輸出參數,假如是輸入參數,不管是援用傳遞照樣指針傳遞,都不克不及應用const來潤飾
7. const與類的數據成員
const潤飾的數據成員不克不及在結構函數中停止初始化,只能應用成員初始化列表停止初始化。
我的懂得是,由於在結構函數履行之前,應用成員初始化列表對數據成員停止初始化,假如在結構函數中對數據成員停止初始化,相當於對const停止二次賦值,這是不被許可的。
之所以這麼懂得,可以參照類中援用類型的初始化,也是必需在初始化列表中停止初始化,由於援用類型也是在界說的時刻必需初始化,請求和const一樣,所以兩者都只能應用成員初始化列表來停止初始化。
8. const與類的成員函數
const成員函數中,const位於函數的參數列表前面(函數聲明後面表現函數的前往值是一個常量)
const潤飾的成員函數表現成員函數是一個只讀的感化,不轉變成員變量。
const成員函數真實的寄義在於,const其實潤飾的成員函數的是隱含參數this指針,也就是說傳入的是const ClassType *this,由於this指向一個const對象,所以不克不及修正。
由於this是指向對象的指針,所以我們須要再次聯合const與指針的常識:
(1)const潤飾了this,獲得const ClassType *this,this指向一個“自以為”是const的對象(也就是自己),所以任何對象(const或許非const)都可以挪用一個const成員函數,由於傳入的指針都把本身這個對象看做是const對象,所以不克不及被修正。
(2)關於一個const對象,當其挪用成員函數的時刻,默許都傳入this指針參數,由於this此時指向一個const對象(自己),所以相當於成員函數被const潤飾,成員函數是一個const成員函數,所以反過去說,const對象只能挪用const成員函數,由於非const潤飾的成員函數,this指針不是指向const對象。
(3)在8.2的根本上,進一步,每一個成員函數都可以挪用其他成員函數,每一個成員函數都傳入this指針,所以成員函數互相挪用必需堅持this指針的分歧性,所以const成員函數只能挪用const成員函數,由於兩者傳入的this指針都是const潤飾的。關於非const成員函數,其傳入非const潤飾的this指針,所以不克不及被挪用。
弄清晰const真實的寄義就明確了,必定要堅持const成員函數傳入的是const指針這個認識,對象挪用就須要看對象(自己,指針,援用)能否是const。