沒有學(xué)不會的 C++:const 關(guān)鍵字

constC++ 中的關(guān)鍵字,它會在編譯期間(時機很重要),告訴編譯器這個對象是不能被修改的。初學(xué)者一般會認為 const 是個麻煩的東西,因為它常常讓你的程序編譯不通過,而去掉了 const 之后,就不會有這么多「問題」了,實不相瞞,其實我剛學(xué) C++ 的時候,有一段時間就處于這種狀態(tài)。

但實際上,const 非常有用:

  1. 他可以保護變量,防止它們被無意的修改。
  2. 它可以傳達有效的信息給讀你代碼的人:這個變量是不能被修改的,或者這個函數(shù)不會修該對象的成員,等。
  3. const 關(guān)鍵字可以優(yōu)化編譯結(jié)果,讓可執(zhí)行程序更為緊湊。
  4. const 修飾的變量還可以寫入 ROM 介質(zhì)。

總之,我認為合理的使用 const 可以讓你寫出來的程序更為嚴謹、健壯,不易出錯,乃至于更加高效。

const 與變量

const 修飾常量,比較容易混淆的是:「 const 類型的常量指針」和「指針?biāo)赶虻膬?nèi)容為 const 」之間的區(qū)別:

int i = 0;
const int* p1 = &i; 
int const* p2 = &i; 

上面代碼表示指針?biāo)傅膬?nèi)容為 const,你不能做 *p1 = 1; 這樣的操作,但可以 p1++;

int* const p3 = &i; 
const int* const p4 = &i; 

以上代碼中,p3const 指針,你無法修改 p3,如 p3++;,但你可以執(zhí)行 *p3 = 1;。最后一行中,p4 和其所指向的內(nèi)容都是 const 的。這里的規(guī)律是:如果 const* 號左邊,就表示指針?biāo)傅膬?nèi)容是常量,否則指針本身是常量。

另外,我們要盡可能的減少對 const 常量的強制轉(zhuǎn)換操作,即將 const 變量強制轉(zhuǎn)換為非 const 的,或相反,尤其是前者,因為這會破壞你對常量賦予的承諾,可能會導(dǎo)致誤操作,從而引入隱蔽 bug

const int i = 9;
// 強制將常量 i 轉(zhuǎn)換為普通變量
const_cast<int&>(i) = 6;  
int j;
// 編譯失敗; 因為該語句強制將變量 j 轉(zhuǎn)換成了常量
static_cast<const int&>(j) = 7; 

const 與函數(shù)

const 與函數(shù)結(jié)合,我們需要考慮3種情況:

  1. const 常量作為函數(shù)的參數(shù)傳入
  2. 函數(shù)返回 const 類型
  3. 聲明類的成員函數(shù)為 const

當(dāng) const 常量作為參數(shù)傳入時,該常量一定需要是引用類型,否則 const 起不到應(yīng)有的作用,例如

class Dog {
    string name_;
public:
    Dog(const string& name) { name_ = name; }
    void setName(const string name);
    void setName(string name);
};

上面兩個 setName() 函數(shù)等價,因為它們都是值傳遞(pass-by-copy),進入函數(shù)的參數(shù)是一個臨時副本,既然是一個副本,修改它或不修改它對外部沒有任何影響,所以這樣的聲明沒有意義。要使上面的 const 產(chǎn)生意義,應(yīng)該改為傳引用(pass-by-reference)的方式

    void setName(const string& name);
...
    Dog dog("");
    string strname = "xiao-D";
    dog.setName(strname)

此時,外部調(diào)用 setName 就不用擔(dān)心該函數(shù)會修改實參 strname 了。除此之外, setName 還可以被重載(overload)

    void setName(string& name); // 這里也只能是引用傳遞
    void setName(const string& name);

調(diào)用規(guī)則為,當(dāng)你的實參為 const 類型時,會調(diào)用 void setName(const string& name); 函數(shù),否則調(diào)用 void setName(string& name);

和函數(shù)的參數(shù)為 const 一樣,當(dāng)函數(shù)返回 const 類型時,也需要是引用類型,否則沒有意義,即

    const string& getName() { return name_; }

這樣可以防止外部對 object 的內(nèi)部成員進行修改。

最后,我們來看一下 const 類型的函數(shù),將以下函數(shù)加到 Dog 類中:

    void bark() const { cout << "dog " << name_ << " bark."; }

const 類型的函數(shù)表明該函數(shù)不會修改對象的成員,同時該函數(shù)也不可以調(diào)用非 const 函數(shù),例如如下操作都是不允許的

    void bark() const {
        name_ = "da-D"; // can't modify any member
        setName("mark"); // can't call a non-const function
    }

除此之外,const 類型的函數(shù)也是可以重載的,即

    void bark() const { cout << "const dog " << name_ << " bark." << endl; }
    void bark() { cout << "non-const dog " << name_ << " bark." << endl; }

調(diào)用規(guī)則是,當(dāng)對象是 const 類型時,調(diào)用 const 類型的函數(shù),否則調(diào)用非 const 類型的函數(shù)。

Dog d1;
d1.bark("QQ");
const Dog d2;
d2.bark("Wechat");

得到的結(jié)果為:

non-const dog QQ bark.
const dog Wechat bark.

參考:

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

相關(guān)閱讀更多精彩內(nèi)容

  • 1.ios高性能編程 (1).內(nèi)層 最小的內(nèi)層平均值和峰值(2).耗電量 高效的算法和數(shù)據(jù)結(jié)構(gòu)(3).初始化時...
    歐辰_OSR閱讀 30,228評論 8 265
  • Swift1> Swift和OC的區(qū)別1.1> Swift沒有地址/指針的概念1.2> 泛型1.3> 類型嚴謹 對...
    cosWriter閱讀 11,644評論 1 32
  • 晚風(fēng)輕溫扶烈酒,意卷深秋味證道,弄堂設(shè)晏方知客,飯露余香浴驅(qū)寒,淺彈輕唱伴燭眠,禪心初始夢還續(xù),如醉今宵戀冬來
    深深是藍閱讀 243評論 2 7
  • 在iOS 11上運行Scrollview向下偏移64px或者20px,因為iOS 11廢棄了automatical...
    c608閱讀 4,274評論 0 2
  • 幼年時,讀賀知章的《回鄉(xiāng)偶書》“ 少小離家老大回,鄉(xiāng)音無改鬢毛衰。兒童相見不相識,笑問客從何處來?!睍r,極為不解。...
    九昸閱讀 265評論 0 2

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