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

            靜以修身,儉以養德,非澹薄無以明志,非寧靜無以致遠。
            隨筆 - 397, 文章 - 0, 評論 - 196, 引用 - 0
            數據加載中……

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

            1.有關 private virtuals:幾乎不用。如果沒有特殊的原因,不提倡使用。
            2.當基類構造函數調用虛函數時,為什么不調用派生類重寫的該虛函數?這樣做是危險的,C++會阻止你這樣做
            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()
             
            當基類被構造時,對象還不是一個派生類的對象,所以如果 Base::Base()調用了虛函數 virt(),則 Base::virt() 將被調用,即使 Derived::virt()(即派生類重寫的虛函數)存在。
            同樣,當基類被析構時,對象已經不再是一個派生類對象了,所以如果 Base::~Base()調用了virt(),則 Base::virt()得到控制權,而不是重寫的 Derived::virt() 。
            如果 Base::Base()調用了虛函數 virt(),這個規則使得 Base::virt()被調用。如果不按照這個規則,Derived::virt()將在派生對象的派生部分被構造之前被調用,此時屬于派生對象的派生部分的某個成員對象還沒有被構造,而 Derived::virt()卻能夠訪問它。這將是災難。
            3.模擬動態綁定在一個基類的構造里的方法
            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;
             };
            實現方法有兩種,根據自己實際情況來選擇。
            第一種方法,把初始化分兩個階段,第一階段是實際的構造,第二階段是"init"方法。動態綁定就在第二階段,第二階段是構造概念的一部分,所以我們可以簡單的把從 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;
             };
            剩下的就是確定哪里調用第一階段,哪里調用第二階段。這里我們要注意以下兩點:第一在創建對象時,要加上小小的約束條件,尤其在同一層中有一處或兩處要創建
            創建時,這個約束可以確保程序不會出錯。第二在第一階段創建對象的方法有三種,是new Derived或是聲明
            Derived對象,或是不知道具體的類型(通過虛構造或
            類工廠創建),用第三種是強壯的,這樣可是你很容易的插入一個Derived對象。
            在第一階段,對象的創建一般在堆上,這時我們需要保存一個管理指針(智能指針
            std::auto_ptr,引用計數的指針,或是其他的析構刪除),最好的預防堆溢出的方法是在第二階段是拋出異常。分配堆空間簡單的示例代碼如下:
            #include <memory>
             
             void joe_user()
             {
               std::auto_ptr<Base> p(/*...somehow create a Derived object via new...*/);
               p->init();
               
            ...
             }

            第二種方案是組合joe_user前兩句到create函數里。如果你是用工廠(factory)模式,譬如虛構造,你可以這兩行放在靜態方法中調用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的功能,更重要的是可以在創建對象不用調用Init().
            void joe_user()
             {
               Base::Ptr p = Base::create();
               ...
             }
            我們在這個方法中,我們應當竭力避免調用Init(),那么就應該使派生類的構造、拷貝構造成為priviate或protected;

            最后的方法,則和上面的都不同,在第二層類結構中加入foo()和
            bar(). 如果這兩個函數要存取Derived的數據時,這個方法是不能用的。
            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類也要刪除init(),Base類和Derived類要刪除foo() and
            bar(),在Base類構造中加入Helper的引用 
             class Base {
             public:
               Base(const Helper& h);
               ...   
            // remove 
               
            ...   
            // remove 
             };
             
             class Derived : public Base {
             public:
               
            ...   
            // remove 
             };
            當我們定義Base::Base(const Helper&)時,它會正確調用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的派生類的構造中,但不是任何的數據都可以傳至Helper派生類。比如Helper::foo()和
            Helper::bar() 就不能存取數據在這個類中,特別是數據是Derived類中中聲明的數據。

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

             }
            如果Helper不需要數據,那么可以通過一個靜態方法來替代它。
            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 閱讀(277) 評論(0)  編輯 收藏 引用

            久久97久久97精品免视看秋霞| 久久国产精品-国产精品| 国产亚洲成人久久| 久久乐国产综合亚洲精品| 亚洲人成伊人成综合网久久久| 亚洲日韩中文无码久久| 久久777国产线看观看精品| 久久久久国产日韩精品网站| 一本色道久久99一综合| 国产精品青草久久久久婷婷| 婷婷久久综合| 久久久久久狠狠丁香| 久久中文字幕人妻熟av女| 中文字幕久久欲求不满| 久久久久久久精品妇女99| 99久久精品九九亚洲精品| 久久亚洲中文字幕精品有坂深雪 | 亚洲精品tv久久久久久久久久| 亚洲狠狠婷婷综合久久蜜芽| 久久99精品久久久久久水蜜桃 | 久久久久综合中文字幕| 久久夜色精品国产网站| 伊人久久精品无码av一区| 久久国产成人午夜AV影院| 国产精品久久免费| 午夜精品久久久久久99热| 久久国产精品免费一区二区三区| 久久99精品久久久久久久久久| 人妻系列无码专区久久五月天| 99国内精品久久久久久久| 91精品国产综合久久婷婷| 99精品久久精品一区二区| 综合久久给合久久狠狠狠97色| 久久精品国产一区二区三区不卡| 精品久久久久久成人AV| 欧美黑人又粗又大久久久| 日韩精品久久无码人妻中文字幕| 奇米影视7777久久精品人人爽| 精品国产青草久久久久福利 | 国产精久久一区二区三区| 97精品国产91久久久久久|