• <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)  編輯 收藏 引用

            思思久久99热免费精品6| 久久久久四虎国产精品| 久久久久综合国产欧美一区二区| 精品无码人妻久久久久久| 久久强奷乱码老熟女网站| 精品久久久无码人妻中文字幕| 国产精品久久久久9999高清| 91精品国产91久久久久久| 久久人妻少妇嫩草AV蜜桃| 久久综合丁香激情久久| 亚洲日本久久久午夜精品| 国产∨亚洲V天堂无码久久久| 久久午夜无码鲁丝片午夜精品| 少妇无套内谢久久久久| 天天综合久久久网| 中文字幕无码久久精品青草 | 亚洲AV无码久久| 99久久综合狠狠综合久久| 久久久久亚洲AV无码专区体验| 久久久久久久综合综合狠狠| 国产精品久久99| 精品久久久久中文字幕日本| 人妻无码精品久久亚瑟影视| 91精品国产91久久久久久青草| 久久久久亚洲av无码专区喷水| 久久青青草原精品国产不卡| 国产精品久久久天天影视香蕉| 久久综合精品国产二区无码| 久久精品国产男包| 手机看片久久高清国产日韩| 久久se精品一区精品二区国产| 国产精品天天影视久久综合网| 久久精品99久久香蕉国产色戒| 国产成人久久精品一区二区三区| 午夜精品久久久久| 久久人人爽人人爽人人片av麻烦| 亚洲国产精品综合久久网络 | 无码精品久久一区二区三区| 久久久不卡国产精品一区二区| 婷婷综合久久狠狠色99h| 国产精品va久久久久久久|