c++ 多态 运行时多态和编译时多态_C++核心编程 第十一节 多态

前言:多态是C++面向对象三大特性之一。

5e68f8da75f447dec4a324201f2ae4df.png

多态,指的是一个类实例的相同方法在不同情形有不同表现形式。具有不同内部结构的对象可以共享外部接口。C++多态就是用一个更通用的基类指针指向不同的子类实例,为了能调用正确的方法,我们需要用到虚函数和虚继承。

#include using namespace std;class Animal{public:    // Speak函数就是虚函数    // 函数前面加上 virtual 关键字变成虚函数,那么编译器在编译的时候就不能确定函数的调用了    virtual void speak(){        cout << "动物在说话" << endl;    }};class Cat : public Animal{public:    void speak(){ cout << "小猫在说话" << endl; }};class Dog : public Animal{public:    void speak(){ cout << "小狗在说话" << endl; }};// 希望传入什么对象,那么就调用什么对象的函数// 如果函数地址在编译阶段就能确定,那么静态联编// 如果函数地址在运行阶段才能确定,就是动态联编void DoSpeak(Animal & animal){ animal.speak(); }// 多态满足条件:// 1、有继承关系// 2、子类重写父类中的虚函数// 多态使用:// 父类指针或引用指向子类对象void test(){    Cat cat;    DoSpeak(cat);    Dog dog;    DoSpeak(dog);}int main(){    test();    return 0;}

多态案例——计算器类

案例描述:分别利用普通写法和多态技术,设计实现两个操作数进行运算的计算器类。

#include#includeusing namespace std;class Calculator{public:    int getResult(string oper){        if(oper == "+"){ return m_Num1 + m_Num2; }        else if(oper == "-"){ return m_Num1 - m_Num2; }        else if (oper == "*"){ return m_Num1 * m_Num2; }        // 如果要提供新的运算,需要修改源码    }    int m_Num1;    int m_Num2;};void test(){    // 普通实现测试    Calculator c;    c.m_Num1 = 10;    c.m_Num2 = 20;    cout << c.m_Num1 << " + " << c.m_Num2 << " = " << c.m_Num1 + c.m_Num2 << endl;    cout << c.m_Num1 << " - " << c.m_Num2 << " = " << c.m_Num1 - c.m_Num2 << endl;    cout << c.m_Num1 << " * " << c.m_Num2 << " = " << c.m_Num1 * c.m_Num2 << endl;}// 多态实现// 抽象计算器类// 多态优点:代码组织结构清晰,可读性强,利于前期和后期的扩展以及维护class AbstractCalculator{public:    virtual int getResult(){ return 0;}    int m_Num1;    int m_Num2;};// 加法计算器class AddCalculator : public AbstractCalculator{public:    int getResult(){ return m_Num1 + m_Num2; }};// 减法计算器class SubCalculator : public AbstractCalculator{public:    int getResult(){ return m_Num1 - m_Num2; }};// 乘法计算器class MulCalculator : public AbstractCalculator{public:    int getResult(){ return m_Num1 * m_Num2; }};void test2(){    // 创建加法计算器    AbstractCalculator *abc = new AddCalculator;    abc->m_Num1 = 10;    abc->m_Num2 = 20;    cout << abc->m_Num1 << " + " << abc->m_Num2 << " = " << abc->getResult() << endl;    delete abc; // 用完了销毁    // 创建减法计算器    abc = new SubCalculator;    abc->m_Num1 = 10;    abc->m_Num2 = 20;    cout << abc->m_Num1 << " - " << abc->m_Num2 << " = " << abc->getResult() << endl;    delete abc;    // 创建乘法计算器    abc = new MulCalculator;    abc->m_Num1 = 10;    abc->m_Num2 = 20;    cout << abc->m_Num1 << " * " << abc->m_Num2 << " = " << abc->getResult() << endl;    delete abc;}int main(){    test();    test2();    return 0;}

总结:C++开发提倡利用多态设计程序架构,因为多态优点很多。

纯虚函数和抽象类

在多态中,通常父类中虚函数的实现没有意义,主要都是调用子类重写的内容。因此可以将虚函数改为纯虚函数。

#includeusing namespace std;class Base{public:    // 纯虚函数    // 类中只要有一个纯虚函数就称为抽象类    // 抽象类无法实例化对象    // 子类必须重写父类中的纯虚函数,否则也属于抽象类    virtual void func() = 0;};class Son : public Base{public:    virtual void func(){ cout << "func调用" << endl; }};void test(){    Base * base = NULL;//    base = new Base; // 抽象类无法实例化对象    base = new Son;    base->func();    delete base;}int main(){    test();    return 0;}

多态案例二—制作饮品

案例描述:制作饮品的大致流程为:煮水 - 冲泡 - 倒入杯中 - 加入辅料

利用多态技术实现本案例,提供抽象制作饮品基类,提供子类制作茶水和咖啡。

