zoukankan      html  css  js  c++  java
  • 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的纯虚析构函数调用
    

    类型转换

  • 相关阅读:
    ASP.NET Core 添加统一模型验证处理机制
    【Spark】开发Spark选择Java还是Scala?
    【设计模式】单例模式-为什么是静态变量
    【Spark】SparkStreaming-如何使用checkpoint
    【Java】Java-ShutDownHook-优雅关闭系统资源
    【Scala】Scala-None-null引发的血案
    【Spark】SparkStreaming-输出到Kafka
    【Spark】Spark-Redis连接池
    【Spark】提交Spark任务-ClassNotFoundException-错误处理
    【大数据】王加林-大数据学习资料
  • 原文地址:https://www.cnblogs.com/zhujiangyu/p/14091122.html
Copyright © 2011-2022 走看看