const對(duì)普通變量進(jìn)行修飾,以表該變量在以后的使用中不被修改。
初始化
/*
*因?qū)ο笠坏﹦?chuàng)建后其值便不能被修改,所以必須進(jìn)行初始化
*根據(jù)初始化的值給定的表達(dá)式,初始化時(shí)機(jī)會(huì)再編譯時(shí)或運(yùn)行時(shí)確定
*當(dāng)編譯確定時(shí),會(huì)在調(diào)用其值的地方編譯時(shí)便用其值進(jìn)行替換
*(類(lèi)似于define文本替換,但是define不會(huì)作類(lèi)型檢查)
*/
const int i = 12; //編譯時(shí)初始化
const int j = get_size(); //運(yùn)行時(shí)初始化
等價(jià)寫(xiě)法:
int const i = 12;
int const j = get_size();
const 對(duì)象作用域
默認(rèn)僅在當(dāng)前文本文件有效
需要在多個(gè)文件中生效時(shí),需要在其聲明和定義處用extern進(jìn)行修飾
xxx.cc
extern const int i = 123;
xxx.h
extern const int i;
const 引用及指針
引用 [1]
當(dāng)我們使用引用時(shí)一般都期望改變其值, 但是對(duì)于const對(duì)象本身是不被允許.
修改的,因此對(duì)于想把const對(duì)象綁定到引用時(shí)需要進(jìn)行const修飾, 以表該引用不會(huì)改變其值.
引用的類(lèi)型必須與其引用對(duì)象的類(lèi)型一致 [2], 但是在初始化常量引用時(shí)只要表達(dá)式的結(jié)果能轉(zhuǎn)換成引用的類(lèi)型即可。例如
double dval = 3.14;
const int &ri = dval;
原因是編譯器做了如下替換:
const int temp = dval;
const int &ri = temp;
// temp 是編譯器臨時(shí)創(chuàng)建的用于暫存表達(dá)式求值結(jié)果的臨時(shí)變量。
// 另const引用可以綁定在非const變量上
int i = 3;
const int &k_ri = i;
i = 5; //此時(shí)k_ri == 5;
指針及頂層const和底層const
指針本身是個(gè)變量,那其也可被const修飾,用于表明該指針的值不會(huì)被改變。
由于指針指向的亦是一個(gè)變量,那么該變量也存在const修飾的可能性,即一個(gè)指針變量可能存在雙層const. 所謂低層const即用于修飾指針本身不會(huì)被改變,頂層const用于修飾指針指向的變量不會(huì)被改變。
int i = 1, b= 2;
const int *p = &i; //底層const, *p解引用的值無(wú)法被改變, 但是p可以指向別的變量
*p = 4; //不合法
p = &b; //合法
int *const p2 = &i; //頂層const, p2無(wú)法指向其它變量,但是*p解引用的值可以改變.
*p2 = 1; //合法
p2 = &b; //不合法
注意:
進(jìn)行對(duì)象拷貝時(shí),對(duì)象必須有相同的底層const, 而頂層const則不影響.
const 在類(lèi)中的使用
class Foo {
public:
...
int get_i() { ++z_; return i_;}
int get_z() { return z_; };
...
private:
int i_; //隨意...
int z_; //計(jì)數(shù)get_i() 被調(diào)用的次數(shù);
}
//對(duì)于Foo這樣的類(lèi),如果某一天我們頭腦發(fā)熱想要聲明一個(gè)常量,并調(diào)用相關(guān)成員,如下
const Foo k_var;
k_var.get_i(); //調(diào)用出錯(cuò)
k_var.get_z(); //調(diào)用出錯(cuò)
//對(duì)于成員函數(shù)的調(diào)用會(huì)提示報(bào)錯(cuò),因?yàn)檫@些函數(shù)的調(diào)用可能會(huì)改變內(nèi)部成員變量的值,
//這與你的期望不匹配。因此我們必須聲明一個(gè)可被常量調(diào)用的版本, 通常如下,
class Foo {
public:
...
int get_i() { ++z_; return i_;}
int get_i() const { ++z_; return i_;} //常量版本
int get_z() { return z_; };
int get_z() const { return z_; }; //常量版本
...
}
k_var.get_i(); //調(diào)用出錯(cuò)
k_var.get_z(); //正確
//此時(shí)對(duì)get_z()的調(diào)用是正確的,但是get_i()仍然是錯(cuò)誤的,
//因?yàn)樗噲D在const成員函數(shù)里面改變成員變量的值z(mì)_,
//成員函數(shù)一旦被const修飾,通常意味著this指針的形態(tài)在其內(nèi)部是const *this(便于理解),
//那么++this->z_這樣的操作肯定是不合法的。
//但是對(duì)于z_這樣我們希望無(wú)論在常量或非常量中都希望能夠改變的值,我們可以在聲明前加mutable修飾,表明是個(gè)可變的數(shù)據(jù)
class Foo {
public:
...
int get_i() { ++z_; return i_;}
int get_i() const { ++z_; return i_;} //常量版本
int get_z() { return z_; };
int get_z() const { return z_; }; //常量版本
...
private:
int i_; //隨意...
mutable int z_; //計(jì)數(shù)get_i() 被調(diào)用的次數(shù);
}
k_var.get_i(); //正確