#includeusing namespace std;class AbstractDringking{public:    // 烧水    virtual void Boil() = 0;    // 冲泡    virtual void Brew() = 0;    // 倒入杯中    virtual void PourInCup() = 0;    // 加入辅料    virtual void PutSomething() = 0;    // 规定流程    void MakeDrink(){        Boil();        Brew();        PourInCup();        PutSomething();    }};// 制作茶水class Tea : public AbstractDringking{public:    void Boil(){ cout << "煮农夫山泉" << endl; }    void Brew(){ cout << "冲泡茶叶" << endl; }    void PourInCup(){ cout << "将茶水倒入杯中" << endl; }    void PutSomething(){ cout << "加入枸杞" << endl; }};// 制作咖啡class Coffee : public AbstractDringking{public:    void Boil(){ cout << "煮纯净水" << endl; }    void Brew(){ cout << "冲泡咖啡" << endl; }    void PourInCup(){ cout << "将咖啡倒入杯中" << endl; }    void PutSomething(){ cout << "加入牛奶" << endl; }};// 业务函数void Dowork(AbstractDringking* drink){    drink->MakeDrink();    delete drink;}void test(){    Dowork(new Tea);    cout << "----------------------" << endl;    Dowork(new Coffee);}int main(){    test();    return 0;}

虚析构和纯虚析构

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

解决方式:将父类中的析构函数改为虚析构或者纯虚析构。

#includeusing namespace std;class Animal{public:    Animal(){ cout << "Animal构造函数" << endl; }    virtual void Speak() = 0;    // 析构函数加上virtual关键字,变成虚析构函数//    virtual ~Animal(){//        cout << "Animal虚析构函数" << endl;//    }    virtual ~Animal() = 0;};Animal::~Animal() { cout << "Animal 纯虚析构函数" << endl; }// 和包含普通纯虚函数的类一样,包含类普通纯虚析构函数的类也是一个抽象类。不能够被实例化。class Cat : public Animal{public:    Cat(string name){         cout << "Cat构造函数" << endl;        m_Name = new string(name);    }    virtual void Speak(){        cout << *m_Name << "小猫在说话" << endl;    }    ~Cat(){        cout << "Cat析构函数" << endl;        if(this->m_Name != NULL)            delete m_Name;        m_Name = NULL;    }    string *m_Name;};void test(){    Animal *animal = new Cat("Tom");    animal->Speak();    // 通过父类指针去释放,会导致子类对象可能清理不干净,造成内存泄露    // 怎么解决?给基类增加一个虚析构函数    // 虚析构函数就是用来解决父类指针释放子类对象    delete animal;}int main(){    test();    return 0;}

总结:

1、虚析构或纯虚析构就是用来解决通过父类指针释放子类对象

2、如果子类中没有堆区数据,可以不写为虚析构或纯虚析构

3、拥有纯虚析构函数的类也属于抽象类

多态案例三 - 电脑组装

案例描述:电脑主要组成部件为CPU(用于计算),显卡(用于显示),内存条(用于存储)

将每个零件封装出抽象基类,并且提供不同的厂商生产不同的零件,例如Intel厂商和Lenovo厂商。

创建电脑类提供让电脑工作的函数,并且调用每个零件工作的接口。

#includeusing namespace std;// 抽象CPU类class CPU{public:    // 抽象的计算函数    virtual void calculate() = 0;};// 抽象显卡类class VideoCard{public:    virtual void display() = 0;};// 抽象内存条类class Memory{public:    virtual void storage() = 0;};class Computer{public:    Computer(CPU * cpu, VideoCard * vc, Memory * men){        m_cpu = cpu;        m_vc = vc;        m_men = men;    }    // 提供工作的函数    void work(){        // 让零件工作起来,调用接口        m_cpu->calculate();        m_vc->display();        m_men->storage();    }    // 提供析构函数,释放三个电脑零件    ~Computer(){        if(m_cpu != NULL){            delete m_cpu;            m_cpu = NULL;        }        if(m_vc != NULL){            delete m_vc;            m_vc = NULL;        }        if(m_men != NULL){            delete m_men;            m_men = NULL;        }    }private:    CPU * m_cpu;    VideoCard * m_vc;    Memory * m_men;};// 具体厂商// Intel厂商class IntelCPU : public CPU{public:    virtual void calculate(){ cout << "Intel的CPU开始计算" << endl; }};class IntelVideoCard : public VideoCard{public:    virtual void display(){ cout << "Intel的显卡开始显示了" << endl; }};class IntelMemory : public Memory{public:    virtual void storage() { cout << "Intel的内存条开始存储了" << endl; }};// Lenovo厂商class LenovoCPU : public CPU{public:    virtual void calculate(){ cout << "Lenovo的CPU开始计算" << endl; }};class LenovoVideoCard : public VideoCard{public:    virtual void display(){ cout << "Lenovo的显卡开始显示了" << endl; }};class LenovoMemory : public Memory{public:    virtual void storage(){ cout << "Lenovo的内存条开始存储了" << endl; }};void test(){    // 第一条电脑零件    CPU * intelCpu = new IntelCPU;    VideoCard * intelCard = new IntelVideoCard;    Memory * intelMem = new IntelMemory;    cout << "Intel零件组装电脑开始工作:" << endl;    // 创建第一台电脑    Computer * computer1 = new Computer(intelCpu, intelCard, intelMem);    computer1->work();    delete computer1;    cout << "------------------------" << endl;    cout << "Lenovo零件组装电脑开始工作:" << endl;    // 组装第二台电脑    Computer * computer2 = new Computer(new LenovoCPU, new LenovoVideoCard, new LenovoMemory);    computer2->work();    delete computer2;    cout << "------------------------" << endl;    cout << "混装零件电脑开始工作:" << endl;    Computer * computer3 = new Computer(new LenovoCPU, new IntelVideoCard, new LenovoMemory);    computer3->work();    delete computer3;}int main(){    test();    return 0;}

                        - END -

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值