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

            Benjamin

            靜以修身,儉以養(yǎng)德,非澹薄無以明志,非寧靜無以致遠(yuǎn)。
            隨筆 - 398, 文章 - 0, 評論 - 196, 引用 - 0
            數(shù)據(jù)加載中……

            深度理解C++概念之繼承(二)

            1.有關(guān) private virtuals:幾乎不用。如果沒有特殊的原因,不提倡使用。
            2.當(dāng)基類構(gòu)造函數(shù)調(diào)用虛函數(shù)時(shí),為什么不調(diào)用派生類重寫的該虛函數(shù)?這樣做是危險(xiǎn)的,C++會(huì)阻止你這樣做
            coder:
            #include <iostream>
             #include <string>
             
             void println(const std::string& msg)
             { std::cout << msg << '\n'; }
             
             class Base {
             public:
               Base()              { println("Base::Base()");  virt(); }
               virtual void virt() { println("Base::virt()"); }
             };
             
             class Derived : public Base {
             public:
               Derived()           { println("Derived::Derived()");  virt(); }
               virtual void virt() { println("Derived::virt()"); }
             };
             
             int main()
             {
               Derived d;
               ...
             }
            程序輸出:

             Base::Base()
             Base::virt() // ← Not Derived::virt()
             Derived::Derived()
             Derived::virt()
             
            當(dāng)基類被構(gòu)造時(shí),對象還不是一個(gè)派生類的對象,所以如果 Base::Base()調(diào)用了虛函數(shù) virt(),則 Base::virt() 將被調(diào)用,即使 Derived::virt()(即派生類重寫的虛函數(shù))存在。
            同樣,當(dāng)基類被析構(gòu)時(shí),對象已經(jīng)不再是一個(gè)派生類對象了,所以如果 Base::~Base()調(diào)用了virt(),則 Base::virt()得到控制權(quán),而不是重寫的 Derived::virt() 。
            如果 Base::Base()調(diào)用了虛函數(shù) virt(),這個(gè)規(guī)則使得 Base::virt()被調(diào)用。如果不按照這個(gè)規(guī)則,Derived::virt()將在派生對象的派生部分被構(gòu)造之前被調(diào)用,此時(shí)屬于派生對象的派生部分的某個(gè)成員對象還沒有被構(gòu)造,而 Derived::virt()卻能夠訪問它。這將是災(zāi)難。
            3.模擬動(dòng)態(tài)綁定在一個(gè)基類的構(gòu)造里的方法
            class Base {
             public:
               Base();
               ...
               virtual void foo(int n) const; // often pure virtual
               virtual double bar() const;    // often pure virtual
               // if you don't want outsiders calling these, make them protected
             };
             
             Base::Base()
             {
               ... foo(42) ... bar() ...
               // these will not use dynamic binding
               // goal: simulate dynamic binding in those calls
             }
             
             class Derived : public Base {
             public:
               ...
               virtual void foo(int n) const;
               virtual double bar() const;
             };
            實(shí)現(xiàn)方法有兩種,根據(jù)自己實(shí)際情況來選擇。
            第一種方法,把初始化分兩個(gè)階段,第一階段是實(shí)際的構(gòu)造,第二階段是"init"方法。動(dòng)態(tài)綁定就在第二階段,第二階段是構(gòu)造概念的一部分,所以我們可以簡單的把從 Base::Base() 移到 Base::init()
            class Base {
             public:
               void init();  // may or may not be virtual
               
            ...
               virtual void foo(int n) const; 
            // often pure virtual
               virtual double bar() const;    
            // often pure virtual
             };
             
             void Base::init()
             {
               
            ... foo(42) ... bar() ...
               
            // most of this is copied from the original 
            Base::Base()
             }
             
             class Derived : public Base {
             public:
               
            ...
               virtual void foo(int n) const;
               virtual double bar() const;
             };
            剩下的就是確定哪里調(diào)用第一階段,哪里調(diào)用第二階段。這里我們要注意以下兩點(diǎn):第一在創(chuàng)建對象時(shí),要加上小小的約束條件,尤其在同一層中有一處或兩處要?jiǎng)?chuàng)建
            創(chuàng)建時(shí),這個(gè)約束可以確保程序不會(huì)出錯(cuò)。第二在第一階段創(chuàng)建對象的方法有三種,是new Derived或是聲明
            Derived對象,或是不知道具體的類型(通過虛構(gòu)造或
            類工廠創(chuàng)建),用第三種是強(qiáng)壯的,這樣可是你很容易的插入一個(gè)Derived對象。
            在第一階段,對象的創(chuàng)建一般在堆上,這時(shí)我們需要保存一個(gè)管理指針(智能指針
            std::auto_ptr,引用計(jì)數(shù)的指針,或是其他的析構(gòu)刪除),最好的預(yù)防堆溢出的方法是在第二階段是拋出異常。分配堆空間簡單的示例代碼如下:
            #include <memory>
             
             void joe_user()
             {
               std::auto_ptr<Base> p(/*...somehow create a Derived object via new...*/);
               p->init();
               
            ...
             }

            第二種方案是組合joe_user前兩句到create函數(shù)里。如果你是用工廠(factory)模式,譬如虛構(gòu)造,你可以這兩行放在靜態(tài)方法中調(diào)用Base::create(): 代碼如下
            #include <memory>
             
             class Base {
             public:
               ...
               typedef std::auto_ptr<Base> Ptr;  
            // typedefs simplify the code
               static Ptr create();
               
            ...
             };
             
             Base::Ptr Base::create()
             {
               Ptr p(
            /*...use a factory to create a Derived object via new...*/);
               p->init();
               return p;
             }
            它簡化了joe_user的功能,更重要的是可以在創(chuàng)建對象不用調(diào)用Init().
            void joe_user()
             {
               Base::Ptr p = Base::create();
               ...
             }
            我們在這個(gè)方法中,我們應(yīng)當(dāng)竭力避免調(diào)用Init(),那么就應(yīng)該使派生類的構(gòu)造、拷貝構(gòu)造成為priviate或protected;

            最后的方法,則和上面的都不同,在第二層類結(jié)構(gòu)中加入foo()和
            bar(). 如果這兩個(gè)函數(shù)要存取Derived的數(shù)據(jù)時(shí),這個(gè)方法是不能用的。
            class Helper {
             public:
               virtual void foo(int n) const = 0;
               virtual double bar() const = 0;
             };
             
             class Helper1 : public Helper {
             public:
               virtual void foo(int n) const;
               virtual double bar() const;
             };
             
             class Helper2 : public Helper {
             public:
               virtual void foo(int n) const;
               virtual double bar() const;
             };
            Base類也要?jiǎng)h除init(),Base類和Derived類要?jiǎng)h除foo() and
            bar(),在Base類構(gòu)造中加入Helper的引用 
             class Base {
             public:
               Base(const Helper& h);
               ...   
            // remove 
               
            ...   
            // remove 
             };
             
             class Derived : public Base {
             public:
               
            ...   
            // remove 
             };
            當(dāng)我們定義Base::Base(const Helper&)時(shí),它會(huì)正確調(diào)用h.foo(42)和
            h.bar()
             Base::Base(const Helper& h)
             {
               ... h.foo(42) ... h.bar() ...

               
            // almost identical to the original 
            Base::Base()
               
            // but with 
            h. in calls to h.foo() and h.bar()
             }
            Derived::Derived()
               : Base(Helper2())   // the magic happens here

             {
               
            ...
             }

            注意:Derived可以傳遞值到Helper的派生類的構(gòu)造中,但不是任何的數(shù)據(jù)都可以傳至Helper派生類。比如Helper::foo()和
            Helper::bar() 就不能存取數(shù)據(jù)在這個(gè)類中,特別是數(shù)據(jù)是Derived類中中聲明的數(shù)據(jù)。

            Helper派生類也可以做成類似joe_user功能,例如:
            Derived::Derived(const Helper& h)
               : Base(h)
             {
               ...

             }
            如果Helper不需要數(shù)據(jù),那么可以通過一個(gè)靜態(tài)方法來替代它。
            class Base {
             public:
               typedef void (*FooFn)(int);  // typedefs simplify

               typedef double (*BarFn)();   
            //    the rest of the code
               Base(FooFn foo, BarFn bar);
               
            ...
             };
             
             Base::Base(FooFn foo, BarFn bar)
             {
               
            ... foo(42) ... bar() ...
               
            // almost identical to the original 
            Base::Base()
               
            // except calls are made via function pointers.
             }
            class Derived : public Base {
             public:
               Derived();
               static void foo(int n); // the static is important!

               static double bar();    
            // the static is important!
               
            ...
             };
             
             Derived::Derived()
               : Base(foo, bar)  
            // pass the function-ptrs into Base's ctor
             {
               
            ...
             }






            posted on 2009-07-04 15:51 Benjamin 閱讀(283) 評論(0)  編輯 收藏 引用


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


            久久国产一片免费观看| 亚洲人成无码网站久久99热国产| 国产亚洲精品久久久久秋霞| 无码人妻久久一区二区三区| 九九久久精品国产| 99久久99久久精品国产片果冻| 丰满少妇人妻久久久久久| 无码乱码观看精品久久| 2021久久精品国产99国产精品| 日韩美女18网站久久精品| 国内精品九九久久久精品| 久久九九久精品国产免费直播| 久久精品国产99国产精品澳门 | 久久亚洲精品人成综合网| 国产成人综合久久久久久| 久久久精品国产免大香伊| 久久国产精品一区| 国产精品久久波多野结衣| 久久久SS麻豆欧美国产日韩| 国产成人久久精品二区三区| 99久久国产综合精品麻豆| 亚洲精品无码专区久久久| 久久激情亚洲精品无码?V| 亚洲乱亚洲乱淫久久| 激情伊人五月天久久综合| 新狼窝色AV性久久久久久| 久久久久波多野结衣高潮| 噜噜噜色噜噜噜久久| 欧美精品九九99久久在观看| 久久午夜综合久久| 性做久久久久久久久久久| 久久久久香蕉视频| 日日狠狠久久偷偷色综合0| 久久婷婷五月综合色99啪ak| 久久精品国产精品亚洲人人| 91久久精品视频| 欧美激情精品久久久久久久九九九 | 久久精品一区二区三区中文字幕| 久久精品国产只有精品2020| 国产成人精品久久免费动漫| 亚洲天堂久久精品|