[C++] const關(guān)鍵字

關(guān)鍵字const多才多藝,
你可以用它在class外部修飾global或namespace作用域中的常量达舒,
或修飾文件,函數(shù)穗椅,或區(qū)塊作用域(block scope)中被聲明為static的對(duì)象下梢。
你也可以用它修飾class內(nèi)部的static和non-static成員變量客蹋。
面對(duì)指針,你也可以指出指針自身孽江,指針?biāo)肝镅扰鳎蛘邇烧撸ɑ蚨疾唬┦莄onst。

1. 指針

STL迭代器系以指針為根據(jù)塑模出來岗屏,所以迭代器的作用就像個(gè)T*指針辆琅,
聲明迭代器為const就像聲明指針為const一樣,即聲明一個(gè)T* const指針这刷,
表示這個(gè)迭代器不得指向不同的東西婉烟,但它所指的東西的值是可以改動(dòng)的。
如果你希望迭代器所指的東西不可以改動(dòng)暇屋,即希望STL模擬一個(gè)const T*指針似袁,
你需要的是const_iterator

std::vector<int> vec;
...

// iter的作用像個(gè) T* const
const std::vector<int>::iterator iter = vec.begin();

// 沒問題咐刨,改變iter所指物
*iter = 10;

// 錯(cuò)誤昙衅,iter是const
++iter;

// cIter的作用像個(gè) const T*
std::vector<int>::const_iterator cIter = vec.begin();

// 錯(cuò)誤,*cIter是const
*cIter = 10;

// 沒問題所宰,改變cIter
++cIter;

2. 函數(shù)

const最具威力的用法是面對(duì)函數(shù)聲明時(shí)的應(yīng)用绒尊。
在一個(gè)函數(shù)聲明式內(nèi),const可以和函數(shù)返回值仔粥,各參數(shù)婴谱,函數(shù)自身(如果是成員函數(shù))產(chǎn)生關(guān)聯(lián)。

2.1 返回值

令函數(shù)返回一個(gè)常量值躯泰,往往可以降低因客戶錯(cuò)誤而造成的意外谭羔,而又不至于放棄安全性和高效性。
例如麦向,有理數(shù)的operator*聲明式:

class Rational { ... };
const Rational operator* (const Rational& lhs, const Rational& rhs);

為什么返回一個(gè)const對(duì)象呢瘟裸?原因是如果不這樣客戶就能實(shí)現(xiàn)這樣的暴行:

Rational a,b,c;
...

// 在 a * b 的成果上調(diào)用 operator=
(a * b) = c;

operator*的回傳值聲明為const,可以預(yù)防那個(gè)“沒意思的賦值動(dòng)作”诵竭,這就是該這么做的原因话告。

2.2 參數(shù)

至于const參數(shù),沒有什么特別新穎的觀念卵慰,
他們不過就像local const對(duì)象一樣沙郭,你應(yīng)該在必要使用它們的時(shí)候使用它們。
除非你有需要改動(dòng)參數(shù)或local對(duì)象裳朋,否則請(qǐng)將它們聲明為const病线。
只不過多打6個(gè)字符,卻可以省下惱人的錯(cuò)誤。

2.3 成員函數(shù)

將const實(shí)施于成員函數(shù)的目的送挑,是為了確認(rèn)該成員函數(shù)可作用于const對(duì)象身上绑莺。
這一類成員函數(shù)之所以重要,基于兩個(gè)理由惕耕。
第一纺裁,它們似class接口比較容易被理解,這是因?yàn)樯耐唬弥膫€(gè)函數(shù)可以改動(dòng)對(duì)象內(nèi)容而哪個(gè)函數(shù)不行对扶,很是重要区赵。
第二惭缰,它們使“操作const對(duì)象”成為可能,這對(duì)編寫高效代碼是個(gè)關(guān)鍵笼才。

(1)成員函數(shù)重載

許多人漠視一件事實(shí):
兩個(gè)成員函數(shù)如果只是常量性不同漱受,可以被重載。
這實(shí)在是一個(gè)重要的C++特性骡送。

考慮以下class昂羡,用來表現(xiàn)一大塊文字:

class TextBlock{
public:
    ...

    // operator[] for const對(duì)象
    const char& operator[] (std::size_t position) const{
        return text[position];
    }

    // operator[] for non-const對(duì)象
    char& operator[] (std::size_t position){
        return text[position];
    }

private:
    std::string text;
};

TextBlockoperator[]可被這樣使用:

TextBlock tb("Hello");

// 調(diào)用non-const TextBlock::operator[]
std::cout << tb[0];

const TextBlock ctb("World");

// 調(diào)用const TextBlock::operator[]
std::cout << ctb[0];

只要重載operator[]并對(duì)不同的版本給予不同的返回類型,就可以令const和non-const TextBlock獲得不同的處理:


// 沒問題摔踱,讀一個(gè)non-const TextBlock
std::cout << tb[0];

// 沒問題虐先,寫一個(gè)non-const TextBlock
tb[0] = 'x';

// 沒問題,讀一個(gè)const TextBlock
std::cout << ctb[0];

// 錯(cuò)誤派敷,寫一個(gè)const TextBlock
ctb[0] = 'x';

注意蛹批,上述錯(cuò)誤只因operator[]的返回類型所致,
錯(cuò)誤起因于企圖對(duì)一個(gè)“由const版之operator[]返回”的const char&施行賦值動(dòng)作篮愉。
也請(qǐng)注意腐芍,non-const operator[]的返回類型是一個(gè)reference to char,不是char试躏,
如果operator[]只是返回一個(gè)char猪勇,下面這樣的句子就無法通過編譯。

tb[0] = 'x';

那是因?yàn)榈咴蹋绻瘮?shù)的返回類型是個(gè)內(nèi)置類型泣刹,那么改動(dòng)函數(shù)返回值從來就不合法。
縱使合法犀被,C++以by value返回對(duì)象這一事實(shí)椅您,意味著被改動(dòng)的其實(shí)是tb.text[0]的一個(gè)副本,不是tb.text[0]自身弱判。

(2)bitwise constness & logical constness

成員函數(shù)如果是const意味什么襟沮?
這有兩個(gè)流行概念:bitwise constness(又稱physical constness),和logical constness。

bitwise const陣營(yíng)的人相信开伏,成員函數(shù)只有在不更改對(duì)象之任何成員變量時(shí)才可以說是const膀跌,
也就是說它不更改對(duì)象內(nèi)的任何一個(gè)bit。
這種論點(diǎn)的好處是很容易偵測(cè)違反點(diǎn)固灵,編譯器只需尋找成員變量的賦值動(dòng)作即可捅伤。
bitwise constness正是C++對(duì)常量性的定義,因此巫玻,const成員函數(shù)不可以更改任何non-static成員變量丛忆。

不幸的是,許多成員函數(shù)雖然不十足具備const性質(zhì)卻能通過bitwise測(cè)試仍秤,
更具體的說熄诡,一個(gè)更改了“指針?biāo)肝铩钡某蓡T函數(shù)雖然不能算是const,但如果只有指針(而非其所指物)隸屬于對(duì)象诗力,
那么稱此函數(shù)為bitwise const不會(huì)引發(fā)編譯器異議凰浮,這導(dǎo)致反直觀結(jié)果。

這種情況導(dǎo)出所謂的logical constness苇本,
這一派擁護(hù)者主張袜茧,一個(gè)const成員函數(shù)可以修改它所處理的對(duì)象內(nèi)的某些bit,但只有在客戶端偵測(cè)不出情況下才得如此瓣窄。

例如笛厦,CTextBlock class有可能高速緩存(cache)文本區(qū)塊的長(zhǎng)度以便應(yīng)付詢問:

class CTextBlock{
public:
    ...
    std::size_t length() const;

private:
    char* pText;
    std::size_t textLength;
    bool lengthIsValid;
};

std::size_t CTextBlock::length() const{
    if(!lengthIsValid){

        // 錯(cuò)誤,在const成員函數(shù)內(nèi)俺夕,不能賦值給textLength和lengthIsValid
        textLength = std::strlen(pText);
        lengthIsValid = true;
    }

    return textLength;
}

length的實(shí)現(xiàn)裳凸,當(dāng)然不是bitwise const,因?yàn)?code>textLength和lengthIsValid都可能被修改啥么。
這兩筆數(shù)據(jù)被修改對(duì)const CTextBlock對(duì)象而言雖然可接受登舞,但編譯器不同意。
它們堅(jiān)持bitwise constness悬荣,怎么辦菠秒?

解決辦法很簡(jiǎn)單,利用C++的一個(gè)與const相關(guān)的擺動(dòng)場(chǎng)氯迂,mutable(可變的)践叠。
mutable釋放掉non-static成員變量的bitwise constness約束。

