多态 进阶

1、虚析构

在这里插入图片描述
一份耕耘,份收获,努力越大,收获越多。

1.1、知识点的引入

class Animal{
public:
    //虚函数 本质函数指针 不涉及继承时 指向自身函数(sleep)
    virtual void sleep(void)
    {
        cout<<"动物在睡觉"<<endl;
    }
    Animal()
    {
        cout<<"animal构造"<<endl;
    }
    ~Animal()
    {
        cout<<"animal析构"<<endl;
    }
};

class Cat:public Animal{
public:
    //虚函数 设计到继承 指针子类的sleep
    virtual void sleep(void)
    {
        cout<<"小猫在睡觉!!喵喵"<<endl;
    }
    Cat()
    {
        cout<<"Cat的构造"<<endl;
    }
    ~Cat()
    {
        cout<<"Cat的析构"<<endl;
    }
};
void test01()
{
    //通过基类  指针、引用 访问子类的成员函数
    Animal *p = new Cat;
    p->sleep();//调用的子类的sleep

    //出现的问题:只能释放 父类析构
    delete p;
}

运行结果:
在这里插入图片描述
原因分析:
在这里插入图片描述

1.2、解决上面的问题 虚析构 (虚函数)

虚析构作用:通过基类指针、引用 释放 子类的所有空间。
虚析构:在虚析构函数前 加virtual修饰

class Animal{
public:
    //虚函数 本质函数指针 不涉及继承时 指向自身函数(sleep)
    virtual void sleep(void)
    {
        cout<<"动物在睡觉"<<endl;
    }
    Animal()
    {
        cout<<"animal构造"<<endl;
    }

    //虚析构
    virtual ~Animal()
    {
        cout<<"animal析构"<<endl;
    }
};

class Cat:public Animal{
public:
    //虚函数 设计到继承 指针子类的sleep
    virtual void sleep(void)
    {
        cout<<"小猫在睡觉!!喵喵"<<endl;
    }
    Cat()
    {
        cout<<"Cat的构造"<<endl;
    }
    virtual ~Cat()
    {
        cout<<"Cat的析构"<<endl;
    }
};
void test01()
{
    //通过基类  指针、引用 访问子类的成员函数
    Animal *p = new Cat;
    p->sleep();//调用的子类的sleep

    //如果设置成了 虚析构 就可以释放 子类以及父类的构造函数
    delete p;
}

运行结果:
在这里插入图片描述
原理分析:
在这里插入图片描述

2、纯虚函数 和抽象类

纯虚函数格式:virtual void sleep(void) = 0;
  • 如果一个类中拥有 纯虚函数 那么这个类 就是抽象类
    抽象类 不能实例化对象。
void test02()
{
    //Animal 抽象类 不能实例化 一个对象
    //Animal ob;//err

}

2.1、抽象类 派生出 子类,那么在子类必须实现所有的纯虚函数

如果 漏掉一个 那个子类也是抽象

class Animal{
public:
    //纯虚函数
    //如果一个类中拥有 纯虚函数 那么这个类 就是抽象类
    //抽象类 不能实例化对象
    virtual void sleep(void) = 0;

    Animal()
    {
        cout<<"animal构造"<<endl;
    }

    //虚析构
    virtual ~Animal()
    {
        cout<<"animal析构"<<endl;
    }
};

class Cat:public Animal{
public:
#if 1
    //在子类中  必须实现 基类的纯虚函数
    virtual void sleep(void)
    {
        cout<<"小猫在睡觉!!喵喵"<<endl;
    }
#endif
    Cat()
    {
        cout<<"Cat的构造"<<endl;
    }
    virtual~Cat()
    {
        cout<<"Cat的析构"<<endl;
    }
};

void test01()
{
    Animal *p = new Cat;
    p->sleep();
    delete p;
}

案例:饮料制作

在这里插入图片描述

