C++学习笔记之 多态

多态

基本概念

多态性提供接口与具体实现之间的另一层隔离,将“什么”和“怎么做”分开

分类

  • 静态多态(函数地址早绑定)
    • 运算符重载
    • 函数重载
  • 动态多态(函数地址晚绑定)
    • 派生类
    • 虚函数

地址早绑定和地址晚绑定

早绑定

#include <iostream>

using namespace std;

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

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

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

void doSpeak(Animal &a) { // 父类的引用指向子类对象
    a.speak(); // 属于地址早绑定
}

void test01() {
    Dog d;
    doSpeak(d);
    
    Cat c;
    doSpeak(c);
}

int main() {
    test01();

    return EXIT_SUCCESS;
}
动物在说话
动物在说话

此时我们需要地址晚绑定

晚绑定(虚函数)

#include <iostream>

using namespace std;

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

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

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

void doSpeak(Animal &a) {
    a.speak();
}

void test01() {
    Dog d;
    doSpeak(d);

    Cat c;
    doSpeak(c);
}

int main() {
    test01();

    return EXIT_SUCCESS;
}
狗在说话
猫在说话

原理

应用

#include <iostream>

using namespace std;

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

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

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

void doSpeak(Animal &a) {
    a.speak();
}

void test() {
    Animal *animal = new Cat;
    // animal->speak();

    // *(int *)animal 解引用到了虚函数表中
    // *(int *)*(int *)animal 解引用到了函数入口地址
    ((void(*)())(*(int *)*(int *)animal))();
}

int main() {
    test();

    return EXIT_SUCCESS;
}
猫在说话

应用:计算器类

#include <iostream>

using namespace std;

// 开闭原则:对拓展进行开放 对修改进行关闭

class AbstractCalculator
{
public:
    // 虚函数
    virtual int getResult() {
        return 0;
    }
    
    int m_A;
    int m_B;
};

class AddCalculator : public AbstractCalculator
{
public:
    virtual int getResult() {
        return m_A + m_B;
    }
};

class MulCalculator : public AbstractCalculator
{
public:
    virtual int getResult() {
        return m_A * m_B;
    }
};

int main() {
    AbstractCalculator *cal = new AddCalculator;
    cal->m_A = 10;
    cal->m_B = 20;
    cout << cal->getResult() << endl;
    
    delete cal;
    
    cal = new MulCalculator;
    cal->m_A = 10;
    cal->m_B = 20;
    cout << cal->getResult() << endl;
    
    delete cal;

    return EXIT_SUCCESS;
}
30
200

使用多态可以方便拓展和修改

纯虚函数和抽象类

class AbstractCalculator
{
public:
    // 虚函数
//    virtual int getResult() {
//        return 0;
//    }

    // 纯虚函数
    // 当类中有了纯虚函数时,这个类属于抽象类
    // 抽象类无法创建对象
    // 当子类继承了抽象类,那么这个子类必须重写父类中的虚函数,否则子类也是抽象类
    virtual int getResult() = 0;

    int m_A;
    int m_B;
};

虚析构和纯虚析构

#include <iostream>
#include <cstring>

using namespace std;

class Animal
{
public:
    virtual void speak() = 0;

    Animal() {
        cout << "Animal构造函数调用" << endl;
    }

    // 利用虚析构可以解决不调用子虚构的问题
//    virtual ~Animal() {
//        cout << "Animal的析构函数调用" << endl;
//    }

    virtual ~Animal() = 0; // 纯虚析构需要有声明,也需要有实现
};

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

class Cat : public Animal
{
public:
    Cat(char *name) {
        this->m_Name = new char[strlen(name)+1];
        strcpy(this->m_Name,name);
    }

    char *m_Name;

    void speak() {
        cout << "小猫" << this->m_Name << "在说话" << endl;
    }

    ~Cat() {
        if (this->m_Name != nullptr) {
            delete this->m_Name;
            this->m_Name = nullptr;
            cout << "Cat的析构函数调用" << endl;
        }
    }
};

int main() {
    Animal *cat = new Cat("Tom");
    cat->speak();
    delete cat;

    return EXIT_SUCCESS;
}
Animal构造函数调用
小猫Tom在说话
Cat的析构函数调用
Animal的纯虚析构函数调用

类型转换

原文地址:https://www.cnblogs.com/zhujiangyu/p/14091122.html