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

            C+之父力作學(xué)習(xí)筆記6——派生類

                  現(xiàn)在來(lái)考慮做一個(gè)程序,處理某公司所雇傭人員的問(wèn)題。這個(gè)程序可能包含如下一種數(shù)據(jù)結(jié)構(gòu):
            struct Employee
            {
                
            string first_name,family_name;
                
            char middle_initial;
                Date hiring_date;
                
            short department;
                
            //
            }
            ;
            下一步我們可能需要去定義經(jīng)理:
            struct Manager
            {
                Employee emp;
                list
            <Employee*> group; //所管理的人員
                short level;
                
            //
            }
            ;
            一個(gè)經(jīng)理同時(shí)也是一個(gè)雇員,所以在Manager對(duì)象的emp成員存儲(chǔ)著Employee數(shù)據(jù)。很明顯這樣的設(shè)計(jì)是糟糕的,大家都會(huì)想到派生:
            struct Manager:public Employee
            {
                list
            <Employee*> group;
                
            short level;
            }
            ;
            這個(gè)Manager是由Employee派生的,反過(guò)來(lái)就是說(shuō),Employee是Manager的一個(gè)基類。類Manager包含類Employee得所有成員,再加上它自己的一些成員。
                  按照這種方式從Employee派生出Manager,就使Manager成為Employee的一個(gè)子類型,使Manager可以用在能夠接受Employee的任何地方。因?yàn)镸anager是Employee,所以Manager*就可以當(dāng)做Employee*使用。然而,因?yàn)镋mployee不一定是Manager,所以Employee*就不能當(dāng)做Manager*用。總而言之類Derived有一個(gè)公用基類Base,那么就可以用Derived*給Base*類型的變量賦值,不需要顯示的類型轉(zhuǎn)換。而相反的方向,從Base*到Derived*則必須顯示轉(zhuǎn)換。例如:
            void g(Manager mm,Employee ee)
            {
                Employee
            * pe = &mm;  //可以:Manager都是Employee
                Manager* pm = &ee;   //錯(cuò)誤:Employee不一定是Manager
                pm->level = 2;       //災(zāi)難:ee沒(méi)有l(wèi)evel
                pm = static_cast<Manager*>(pe);//蠻力:這個(gè)可以,因?yàn)閜e指向的是Manager mm
                pm->level = 2;       //沒(méi)問(wèn)題
            }

                  派生類的成員可以使用其基類的公用的和保護(hù)的成員,但是,派生類不能使用基類的私有成員。對(duì)于派生類的成年公園而言,保護(hù)成員就像是公用成員;但對(duì)于其他函數(shù)它們則像是私用成員。
                  下面說(shuō)說(shuō)派生類的構(gòu)造函數(shù)和析構(gòu)函數(shù)
                  有些派生類需要構(gòu)造函數(shù)。如果某個(gè)基類中有構(gòu)造函數(shù),那么就必須調(diào)用這些構(gòu)造函數(shù)中的某一個(gè)。默認(rèn)構(gòu)造函數(shù)可以被隱含的調(diào)用,但是,如果一個(gè)基類的所有構(gòu)造函數(shù)都有參數(shù),那么就必須顯示的調(diào)用其中的某一個(gè)。基類構(gòu)造函數(shù)的參數(shù)應(yīng)在派生類構(gòu)造函數(shù)的定義中有明確描述。在這方面,基類的行為恰恰就像是派生類的一個(gè)成員。例如:
            Employee::Employee(const string& n,int d):family(n),department(d)
            {
                
            //
            }


            Manager::Manager(
            const string& n,int d,int lvl):Employee(n,d),/*初始化基類*/level(lvl)/*初始化成員*/
            {
                
            //
            }
            派生類的構(gòu)造函數(shù)只能描述它自己的成員和自己的直接基類的初始式,它不能直接去初始化基類的成員,例如:
            Manager::Manager(const string& n,int d,int lvl):family_name(n).department(d),level(lvl)//錯(cuò)誤:在Manager里沒(méi)有family_name和department的聲明
            {
            //
            }
             類對(duì)象的構(gòu)造是自下而上進(jìn)行的:首先是基類,而后是成員,再后才是派生類本身。類對(duì)象的銷毀則正好以相反的順序進(jìn)行:首先是派生類本身,而后是成員,再后才是基類。
                  對(duì)于給定的一個(gè)類型為Base*的指針,被指的對(duì)象到底屬于哪個(gè)派生類型呢?這個(gè)問(wèn)題有四種基本的解決方案:
            1.  保證被指的只能是唯一類型的對(duì)象
            2. 在基類里安排一個(gè)類型域,供函數(shù)檢查
            3.  使用dynamic_cast
            4.  使用虛函數(shù)  

                   從Employee的函數(shù)中取得“正確的”行為i,而又不依賴于實(shí)際使用的到底是哪一種Employee,這就是所謂的多態(tài)性。一個(gè)帶有虛函數(shù)的類型被稱為是一個(gè)多態(tài)類型。要在C++里取得多態(tài)行為,被調(diào)用的函數(shù)就必須是虛函數(shù),而對(duì)象則必須是通過(guò)指針或者引用去操作的。如果直接操作一個(gè)對(duì)象(而不是通過(guò)指針或引用),它的確切類型就已經(jīng)為編譯器所知,因此也就不需要運(yùn)行時(shí)的多態(tài)性了。
                  那么一個(gè)虛函數(shù)聲明為純虛函數(shù),則這個(gè)虛函數(shù)所在的類為抽象類。用=0作為初始式就使虛函數(shù)成為“純虛的”。注意:不能創(chuàng)建抽象類的對(duì)象。抽象類只能做界面,作為其他類的基類。還有一點(diǎn)也要指的注意,一個(gè)未在派生類里定義的純虛函數(shù)仍舊還是一個(gè)純虛函數(shù),這種情況也將使該派生類仍為一個(gè)抽象類。例如:

            class Shape
            {
                 
            public:
                    
            virtual void draw()=0;
                    
            virtual bool isClose()=0;
                 
            //
            }
            ;

            class Circel:public Shape
            {
                
            public:
                   
            bool isClose(){return true;}//覆蓋Shap::isClose
                   
            //draw尚未覆蓋
            }
            ;

            Circel a;//錯(cuò)誤:聲明的是抽象類Circel對(duì)象

            抽象類的最重要用途就使提供一個(gè)界面,而又不是暴露任何實(shí)現(xiàn)的細(xì)節(jié)。
                  
                 忠告 :

            • 避免類型域
            • 用抽象類將設(shè)計(jì)的中心集中到提供清晰的界面方面
            • 用抽象類使界面最小化
            • 一個(gè)有虛函數(shù)的類應(yīng)該有一個(gè)虛析構(gòu)函數(shù)
            • 抽象類通常不需要構(gòu)造函數(shù)

            posted on 2011-08-28 17:20 Daywei 閱讀(1988) 評(píng)論(0)  編輯 收藏 引用 所屬分類: C++之父力作學(xué)習(xí)筆記

            <2011年8月>
            31123456
            78910111213
            14151617181920
            21222324252627
            28293031123
            45678910

            導(dǎo)航

            統(tǒng)計(jì)

            常用鏈接

            留言簿

            隨筆分類

            隨筆檔案

            文章檔案

            牛人博客

            搜索

            積分與排名

            最新評(píng)論

            閱讀排行榜

            久久精品亚洲日本波多野结衣| 久久精品国产亚洲AV电影| 国产成人久久777777| 久久精品三级视频| 18岁日韩内射颜射午夜久久成人 | 99久久国产主播综合精品 | 国产精品99久久99久久久| 99国产精品久久| 欧洲性大片xxxxx久久久| 久久国产劲爆AV内射—百度| 久久本道伊人久久| 久久亚洲国产精品成人AV秋霞| 99久久中文字幕| 99久久精品免费看国产一区二区三区 | 色婷婷综合久久久久中文| 精品国产乱码久久久久久浪潮 | 蜜臀久久99精品久久久久久| 亚洲AV乱码久久精品蜜桃| 久久久精品无码专区不卡| 国产综合久久久久久鬼色| 中文字幕乱码久久午夜| 香蕉久久影院| 久久精品成人影院| 国产精品99久久久久久猫咪| 欧美熟妇另类久久久久久不卡| 欧美日韩中文字幕久久久不卡| 香蕉久久夜色精品国产小说| 久久亚洲精品成人av无码网站| 久久久久久伊人高潮影院| 久久免费观看视频| 久久九色综合九色99伊人| 精品久久久久久99人妻| 日本免费一区二区久久人人澡| 久久精品国产91久久麻豆自制 | 久久久精品国产| 欧美久久综合九色综合| 久久久久综合国产欧美一区二区| 精品亚洲综合久久中文字幕| 97久久国产亚洲精品超碰热 | 久久久午夜精品福利内容| 亚洲国产成人精品无码久久久久久综合|