• <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>
            隨筆 - 55  文章 - 15  trackbacks - 0
            <2012年6月>
            272829303112
            3456789
            10111213141516
            17181920212223
            24252627282930
            1234567

            常用鏈接

            留言簿

            隨筆分類

            隨筆檔案

            搜索

            •  

            最新評(píng)論

            閱讀排行榜

            評(píng)論排行榜

            一個(gè)函數(shù)接受一個(gè)基類的指針或者引用,傳入一個(gè)子類的指針或者引用(向上類型轉(zhuǎn)換),希望調(diào)用子類的相應(yīng)函數(shù)。目的:以后添加新的子類,都可以傳入該函數(shù)。
            早綁定:編譯器通過上下文,判斷該函數(shù)屬于哪個(gè)對(duì)象,并在編譯期將函數(shù)名與函數(shù)地址綁定。
            晚綁定:在運(yùn)行的時(shí)候,判斷該函數(shù)屬于哪個(gè)對(duì)象,并在運(yùn)行時(shí)將函數(shù)名與函數(shù)地址綁定。必須有類型信息裝在對(duì)象自身中。
            聲明時(shí)添加virtual關(guān)鍵字,定義時(shí)不需要。

            使用指針和引用的目的是讓編譯器不能完全知道該對(duì)象的確切類型,不然就會(huì)調(diào)用早綁定。晚綁定是根據(jù)VTABLE來實(shí)現(xiàn),并且基類和子類的每個(gè)虛函數(shù)的排列順序都是相同的,所以調(diào)用函數(shù)的時(shí)候已經(jīng)不是通過名字來調(diào)用,而是通過指令,通過函數(shù)地址的偏移量來調(diào)用了。

            抽象基類的意義,為子類提供一個(gè)公共的接口。

            通過基類指針調(diào)用基類中不存在的函數(shù)是危險(xiǎn)的,因?yàn)?,也許你恰好知道子類對(duì)象中有這個(gè)函數(shù),那你的調(diào)用時(shí)成功的,但是萬一木有呢?
            class Base(){
            public:
             virtual void f(){}
            };

            class Derived1: public Base
            {
            public:
             virtual void f(){}
             virtual void g(){}
            };
            class Derived2: public Base
            {
            public:
             virtual void f(){}
             virtual void m(){}
            };

            void func(Base* b){
            b->g();
            }
            int main{
            Base*Test1 = new Derived1;
            Base*Test2 = new Derived2;
            func(Test1);// right;
            func(Test2);// crash
            }

            這里涉及到運(yùn)行時(shí)類型識(shí)別(RTTI)和向下類型轉(zhuǎn)換問題。向下類型轉(zhuǎn)換不安全,因?yàn)闆]有類型信息,基類指針不知道基類的內(nèi)存塊之后的東西是屬于哪個(gè)子類的,如果轉(zhuǎn)錯(cuò),將會(huì)比較麻煩。

            在編程時(shí)注意防止對(duì)象的切片,如果按傳值方式而不是傳址和傳引用方式
            將子類對(duì)象傳入一個(gè)接受基類對(duì)象的函數(shù)中去的話,那么,只拷貝子類對(duì)象中基類的部分?jǐn)?shù)據(jù),又因?yàn)榫幾g器能明確地知道該對(duì)象的類型,所以不會(huì)產(chǎn)生晚綁定,而是早綁定。我們應(yīng)該避免在這種情況下傳值。

            如果重新定義了基類中的虛函數(shù),則基類中其他重載版本將被隱藏。(同非虛函數(shù)一樣)
            如果重載了基類中的虛函數(shù),則基類中其他版本將被隱藏(同非虛函數(shù)一樣)
            不能在子類中修改基類中虛函數(shù)的返回值(非虛函數(shù)可以修改返回值,并且隱藏其他重載版本)
            但是,也有特例
            class PetFood{
            public:
              virtual string foodType() const = 0;
            };

            class Pet{
            public:
              virtual string type() const = 0;
              virtual PetFood* eat() = 0;
            };

            class Bird : public Pet{
            public:
              string type()const {return "bird";}
              class BirdFood  :  public PetFood{
                public:
                  string foodType()const{
                     return "Bird food";
                   }
                 };
               PetFood* eat(){ return &bf;}
            private:
               BirdFood bf;
            };

            class Cat: public Pet{
            public:
              string type()const {return "cat";}
              class CatFood  :  public PetFood{
                public:
                  string foodType()const{
                     return "Cat food";
                   }
                 };
               CatFood* eat(){ return &cf;}// Here, you can return a CatFood*, because it's a PetType* type. Why don't return a type as PetFood? See segment in main()
            private:
               CatFood cf;
            };

            int main(){
             Bird b;
             Cat c;
             Cat::CatFood* cf = c.eat();
             Bird::BirdFood* bf = b.eat();//downcast, warning!!!Cast PetFood* to BirdFood. So you better return a special pointer, not a base type.
            }
            }
            返回確切的類型要更通用些。

            vptr vtable由誰來初始化?構(gòu)造函數(shù)?是編譯器插入一小段代碼在構(gòu)造函數(shù)中初始化。
            派生類只訪問它自己的成員,而不訪問基類的成員。只有基類的構(gòu)造函數(shù)才能正確地初始化自己的成員。所以要在構(gòu)造函數(shù)中:子要可能,我們應(yīng)該在這個(gè)構(gòu)造函數(shù)初始化列表中從初始化所有的成員對(duì)象(通過組合置于類中),因?yàn)槟惚仨毐WC所有的東西都被初始化了,才能使用該對(duì)象。

            在構(gòu)造函數(shù)中調(diào)用虛函數(shù),調(diào)用的只是本地版本。
            原因:該對(duì)象還未初始完畢,但是vptr已經(jīng)初始化,而且指向自己的vtable,所以調(diào)用的只是本地的函數(shù)。


            1
            posted on 2012-06-04 16:27 Dino-Tech 閱讀(239) 評(píng)論(0)  編輯 收藏 引用

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


            国产亚洲欧美精品久久久| 久久精品国产色蜜蜜麻豆| 久久ZYZ资源站无码中文动漫| 久久久久久国产a免费观看黄色大片 | 久久亚洲精品国产亚洲老地址| 中文精品99久久国产| 久久午夜无码鲁丝片秋霞| 成人久久精品一区二区三区 | 欧美亚洲日本久久精品| 伊人久久大香线蕉AV色婷婷色 | 国产精品久久久久久久午夜片| 亚洲国产成人精品女人久久久| 99久久er这里只有精品18| 久久久无码精品亚洲日韩软件| 久久精品国产亚洲av高清漫画| 亚洲国产精品狼友中文久久久| 伊人久久精品线影院| 精品久久久久久国产免费了| 亚洲中文字幕无码一久久区| 99久久www免费人成精品| 久久偷看各类wc女厕嘘嘘| 蜜桃麻豆www久久国产精品| www.久久热| 国产精品久久久久久久久鸭 | 久久只有这精品99| 777久久精品一区二区三区无码| 国产99精品久久| 久久亚洲精品成人AV| 久久精品桃花综合| 青青草国产97免久久费观看| 久久久久综合网久久| 99久久精品国产高清一区二区 | 亚洲国产天堂久久久久久| 国产福利电影一区二区三区,免费久久久久久久精 | 久久亚洲国产成人精品无码区| 久久精品国产72国产精福利| 狠狠色丁香久久综合五月| 亚洲午夜久久久精品影院| 久久精品成人国产午夜| 国产精品久久久久影院嫩草| 久久婷婷久久一区二区三区|