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

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

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




#0004  class CEmployee   // 职员 

#0005  { 

#0006  private: 

#0007  char m_name'30'; 

#0008 

#0009  public: 

#0010    CEmployee(); 

#0011    CEmployee(const char* nm) { strcpy(m_name; nm); } 

#0012  }; 



                                                                                    63 


…………………………………………………………Page 126……………………………………………………………

                  #0013  //……………………………………………………………………………………………………………………………………………………………………

                  #0014  class CWage : public CEmployee      // 时薪职员是一种职员 

                  #0015  { 

                  #0016  private : 

                  #0017    float m_wage; 

                  #0018    float m_hours; 

                  #0019 

                  #0020  public : 

                  #0021    CWage(const char* nm)  : CEmployee(nm) { m_wage = 250。0; m_hours = 40。0; } 

                  #0022    void setWage(float wg)  { m_wage = wg; } 

                  #0023    void setHours(float hrs)  { m_hours = hrs; } 

                  #0024    float putePay(); 

                  #0025  }; 

                  #0026  //……………………………………………………………………………………………………………………………………………………………………

                  #0027  class CSales : public CWage     // 销售员是一种时薪职员 

                  #0028  { 

                  #0029  private : 

                  #0030    float m_m; 

                  #0031    float m_sale; 

                  #0032 

                  #0033  public : 

                  #0034    CSales(const char* nm) : CWage(nm)  { m_m = m_sale = 0。0; } 

                  #0035    void setmission(float m)      { m_m = m; } 

                  #0036    void setSales(float sale)           { m_sale = sale; } 

                  #0037    float putePay(); 

                  #0038  }; 

                  #0039  //……………………………………………………………………………………………………………………………………………………………………

                  #0040  class CManager : public CEmployee   // 经理也是一种职员 

                  #0041  { 

                  #0042  private : 

                  #0043    float m_salary; 

                  #0044  public : 

                  #0045    CManager(const char* nm) : CEmployee(nm)  { m_salary = 15000。0; } 

                  #0046    void setSalary(float salary)              { m_salary = salary; } 

                  #0047    float putePay(); 

                  #0048  }; 

                  #0049  //……………………………………………………………………………………………………………………………………………………………………

                  #0050  void main () 

                  #0051  { 

                  #0052  CManager aManager(〃陈美静〃); 

                  #0053  CSales   aSales(〃侯俊杰〃); 

                  #0054  CWage    aWager(〃曾铭源〃); 

                  #0055  } 

                  #0056  //……………………………………………………………………………………………………………………………………………………………………

                  #0057  // 虽然各类別的 putePay 函数都没有定义,但因为程序也没有调用之,所以无妨。 



64 


…………………………………………………………Page 127……………………………………………………………

如此一来,CWage 继承了CEmpl oyee 所有的成员(包括资料与函数),CSales 又继承 



了CWage 所有的成员(包括资料与函数)。在意义上, 相当于CSales 拥有资料如下: 



    // private data of CEmployee 

   char m_name'30'; 



    // private data of CWage 

   float m_wage; 

   float m_hours; 



    // private data of CSales 

   float m_m; 

   float m_sale; 



 以及函数如下: 



   void setWage(float wg); 

   void setHours(float hrs); 

   void setmission(float m); 

   void setSale(float sales); 

   void putePay(); 



  从Visual C++  的除错器中,我们可以看到,上例的main 执行之后,程序拥有三个对象, 



  内容(我是指成员变量)分别为: 



                                                                                 65 


…………………………………………………………Page 128……………………………………………………………

从薪水说起 



    虚拟函数的故事要从薪水的计算说起。根据不同职员的计薪方式,我设计put ePay  函 



    数如下: 



       float CManager::putePay () 



        { 



            return m_salary; // 经理以「固定周薪」计薪。 



        } 



       float CWage::putePay () 



        { 



            return  (m_wage * m_hours); // 时薪职员以「钟点费* 每周工时」计薪。 



        } 



       float CSales::putePay () 



        { 



       // 销售员以「钟点费* 每周工时」再加上「佣金* 销售额」计薪。 



            return  (m_wage * m_hours + m_m * m_sale); // 语法错误。 



        } 



        CSales                  CWage   m_wage   m_hours           pr ivate 

    但是        对象不能够直接取用               的        和        ,因为它们是 



    成员变量。所以是不是应该改为这样: 



       float CSales::putePay () 



        { 



            return putePay () + m_m * m_sale; 



        } 



                                       put ePay       … 

    这也不好,我们应该指明函数中所调用的                            究归谁属  编译器没有厉害到能 



    够自行判断而保证不出错。正确写法应该是: 



       float CSales::putePay () 



        { 



            return CWage::putePay () + m_m * m_sale; 



        } 



    这就合乎逻辑了:销售员是一般职员的一种,他的薪水应该是以时薪职员的计薪方式作 



    为底薪,再加上额外的销售佣金。我们看看实际情况,如果有一个销售员: 



    CSales aSales(〃侯俊杰〃); 



                                                                                      66 


…………………………………………………………Page 129……………………………………………………………

那么侯俊杰的底薪应该是: 



   aSales。CWage::putePay (); // 这是销售员的底薪。注意语法。 



而侯俊杰的全薪应该是: 



   aSales。putePay (); // 这是销售员的全薪 



                                scope resolution operator :: 

结论是:要调用父类别的函数,你必须使用                               明白指出。 



接下来我要触及对象类型的转换,这关系到指针的运用,更直接关系到为什么需要虚拟 



函数。了解它,对于application framework 如MFC 者的运用十分十分重要。 



假设我们有两个对象: 



   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; 



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