• 深入浅出之多态分析(笔记二)


    看上图,我们创建了四个类,有职员类,经理类,时薪员工类,销售员类。通过代码将一步步分析引入虚函数,纯虚函数,虚函数表,多态,抽象类。

    为了解说的方便,我们先从c++程序代码分析,最后再来验证是否与.net的结果一致,欢ying您提出宝贵的意见。程序代码如下:

    Code

    运行后,我们跟踪了一下,其跟踪过程如图:

    我们可以看到:

    1.CSales对象zhu这个销售员,因为继承了CWage,而CWage又继承了CEmployee,所以CSales相当于拥有了基类的所有成员变量和成员函数。

    2.当new一个派生类时,其构造函数的执行顺序都是从基类一层层往下执行,而析构函数则刚好相反

    如果你是公司的一个财务,那么如果现在要你计算经理,时薪员,销售员的工资,你会如何做呢?其中

    经理:固定周薪计算

    时薪员:钟点费×每周工时

    销售员:钟点费×每周工时+佣金*销售额

    如果是这样,设计一个成员函数computerpay(),这个成员函数可设计如下:

    Code

    这是表示计算时薪员工资,如果我想用此方法表示销售员工资呢,能否这样写:

    Code

    很显然,其中的computerPay具有不确定性,编译器没那么智能到能自动判断究竟是哪个类中的方法,所以要调用父类的函数,必须使用CWage::computerPay()

    接下来,该虚函数登场了,我们先来分析一下为什么要使用虚函数?

    假设我们有两个对象,一个是时薪员,一个是销售员,表示如下:

    CWage wage;

    CSales sale;

    我们能否这样做:

    wage=sale;合理,为什么?因为销售员是属于时薪员

    sale=wage;不合理,因为时薪员不一定是属于销售员

    我们把wage=sale类似这样的情况,称为基类的指针指向派生类的对象。

    现实世界中,我们总用动物来形容猫,狗,狐,狼等,那么我们能不能创建一个通用的指针来表示把有的职员类型呢。所以我们可以用如下代码来表示:

    Code

    但是,运行后,你会发现,生活并不是你想像中的那样,总是调用的是基类的ComputerPay方法。由此我们总结以下几点:

    1.如果你以基类的指针指向派生类的对象,那么调用的总是基类所定义的函数。

    2.如果你以派生类的对象指向基类的指针,这种不切合实际,往往最危险且容易使人迷糊。

    3.如果基类和派生类调用了相同名称的成员函数,那么调用时视指针的原始类弄而定,而不是由指针所指的对象的类型而定。

    如果我希望emp指向经理时,调用的是经理的computerPay();

                  emp指向时薪员时,调用的是时薪员的computerPay();

                  emp指向销售员时,调用的是销售员的computerPay();

    那么此时我们应如何办呢:很简单,在所有类的computerPay方法前端加virtual修辞符。

    这种做法就是虚函数,虚函数就是对“基类指针指向派生类对象时,总是调用基类所定义的方法”北道而弛的一种做法。如果你预期派生类中有可能重新定义某一个成员函数时,就是虚函数粉末登场的时候了。

    看到了吗?我们以相同的指令却调用了不同的函数,这就是多态。编译器无法在编译时判断emp->computerPay()调用的是哪种方法,而只能在执行期才能判断,这称之为动态绑定。其它的变量和非虚函数在编译时就确认了固定地址的调用了,这称为静态绑定。

    那么何时使用多态呢?

    举一个例子:有一个图形类,他有几个派生类,如圆形,三角形,矩形。图形类有一个函数area();用来求面积,但是由于不同图形求面积的方法不同,要由具体的派生类来决定,所以可以把它定义为一个虚函数,由派生类来重载这个函数,所以不同的派生类里面area()函数的函数体是不同的。

    让我们回头看看上一讲我们讲的Csharp例子,在上一讲我们谈到了CSharp形状基类,我们说它是抽象的,所以它根本就不该创建对象,因为没有任何意义,但为了在各派生类中绘图,我们又不得不加上display这个虚函数。所以在这种情况下你可以定义它什么都不做。看以下情况定义合理吗?如:

    class CSharp

    {

         public:

            virtual void display();{......}

    }

    不合理,因为这个函数根本就不应不调用,因为CSharp是抽像的,但我们又必须留一块空间给它(因为派生类要绘图用),在这样的情况下,就出现了纯虚函数,即virtual void display()=0即可。

    好了,该说总结的时候了

    1.如果你期望在派生类中重新定义方法,那么你应当在基类中声明虚函数

    2.以单一指令可调用不同的函数,这就是多态

    3.虚函数是实行动态与动态绑定的关健

    4.即然抽像类中的虚函数不打算被调用,那么我们可以设定它为纯虚函数

    5.我们可以说拥有纯虚函数者为抽像类

    6.抽像类不能产生对象,但我们可以定义一个基类指针指向派生类对象,对方便对派生类进行操作

    下面,附出这一节完整的c++源码,以方便大家调试:

    Code
  • 相关阅读:
    free和delete把指针怎么啦?
    动态内存会被自动释放吗?
    杜绝“野指针”
    有了malloc/free为什么还要new/delete ?
    Linux Shell Bash 带有特殊含义的退出码
    centos中更换jdk的版本
    shift移动变量
    shell script针对参数已经有配置好变量名称
    输入两个数后输出相乘的结果
    输入变量
  • 原文地址:https://www.cnblogs.com/chuncn/p/1399900.html
Copyright © 2020-2023  润新知