在剛接觸const時,只是簡單的記const修飾的變數為常量,然而,const遠非如此。
一、初級部分
1 .const作為限定符
(1)修飾一般變數,定義const對象
const int a = 10;a = 15; //errorconst int b;//errorb = a;
const限定了它修飾的變數a只能讀,而不能被修改,這在編譯時間進行檢測。變數a本質上依然是變數,或者說仍然是一個左值,具備一個左值應有的屬性。
而const修飾變數b時,規定在定義時需要進行初始化,否則報錯。
在http://www.embedu.org/Column/Column311.htm一文中,有如下代碼:
int main(){ int buf[4]; const int a = 0; buf[4] = 97; printf("%d",a); return 0; }
只是我在VS2008中得到的依然是0!
(2)const對象在檔案中預設為局部變數
先看如下代碼:
//--------file_1.cppconst int bufsize = 1234;//--------file_2.cppextern const int bufsize;int main(){ printf("%d",bufsize); return 0;}
上述代碼編譯通不過,那是因為在全域範圍中聲明的變數bufsize在定義它的檔案中是局部變數,不能被其他檔案訪問。
註:在全域範圍定義非const變數時,預設為extern。而要使const對象能夠被其他檔案訪問,則必須顯式指定為extern。
2.const與define
在《Effective C++》條款2:盡量以const,enum,inline替換#define。
為什麼呢?
怎麼說呢,#define是一種預先處理,在編譯之前做一個字元的替換,它缺乏一種類型檢查,所以可能會帶來意想不到的隱患。相關知識可以看#define介紹。編程過程中,盡量使用const代替#define。
進一步瞭解可以百度或者google:摺疊常量
3.const與&、*
const引用就是指向const對象的引用。引用一旦定義,就不能再指向其他對象,所以必須初始化。非const引用只能初始為非const同類型對象,而const引用它可以初始化為不同類型的對象或者右值。例如:
int i = 20;double dval = 1.34;const int &r = 20;//okconst int &r2 = i;//okconst int &r3 = i+20;//okconst int &r4 = dval; //ok
對於
const int &r4 = dval;
編譯器會將以上代碼轉化成如下形式編碼:
int temp = dval;const int &r4 = temp;
接下來我們看const限定符和*,依照慣例,先看代碼:
const int *pContents;//①int * const pContents;//②const int * const pContents;//③
對於上述三種情況,假如你能說清楚,恭喜你,你已經不用擔心const指標問題了。在《effective C++》中有一種簡單的判別方法:如果const在星號左邊,則表示指標指向的是一個const對象,你不能修改它所指向的值,但是你能夠修改指標本身;如果const在星號右邊,則表示指標本身是const,你可以修改指標指向的對象,但是指標是唯讀。而③則表示,你既不能修改指標,也不能修改指標所指向的對象。
上面提到,對於一個const對象,它的引用應該是具備const特性的,同樣,指向一個const對象的指標也應該具備const特性。如果指標是非const的,而試圖去指向一個const對象時,就會報錯。但是const指標可以接受一個非const對象的地址,不過依然不能通過指標去修改它指向的值,但是可以用其他方法修改它指向的值。
const double pi = 3.14;double *ptr = π//errordouble *cptr = π//okdouble dval = 2.34;const double *cptr = &dval;//ok*cptr = 3.45;//error//通過非const指標修改非const對象double *ptr = &dval;*ptr = 3.45;//ok
在《C++primer》裡說:如果把指向const的指標理解為“自以為指向const的指標”,這可能會對理解有所協助。確實如此!!!
二、中級部分
1 const與函數