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


            久久人人爽人人人人爽AV| 日韩欧美亚洲综合久久影院Ds | 亚洲av伊人久久综合密臀性色| 日本欧美国产精品第一页久久| 久久久久黑人强伦姧人妻| 久久午夜无码鲁丝片午夜精品| 青青草原综合久久大伊人| 久久国产色av免费看| 日本久久久久久中文字幕| 精品国产日韩久久亚洲| 亚洲国产精品人久久| 无码任你躁久久久久久老妇App| 少妇人妻综合久久中文字幕| 99久久综合国产精品二区| 久久久久成人精品无码中文字幕 | 久久精品极品盛宴观看| 久久精品国产精品亚洲人人| 久久精品中文无码资源站| 午夜欧美精品久久久久久久| 久久青青草原精品国产不卡| 亚洲国产精品综合久久一线| yellow中文字幕久久网| 色综合久久最新中文字幕| 国产L精品国产亚洲区久久| 成人午夜精品久久久久久久小说| 国产精品视频久久| 精品久久久久久国产三级| 国产精品一区二区久久精品无码| 亚洲国产精品人久久| 亚洲精品成人网久久久久久| 奇米影视7777久久精品人人爽| 久久一日本道色综合久久| 国产精品丝袜久久久久久不卡| 久久久精品波多野结衣| 亚洲熟妇无码另类久久久| 亚洲欧美精品伊人久久| 久久久久久久久波多野高潮| 久久国产精品99精品国产| 人妻系列无码专区久久五月天| 天天躁日日躁狠狠久久| 亚洲精品乱码久久久久久蜜桃|