17_多态

多态

静态多态(编译时多态, 早绑定): 函数重载, 运算符重载, 重定义

动态多态(运行时多态, 晚绑定): 虚函数

虚函数

父类指针 保存 子类空间地址 (带来的问题)

#include <iostream>

using namespace std;

class Animal
{
public:
    void speak()
    {
        cout << "动物在说话" << endl;
    }
};

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

int main()
{
    Animal *p = new Dog;
    p->speak(); //动物在说话
    return 0;
}

其实用户的需求: p->speak希望等到的是"狗在汪汪"而不是"动物在说话"。原因在此:

image-20231007204917852

虚函数的定义

成员函数前jiavirtual修饰

#include <iostream>

using namespace std;

class Animal
{
public:
    //虚函数
    virtual void speak()
    {
        cout << "动物在说话" << endl;
    }
};

class Dog: public Animal
{
public:
    //子类重写 父类的虚函数:函数名, 返回值类型, 参数类型个数顺序 必须完全一致
    void speak() //virtual可加可不加 都是虚函数
    {
        cout << "狗在汪汪" << endl;
    }
};

int main()
{
    Animal *p = new Dog;
    p->speak(); //狗在汪汪
    return 0;
}

多态条件: 有继承, 子类重写父类的虚函数, 父类指针 指向子类空间

虚函数的动态绑定机制

image-20231007205859134

#include <iostream>

using namespace std;

class Animal
{
public:
    //虚函数
    virtual void speak()
    {
        cout << "动物在说话" << endl;
    }
};

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

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

void animalSpeak(Animal *p)
{
    p->speak();
}

int main()
{
    Dog *dog = new Dog;
    Cat *cat = new Cat;
    animalSpeak(dog); //狗在汪汪
    animalSpeak(cat); //猫在喵喵
    return 0;
}

纯虚函数

如果基类一定派生处子类,而子类一定会重写父类的虚函数,那么父类的虚函数中的函数体是无意义,可不可以不写父类虚函数的函数体呢?可以的,那就必须了解纯虚函数。

纯虚函数的定义方式

class Animal
{
public:
    //纯虚函数
    virtual void speak() = 0;
};

1一旦类中有纯虚函数,那么这个类 就是抽象类。

2抽象类不能实例化对象。(Animal ob;错误)

3抽象类 必须被继承 同时 子类 必须重写 父类的所有纯虚函数,否则 子类也是抽象类。

4抽象类主要的目的 是设计 类的接口:

#include <iostream>

using namespace std;

//有纯虚函数的类: 抽象类
class Animal
{
public:
    //纯虚函数
    virtual void speak01() = 0;
    virtual void speak02() = 0;
};

class Dog: public Animal
{
public:
    //子类一定要重写父类所有的纯虚函数
    void speak01()
    {
        cout << "Dog在汪汪" << endl;
    }
    void speak02(){}
};

int main()
{
//    Animal ob; //error 抽象类不能实例化对象
    Dog *dog = new Dog;
    dog->speak01();
    return 0;
}

抽象类主要的目的 是设计 类的接口:

虚函数和纯虚函数的区别

虚函数: virtual修饰 有函数体 不会导致父类为抽象类。

纯虚函数: virtual修饰, =0,没有函数体导致父类为抽象类。子类必须重写父类的所有纯虚函数。

虚析构函数

虚析构函数的定义

virtual修饰析构函数

目的: 通过父类指针 释放子类空间

#include <iostream>

using namespace std;

class Animal
{
public:
    Animal()
    {
        cout << "Animal的无参构造" << endl;
    }
    virtual void speak(){}
    //虚析构
    virtual ~Animal()
    {
        cout << "Animal的析构函数" << endl;
    }
};

class Dog: public Animal
{
public:
    Dog()
    {
        cout << "Dog的无参构造" << endl;
    }
    void speak()
    {
        cout << "Dog在汪汪" << endl;
    }
    ~Dog()
    {
        cout << "Dog的析构函数" << endl;
    }
};

int main()
{
    Animal *dog = new Dog;
    dog->speak();
    //通过父类指针, 释放子类的所有空间
    delete dog;
    return 0;
}

image-20231009142541570

纯虚析构函数的定义

纯虚析构的本质:是析构函数,各个类的回收工作。而且析构函数不能被继承。

必须为纯虚析构函数提供一个函数体。

纯虚析构函数 必须在类外实现.

#include <iostream>

using namespace std;

class Animal
{
public:
    //纯虚函数
    virtual void speak() = 0;

    //纯虚析构函数 必须在类外实现
    virtual ~Animal() = 0;
};

class Dog: public Animal
{
public:
    void speak()
    {
        cout << "狗汪汪" << endl;
    }
    ~Dog()
    {
        cout << "Dog析构函数" << endl;
    }
};

Animal::~Animal()
{
    cout << "Animal的析构函数" << endl;
}

int main()
{
    Animal *p = new Dog;
    p->speak();
    delete p;
    return 0;
}
posted @ 2023-10-11 16:59  爱吃冰激凌的黄某某  阅读(9)  评论(0编辑  收藏  举报