当前位置:C++技术网 > 资讯 > [多态概念理解]多态一直不理解可否定死为以下几点就可以了。

[多态概念理解]多态一直不理解可否定死为以下几点就可以了。

更新时间:2016-08-10 13:28:57浏览次数:1+次

父类引用子类对象:

【子类有,父类没有】编译失败

【子类有,父类有,重写,非静态】调用子类

如果不可以 是否有更好的文章或者方法理解,求推荐或解答,感谢!


C++技术网解答:

    看来确实没有理解多态。

    我来解释下。从字面意思来看,多态就是多种状态。多种状态又是哪样的呢?

    我们C++语言里的多态是描述程序执行的多种结果状态。通常来说,一个函数执行,都是一个固定的流程走下去,也就是表现为一个固定的状态。我们从这里可以看出,多态的态,不是静态的,而是动态动作执行的状态结果。

    多态必然对应一个执行动作,比如一个函数调用语句,一个函数调用,却可以产生不同的执行流程。没有多态的时候,这样一个动作只会一个执行流程。比如自己打自己的脸。没有多态的时候,也就是脸疼。加入多态后,同样的力度、同样的角度,反正就是和之前打一巴掌一模一样的情景,最后可以是脸疼、脸不疼、脸被打白了、脸被大黑了...,你想有多少种就有多少种结果。你会很惊讶,明明是同一个动作,没有任何附加的动作,有多态之后,我就可以随意的定制随后发生的结果。这就是多态。

    你可以仔细体会一下上面的类比。而反应在程序中,多态可以结合程序特性,实现为函数的重载多态、虚函数继承的多态。还可能有其他类型的多态,只要符合【同一个代码执行,可以定制不同的代码流程,就是多态】,就可以了。我们学习多态,是学习广义上的多态,然后熟悉语言中具体的对广义的多态的思想的实现。不要去固化一个思想的具体实现,你可以熟悉记忆,但千万不要固化思想,固化后你就不容易融会贯通了。

    而在C语言中,似乎没有多态的实现机制。在C++中,提供了很多特性,其中有类函数重载,我称之为横向重载。还有虚函数继承时发生的重载,我称之为纵向重载。

    我看横纵是将类的继承关系以分层的角度来看,一个类属于一层,继承的类属于另一层,也就有一个继承的层次结构。在同一个类中发生的,都叫做横向重载。在层次之间发生的,就是纵向重载。横向纵向重载更多了解,请阅读《C++重载:横向重载(静态重载)与纵向重载(动态重载)》。

    多态要能够发生,就需要发生重载。重载的含义就是,同一个调用形式,会根据参数或者调用者类型不同,而使结果不一样。所以。类成员函数的重载是通过参数列表来实现的,同时还可以利用默认值来实现参数的缺省。这样表现为,同样的参数个数,仅仅因为传参的类型不同,C++自动调用不同的重载版本,从而达到一个调用,可以实现多个执行结果,即调用了不同的函数来处理。如果没有重载,就没有办法得到这样的效果。

    类成员函数的重载代码示例:

class A
{
    void test(int a, int b=1, int c=2)
    {

    }
    void test(float a, float b=1.0, float c=2.0)
    {

    }
}

void main()
{
    A a;
    a.test(12);//void test(int a, int b=1, int c=2)
    a.test(12,10);//void test(int a, int b=1, int c=2),b的默认值被10替代
    a.test(12,10,20);//void test(int a, int b=1, int c=2),c的默认值被20替代
    a.test(12.0);//void test(float a, float b=1.0, float c=2.0)//不同的参数类型,决定了调用不同的重载版本
    a.test(12.0,10.0);//void test(float a, float b=1.0, float c=2.0)//,b的默认值被10.0替代
    a.test(12.0,10.0,20.0);//void test(float a, float b=1.0, float c=2.0),c的默认值被20.0替代
}
     从代码中可以看到,A类的test函数同一个函数调用,却实现了6中结果。如果你再写不同的类型,还可以实现更多的结果。最终调用test时,都是用函数名test。这就是多态中的横向多态。而在这个例子中,横向多态表现为默认参数和函数重载两种。

    而纵向多态,是类继承时实现的虚函数的重载。下面是示例代码:

class A
{
    virtual void test(int a, int b=1, int c=2)
    {

    }
}

class AA:public A
{
    void test(int a, int b=10, int c=20)
    {

    }
}

void main()
{
    A* pA = new AA();//基类指针指向派生类对象
    pA->test(12);//AA: void test(int a, int b=10, int c=20)
    
    A* pA2 = new A();//A类指针指向A类对象,A类为AA的基类
    a.test(12);//A: void test(int a, int b=1, int c=2)
}
     这里可看到,pA和pA2都是A类的指针,调用同一个函数test函数,却调用了不同的版本。pA因为指向的是派生类,所以调用了派生类的的test函数,而不是基类的test。pA2本身就是指向基类对象,所以调用了基类的test函数。

    从这里看出,同样类型的指针,调用同样的函数名,却产生了不同的调用结果,即调用了不同的函数,而且是不同类的函数。我们可以利用这个虚函数重载实现的多态机制,自己定义很多种派生类,然后基类指针指向哪个派生类就调用哪个派生类的对应的函数,而我们的调用的代码始终都是不变的。这就是我们经常利用的虚函数重载多态机制,也就是纵向重载实现的多态。举个实际的应用的例子,如果你要查询研究生、本科生、高中生、初中生、小学生的信息,你只需要定义一个基类,各种学生的类派生于基类,然后在查询的时候,用基类的指针指向不同的学生对象,然后就可以查询不同类别的学生信息。就不用查某种类型的时候定义某种类型的对象指针,现在是用同一个指针搞定所有类型查询。这种应用模型太多了。

    而虚函数重载机制的实现,是借助虚函数表实现的,这里就不介绍了,给你做一个提醒,先自己去查资料学习虚函数表实现虚函数重载的机制,面试经常问到。

    如果有人和你一样对多态概念不理解,请将这个答案告诉他哦。