友情提示:如果本网页打开太慢或显示不完整,请尝试鼠标右键“刷新”本网页!阅读过程发现任何错误请告诉我们,谢谢!! 报告错误
狗狗书籍 返回本书目录 我的书架 我的书签 TXT全本下载 进入书吧 加入书签

深入浅出MFC第2版(PDF格式)-第38章

按键盘上方向键 ← 或 → 可快速上下翻页,按键盘上的 Enter 键可回到本书目录页,按键盘上方向键 ↑ 可回到本页顶部!
————未阅读完?加入书签已便下次继续阅读!






假设我们有两个对象: 



   CWage aWager; 



   CSales aSales(〃侯俊杰〃); 



销售员是时薪职员之一,因此这样做是合理的: 



   aWager = aSales; // 合理,销售员必定是时薪职员。 



这样就不合理: 



   aSales = aWager; // 错误,时薪职员未必是销售员。 



如果你一定要转换,必须使用指针,并且明显地做型别转换(cast )动作: 



   CWage* pWager; 



   CSales* pSales; 



   CSales aSales(〃侯俊杰〃); 



   pWager = &aSales; // 把一个「基础类别指针」指向衍生类别之对象,合理且自然。 



   pSales =  (CSales *)pWager; // 强迫转型。语法上可以,但不符合现实生活。 



真实世界中某些时候我们会以「一种动物」来总称猫啊、狗啊、兔子猴子等等。为了某 



种便利(这个便利稍后即可看到),我们也会想以「一个通用的指针」表示所有可能的 



职员类型。无论如何,销售员、时薪职员、经理,都是职员,所以下面动作合情合理: 



                                                                       67 


…………………………………………………………Page 130……………………………………………………………

        CEmployee* pEmployee; 



        CWage aWager (〃曾铭源〃); 



        CSales aSales(〃侯俊杰〃); 



        CManager aManager (〃陈美静〃); 



        pEmpolyee = &aWager; // 合理,因为时薪职员必是职员 



        pEmpolyee = &aSales; // 合理,因为销售员必是职员 



        pEmpolyee = &aManager; // 合理,因为经理必是职员 



    也就是说,你可以把一个「职员指针」指向任何一种职员。这带来的好处是程序设计的 



    巨大弹性,譬如说你设计一个串行(linked list ),各个元素都是职员(哪一种职员都可 



             add  

    以),你的       函数可能因此希望有一个「职员指针」作为参数: 



        add (CEmployee* pEmp); // pEmp 可以指向任何一种职员 



晴天霹雳 



    我们渐渐接触问题的核心。上述C++ 性质使真实生活经验的确在计算机语言中仿真了出 



    来,但是万里无云的日子里却出现了一个晴天霹雳:如果你以一个「基础类别之指针」 



    指向一个「衍生类别之对象」,那么经由此指针,你就只能够调用基础类别(而不是衍 



    生类别)所定义的函数。因此: 



        CSales aSales(〃侯俊杰〃); 



        CSales* pSales; 



        CWage* pWager; 



        pSales = &aSales; 



        pWager = &aSales; // 以「基础类别之指针」指向「衍生类别之对象」 



        pWager…》setSales(800。0); //                  ) 

                                   错误(编译器会检测出来 , 



        // 因为CWage 并没有定义setSales 函数。 



        pSales…》setSales(800。0); // 正确,调用CSales::setSales 函数。 



       pSal es  pWage r  

    虽然       和       指向同一个对象,但却因指针的原始类型而使两者之间有了差异。 



    延续此例,我们看另一种情况: 



        pWager…》putePay (); // 调用CWage::putePay () 



        pSales…》putePay (); // 调用CSales::putePay () 



       pSal es  pWage r         CSales                  put ePay  

    虽然       和       实际上都指向          对象,但是两者调用的                  却不 



                                                                                68 


…………………………………………………………Page 131……………………………………………………………

    相同。到底调用到哪个函数,必须视指针的原始类型而定,与指针实际所指之对象无关。 



三个结论 



    我们得到了三个结论: 



    1。 如果你以一个「基础类别之指针」指向「衍生类别之对象」,那么经由该指针 



      你只能够调用基础类别所定义的函数。 



        class CBase                      CBase* pBase; 



        BaseFunc() 



                                 虽然我们可以令pBase 实际指向CD erived 对象, 



                                 却因为pBase 的类型(〃一个CBase* 指针〃) 

      class CDerived 

                                 使它只能够调用BaseFunc(),不能够调用DeriFunc()。 

        DeriFunc() 

     



    2。 如果你以一个「衍生类别之指针」指向一个「基础类别之对象」,你必须先做 



      明显的转型动作(explicit cast )。这种作法很危险,不符合真实生活经验,在 



      程序设计上也会带给程序员困惑。 



        class CBase       CDerived *pDeri; 

                          CBase aBase(〃Jason〃); 

        BaseFunc() 

                                             这种作法很危险,不符合真实生活经验, 

                          pDeri = &aBase;  //  

                                           //  

                                              在程序设计上也会带给程序员困惑。 



      class CDerived                  CDerived* pDeri; 



        DeriFunc() 

     



    3。 如果基础类别和衍生类别都定义了「相同名称之成员函数」,那么透过对象指 



      针调用成员函数时,到底调用到哪一个函数,必须视该指针的原始型别而定, 



      而不是视指针实际所指之对象的型别而定。这与第  点其实意义相通。 

                                              1  



                                                                                   69 


…………………………………………………………Page 132……………………………………………………………

                       class CBase 

                                         CBase* pBase; 

                        BaseFunc() 

                                         CDerived* pDeri; 

                        mFunc() 



                                           不论你把这两个指针指向何方,由于它们的原始类型, 

                      class CDerived       使它们在调用同名的 m Func() 时有着无可改变的宿命: 



                                           o pBase…》mFunc() 永远是指CBase::mFunc 

                        DeriFunc() 

                        mFunc()         o pDeri…》mFunc() 永远是指CDerived::mFunc 



                 得到这些结论后,看看什么事情会困扰我们。前面我曾提到一个由职员组成的串行,如 



                             pr intNames  

                  果我想写一个              函数走访串行中的每一个元素并印出职员的名字,我们可以在 



                  CEmpl oyee                     getName                   while  

                           (最基础类别)中多加一个                  函数,然后再设计一个             循环如下: 

                      int count = 0; 

                     CEmployee* pEmp; 

                      。。。 

                     while (pEmp = anIter。getNext()) 

          
返回目录 上一页 下一页 回到顶部 0 0
未阅读完?加入书签已便下次继续阅读!
温馨提示: 温看小说的同时发表评论,说出自己的看法和其它小伙伴们分享也不错哦!发表书评还可以获得积分和经验奖励,认真写原创书评 被采纳为精评可以获得大量金币、积分和经验奖励哦!