• <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>

            洛譯小筑

            別來無(wú)恙,我的老友…
            隨筆 - 45, 文章 - 0, 評(píng)論 - 172, 引用 - 0
            數(shù)據(jù)加載中……

            [ECPP讀書筆記 條目3] 盡可能使用const

            const令人贊嘆之處就是:你可以通過它來指定一個(gè)語(yǔ)義上的約束——一個(gè)特定的不能夠更改的對(duì)象——這一約束由編譯器來保證。通過一個(gè)const,你可以告訴編譯器和其他程序員,你的程序中有一個(gè)數(shù)值需要保持恒定不變。不管何時(shí),當(dāng)你需要這樣一個(gè)數(shù)時(shí),你都應(yīng)確保對(duì)這一點(diǎn)做出聲明,因?yàn)檫@樣你便可以讓編譯器來協(xié)助你確保這一約束不被破壞。

            const關(guān)鍵字的用途十分廣泛。在類的外部,你可以利用它定義全局的或者名字空間域的常量(參見條目2),也可以通過添加static關(guān)鍵字來定義文件、函數(shù)、或者程序塊域的對(duì)象。在類的內(nèi)部,你可以使用它來定義靜態(tài)的或者非靜態(tài)的數(shù)據(jù)成員。對(duì)于指針,你可以指定一個(gè)指針是否是const的,其所指的數(shù)據(jù)是否是const的,或者兩者都是const,或者兩者都不是。

            char greeting[] = "Hello";

            char *p = greeting;                // const指針,非const數(shù)據(jù)

            const char *p = greeting;         // const指針,const數(shù)據(jù)

            char * const p = greeting;        // const指針,非const數(shù)據(jù)

            const char * const p = greeting;  // const指針,const數(shù)據(jù)

            這樣的語(yǔ)法乍一看反復(fù)無(wú)常,實(shí)際上并非如此。如果const關(guān)鍵字出現(xiàn)在星號(hào)的左邊,那么指針?biāo)赶虻木褪且粋€(gè)常量;如果const出現(xiàn)在星號(hào)的右邊,那么指針本身就是一個(gè)常量;如果const同時(shí)出現(xiàn)在星號(hào)的兩邊,那么兩者就都是常量。

            當(dāng)指針?biāo)傅膬?nèi)容為常量時(shí),一些程序員喜歡把const放在類型之前,其他一些人則喜歡放在類型后邊,但要在星號(hào)的前邊。這兩種做法沒有什么本質(zhì)的區(qū)別,所以下邊給出的兩個(gè)函數(shù)聲明的參數(shù)類型實(shí)際上是相同的:

            void f1(const Widget *pw);        // f1傳入一個(gè)指向 Widget對(duì)象常量的指針

            void f2(Widget const *pw);        // f2也一樣

            由于這兩種形式在實(shí)際代碼中都會(huì)遇到,所以二者你都要適應(yīng)。

            STL迭代器是依照指針模型創(chuàng)建的,所以說iterator更像一個(gè)T*指針。把一個(gè)iterator聲明為 const的更像是聲明一個(gè)const指針(也就是聲明一個(gè)T* const指針):iterator不允許指向不同類型的內(nèi)容,但是其所指向的內(nèi)容可以被修改。如果你希望一個(gè)迭代器指向某些不能被修改的內(nèi)容(也就是指向const T*的指針),此時(shí)你需要一個(gè)const_iterator

            std::vector<int> vec;

            ...

            const std::vector<int>::iterator iter = vec.begin();

                                               // iter就像一個(gè)T* const

            *iter = 10;                        // 正確,可以改變iter所指向的內(nèi)容

            ++iter;                            // 出錯(cuò)!Iter是一個(gè)const

             

            std::vector<int>::const_iterator cIter = vec.begin();

                                               // cIter就像一個(gè)const T*

            *cIter = 10;                       // 出錯(cuò)!*cIter是一個(gè)const

            ++cIter;                           // 正確,可以改變cIter

            const在函數(shù)聲明方面還有一些強(qiáng)大的用途。在一個(gè)函數(shù)聲明的內(nèi)部,const可以應(yīng)用在返回值、單個(gè)參數(shù),對(duì)于成員函數(shù),可以將其本身聲明為const的。

            讓函數(shù)返回一個(gè)常量通常可以在兼顧安全和效率問題的同時(shí),減少客戶產(chǎn)生錯(cuò)誤的可能。好比有理數(shù)乘法函數(shù)(operator*)的聲明,更多信息請(qǐng)參見條目24。

            class Rational { ... };

            const Rational operator*(const Rational& lhs, const Rational& rhs);

            很多程序員在初次到這樣的代碼時(shí)都不會(huì)正眼看一下。為什么operator*要返回一個(gè)const對(duì)象呢?這是因?yàn)槿绻皇沁@樣,客戶端將會(huì)遇到一些不愉快的狀況,比如:

            Rational a, b, c;

            ...

            (a * b) = c;                       // 調(diào)用operator= 能為a*b的結(jié)果賦值!

            我不知道為什么一些程序員會(huì)企圖為兩個(gè)數(shù)的乘積賦值,但是我確實(shí)知道好多程序員的初衷并非如此。他們也許僅僅在錄入的時(shí)候出了個(gè)小差錯(cuò)(他們的本意也許是一個(gè)布爾型的表達(dá)式):

            if (a * b = c) ...                 // 啊哦本來是想進(jìn)行一次比較!

            如果ab是內(nèi)建數(shù)據(jù)類型,那么這樣的代碼很明顯就是非法的。避免與內(nèi)建數(shù)據(jù)類型不必要的沖突,這是一個(gè)優(yōu)秀的用戶自定義類型的設(shè)計(jì)標(biāo)準(zhǔn)之一(另請(qǐng)參見條目18),而允許為兩數(shù)乘積賦值這讓人看上去就很不必要。如果將operator*的返回值聲明為const的則可以避免這一沖突,這便是要這樣做的原因所在。

            const參數(shù)沒有什么特別新鮮的——它與局部const對(duì)象的行為基本一致,你在應(yīng)該在必要的時(shí)候盡可能使用它們。除非你需要更改某個(gè)參數(shù)或者局部對(duì)象,其余的所有情況都應(yīng)聲明為const。這僅僅需要你多打六個(gè)字母,但是它可以使你從惱人的錯(cuò)誤(比如我們剛才見到的“我本想打’==’但是卻打了’=’”)中解放出來。

            const成員函數(shù)

            對(duì)成員函數(shù)使用const的目的是:指明哪些成員函數(shù)可以被const對(duì)象調(diào)用。這一類成員函數(shù)在兩層意義上是十分重要的。首先,它們使得類的接口更加易于理解。很有必要了解哪些函數(shù)可以對(duì)對(duì)象做出修改而哪些不可以。其次,它們的出現(xiàn)使得與const對(duì)象協(xié)同工作成為可能。這對(duì)于高效編碼來說是十分關(guān)鍵的一個(gè)因素,這是由于(將在條目20中展開解釋)提高C++程序性能的一條最基本的途徑就是:傳遞對(duì)象的const引用。使用這一技術(shù)需要一個(gè)前提:就是必須要有const成員函數(shù)存在,只有它們能夠處理隨之生成的const對(duì)象。

            如果若干成員函數(shù)之間的區(qū)別僅僅為“是否是const的”,那么它們也可以被重載。很多人都忽略了這一點(diǎn),但是這是C++的一個(gè)重要特征。請(qǐng)觀察下面的代碼,這是一個(gè)文字塊的類:

            class TextBlock {

            public:

              ...

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

              { return text[position]; }       // operator[] :用于const對(duì)象

             

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

              { return text[position]; }       // operator[] :用于非const對(duì)象

             

            private:

               std::string text;

            };

            TextBlockoperator[]可以這樣使用:

            TextBlock tb("Hello");

            std::cout << tb[0];                // 調(diào)用非constTextBlock::operator[]

             

            const TextBlock ctb("World");

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

            順便說一下,在真實(shí)的程序中,const對(duì)象在大多數(shù)情況下都以“傳遞指針”或“傳遞const引用”的形式出現(xiàn)。 上面的ctb的例子純粹是人為的,而下面的例子在真實(shí)狀況中常會(huì)出現(xiàn):

            void print(const TextBlock& ctb)  // 在這個(gè)函數(shù)中ctbconst

            {

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

              ...

            }

            通過對(duì)operator[]的重載以及為每個(gè)版本提供不同類型的返回值,你便可以以不同的方式處理const的或者非constTextBlock

            std::cout << tb[0];                // 正確:讀入一個(gè)非constTextBlock

            tb[0] = 'x';                       // 正確:改寫一個(gè)非constTextBlock

            std::cout << ctb[0];               // 正確:讀入一個(gè)constTextBlock

            ctb[0] = 'x';                      // 錯(cuò)誤! 不能改寫constTextBlock

            請(qǐng)注意,這一錯(cuò)誤只與所調(diào)用的operator[]的返回值的類型有關(guān),然而對(duì)operator[]調(diào)用本身的過程則不會(huì)出現(xiàn)任何問題。錯(cuò)誤出現(xiàn)在企圖為一個(gè)const char&賦值時(shí),這是因?yàn)?span style="font-family:"Courier New";">const char&是operator[]const版本的返回值類型。

            同時(shí)還要注意的是,非constoperator[]的返回值是一個(gè)char的引用,而不是char本身。如果operator[]真的簡(jiǎn)單的返回一個(gè)char,那么下面的語(yǔ)句將不能正確編譯:

            tb[0] = 'x';

            這是因?yàn)?,企圖修改一個(gè)返回內(nèi)建數(shù)據(jù)類型的函數(shù)的返回值根本都是非法的。即使假設(shè)這樣做合法,而C++是通過傳值返回對(duì)象的,所修改的僅僅是由tb.text[0]復(fù)制出的一份副本,而不是tb.text[0]本身,你也不會(huì)得到預(yù)期的效果。

            讓我們暫停一小會(huì)兒,來考慮一下這里邊的哲學(xué)問題。把一個(gè)成員函數(shù)聲明為const的有什么涵義呢?這里有兩個(gè)流行的說法:按位恒定(也可叫做物理恒定)和邏輯恒定。

            按位恒定陣營(yíng)堅(jiān)信:當(dāng)且僅當(dāng)一個(gè)成員函數(shù)對(duì)于其所在對(duì)象所有的數(shù)據(jù)成員(static數(shù)據(jù)成員除外)都不做出改動(dòng)時(shí),才需要將這一成員函數(shù)聲明為const,換句話說,將成員函數(shù)聲明為const的條件是:成員函數(shù)不對(duì)其所在對(duì)象內(nèi)部做任何的改動(dòng)。按位恒定有這樣一個(gè)好處,它使得對(duì)違反規(guī)則行為的檢查十分輕松:編譯器僅需要查找對(duì)數(shù)據(jù)成員的賦值操作。實(shí)際上,按位恒定就是C++對(duì)于恒定的定義,如果一個(gè)對(duì)象調(diào)用了某個(gè)const成員函數(shù),那么該成員函數(shù)對(duì)這個(gè)對(duì)象內(nèi)所有非靜態(tài)數(shù)據(jù)成員的修改都是不允許的。

            不幸的是,大多數(shù)不完全const的成員函數(shù)也可以通過按位恒定的測(cè)試。在特定的情況下,如果一個(gè)成員函數(shù)頻繁的修改一個(gè)指針?biāo)傅奈恢?,那么它就不?yīng)是一個(gè)const成員函數(shù)。但是只要這個(gè)指針存在于對(duì)象內(nèi)部,這個(gè)函數(shù)就是按位恒定的,這時(shí)候編譯器不會(huì)報(bào)錯(cuò)。這樣會(huì)導(dǎo)致違背常理的行為。比如說,我們手頭有一個(gè)類似于TextBlock的類,其中保存著char*類型的數(shù)據(jù)而不是string,因?yàn)檫@段代碼有可能要與一些C語(yǔ)言的API交互,但是C語(yǔ)言中沒有string對(duì)象一說。

            class CTextBlock {

            public:

              ...

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

              // operator[]不恰當(dāng)?shù)?a name="ch01index80">(但是符合按位恒定規(guī)則)定義方法

              { return pText[position]; }

             

            private:

              char *pText;

            };

            盡管operator[]返回一個(gè)對(duì)象內(nèi)部數(shù)據(jù)的引用,這個(gè)類仍(不恰當(dāng)?shù)兀⑵渎暶鳛?span style="font-family:"Courier New";">const成員函數(shù)(條目28將深入討論這個(gè)問題)。先忽略這個(gè)問題,請(qǐng)注意這里的operator[]實(shí)現(xiàn)中并沒有以任何形式修改pText。于是編譯器便會(huì)欣然接受這樣的做法,畢竟,它是按位恒定的,所有的編譯器所檢查的都是這一點(diǎn)。但是請(qǐng)觀察,在編譯器的縱容下,還會(huì)有什么樣的事情發(fā)生:

            const CTextBlock cctb("Hello");   // 聲明常量對(duì)象

             

            char *pc = &cctb[0];               // 調(diào)用constoperator[]

                                               // 從而得到一個(gè)指向cctb中數(shù)據(jù)的指針

             

            *pc = 'J';                         // cctb現(xiàn)在的值為"Jello"

            當(dāng)你創(chuàng)建了一個(gè)包含具體值的對(duì)象常量后,你僅僅通過對(duì)其調(diào)用const的成員函數(shù),就可以改變它的值!這顯然是有問題的。

            邏輯恒定應(yīng)運(yùn)而生。堅(jiān)持這一宗旨的人們爭(zhēng)論到:如果某個(gè)對(duì)象調(diào)用了一個(gè)const的成員函數(shù),那么這個(gè)成員函數(shù)可以對(duì)這個(gè)對(duì)象內(nèi)部做出改動(dòng),但是僅僅以客戶端無(wú)法察覺的方式進(jìn)行。比如說,你的CTextBlock類可能需要保存文字塊的長(zhǎng)度,以便在需要的時(shí)候調(diào)用:

            class CTextBlock {

            public:

              ...

              std::size_t length() const;

             

            private:

              char *pText;

              std::size_t textLength;          // 最后一次計(jì)算出的文字塊長(zhǎng)度

              bool lengthIsValid;              // 當(dāng)前長(zhǎng)度是否可用

            };

             

            std::size_t CTextBlock::length() const

            {

              if (!lengthIsValid) {

                textLength = std::strlen(pText);    // 錯(cuò)誤!不能在const成員函數(shù)中

                lengthIsValid = true;          // 對(duì)textLengthlengthIsValid賦值

              }

              return textLength;

            }

            以上length的實(shí)現(xiàn)絕不是按位恒定的。這是因?yàn)?span style="font-family:"Courier New";">textLength和lengthIsValid都可以改動(dòng)。盡管看上去它應(yīng)該對(duì)于CTextBlock對(duì)象常量可用,但是編譯器會(huì)拒絕。編譯器始終堅(jiān)持遵守按位恒定。那么該怎么辦呢?

            解決方法很簡(jiǎn)單:利用C++中與const相關(guān)的靈活性,使用可變的(mutable)數(shù)據(jù)成員。mutable可以使非靜態(tài)數(shù)據(jù)成員不受按位恒定規(guī)則的約束:

            class CTextBlock {

            public:

              ...

              std::size_t length() const;

             

            private:

              char *pText;

             

              mutable std::size_t textLength;  // 這些數(shù)據(jù)成員在任何情況下均可修改

              mutable bool lengthIsValid;      // const成員函數(shù)中也可以

            };

             

            std::size_t CTextBlock::length() const

            {

              if (!lengthIsValid) {

                textLength = std::strlen(pText);    // 現(xiàn)在可以修改了

                lengthIsValid = true;          // 同上

              }

              return textLength;

            }

            避免const與非const成員函數(shù)之間的重復(fù)

            mutable對(duì)于“我不了解按位恒定”的情況不失為一個(gè)良好的解決方案,但是它并不能對(duì)于所有的const難題做到一勞永逸。舉例說,TextBlock(以及CTextBlock)中的operator[]不僅僅返回一個(gè)對(duì)恰當(dāng)字符的引用,同時(shí)還要進(jìn)行邊界檢查、記錄訪問信息,甚至還要進(jìn)行數(shù)據(jù)完整性檢測(cè)。如果將所有這些統(tǒng)統(tǒng)放在const或非const函數(shù)(我們現(xiàn)在會(huì)得到過于冗長(zhǎng)的隱式內(nèi)聯(lián)函數(shù),不過不要驚慌,在條目30中這個(gè)問題會(huì)得到解決)中,看看我們會(huì)得到什么樣的龐然大物:

            class TextBlock {

            public:

              ...

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

              {

                ...                             // 邊界檢查

                ...                             // 記錄數(shù)據(jù)訪問信息

                ...                             // 確認(rèn)數(shù)據(jù)完整性

                return text[position];

              }

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

              {

                ...                             // 邊界檢查

                ...                             // 記錄數(shù)據(jù)訪問信息

                ...                             // 確認(rèn)數(shù)據(jù)完整性

                return text[position];

              }

             

            private:

               std::string text;

            };

            啊哦!重復(fù)代碼讓人頭疼,還有隨之而來的編譯時(shí)間增長(zhǎng)、維護(hù)成本增加、代碼膨脹,等等……當(dāng)然,像邊界檢查這一類代碼是可以移走的,它們可以單獨(dú)放在一個(gè)成員函數(shù)(很自然是私有的)中,然后讓這兩個(gè)版本的operator[]來調(diào)用它,但是你的代碼仍然有重復(fù)的函數(shù)調(diào)用,以及重復(fù)的return語(yǔ)句。

            對(duì)于operator[]你真正需要的是:一次實(shí)現(xiàn),兩次使用。也就是說,你需要一個(gè)版本的operator[]來調(diào)用另一個(gè)。這樣便可以通過轉(zhuǎn)型來消去函數(shù)的恒定性。

            通常情況下轉(zhuǎn)型是一個(gè)壞主意,后邊我將專門用一條來告訴你為什么不要使用轉(zhuǎn)型(條目21),但是代碼重復(fù)也不會(huì)讓人感到有多輕松。在這種情況下,const版的operator[]與非const版的operator[]所做的事情完全相同,不同的僅僅是它的返回值是const的。通過轉(zhuǎn)型來消去返回值的恒定性是安全的,這是因?yàn)槿魏稳苏{(diào)用這一非constoperator[]首先必須擁有一個(gè)非const的對(duì)象,否則它就不能調(diào)用非const函數(shù)。所以盡管需要一次轉(zhuǎn)型,在constoperator[]中調(diào)用非const版本,可以安全地避免代碼重復(fù)。下面是實(shí)例代碼,讀完后邊的文字解說你會(huì)更明了。

            class TextBlock {

            public:

              ...

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

              {                                // 同上

                ...

                ...

                ...

                return text[position];

              }

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

              {                                // 現(xiàn)在僅調(diào)用 constop[]

                return

                  const_cast<char&>(           // 消去op[]返回值的const屬性

                    static_cast<const TextBlock&>(*this)

                                               // *this的類型添加const屬性;

                    [position];                 // 調(diào)用const版本的op[]

                  );

              }

            ...

            };

            就像你所看到的,上面的代碼進(jìn)行了兩次轉(zhuǎn)型,而不是一次。我們要讓非constoperator[]去調(diào)用const版本的,但是如果在非constoperator[]的內(nèi)部,我們只調(diào)用operator[]而不標(biāo)明const,那么函數(shù)將對(duì)自己進(jìn)行遞歸調(diào)用。那將是成千上萬(wàn)次的毫無(wú)意義的操作。為了避免無(wú)窮遞歸的出現(xiàn),我們必須要指明我們要調(diào)用的是const版本的operator[],但是手頭并沒有直接的辦法。我們可以用*this從其原有的TextBlock&轉(zhuǎn)型到const TextBlock&。是的,我們使用了一次轉(zhuǎn)型添加了一個(gè)const!這樣我們就進(jìn)行了兩次轉(zhuǎn)型:一次為*this添加了const(于是對(duì)于operator[]的調(diào)用將會(huì)正確地選擇const版本),第二次轉(zhuǎn)型消去了const operator[]返回值中的const

            添加const屬性的那次轉(zhuǎn)型是為了強(qiáng)制保證轉(zhuǎn)換工作的安全性(從一個(gè)非const對(duì)象轉(zhuǎn)換為一個(gè)const對(duì)象),我們使用static_cast來進(jìn)行。消去const的那次轉(zhuǎn)型只可以通過const_cast來完成,所以這里實(shí)際上也沒有其他的選擇。(從技術(shù)上講還是有的。C語(yǔ)言風(fēng)格的轉(zhuǎn)型在這里也能工作,但是,就像我在條目27中所解釋的,這一類轉(zhuǎn)型在很多情況下都不是好的選擇。如果你對(duì)于static_castconst_cast還不熟悉,條目27中有相關(guān)介紹。)

            在眾多的示例中,我們最終選擇了一個(gè)運(yùn)算符來進(jìn)行演示,因此上面的語(yǔ)法顯得有些古怪。這些代碼可能不會(huì)贏得任何選美比賽,但是通過以const版本的形式實(shí)現(xiàn)非const版本的operator[],可以避免代碼重復(fù),這正是我們所期望的效果。為達(dá)到這一目標(biāo)而寫下看似笨拙的代碼,這樣做是否值得全看你的選擇,但是,以const版本的形式來實(shí)現(xiàn)非const的成員函數(shù)——了解這一技術(shù)肯定是值得的。

            更值得你了解的是,上面的操作是不可逆的,即:通過讓const版本的函數(shù)調(diào)用非const版本來避免代碼重復(fù),是不可行的。請(qǐng)記住,一個(gè)const成員函數(shù)應(yīng)保證永遠(yuǎn)不會(huì)更改其所在對(duì)象的邏輯狀態(tài),但是一個(gè)非const的成員函數(shù)無(wú)法做出這樣的保證。如果你在一個(gè)const函數(shù)中調(diào)用了一個(gè)非const函數(shù),那么你曾保證不會(huì)被改動(dòng)的對(duì)象就有被修改的風(fēng)險(xiǎn)。這就是為什么說讓一個(gè)const成員函數(shù)調(diào)用一個(gè)非const成員函數(shù)是錯(cuò)誤的:對(duì)象有可能被修改。實(shí)際上,為了使代碼能夠得到編譯,你還需要使用一個(gè)const_cast來消去*thisconst屬性,顯然這是不必要的麻煩。上一段中按相反的調(diào)用次序才是安全的:非const成員函數(shù)可以對(duì)一個(gè)對(duì)象做任何想做的事情,因此調(diào)用一個(gè)const成員函數(shù)不會(huì)帶來任何風(fēng)險(xiǎn)。這就是為什么static_cast可以這樣操作*this的原因:這里不存在const相關(guān)的危險(xiǎn)。

            就像本條目一開始所說的,const是一個(gè)令人贊嘆的東西。對(duì)于指針和迭代器,以及對(duì)于指針、迭代器和引用所涉及的對(duì)象,對(duì)于函數(shù)的參數(shù)和返回值,對(duì)于局部變量,以及對(duì)于成員函數(shù)來說,const都是一個(gè)強(qiáng)大的伙伴。盡可能去利用它。你一定不會(huì)后悔。

            時(shí)刻牢記

            將一些東西聲明為const可以幫助編譯器及時(shí)發(fā)現(xiàn)用法上的錯(cuò)誤。const可以用于各個(gè)領(lǐng)域,包括任意作用域的對(duì)象、函數(shù)參數(shù)和返回值、成員函數(shù)。

            編譯器嚴(yán)格遵守按位恒定規(guī)則,但是你應(yīng)該在需要時(shí)應(yīng)用邏輯恒定。

            當(dāng)const和非const成員函數(shù)的實(shí)現(xiàn)在本質(zhì)上相同時(shí),可以通過使用一個(gè)非const版本來調(diào)用const版本來避免代碼重復(fù)。

            posted on 2007-04-11 19:55 ★ROY★ 閱讀(1433) 評(píng)論(3)  編輯 收藏 引用 所屬分類: Effective C++

            評(píng)論

            # re: 【翻譯】Effective C++ (第3項(xiàng):盡可能使用const)  回復(fù)  更多評(píng)論   

            哈哈 ,我最近在看這本書,蠻好的,但我感覺有的準(zhǔn)則不實(shí)用,可能是我代碼寫太少了,沒有用到吧!
            2007-04-13 16:18 | 攀升

            # re: 【翻譯】Effective C++ (第3項(xiàng):盡可能使用const)  回復(fù)  更多評(píng)論   

            請(qǐng)問這個(gè)翻譯是干嘛用的?博主自己翻譯的嗎?不是已經(jīng)有中文版了嗎?
            2007-04-24 17:49 | 匿名

            # re: 【翻譯】Effective C++ (第3項(xiàng):盡可能使用const)  回復(fù)  更多評(píng)論   

            @匿名
            向領(lǐng)導(dǎo)匯報(bào):
            翻著玩的,自己學(xué)習(xí)。
            是自己翻譯的。
            是有中文版了,但是我們干的好多事都是別人干過的,不是嗎?
            2007-04-24 17:55 | ★田德健★
            无码久久精品国产亚洲Av影片| 99久久精品影院老鸭窝| 久久精品99无色码中文字幕| 久久99精品国产麻豆婷婷| 青青热久久国产久精品 | 久久久99精品一区二区| 亚洲国产天堂久久综合| 欧美va久久久噜噜噜久久| 一本久久久久久久| 久久AV高潮AV无码AV| 国产精品欧美亚洲韩国日本久久 | 亚洲国产成人久久综合野外| 亚洲成色WWW久久网站| 久久久久国产精品三级网| 亚洲国产欧洲综合997久久| 久久久不卡国产精品一区二区| 欧美va久久久噜噜噜久久| 亚洲色欲久久久久综合网| 九九久久99综合一区二区| 99久久精品免费看国产一区二区三区| 99久久精品免费| 东京热TOKYO综合久久精品| 久久久无码精品亚洲日韩京东传媒 | 久久精品国产一区二区三区日韩| 亚洲色欲久久久综合网| 久久福利片| MM131亚洲国产美女久久| 无码人妻久久一区二区三区| 综合久久给合久久狠狠狠97色| 欧美亚洲另类久久综合| 97精品国产91久久久久久| 欧洲人妻丰满av无码久久不卡 | 日韩欧美亚洲综合久久影院d3| 人妻无码αv中文字幕久久| 久久精品综合网| 日本久久中文字幕| 久久强奷乱码老熟女网站| 日本精品一区二区久久久| 亚洲国产精品无码久久九九| 久久福利片| 波多野结衣久久精品|