class CTextBlock{
public:
    ...

private:
    // 這些成員變量可能總是會(huì)被改變嚼蚀,即使在const成員函數(shù)內(nèi)
    mutable std::size_t textLength;
    mutable bool lengthIsValid;
};

Effective C++ - P17

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末禁灼,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子轿曙,更是在濱河造成了極大的恐慌弄捕,老刑警劉巖僻孝,帶你破解...
    沈念sama閱讀 217,509評(píng)論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異守谓,居然都是意外死亡穿铆,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,806評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門斋荞,熙熙樓的掌柜王于貴愁眉苦臉地迎上來荞雏,“玉大人,你說我怎么就攤上這事平酿》镉牛” “怎么了?”我有些...
    開封第一講書人閱讀 163,875評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵蜈彼,是天一觀的道長(zhǎng)筑辨。 經(jīng)常有香客問我,道長(zhǎng)柳刮,這世上最難降的妖魔是什么挖垛? 我笑而不...
    開封第一講書人閱讀 58,441評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮秉颗,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘送矩。我一直安慰自己蚕甥,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,488評(píng)論 6 392
  • 文/花漫 我一把揭開白布栋荸。 她就那樣靜靜地躺著菇怀,像睡著了一般。 火紅的嫁衣襯著肌膚如雪晌块。 梳的紋絲不亂的頭發(fā)上爱沟,一...
    開封第一講書人閱讀 51,365評(píng)論 1 302
  • 那天,我揣著相機(jī)與錄音匆背,去河邊找鬼呼伸。 笑死,一個(gè)胖子當(dāng)著我的面吹牛钝尸,可吹牛的內(nèi)容都是我干的括享。 我是一名探鬼主播,決...
    沈念sama閱讀 40,190評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼珍促,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼铃辖!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起猪叙,我...
    開封第一講書人閱讀 39,062評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤娇斩,失蹤者是張志新(化名)和其女友劉穎仁卷,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體犬第,經(jīng)...
    沈念sama閱讀 45,500評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡五督,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,706評(píng)論 3 335
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了瓶殃。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片充包。...
    茶點(diǎn)故事閱讀 39,834評(píng)論 1 347
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖遥椿,靈堂內(nèi)的尸體忽然破棺而出基矮,到底是詐尸還是另有隱情,我是刑警寧澤冠场,帶...
    沈念sama閱讀 35,559評(píng)論 5 345
  • 正文 年R本政府宣布家浇,位于F島的核電站,受9級(jí)特大地震影響碴裙,放射性物質(zhì)發(fā)生泄漏钢悲。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,167評(píng)論 3 328
  • 文/蒙蒙 一舔株、第九天 我趴在偏房一處隱蔽的房頂上張望莺琳。 院中可真熱鬧,春花似錦载慈、人聲如沸惭等。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,779評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽辞做。三九已至,卻和暖如春寡具,著一層夾襖步出監(jiān)牢的瞬間秤茅,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,912評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工童叠, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留框喳,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,958評(píng)論 2 370
  • 正文 我出身青樓拯钻,卻偏偏與公主長(zhǎng)得像帖努,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子粪般,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,779評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容

  • 前言 把《C++ Primer》[https://book.douban.com/subject/25708312...
    尤汐Yogy閱讀 9,516評(píng)論 1 51
  • 1. 讓自己習(xí)慣C++ 條款01:視C++為一個(gè)語言聯(lián)邦 為了更好的理解C++拼余,我們將C++分解為四個(gè)主要次語言:...
    Mr希靈閱讀 2,804評(píng)論 0 13
  • C++運(yùn)算符重載-下篇 本章內(nèi)容:1. 運(yùn)算符重載的概述2. 重載算術(shù)運(yùn)算符3. 重載按位運(yùn)算符和二元邏輯運(yùn)算符4...
    Haley_2013閱讀 1,440評(píng)論 0 49
  • 8月25-26日,由用友和MSUP共同發(fā)起的以“技術(shù)變革 企業(yè)互聯(lián)”為主題的技術(shù)開放日在北京用友產(chǎn)業(yè)園中區(qū)成功舉行...
    Cynthia成閱讀 352評(píng)論 0 0
  • “妳喜歡我亩歹,毋庸置疑的匙监》渤鳎” 如果在拉斯維加斯,艾蜜莉·吉拉德一定是個(gè)很在行的賭徒亭姥。她懂得何時(shí)下注稼钩,懂得察言觀色,更...
    雀咬咬閱讀 228評(píng)論 0 0