C++面向对象多态的理解

多态与递归类似,不管是书中还是老师授课,都把其讲得神乎其神,让读者一头雾水,莫名其妙。多态实际上非常简单,学习的难点在于在接触多态之前,缺乏一个感性的认识。
多态允许将子类的对象当作基类的对象使用,某基类型的引用指向其子类型的对象,调用的方法是该子类型的方法。这里引用和调用方法在代码编译前就已经决定了,而引用所指向的对象可以在运行期间动态绑定。再举个比较形象的例子:
比如有一个函数是叫某个人来吃饭,函数要求传递的参数是人的对象,可是来了一个美国人,你看到的可能是用刀和叉子在吃饭,而来了一个中国人你看到的可能是用筷子在吃饭,这就体现出了同样是一个方法,可以却产生了不同的形态,这就是多态!

多态的意义:
增加了程序的可拓展性,实现了模块之间的解耦;
1. 应用程序不必为每一个派生类编写功能调用,只需要对抽象基类进行处理即可。大大提高程序的可复用性。//继承
2. 派生类的功能可以被基类的方法或引用变量所调用,这叫向后兼容,可以提高可扩充性和可维护性。 //多态的真正作用,以前需要用switch实现

多态的表现(效果):
一个调用语句可以出现/实现多种形态.
比如,在发生多态时,如果传入参数是一个子对象,那么会调用子对象的成员方法,如果传入参数是一个父对象,那么会调用父对象的成员方法.

C++中多态的实现:
C++中多态的实现需要三个条件.
1. 存在继承关系
2. 虚函数;虚函数对多态的实现是必要的,遇到这个处理过程要等到执行时再确定到底调用哪个类的处理过程;
3. 子类重写基类虚函数,基类指针或引用指向子类对象.

C++面向对象三大特性分别是封装,继承,多态. 
封装 站在类的对象作函数参数的角度思考.当类的对象作为函数的参数进行传递时,参数的颗粒度变大,一次性可以传递多个属性和多个方法,突破了C语言的函数的概念. 
继承 使子类可以使用基类的东西,增加了代码的可复用性. 
多态 使基类对象可以使用子类对象写的代码,实现了解耦和;使之前的代码可以执行后来人写的代码,增加了程序的可拓展性和可维护性.

C++实现多态原理:
C++编译器为含有虚函数的类对象提前布局vptr指针,生成虚函数表;当发生多态时(虚函数调用时),去虚函数表中查找调用地址(函数的入口地址).
如果用面向过程的实现就是在接口中使用typeof判断入参并使用switch语句处理不同的类型;而C++直接使用虚函数就可以实现动态绑定;

多态的分类(Java)
1、编译时多态,即方法的重载,从JVM的角度来讲,这是一种静态分派(static dispatch)
2、运行时多态,即方法的重写,从JVM的角度来讲,这是一种动态分派(dynamic dispatch)

从使用角度看多态无非就是三句话:
比如我们有一个基类Basic并定义了虚方法,有一个子类SubClass也实现了自己的方法;
1、向上转型是自动的。即Basic b = new Children()是自动的,不需要强转;
2、向下转型需要强转。即SubClass s = new Basic()是无法编译通过的,必须要SubClass s = (SubClass)new Basic(),让基类知道它要转成具体哪个子类
3、基类引用指向子类对象,子类重写了基类的方法,在调用基类的方法时,实际调用的是子类重写的基类的该方法。即Basic b = new SubClass(),b.toString()实际上调用的是SubClass中的toString()方法;

多态性往往用于面向对象中抽象和具体类的层次设计中,好处就在于提供系统的弹性,避免代码的僵化。
例如,可以增加一个新的子类而不需要修改原代码,避免程序中的复杂的条件分析语句。也就是面向对象中的“对扩展开放、对修改封闭”的原则。


案例
// 多态
// 多态现象:同一个调用语句 可以有多种形态 扔过来一个子类对象,执行子类的API函数 扔过来一个基类对象,执行基类API函数
// 多态成立的三个条件:继承、基类中定义了虚函数、子类重写基类的虚函数 使用时:基类指针(引用)指向子类对象
// 效果:同样一个调用语句可以有多种形态(多种调用方法)

#include <iostream>
using namespace std;

class BasicClass {
    public:
        BasicClass() { cout << "Basic Class init" <<endl; }
        virtual void work() { cout << "Basic Class working" <<endl; }
        virtual ~BasicClass() { cout << "Basic Class deinit" <<endl; }
};

class SubClass: public BasicClass {
    public:
        SubClass() { cout << "\tSub Class init" <<endl; }
        virtual void work() { cout << "\tSub Class working" <<endl; }
        virtual ~SubClass() { cout << "\tSub Class deinit" <<endl; }
};

class SubSubClass: public SubClass {
    public:
        SubSubClass() { cout << "\t\tSub-Sub Class init" <<endl; }
        virtual void work() { cout << "\t\tSub-Sub Class working" <<endl; }
        ~SubSubClass() { cout << "\t\tSub-Sub Class deinit" <<endl; }
};

/* 当调用how2Work()函数时表现多态性,根据入参不同调用不同的方法 */
/* 如果父类没有声明为virtual即没有实现多态,传入子类对象时就不会调用子类的方法 */
void how2Work(BasicClass *base)
{
    base->work();
}

int main(void)
{
#ifdef CASE1
    BasicClass *person = NULL;
    person = new BasicClass();
    person->work();
    delete person;
    person = NULL;

    person = new SubClass();
    person->work();
    delete person;
    person = NULL;

    person = new SubSubClass();
    person->work();
    delete person;
    person = NULL;
    /* 虽然都是person->work()结果却有不同的表现 */
#else
    /* 多态的使用常见的是下面这种方式 */
    BasicClass p1;
    SubClass c1;
    SubSubClass cc1;

    how2Work(&p1);
    how2Work(&c1);
    how2Work(&cc1);
#endif

    return 0;
}

猜你喜欢

转载自blog.csdn.net/halazi100/article/details/81452465