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

            chaosuper85

            C++博客 首頁(yè) 新隨筆 聯(lián)系 聚合 管理
              118 Posts :: 0 Stories :: 3 Comments :: 0 Trackbacks

                多繼承與虛函數(shù)重復(fù)

                既然說(shuō)到了多繼承,那么還有一個(gè)問(wèn)題可能會(huì)需要解決,那就是如果兩個(gè)父類里都有相同的虛函數(shù)定義,在子對(duì)象的布局里會(huì)是怎么樣個(gè)情況?是否依然可以將這個(gè)虛函數(shù)指向到正確的實(shí)現(xiàn)代碼上呢?

                修改前面一個(gè)源代碼,在parent2的接口里增加下面的虛函數(shù)定義:

                virtual int fun1(){cout<<"parent2::fun1()"<<endl;return 0;};

                上面的fun1的定義與parent1類里的完全重復(fù)相同(類型,參數(shù)列表),增加上面的代碼后立即開(kāi)始編譯,程序正常編譯通過(guò)。運(yùn)行之,得到下面的結(jié)果:

                child1::fun1()

                child1::fun2()

                這個(gè)程序居然正確的完成了執(zhí)行,編譯器在其中做了些怎樣的工作,是怎么樣避免掉隊(duì)fun1函數(shù)的沖突問(wèn)題呢?

                讓我們來(lái)看看這個(gè)時(shí)候的child1的對(duì)象布局:
             class child1    size(8):
                    +---
                    | +--- (base class parent1)
             0      | | {vfptr}
                    | +---
                    | +--- (base class parent2)
             4      | | {vfptr}
                    | +---
                    +---

            child1::$vftable@parent1@:
                    | &child1_meta
                    |  0
             0      | &child1::fun1

            child1::$vftable@parent2@:
                    | -4
             0      | &child1::fun2
             1      | &thunk: this-=4; goto child1::fun1

            child1::fun1 this adjustor: 0
            child1::fun2 this adjustor: 4

             


                恩~~~還是兩個(gè)vfptr在child1的對(duì)象布局里(不一樣就怪啦,呵呵),但是第二個(gè)vfptr所指的虛函數(shù)表的內(nèi)容有所變化哦!

                注意看紅色字體部分,虛函數(shù)表里并沒(méi)有直接填寫child::fun1的代碼,而是多了一個(gè) &thunk: this-=4;然后才goto child1::fun1!注意到一個(gè)關(guān)鍵名詞thunk了吧?沒(méi)錯(cuò),vc在這里使用了名為thunk的技術(shù),避免了虛函數(shù)fun1在兩個(gè)基類里重復(fù)出現(xiàn)導(dǎo)致的沖突問(wèn)題!(除了thunk,還有其他方法可以解決此類問(wèn)題的)。

                現(xiàn)在,我們知道為什么相同的虛函數(shù)不會(huì)在子類里出現(xiàn)沖突的情況了。

                但是,倘若我們?cè)诨惱锞褪怯蓛蓚€(gè)沖突的普通函數(shù),而不是虛函數(shù),是個(gè)怎樣的情況呢?

                多繼承產(chǎn)生的沖突與虛繼承,虛基類

                我們?cè)趐arent1和parent2里添加一個(gè)相同的函數(shù)void fun3(),然后再進(jìn)行編譯,通過(guò)了!查看類對(duì)象布局,跟上面的完全一致。但是在main函數(shù)里調(diào)用chobj.fun3()的時(shí)候,編譯器卻不再能正確編譯了,并且會(huì)提示“error C2385: 對(duì)”fun3“的訪問(wèn)不明確”的錯(cuò)誤信息,沒(méi)錯(cuò),編譯器不知道你要訪問(wèn)哪個(gè)fun3了。

                如何解決這樣的多繼承帶來(lái)的問(wèn)題呢,其實(shí)有一個(gè)簡(jiǎn)單的做法。就是在方法前限定引用的具體是哪個(gè)類的函數(shù),比如:chobj.parent1::fun3();  ,這樣的寫法就寫明了是要調(diào)用chobj的父類parent1里的fun3()函數(shù)!

                我們?cè)倏纯戳硗庖环N情況,從parent1和parent2里抹去剛才添加的fun3函數(shù),將之放到一個(gè)共同的基類里:
                 class commonbase

                {

                public:

                void fun3(){cout<<"commonbase::fun3()"<<endl;}

                };
             


                而parent1和parent2都修改為從此類繼承。可以看到,在這個(gè)情況下,依然需要使用chobj.parent1::fun3();  的方式才可以正確調(diào)用到fun3,難道,在這種情況下,就不能自然的使用chobj.fun3()這樣的方式了嗎?

                虛繼承可以解決這個(gè)問(wèn)題——我們?cè)趐arent1和parent2繼承common類的地方添加上一個(gè)關(guān)鍵詞virtual,如下:
                 class parent1:virtual public commonbase

                {

                public:

                virtual int fun1(){cout<<"parent1::fun1()"<<endl;return 0;};

                };
             


                給parent2也同樣的處理,然后再次編譯,這次chobj.fun3()可以編譯通過(guò)了!!!

                編譯器這次又在私下里做了哪些工作了呢????
             class child1    size(16):
                    +---
                    | +--- (base class parent1)
             0      | | {vfptr}
             4      | | {vbptr}
                    | +---
                    | +--- (base class parent2)
             8      | | {vfptr}
            12      | | {vbptr}
                    | +---
                    +---
                    +--- (virtual base commonbase)
                    +---

            child1::$vftable@parent1@:
                    | &child1_meta
                    |  0
             0      | &child1::fun1

            child1::$vftable@parent2@:
                    | -8
             0      | &child1::fun2
             1      | &thunk: this-=8; goto child1::fun1

            child1::$vbtable@parent1@:
             0      | -4
             1      | 12 (child1d(parent1+4)commonbase)

            child1::$vbtable@parent2@:
             0      | -4
             1      | 4 (child1d(parent2+4)commonbase)

            child1::fun1 this adjustor: 0
            child1::fun2 this adjustor: 8

            vbi:       class  offset o.vbptr  o.vbte fVtorDisp
                  commonbase      16       4       4 0

             


                這次變化可大了去了!!!

                首先,可以看到兩個(gè)類parent1和parent2的對(duì)象布局里,都多了一個(gè)vbptr的指針。而在child1的對(duì)象布局里,還有一個(gè)virtual base commonbase的虛擬基類。再看看兩個(gè)vbptr的內(nèi)容:

                12 (child1d(parent1+4)commonbase) 這個(gè)很好理解,從parent1的vbptr開(kāi)始,偏移12個(gè)字節(jié),指向的是virtual base commonbase!

                再看看4 (child1d(parent2+4)commonbase) ,從parent2的vbptr開(kāi)始,便宜4個(gè)字節(jié),也指向了virtual base commonbase!

                這下明白了。虛基類在child1里只有一個(gè)共同的對(duì)象布局了,所以就可以直接用chobj.fun3()啦,當(dāng)然,在commonbase里的其他成員變量此時(shí)也可以同樣的方式訪問(wèn)了!

                雖然解決方案有了,但是在一個(gè)系統(tǒng)的設(shè)計(jì)里,如果有一個(gè)基類出現(xiàn)多繼承沖突的情況,大部分情況下都說(shuō)明這樣的設(shè)計(jì)是有問(wèn)題的,應(yīng)該盡量避免這樣的設(shè)計(jì),并且盡量用純虛函數(shù),來(lái)提取一些抽象的接口類,把共同的方法接口都抽取出來(lái),通常就能避免多繼承的問(wèn)題。

             

            posted on 2009-08-05 17:46 chaosuper 閱讀(145) 評(píng)論(0)  編輯 收藏 引用

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


            亚洲精品第一综合99久久| 国产成人精品综合久久久| 嫩草影院久久99| 久久久久亚洲精品无码蜜桃| 尹人香蕉久久99天天拍| 中文字幕久久精品| 精品久久久久成人码免费动漫| 无码任你躁久久久久久久| 久久人人爽人人爽人人片AV麻豆 | 久久无码高潮喷水| 人人狠狠综合88综合久久| 久久精品无码一区二区三区免费| 亚洲国产精品久久久久| 天天久久狠狠色综合| 久久99精品久久久久久齐齐| 精品久久人人做人人爽综合 | 日产精品久久久一区二区| 成人久久免费网站| 久久水蜜桃亚洲av无码精品麻豆| 精品国产乱码久久久久久人妻| 亚洲国产精品无码久久久秋霞2 | 色偷偷91久久综合噜噜噜噜| 亚洲精品97久久中文字幕无码| 久久精品aⅴ无码中文字字幕不卡| 熟妇人妻久久中文字幕| 久久精品男人影院| 亚洲日韩欧美一区久久久久我| 狠狠色综合网站久久久久久久高清 | 国产精品日韩深夜福利久久| 日本亚洲色大成网站WWW久久 | 久久久久久精品久久久久| 久久AV高清无码| 久久久中文字幕日本| 午夜人妻久久久久久久久| 色综合久久88色综合天天| 久久婷婷色综合一区二区| AV无码久久久久不卡蜜桃| 久久国产香蕉视频| 久久91亚洲人成电影网站| 久久精品一本到99热免费| 日韩欧美亚洲综合久久影院d3|