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 -

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/503027.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

多线程操作时操作系统时间片_从零开始自制操作系统(15):内核多线程

1.多线程原理&#xff1a;&#xff08;1&#xff09;概述&#xff1a;多线程是指CPU可以在一段时间中并行执行多个程序&#xff0c;比如我们可以一边听音乐、一边写代码&#xff08;这两个程序可以“同时进行”&#xff0c;我们称之为多进程&#xff0c;而多进程实现的本质就是…

打开git界面_使用 Gitea 快速搭建私有 Git 版本控制服务

1. 前言分布式版本控制工具 Git 已经是现代软件源代码版本控制首选方案之一。公有 Git 服务提供商 国外知名如 GitHub 国内网络延迟高,Gitlab 涉嫌对中国的歧视不推荐。国内有 Gitee、Coding 生态还不错。但是一般公司的源代码除非开源项目是不会放在公有 Git 服务上的。所以我…

dev项目属性按钮是灰色_Spring Boot 中的项目属性配置

阅读本文约需要5分钟大家好&#xff0c;我是你们的导师&#xff0c;我每天都会在这里给大家分享一些干货内容(当然了&#xff0c;周末也要允许老师休息一下哈)。上次老师跟大家分享了Spring Boot 如何使用 SLF4J 进行日志记录&#xff0c;今天跟大家分享一下 Spring Boot 中的项…

diskgenius扩容c盘重启电脑卡住_电脑开机显示:reboot and select proper boot device怎么办?...

今天就碰到有一个知友问&#xff0c;自己电脑开机就提示&#xff1a;reboot and select proper boot device&#xff0c;整个人都懵了&#xff0c;不知道怎么办?其实对于电脑出现问题&#xff0c;大家不要着急&#xff0c;坚哥就来为大家分析下原因以及试着去解决。第一种原因…

大并发下程序出错_Python并发编程理论篇

前言其实关于Python的并发编程是比较难写的一章&#xff0c;因为涉及到的知识很复杂并且理论偏多&#xff0c;所以在这里我尽量的用一些非常简明的语言来尽可能的将它描述清楚&#xff0c;在学习之前首先要记住一个点&#xff1a; 并发编程永远的宗旨就是提高程序的运行效率&am…

月薪30K程序员花了一个小时,用c++做出经典扫雷游戏 !

上次发过一个俄罗斯方块的游戏源码&#xff0c;由于是通过Easy X实现的&#xff0c;但是很多和我一样的新手&#xff0c;一开始不知道Easy X是什么&#xff0c;到时源码拿过去之后&#xff0c;运行报错&#xff0c;我这次发的扫雷&#xff0c; 也是通过Easy X实现&#xff0c;…

用python写web网页_从零开始,使用python快速开发web站点(1) | 学步园

环境&#xff1a;ubuntu 12.04 python版本: 2.73 ok,首先&#xff0c;既然是从零开始&#xff0c;我们需要的是一台可以运行的python的计算机环境&#xff0c;并且假设你已经安装好了python, 然后&#xff0c;既然是快速开发&#xff0c;必不可少的需要用到框架&#xff0c;py…

修改so_货代、海运操作、船务操作还分不清?船公司SO文件看不懂?

货代是货物代理&#xff08;freight forwarding agent&#xff09;的简称&#xff0c;是指经营受他人委托&#xff0c;为其提供代办运输手续&#xff0c;代提、代发、代运货物服务的业务。货物代理&#xff0c;有些是中间商就是自己没有船或者飞机的或者船公司、航空公司&#…

一行代码蒸发64亿人民币!黑客盯上区块链漏洞!Python真的变态!

此前认为&#xff0c;区块链技术由于分布存储、加密算法等技术的应用&#xff0c;拥有了不可篡改、可追溯等被认为是“万无一失”的特性。然而&#xff0c;该特性主要针对存储在区块中的信息来说&#xff0c;以文中开头的案例为例&#xff0c;区块链技术保障了可以追溯到这64亿…

太吾绘卷第一世攻略_建平中学高二数学周练卷(2020.09)

试卷图片仅供学习交流使用&#xff0c;答案仅供参考【往期内容】高一是坎, 高二是坡, 高三是峰! 最全学习攻略新高一数学教材必修第一册第一章习题答案往年高中9月开学考月考数学试卷汇总2020上海高考复交综评录取率top202020北京大学强基计划数学试题2020上海16区零志愿、名额…

