类与对象--多态

多态的基本语法

多态分为两类
1.静态多态:函数重载和运算符重载属于静态多态,复用函数名。
2.动态多态:派生类和虚函数实现运行时多态。

静态多态和动态多态的区别:
1.静态多态的函数地址早绑定,编译阶段确定函数地址。
2.动态多态的函数地址晚绑定,运行阶段确定函数地址。
下面我们来看:

在这里插入代码片
#include<iostream>
using namespace std;

class Animal
{
public:
     void speak()
    {
        cout<<"Animal在叫"<<endl;
    }

};

class Cat : public Animal
{
public:
    void speak()
    {
        cout<<"Cat在叫"<<endl;
    }
};
void DoSpeak(Animal &animal) //Animal & animal = Cat
{
    animal.speak();
}
void test01()
{
    Cat cat;
    DoSpeak(cat);
}
int main()
{
    test01();
    return 0;
}

结果:
在这里插入图片描述
这里我们本来是想传入cat这个对象的地址,输出“Cat在叫”,但是我们写的是函数地址早绑定,所以无论输入什么类,函数传进去的地址都是Animal的地址。如果我们想让Cat说话,就不能使用函数地址早绑定,要在运行阶段再进行函数地址绑定,也就是晚绑定。

解决方法: 在Animal中的Speak()函数前加上关键字virtual,使其变成虚函数,在这里插入图片描述
下面我们再来看一下结果:
在这里插入图片描述
下面我们再来补充一个Dog类,

在这里插入代码片
#include<iostream>
using namespace std;

class Animal
{
public:
     virtual void speak()
    {
        cout<<"Animal在叫"<<endl;
    }

};

class Cat : public Animal
{
public:
    void speak()
    {
        cout<<"Cat在叫"<<endl;
    }
};
class Dog : public Animal
{
public:
    void speak()
    {
        cout<<"Dog在叫"<<endl;
    }
};

void DoSpeak(Animal &animal) //Animal & animal = Cat
{
    animal.speak();
}
void test01()
{
    Cat cat;
    DoSpeak(cat);
    Dog dog;
    DoSpeak(dog);
}
int main()
{
    test01();
    return 0;
}

结果我们来看:在这里插入图片描述
这里面的这一块代码

在这里插入代码片
void DoSpeak(Animal &animal) //Animal & animal = Cat
{
    animal.speak();
}

我们想传入cat,就传入cat的地址;我们传入dog的地址,就传入dog的地址;这是就体现了多态,传入哪一个对象,就走哪一块代码,没有固定了。

下面我们来总结一下动态多态:
1.首先我们要满足一个继承关系;
2.子类要重写父类的虚函数;
!!!重写:函数的返回值类型、函数的名称、函数的参数列表要完全相同;

动态多态使用:
父类的指针或引用 执行子类对象。
引用:Animal & animal = Cat
Animal *p = new Cat;

多态的原理剖析

在这里插入代码片
class Animal
{
public:
     virtual void speak()
    {
        cout<<"Animal在叫"<<endl;
    }

};

在加上virtual关键字后,父类函数的内部结构就发生了改变,内部相当于多了一个虚函数指针(vfptr)。
v:virtual ; f:function; ptr:pointer;
虚函数指针指向一个虚函数表(vftable),虚函数表内储存着虚函数地址,当子类继承父类后,会将父类的一份数据继承下来,那么虚函数表中同样也是父类虚函数的地址,当我们在子类中进行重写虚函数时,就会使子类虚函数的地址覆盖掉原来父类虚函数的地址。
这就是多态为什么必须要满足继承和重写这两个步骤。

多态的优点

1.代码的组织结构清晰;
2.可读性强;
3.方便前期和后期的拓展以及维护;

纯虚函数和抽象类

在多态中,通常父类中的虚函数式毫无意义的,主要都是调用子类重写的内容,因此可以将虚函数写为纯虚函数。
纯虚函数语法:
virtual 返回值类型 函数名 (参数列表) = 0;
当类中有了纯虚函数,这个类也称为抽象类;

抽象类特点:
1.无法实例化对象;
2.子类必须重写抽象类中的纯虚函数,否则也属于抽象类,子类也无法实例化对象;

下面我们用多态的形式写一个 :制作饮品

在这里插入代码片
#include<iostream>
using namespace std;

class AbstructDrinking
{
public:
    //煮水
    virtual void boil() = 0;
    //冲泡
    virtual void Brew() = 0;
    //倒入杯中
    virtual void Pour() = 0;
    //加入辅料
    virtual void Add() = 0;

    void operation()
    {
        boil();
        Brew();
        Pour();
        Add();
    }
};
class Tea : public AbstructDrinking
{
    //煮水
    virtual void boil() {
        cout<<"煮农夫山泉"<<endl;
    }
    //冲泡
    virtual void Brew() {
        cout<<"冲泡茶叶"<<endl;
    }
    //倒入杯中
    virtual void Pour() {
        cout<<"倒入茶杯中"<<endl;
    }
    //加入辅料
    virtual void Add() {
        cout<<"加入枸杞"<<endl;
    }
};
class Coffee : public AbstructDrinking
{
    //煮水
    virtual void boil() {
        cout<<"煮百岁山"<<endl;
    }
    //冲泡
    virtual void Brew() {
        cout<<"冲泡咖啡"<<endl;
    }
    //倒入杯中
    virtual void Pour() {
        cout<<"倒入玻璃杯中"<<endl;
    }
    //加入辅料
    virtual void Add() {
        cout<<"加入牛奶和糖"<<endl;
    }
};
void DoWork(AbstructDrinking *abc)
{
    abc->operation();
    delete abc;
    abc = NULL;
}
void test01()
{
    DoWork(new Tea);

    cout<<"----------------------------"<<endl;

    DoWork(new Coffee);
}
int main()
{
    test01();
    return 0;
}

感受一下多态带来的好处!!!

虚析构和纯虚析构

多态使用时,如果子类有属性开辟到堆区,那么父类指针在释放时无法调用子类的析构代码;

解决方式:将父类的析构改为虚析构或者纯虚析构;

虚析构和纯虚析构的共性:
1:可以父类指针释放子类对象;
2.都需要有具体的实现;

虚析构和纯虚析构的区别:
如果是纯虚析构,该类也属于抽象类,不能实例化对象;

父类指针在析构时不会调用子类中的析构函数,导致子类如果有堆区属性,出现内存泄漏;
利用虚析构可以解决;

纯虚析构语法:]
类内:声明
virtual ~ 函数名()= 0;

在类外:实现
类名::~函数名()
{
cout<<“纯虚析构的实现”<<endl;
}

✨纯虚析构必须要代码实现,否则就会报错;

如果子类没有堆区属性,可以不写虚析构或纯虚析构;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值