有時候我們希望定義這樣一種變數,它的值不能被改變,比如需要設定乙個快取區大小:
const int buffsize = 512;
這樣就通過使用const限定符將這個大小設定為了常量,之後,任何為buffsize賦值的操作都將引發錯誤:
buffsize = 1024; //報錯,試圖向const物件寫值
const物件一旦建立後就不能改變,因此必須初始化:
const int i = get_size(); //執行時初始化
const int j = 42; //編譯時初始化
const int k; //未經初始化,報錯
由於物件的型別決定了其上的操作,與非const物件能完成的操作相比,主要的限制就是不能執行改變其內容的操作。
在不改變const物件的操作中,還有一種操作是初始化操作,如果利用乙個物件去初始化另乙個物件,則它們是不是const物件都無所謂:
int i = 42; //正確
const int ci = i; //正確
int j = ci; //正確
ci的常量特徵僅僅在執行改變ci的操作時才會發揮作用。當用ci去初始化j時,根本無需在意ci是不是常量,拷貝乙個物件的值並不會改變它,一旦拷貝完成,新的物件就和原來的物件沒什麼關係了。
可以把引用繫結到const物件上,稱為對常量的引用。
const int ci = 1024;
const int &r1 = ci; //正確,都是常量
r1= 42; //報錯,試圖修改常量
int &r2 = ci; //報錯,試圖讓乙個非常量引用去指向乙個常量物件
為什麼r2會報錯呢?因為ci是常量,自然不允許為ci賦值,當然也不允許通過引用的方式去改變ci,因此r2的初始化是錯誤的。假設該初始化合法,那麼就可以通過r2改變ci的值,顯然不正確。
引用要求引用型別和物件的型別一致,這裡存在兩個例外:
第乙個例外:初始化常量引用時允許用任意表示式作為初始值,只要該表示式的結果能轉換成引用的型別即可。尤其允許為乙個常量引用繫結非常量的物件、字面值,甚至是個一般表示式。
看下面的例子:
int i = 42;
const int &r1 = i; //正確,允許const int&繫結到乙個普通int物件上
const int &r2 = 42; //正確,r2是乙個常量引用
const int &r3 = r1 * 2; //正確,r3是乙個常量引用
int &r4 = r1 * 2; //錯誤,r4是乙個普通非常量引用
要知道為什麼會發生這種例外,需要明白乙個常量引用繫結到另外一種型別上時到底發生了什麼:
double dval = 3.14;
const int &ri = dval; //合法
const int temp = dval;
const int &ri = temp;
ri繫結了乙個臨時量(臨時建立的未命名的物件),如果ri不是常量,就允許對ri賦值,就會改變所引用物件的值,但此時繫結的是臨時量,無法改變dval的值,歸於非法,也就是說:
double dval = 3.14;
int &ri = dval; //非法
常量引用僅限制了引用可參與的操作,對引用本身是否為常量未做限定。因此,對const的引用可能引用乙個非const的物件。
指向常量的指標不能用於改變其所指物件的值。想存放常量物件的位址,只能使用指向常量的指標。
const double pi = 3.14;
double *ptr = π //錯
const double *cptr = π //對
指標型別同樣要求型別一致,也存在兩個例外:
第乙個例外:允許令乙個指向常量的指標指向乙個非常量物件
double dval = 3.14;
const double *cptr = &dval; //合法
和常量引用一樣,指向常量的指標也沒有規定其所指的物件必須是乙個常量,指向常量的指標僅僅要求不能通過該指標改變物件的值,而沒有規定那個物件的值不能通過其他途徑改變。
int a = 0;
int *const cur = &a;
const double pi = 3.14;
const double *const pip = π
指標是物件,所以可以把指標本身定義為常量。即常量指標。
必須被初始化,把*放在const之前說明指標是乙個常量:隱含:不變的是指標本身而非指向的值。
頂層const表示指標本身是個常量。
底層const表示指標所指向的物件是乙個常量。
更一般的:
頂層const可以表示任意的物件是常量,對任何資料型別都適用。
底層cosnt與指標和引用等符合型別的基本型別部分有關。
指標既可以是頂層const也可以是底層const。
int i = 0;
int *const p1 = &i; //不能改變p1的值,頂層const
const int ci = 42; //不能改變ci的值,頂層const
const int *p2 = &ci; //允許改變p2,底層const
const int *const p3 = p2; //靠右的是頂層const,靠左的是底層const
const int &r = ci; //用於宣告引用的const都是底層const
執行物件的拷貝操作時,頂層const不受什麼影響:
i = ci;
p2 = p3; //p2和p3指向的物件型別相同,p3頂層const部分不影響
執行拷貝操作時,拷入和拷出的物件必須具有相同的底層const資格,或者兩個物件的資料型別必須能夠轉換。一般來說非常量可以轉換成常量,反之不行。
int *p = p3; //錯誤:p3包含底層const的定義,而p沒有
p2 = p3; //正確:p2和p3都是底層const
p2 = &i; //正確:int *能夠裝換成const int*
int &r = ci; //錯誤:普通的int&不能繫結到int常量上
const int &r2 = i; //正確:const int&可以繫結到乙個普通int上
關於C const限定符與define
const限定符修飾的常量無法修改,且在定義的時候必須同時初始化,否則error xcode平台 相比define,const指定的常量有型別,而define只是簡單的字元替換。const修飾的常量只能由const指標來指向,不能用乙個普通的指標指向乙個const修飾的常量 const int a ...
C const 限定符 指標的使用方法
c 中的常量符號const限定符相信大家都比較熟悉它對於基本型別變數的使用方法了 無非有最常用的那種 const type name value 在宣告的時候進行初始化。這個放下不表,看下面 const int a int const a int const a 這三種const限定符指標有什麼區別...
引用限定符
通常,我們在乙個物件上呼叫成員函式,而不管該物件是乙個左值還是乙個右值。例如 string s1 a value s2 another auto n s1 s2 find a 此例中,我們在乙個string右值上呼叫find成員,該string右值是通過連線兩個 string 而得到的。有時,右值的...