自动补足算法是什么_数据、算法岗的几点经验分享!

learners | 作者Datawhale | 来源目录有哪些好的秋招经验分享&#xff1f;机器学习中常用的最优化方法有哪些&#xff1f;想通过数据竞赛来提升实践能力&#xff0c;作为小白有什么入门经验&#xff1f;(今日问题)有哪些好的秋招经验分享&#xff1f;1李玲 - 携程算法工程师(…

我精心珍藏的Python代码技巧

01.****简洁的表达式 image 点评&#xff1a;Python因为简洁高效而出名&#xff0c;就是因为语法非常简单&#xff0c;而且内置了很多强大的数据结构&#xff1a; 比如我们可以大量用推导列表来生成很多简洁的代码 比如我们可以用if else组合&#xff0c;本来需要2-3行代码写…

python函数和类的区别_Python中类中的方法还有区别?

上一篇&#xff0c;我们讲到Python类中的属性是有区别的&#xff0c;爱思考的小伙伴们可能就会问了&#xff0c;Python中的方法是不是也有区别呢&#xff1f;是的&#xff0c;而且Python中的方法区别更大&#xff0c;让我们来看看吧~ Python类中的三种方法 Python中的方法可以分…

python 获取昨天的日期_利用Python来实现报表的自动发送,解放你时间去做更有意思的事情...

前言在日常工作中你可能因为每天都被各种各样的数据数据报表搞得焦头烂额&#xff0c;老板的&#xff0c;运营的、产品的等等。而且大部分报表都是重复性的工作&#xff0c;这篇文章就是帮助大家如何用Python来实现报表的自动发送&#xff0c;解放你的劳动力&#xff0c;可以让…

大数据 深度 分页_机器学习、深度学习、大数据 ?傻傻分不清楚?

提起机器学习四个字&#xff0c;不知你的脑海中是否会有一丝印象&#xff1f;毕竟身处信息时代&#xff0c;在日常生活中&#xff0c;无论通过什么媒介&#xff0c;接触到这个名词概念的机会还是挺大的。与之类似&#xff0c;还有以下这些名词概念&#xff1a;数据分析、数据挖…

jieba结巴分词--关键词抽取_结巴中文分词原理分析2

作者&#xff1a;白宁超&#xff0c;工学硕士&#xff0c;现工作于四川省计算机研究院&#xff0c;著有《自然语言处理理论与实战》一书&#xff0c;作者公众号&#xff1a;机器学习和自然语言处理(公众号ID&#xff1a;datathinks)结巴分词详解1中文分词介绍中文分词特点词是最…

cad动态块制作翻转_定制橱柜家具中CAD门型动态块制作方式图文讲解加视频

在定制橱柜家具中&#xff0c;我们用CAD我们经常会用一些门型放置到绘图当中&#xff0c;来展示CAD图纸的美观性&#xff0c;如下图&#xff1a;那么这些门型要是一点点画却是麻烦&#xff0c;所以我们可以把门型做成动态快的形式&#xff0c;对门型进行任意拉伸&#xff0c;方…

python json库安装_python怎么安装requests库

requests是python实现的简单易用的HTTP库&#xff0c;使用起来比urllib简洁很多 因为是第三方库&#xff0c;所以使用前需要cmd安装pip install requests 安装完成后import一下&#xff0c;正常则说明可以开始使用了。 基本用法&#xff1a; requests.get()用于请求目标网站&am…

32获取外部中断状态_Linux中断一网打尽(1) — 中断及其初始化

1中断是什么既然叫中断, 那我们首先就会想到这个中断是中断谁&#xff1f;想一想计算机最核心的部分是什么&#xff1f;没错&#xff0c; CPU&#xff0c; 计算机上绝大部分的计算都在CPU中完成&#xff0c;因此这个中断也就是中断CPU当前的运行&#xff0c;让CPU转而先处理这个…

文件夹_【教程】创建透明文件夹(非隐藏文件夹哦)

Hello 今天 不夜君 来教大家如何创建 一个 透明的 文件夹 效果类似这样哦~~是不是什么都看不到呢 大家不要慌 下面来看一下选中后的样子呀~~怎么样 是不是十分的酷炫呢其实这个方法的原理 我也不是很懂 所以就不献丑了 直接附上教程吧&#xff01;&#xff01;当然 有多种实现方…