<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    so true

    心懷未來,開創(chuàng)未來!
    隨筆 - 160, 文章 - 0, 評(píng)論 - 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ū)別?
    回答完上述問題, 我順便還能回答一個(gè)問題: A(A& a)與A(const A& a)有什么區(qū)別?
    下面就來回答這個(gè)問題:
    首先來分析(2)是如何執(zhí)行的,分為以下步驟:
    1. b能轉(zhuǎn)化為一個(gè)A的臨時(shí)對(duì)象;(轉(zhuǎn)化的方法可以是B自身包含一個(gè)到A的強(qiáng)制類型轉(zhuǎn)換操作符或者A有一個(gè)未指定explicit的參數(shù)為B或者B&或者const B&的構(gòu)造函數(shù)
    2. 調(diào)用A的拷貝構(gòu)造函數(shù), 而且必須是A(const A& a), 如果沒有const是不行的, 至于原因我一會(huì)兒再說
    再說說(3)執(zhí)行的步驟與條件:
    1. B的這個(gè)臨時(shí)對(duì)象能轉(zhuǎn)化為一個(gè)A的臨時(shí)對(duì)象; (轉(zhuǎn)化的方法可以是B自身包含一個(gè)到A的強(qiáng)制類型轉(zhuǎn)換操作符或者A有一個(gè)未指定explicit的參數(shù)必須為B或者const B&的構(gòu)造函數(shù)
    2. 調(diào)用A的拷貝構(gòu)造函數(shù), 而且必須是A(const A& a), 如果沒有const是不行的, 至于原因我一會(huì)兒再說
    最后說說(4)執(zhí)行的條件:
    A有參數(shù)為B或者B&或者const B&的構(gòu)造函數(shù);
    或者是: B自身支持強(qiáng)制類型轉(zhuǎn)化為某種類型, 該類型能恰好為A的某一個(gè)構(gòu)造函數(shù)的參數(shù).

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

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

    所以大家要消除一個(gè)固有的概念: 拷貝構(gòu)造函數(shù)就得A(const A&)這么寫, 完全錯(cuò)誤, 其實(shí)A(A&)有些情況下是必須有的, 沒有都不行, 比如auto_ptr, 因?yàn)樗谡{(diào)用拷貝構(gòu)造函數(shù)時(shí), 需要把自己當(dāng)前維護(hù)的那根指針銷毀掉(即設(shè)為NULL)同時(shí)把這根指針交給另一個(gè)auto_ptr保管.
    下面的代碼是我自己實(shí)驗(yàn)的一個(gè)小例子:
    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è)拷貝構(gòu)造函數(shù)都加上const,或者把模板拷貝構(gòu)造函數(shù)的那個(gè)const移到非模板拷貝構(gòu)造函數(shù)上, 結(jié)果都會(huì)為:
    Ss
    i
    A(A<T2>&a)
    上述代碼是在linux的gcc3.4下通過的, 我相信大家應(yīng)該可以分析出原因來, 不過對(duì)于模板類我還是得羅唆幾句, 首先大家應(yīng)該清楚A<int>和A<string>是完全不同的兩個(gè)類型, 就像int和string一樣風(fēng)馬牛不相及, 只不過它們公用了一些模板代碼而已, 因此你把A<int>和A<string>看作兩個(gè)不同的類型來分析就應(yīng)該能分析透徹了.

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

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

    評(píng)論

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

    非常感謝,你寫的太好了
    2013-12-30 22:16 | 游客
    主站蜘蛛池模板: 亚洲av永久中文无码精品综合| 亚洲成a人不卡在线观看| 国产精品久久久久久亚洲影视| 免费国产黄网站在线观看可以下载| 亚洲日韩小电影在线观看| 9久久免费国产精品特黄| 国产精品亚洲w码日韩中文| 一级人做人爰a全过程免费视频 | 啦啦啦中文在线观看电视剧免费版 | 亚洲一区二区三区无码中文字幕| 十八禁的黄污污免费网站| 亚洲欧洲精品成人久久奇米网| 人成午夜免费大片在线观看| 国产精品亚洲综合专区片高清久久久 | 鲁死你资源站亚洲av| 四虎免费久久影院| 一级毛片a女人刺激视频免费| 青青草原亚洲视频| 久久免费观看国产精品| 亚洲欧洲日本精品| 日本19禁啪啪无遮挡免费动图| 久久久久久久久无码精品亚洲日韩| 免费成人av电影| 久久免费视频网站| 亚洲日韩乱码久久久久久| 性感美女视频在线观看免费精品 | 亚洲国产精品激情在线观看| www在线观看播放免费视频日本| 亚洲成AV人片天堂网无码| 国产在线jyzzjyzz免费麻豆| 亚洲Av永久无码精品一区二区| 亚洲国产V高清在线观看| 国产精品白浆在线观看免费| 亚洲国产日韩在线| xvideos亚洲永久网址| 久久99热精品免费观看动漫| 亚洲国产日韩综合久久精品| 亚洲成a人一区二区三区| 久久久久久国产精品免费无码| 亚洲AV性色在线观看| 亚洲VA中文字幕不卡无码|