//抽象类  提供一个固定的流程 接口
class AbstractDrinking{
public:
    //烧水
    virtual void Boil() = 0;
    //冲泡
    virtual void Brew() = 0;
    //倒入杯中
    virtual void PourInCup() = 0;
    //加入辅料
    virtual void PutSomething() = 0;
    //规定流程
    void MakeDrink(){
        Boil();
        Brew();
        PourInCup();
        PutSomething();
    }
};
//制作咖啡
class Coffee : public AbstractDrinking{
public:
    //烧水
    virtual void Boil(){
        cout << "煮农夫山泉!" << endl;
    }
    //冲泡
    virtual void Brew(){
        cout << "冲泡咖啡!" << endl;
    }
    //倒入杯中
    virtual void PourInCup(){
        cout << "将咖啡倒入杯中!" << endl;
    }
    //加入辅料
    virtual void PutSomething(){
        cout << "加入牛奶!" << endl;
    }
};

//制作茶水
class Tea : public AbstractDrinking{
public:
    //烧水
    virtual void Boil(){
        cout << "煮自来水!" << endl;
    }
    //冲泡
    virtual void Brew(){
        cout << "冲泡茶叶!" << endl;
    }
    //倒入杯中
    virtual void PourInCup(){
        cout << "将茶水倒入杯中!" << endl;
    }
    //加入辅料
    virtual void PutSomething(){
        cout << "加入食盐!" << endl;
    }
};
//业务函数
void DoBussiness(AbstractDrinking* drink){
    drink->MakeDrink();
    delete drink;
}

void test01()
{
    //制作 咖啡
    DoBussiness(new Coffee);

    //制作 茶水
    DoBussiness(new Tea);
}

运行结果:
在这里插入图片描述

3、纯虚析构

纯虚函数:不需要实现函数体

//纯虚析构函数
class B{
public:
    1virtual修饰  加上=0
    virtual ~B() = 0;
};
//2、必须实现  析构函数的函数体
B::~B(){}

原因:通过基类指针 释放子类对象时 先调用子类析构 再父类析构
(如果父类的析构不实现,无法实现调用)
class Base
{
public:
    //纯虚析构函数
    virtual ~Base()=0;
};
Base::~Base()
{
    
}
int main(int argc, char *argv[])
{
    //Base ob;//不能实例化对象
    return 0;
}

4、虚函数 纯虚函数 虚析构 纯虚析构(重要)

4.1、虚函数:只是virtual修饰有函数体 (作用于成员函数)

目的:通过基类指针或引用 操作 子类的方法

class Base
{
public:
    virtual my_fun(void)
    {
        //有函数体;
    }
}

4.2、纯虚函数:virtual修饰 加=0 没有函数 所在的类为抽象类

目的:为子类提供固定的流程和接口

class Base
{
public:
    virtual my_fun(void)=0;
}

4.3、虚析构:virtual修饰 类中的析构函数

目的:为了解决基类的指针指向派生类对象,并用基类的指针删除派生类对 象

class Base
{
public:
    virtual ~Base()
    {}
}

4.4、纯虚析构:virtual修饰 加=0 必须实现析构的函数体

目的:用基类的指针删除派生类对象、同时提供固定接口

class Base
{
public:
    virtual ~Base()=0;
}
Base::~Base()
{函数体}

5、重写 重载 重定义(了解)

5.1、重载

同一作用域的同名函数、参数个数,参数顺序,参数类型不同
和函数返回值,没有关系
const也可以作为重载条件 //do(const Teacher& t){} do(Teacher& t)
int fun(int a){}
int fun(int b,int c){}
int fun(char b,int c){}

5.2、重定义(隐藏)

有继承
子类(派生类)重新定义父类(基类)的同名成员(非virtual函数)
class Base{
public:
    void fun(int){}
    void fun(int,int){}        
}
class Son:public Base{
public:
    void fun(参数可以不同){}//重定义
}

5.3、重写(覆盖)

有继承
子类(派生类)重写父类(基类)的virtual函数
函数返回值,函数名字,函数参数,必须和基类中的虚函数一致
class Base{
public:
    virtual void fun(int){}
           
}
class Son:public Base{
public:
    virtual void fun(int){}//重写
}
发布了52 篇原创文章 · 获赞 42 · 访问量 4924

猜你喜欢

转载自blog.csdn.net/weixin_43288201/article/details/105127014
今日推荐