• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            歸去來(lái)兮

             

            Effective C++讀書筆記之二 :盡可能使用const

            條款三:盡可能使用const(use const whenever possible)
            const允許你指定一個(gè)語(yǔ)義約束,而編譯器會(huì)強(qiáng)制實(shí)施這項(xiàng)約束。它允許你告訴編譯器和其他程序員某值應(yīng)該保持不變。有一條約束需要注意,那就是:如果const出現(xiàn)在*號(hào)的左邊,那就是說(shuō)被指物是常量;如果出現(xiàn)在星號(hào)右邊,則表示指針本身是常量;如果出現(xiàn)在兩邊,則被指物和指針都是常量。如果被指物是常量,則關(guān)鍵字const寫在類型的前面和類型之后,星號(hào)之前兩種所表示的語(yǔ)義是相同的。例如下面這兩種寫法是一樣的:
            void f1(const Widget* pw);
            void f2(Widget const * pw);
            const也可用來(lái)修飾STL中的迭代器。聲明迭代器為const就想聲明指針為const一樣(即T* const 指針),表示這個(gè)迭代器不得指向不同的東西。但它所指的東西的值是可以改變的。如果希望迭代器所指的東西不可改變(即模擬一個(gè)const T*指針),需要的是const_iterator:
            std::vector<int> vec;
            ...
            const std::vector<int>::iterator iter = vec.begin();// same as T* const
            *iter = 10;                                                        //no problem
            ++iter;                                                              //wrong!!
            std::vector<int>::const_iterator cIter = vec.begin();//same as const T*
            *iter = 10;                                                             //wrong!!
            ++iter;                                                                  //no problem

            const 最具威力(?)的用法是面對(duì)函數(shù)聲明時(shí)的應(yīng)用。在一個(gè)函數(shù)聲明式內(nèi),const可以和函數(shù)返回值,各參數(shù),函數(shù)自身(成員函數(shù))產(chǎn)生關(guān)聯(lián)。
            令函數(shù)返回一個(gè)常量值,往往可以降低因客戶錯(cuò)誤而造成的意外,而又不至于放棄安全性和高效性。例如,考慮有理數(shù)的operator*聲明式:
            class Rational(){...};
            const Rational operator* (const Rational & lhs, const Rational & rhs);
            也許你會(huì)說(shuō)為什么返回一個(gè)const對(duì)象?原因是如果不這樣別人可能實(shí)現(xiàn)這樣的暴行:
            Rational a,b,c;
            ...
            (a*b)=c;
            下面,主要說(shuō)明const作用于成員函數(shù)。
            許多人都忽視了這么一個(gè)事實(shí),那就是如果兩個(gè)成員函數(shù)只是常量性不同,那么他們是可以重載的。考慮以下這個(gè)用來(lái)表示一大塊文字的class:

            class TextBlock{
            public:

            const char& operator[](std::size_t position) const
            {return text[position];}
            char& operator[](std::size_t position)
            {return text[position];}
            private:
            std::
            string text;
            }
            ;
            TextBlock的operator[]可以這么使用:
            TextBlock tb(
            "Hello");
            std::cout 
            << tb[0];  //調(diào)用non-const 

            const TextBlock ctb("Hello");
            std::cont 
            << ctb[0]; //調(diào)用const

            真是情形中const對(duì)象多用于passed by pointer-to-const或passed by reference-to-const的傳遞結(jié)果。上述的ctb太過(guò)于造作,下邊這個(gè)比較真實(shí):
            void print (const TextBlocd& ctb)
            {
              std::cout 
            << ctb[0];
              
            }

            只用重載operator[]并對(duì)不同的版本給予不同的返回類型,就可以令const和non-const獲得不同的處理。
            此處需要注意一點(diǎn),non-const operator[]的返回類型是個(gè)reference to char,不是char。如果operator[]返回的是個(gè)char,下邊的賦值就不能通過(guò)編譯:
            tb[0] = 'x'; //error c2106: ' = ' : left operand must be l-value
            那是因?yàn)椋绻瘮?shù)的返回類型是個(gè)內(nèi)置類型,那么改動(dòng)函數(shù)的返回值從來(lái)就不合法。縱使合法,C++以by value返回對(duì)象這一事實(shí)(條款20)意味著改動(dòng)的其實(shí)只是tb.text[0]的一個(gè)副本,不是tb.text[0]本身,那不是我們想要的結(jié)果。
            下邊來(lái)說(shuō)說(shuō)在const和non-const成員函數(shù)中避免重復(fù)
            假設(shè)TextBlock(和CTextBlock)內(nèi)的operator[]不單只是返回一個(gè)reference指向某字符,也執(zhí)行邊界檢查、志記訪問(wèn)信息、甚至可能進(jìn)行數(shù)據(jù)完整性檢驗(yàn)。把所有這些同時(shí)放進(jìn)const和non-const operator[]中,導(dǎo)致這樣的一個(gè)怪物:
            class TextBlock{
            public:

            const char& operator[](std::size_t position) const
            {
                  
            //邊界檢查(bounds checking)
                  //志記數(shù)據(jù)訪問(wèn)(log access data)
                  //檢驗(yàn)數(shù)據(jù)完整性(verify data integrity)
            return text[position];
            }

            char& operator[](std::size_t position)
            {
                  
            //邊界檢查(bounds checking)
                  //志記數(shù)據(jù)訪問(wèn)(log access data)
                  //檢驗(yàn)數(shù)據(jù)完整性(verify data integrity)
            return text[position];
            }

            private:
            std::
            string text;
            }
            ;
            其中代碼的代碼重復(fù)性及伴隨的編譯時(shí)間,維護(hù),代碼膨脹等問(wèn)題真是令人頭疼啊。當(dāng)然了,將邊界檢查……等所有代碼移植到另一個(gè)成員函數(shù),并令兩個(gè)版本的operator[]調(diào)用它,是可能的,但是還是重復(fù)了一些代碼,例如函數(shù)調(diào)用,兩次return語(yǔ)句等。
            我們真正要做的,是實(shí)現(xiàn)operator[]的機(jī)能一次并使用它兩次。也就是說(shuō),你必須使一個(gè)調(diào)用另一個(gè)。這促使我們將常量性轉(zhuǎn)除(casting away constness)。
            就一般而言,casting是一個(gè)糟糕的想法,在條款27中有詳細(xì)的說(shuō)明。然而代碼重復(fù)也不是什么令人愉快的經(jīng)驗(yàn)。本例中cosnt operator[]完全做掉了non-const版本該做的一切,唯一不同是其返回類型多了一個(gè)const資格修飾。這種情況下如果將返回值的const轉(zhuǎn)除是安全的,因?yàn)椴徽撜l(shuí)調(diào)用non-const operator[]都一定首先有個(gè)non-const對(duì)象,否則就不能夠調(diào)用non-const函數(shù)。所以令non-const operator[]調(diào)用其const兄弟是一個(gè)避免重復(fù)的安全做法:
            class TextBlock{
            public:

            const char& operator[](std::size_t position) const
            {



            return text[position];
            }

            char& operator[](std::size_t position)
            {
            const_cast
            <char&>(static_cast<const TextBlock&>
            (
            *this)[position]);
            }


            }
            ;
            這里面有兩個(gè)轉(zhuǎn)型動(dòng)作,而不是一個(gè)。我們打算讓non-const operator[]調(diào)用const兄弟,但是non-const如果只是單純調(diào)用operator[],會(huì)遞歸調(diào)用自己。為了避免無(wú)窮遞歸,我們必須明確指出調(diào)用的是const operator[]。因此,這里將*this從其原始類型TextBlock&轉(zhuǎn)型為const TextBlock&。所以這里有兩次轉(zhuǎn)型:第一次用來(lái)為*this添加const,第二次則是從const operator[]的返回值中移除const。添加const的那一次轉(zhuǎn)型強(qiáng)迫進(jìn)行了一次安全轉(zhuǎn)型,所以采用static_cast。移除const的那個(gè)動(dòng)作只能由const_cast完成,沒(méi)有其他選擇。
            下面來(lái)考慮一下反向的做法:令const來(lái)調(diào)用non-const以避免重復(fù)。這個(gè)不是我們應(yīng)該做的。const成員函數(shù)承諾絕對(duì)不改變其對(duì)象的邏輯狀態(tài),non-const成員函數(shù)卻沒(méi)有這般承諾。如果在const函數(shù)內(nèi)部調(diào)用了non-const函數(shù),就是冒了這樣的風(fēng)險(xiǎn):你曾經(jīng)承諾不改動(dòng)的那個(gè)對(duì)象被改動(dòng)了。這就是為什么“const成員函數(shù)調(diào)用non-const成員函數(shù)”是一種錯(cuò)誤行為:因?yàn)閷?duì)象有可能因此而被改動(dòng)。反向調(diào)用才是安全的:non-const函數(shù)本來(lái)就可以對(duì)其對(duì)象做任何動(dòng)作,所以在其中調(diào)用一個(gè)const成員函數(shù)并不會(huì)帶來(lái)任何風(fēng)險(xiǎn)。

            本條目總結(jié):

            Things to Remember

            • Declaring something const helps compilers detect usage errors. const can be applied to objects at any scope, to function parameters and return types, and to member functions as a whole.

            • Compilers enforce bitwise constness, but you should program using conceptual constness.

            • When const and non-const member functions have essentially identical implementations, code duplication can be avoided by having the non-const version call the const version.

            posted on 2008-12-09 23:00 Edmund 閱讀(270) 評(píng)論(0)  編輯 收藏 引用


            只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。
            網(wǎng)站導(dǎo)航: 博客園   IT新聞   BlogJava   博問(wèn)   Chat2DB   管理


            導(dǎo)航

            統(tǒng)計(jì)

            常用鏈接

            留言簿(1)

            隨筆分類

            隨筆檔案

            搜索

            最新評(píng)論

            閱讀排行榜

            評(píng)論排行榜

            99久久精品免费看国产一区二区三区 | 韩国无遮挡三级久久| 久久久久无码精品| 狠狠狠色丁香婷婷综合久久五月 | 亚洲欧洲精品成人久久奇米网| 2020久久精品国产免费| 久久综合给合久久狠狠狠97色| 国产99久久久国产精品小说| 热综合一本伊人久久精品| 国内精品久久久久影院网站| 久久精品成人欧美大片| 国产精品日韩欧美久久综合| 久久精品无码一区二区日韩AV| 老司机午夜网站国内精品久久久久久久久| 久久成人18免费网站| 久久精品无码一区二区三区免费 | 国产精品伦理久久久久久| 久久香蕉国产线看观看99| 国产高潮久久免费观看| 久久最新免费视频| 欧美牲交A欧牲交aⅴ久久| 久久99国产精品二区不卡| 久久久亚洲精品蜜桃臀 | 国产女人aaa级久久久级| 国产精品无码久久综合网| 欧美激情精品久久久久久久九九九| 亚洲日韩欧美一区久久久久我| 亚洲精品无码久久久久去q| 蜜臀av性久久久久蜜臀aⅴ| 99久久成人18免费网站| 最新久久免费视频| 久久天天躁狠狠躁夜夜avapp| 97久久精品午夜一区二区| 久久亚洲精品无码观看不卡| 亚洲AV无码久久| 丁香久久婷婷国产午夜视频| 久久伊人精品一区二区三区| 精品九九久久国内精品| 亚洲午夜精品久久久久久浪潮| 久久精品水蜜桃av综合天堂| 久久青青草原精品国产不卡|