so true

          心懷未來,開創(chuàng)未來!
          隨筆 - 160, 文章 - 0, 評論 - 40, 引用 - 0
          數(shù)據(jù)加載中……

          構(gòu)造函數(shù)與const的關(guān)系

          B b;(1)
          A a=b;(2)
          A a=B();(3)
          A a(b);(4)
          如果(2)能執(zhí)行成功的話,那么需要滿足什么?(2)到底與(4)有什么區(qū)別?(4)能執(zhí)行成功的條件與(2)有什么區(qū)別?
          回答完上述問題, 我順便還能回答一個問題: A(A& a)與A(const A& a)有什么區(qū)別?
          下面就來回答這個問題:
          首先來分析(2)是如何執(zhí)行的,分為以下步驟:
          1. b能轉(zhuǎn)化為一個A的臨時對象;(轉(zhuǎn)化的方法可以是B自身包含一個到A的強制類型轉(zhuǎn)換操作符或者A有一個未指定explicit的參數(shù)為B或者B&或者const B&的構(gòu)造函數(shù)
          2. 調(diào)用A的拷貝構(gòu)造函數(shù), 而且必須是A(const A& a), 如果沒有const是不行的, 至于原因我一會兒再說
          再說說(3)執(zhí)行的步驟與條件:
          1. B的這個臨時對象能轉(zhuǎn)化為一個A的臨時對象; (轉(zhuǎn)化的方法可以是B自身包含一個到A的強制類型轉(zhuǎn)換操作符或者A有一個未指定explicit的參數(shù)必須為B或者const B&的構(gòu)造函數(shù)
          2. 調(diào)用A的拷貝構(gòu)造函數(shù), 而且必須是A(const A& a), 如果沒有const是不行的, 至于原因我一會兒再說
          最后說說(4)執(zhí)行的條件:
          A有參數(shù)為B或者B&或者const B&的構(gòu)造函數(shù);
          或者是: B自身支持強制類型轉(zhuǎn)化為某種類型, 該類型能恰好為A的某一個構(gòu)造函數(shù)的參數(shù).

          按照我上面的分析, 對于(2)和(3)如果B自身不提供轉(zhuǎn)化機制的話, 那么豈不是要調(diào)用A的構(gòu)造函數(shù)兩次了, 其實最后只調(diào)用一次就可以了, 也就是步驟2里調(diào)用A的拷貝構(gòu)造函數(shù)不會被調(diào)用, 但這只是編譯器作了優(yōu)化, 省掉了一次, 并不代表只執(zhí)行步驟1, 不信的話你把A拷貝構(gòu)造函數(shù)里的const去掉試試看, 要是能編譯過去才怪.

          那說到根兒上, 加不加const修飾到底有啥區(qū)別呢?
          其實這才是關(guān)鍵所在, 理解了這個也就知道本質(zhì)原因了, 下面我就來說說這個const:
          首先要讓大家知道A(const A&)和A(A&)是兩個函數(shù)吧?也就是構(gòu)造函數(shù)的重載, 對于重載的函數(shù)參數(shù)類型或個數(shù)至少得有點不同, 這里我告訴你參數(shù)類型加不加const是完全不同的兩種參數(shù)類型.
          知道了上面的概念, 再引用一段話:(出自http://www.xmsc.com.cn/InfoView/Article_122425.html)
          說說左值和右值以及臨時對象的問題。也許你會說左值應該就是能夠改變的變量,右值當然就是不能改變的變量嘍!對嗎?對了一點點,實際上左值是能夠被引用的變量,說的通俗點就是有名字的變量,你一定想到了些什么,對了,臨時變量就沒有名字,即使有你也不會知道,因為它不是由你創(chuàng)建的,編譯器會在內(nèi)部辨別它,但你并不知道,因此臨時變量不是左值,而是右值。你也許還會問,那const變量是不是左值呢?根據(jù)定義,它有名字,當然就是左值了。因此左值并非一定“ 可被修改”。但是左值和右值與參數(shù)有什么關(guān)系嗎?我要告訴你的是:有,而且相當密切,因為標準c++規(guī)定:若傳遞給類型為引用的形參的實參是右值的話必須保證形參為const引用。
          其實上面這段話最關(guān)鍵的地方在于指出了左值能被引用右值不能被引用, 臨時變量以及沒有顯示名字的變量都是右值, 因此在(2)或(3)中生成的A的臨時變量必定是右值, 而A的構(gòu)造函數(shù)必須為引用類型, 因此按照"若傳遞給類型為引用的形參的實參是右值的話必須保證形參為const引用"這個斷言, A的拷貝構(gòu)造函數(shù)里包含const也就是必須的了.

          所以大家要消除一個固有的概念: 拷貝構(gòu)造函數(shù)就得A(const A&)這么寫, 完全錯誤, 其實A(A&)有些情況下是必須有的, 沒有都不行, 比如auto_ptr, 因為它在調(diào)用拷貝構(gòu)造函數(shù)時, 需要把自己當前維護的那根指針銷毀掉(即設(shè)為NULL)同時把這根指針交給另一個auto_ptr保管.
          下面的代碼是我自己實驗的一個小例子:
          using namespace std;

          template <typename T>
          class A
          {
          public:
              A(){}

              A(A& a)
              {
                  cout<<"A(A& a)"<<endl;
              }

              template <typename T2>
              A(const A<T2>& a)
              {
                  cout<<typeid(T).name()<<endl;
                  cout<<typeid(T2).name()<<endl;
                  cout<<"A(const A<T2>&a)"<<endl;
              }
          };

          int main(int argc, char* argv[])
          {
              A<int> a_int;
              A<string> a=(a_int);
              return 0;
          }

          輸出結(jié)果是:
          Ss
          i
          A(A<T2>&a)
          Ss
          Ss
          A(A<T2>&a)
          如果把A的兩個拷貝構(gòu)造函數(shù)都加上const,或者把模板拷貝構(gòu)造函數(shù)的那個const移到非模板拷貝構(gòu)造函數(shù)上, 結(jié)果都會為:
          Ss
          i
          A(A<T2>&a)
          上述代碼是在linux的gcc3.4下通過的, 我相信大家應該可以分析出原因來, 不過對于模板類我還是得羅唆幾句, 首先大家應該清楚A<int>和A<string>是完全不同的兩個類型, 就像int和string一樣風馬牛不相及, 只不過它們公用了一些模板代碼而已, 因此你把A<int>和A<string>看作兩個不同的類型來分析就應該能分析透徹了.

          在http://www.xmsc.com.cn/InfoView/Article_122425.html一文中還講解了auto_ptr中auto_ptr_ref的作用, 說到這里,讓我真的很恨auto_ptr源碼中的注釋啊,因為它的注釋有錯誤,一直誤導了我, 現(xiàn)在才體會到“錯誤的注釋還不如沒有注釋”的真諦了。錯誤出現(xiàn)在:
                 *    auto_ptr<Derived>  func_returning_auto_ptr(.....);
                 *    ...
                 *    auto_ptr<Base> ptr = func_returning_auto_ptr(.....);
          其實應該是:
                 *    auto_ptr<Derived>  func_returning_auto_ptr(.....);
                 *    ...
                 *    auto_ptr<Base> ptr(func_returning_auto_ptr(.....));   or   auto_ptr<Derived> ptr = func_returning_auto_ptr ;
          不要小看這點改動,上面的那種方案是編譯不過去的。因為上面的方案里需要轉(zhuǎn)換兩次再調(diào)用一次拷貝構(gòu)造函數(shù),這違背了C++最多轉(zhuǎn)換一次的限制。
          最后, 或許你在VC下實驗的結(jié)果會和我說的不一樣, 這是因為VC在臨時對象這一點上對標準C++的支持不夠好,用臨時對象作參數(shù)的時候不加const也可以編譯通過.

          posted on 2009-07-05 21:33 so true 閱讀(1662) 評論(1)  編輯  收藏 所屬分類: C&C++

          評論

          # re: 構(gòu)造函數(shù)與const的關(guān)系  回復  更多評論   

          非常感謝,你寫的太好了
          2013-12-30 22:16 | 游客
          主站蜘蛛池模板: 定兴县| 隆子县| 澎湖县| 娱乐| 民权县| 宁波市| 益阳市| 尼玛县| 桃园县| 出国| 宁蒗| 东兰县| 荆门市| 阿拉善右旗| 聊城市| 泌阳县| 屏南县| 承德市| 茌平县| 洪洞县| 永登县| 海口市| 西乌| 永城市| 丽江市| 大石桥市| 新田县| 普兰县| 迁安市| 将乐县| 济源市| 剑河县| 阿克苏市| 大兴区| 太和县| 墨竹工卡县| 根河市| 古交市| 蓝田县| 寿光市| 丹阳市|