c++学习——多态
多态
- **多态的语法**
- **多态的底层原理图**
- **多态案1——计算机类**
- **纯虚函数和抽象类**
- **多态案例2——饮品**
- **虚析构和纯虚析构**
- **多态案例3—— 电脑组装**
多态是C++面向对象三大特性之一
多态分为两类
静态多态:函数重载和运算符重载属于静态多态,复用函数名
动态多态:派生类和虚函数实现运行时多态
静态多态和动态多态区别:
静态多态的函数地址早绑定–编译阶段确定函数地址·动态多态的函数地址晚绑定–运行阶段确定函数地址
C++中的多态性通常通过虚函数来实现。虚函数是在基类中声明的,派生类可以重写该函数并提供自己的实现。当通过基类指针或引用调用虚函数时,实际调用的是派生类的实现。这种机制允许在运行时动态地确定要调用哪个函数,从而实现多态性。如果没有虚函数,就无法实现多态性。
多态的语法
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;
//多态//动物类
class Animal
{
public://虚函数virtual void speak(){cout << "动物在说话" << endl;}
};//猫类
class Cat :public Animal
{
public:void speak(){cout << "小猫在说话" << endl;}
};//狗类
class Dog :public Animal
{
public:void speak(){cout << "小狗在说话" << endl;}
};
//执行说话的函数
//c++中父类的引用能够直接指向子类对象
//地址早绑定 在编译阶段确定了函数地址
//如果想执行让猫说话,那么这个函数地址就不能提前绑定,需要在运行阶段进行绑定
//也就是地址晚绑定 //动态多态的满足条件
//1、有继承关系
//2、子类要重写父类的虚函数 //重载和重写的区别
//1、重载:函数的名字相同,参数不同
//2、重写:函数的返回值类型,函数名要相同,参数列表要完全相同//动态多态的使用
//父类的指针或者引用 指向子类对象
void doSpeak(Animal &animal)//Animal &animal=cat
{animal.speak();
}void test01()
{Cat cat;doSpeak(cat);Dog dog;doSpeak(dog);
}int main()
{test01();system("pause");return EXIT_SUCCESS;
}
多态的底层原理图
动态的多态
子类不重写的结构原理图
静态成员函数和非静态成员函数都是存放在代码区的。
是类可以直接调用静态成员函数。不可以直接调用非静态成员函数
因此这里的Size(1)
子类重写后的结构原理图
多态案1——计算机类
案例描述:
分别利用普通写法和多态技术,设计实现两个操作数进行运算的计算器类
多态的优点:
代码组织结构清晰 可读性强
利于前期和后期的扩展以及维护
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <string>
using namespace std;//分别利用普通写法和多态技术实现计算机类//普通写法
class Calculator
{
public:int getResulr(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 test01()
{//创建计算机对象Calculator c;c.m_Num1 = 10;c.m_Num2 = 10;//cout << c.getResulr("+") << endl;cout << c.m_Num1 << " + " << c.m_Num2 << " = " <<c.getResulr("+")<< endl;cout << c.m_Num1 << " - " << c.m_Num2 << " = " << c.getResulr("-") << endl;cout << c.m_Num1 << " * " << c.m_Num2 << " = " << c.getResulr("*") << endl;
}//利用多态来实现计算器
//多态的好处:
//1、组织结构清晰
//2、可读性强
//3、对于前期和后期的拓展和维护性高
//实现计算机抽象类
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 test02()
{//多态的使用条件 这里用的是指针AbstractCalculator *abc = new AbstractCalculator;abc->m_Num1 = 10;abc->m_Num2 = 10;cout << abc->m_Num1 << "+" << abc->m_Num2 << "=" << abc->getResult() << endl;//用完后销毁数据delete abc;//释放的是堆区的数据 但指针的类型没有变化//减法运算abc = new SubCalculator;abc->m_Num1 = 100;abc->m_Num2 = 100;cout << abc->m_Num1 << "-" << abc->m_Num2 << "=" << abc->getResult() << endl;delete abc;//乘法运算abc = new MulCalculator;abc->m_Num1 = 100;abc->m_Num2 = 100;cout << abc->m_Num1 << "*" << abc->m_Num2 << "=" << abc->getResult() << endl;delete abc;
}int main()
{//test01();test02();system("pause");return EXIT_SUCCESS;
}
纯虚函数和抽象类
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;//纯虚函数和抽象类
//只要有一个纯虚函数,这个类称为抽象类
class Base
{
public:virtual void func() = 0;
};class Son :public Base
{
public://子类必须重写父类中的纯虚函数,否则无法实例化//virtual void func() = 0;
};void test01()
{//1、无法实例化对象//Base b; err//new Base; err//2、子类中没有重写父类中的纯虚函数//Son s; err
}int main()
{//test01();system("pause");return EXIT_SUCCESS;
}
多态案例2——饮品
案例描述:
制作饮品的大致流程为:煮水-冲泡-倒入杯中-加入辅料
利用多态技术实现本案例,提供抽象制作饮品基类,提供子类制作咖啡和茶叶
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;//多态案例2 制作饮品
class AbstractDrinking
{
public://煮水virtual void Boil() = 0;//冲泡virtual void Brew() = 0;//倒入杯中virtual void PourInCup() = 0;//加入辅料virtual void PutSomething() = 0;//制作饮品void makeDrink(){Boil();Brew();PourInCup();PutSomething();}
};//制作咖啡
class Coffee :public AbstractDrinking
{//煮水virtual void Boil(){cout << "煮农夫山泉" << endl;}//冲泡virtual void Brew(){cout << "冲泡咖啡" << endl;}//倒入杯中virtual void PourInCup(){cout << "倒入杯中" << endl;}//加入辅料virtual void PutSomething(){cout << "加入精液" << endl;}
};//制作茶叶
class Tea :public AbstractDrinking
{//煮水virtual void Boil(){cout << "煮矿泉水" << endl;}//冲泡virtual void Brew(){cout << "冲泡茶叶" << endl;}//倒入杯中virtual void PourInCup(){cout << "倒入玻璃杯" << endl;}//加入辅料virtual void PutSomething(){cout << "加入尿液" << endl;}
};//制作函数
void doWork(AbstractDrinking * abs)
{abs->makeDrink();delete abs;
}int main()
{//制作咖啡doWork(new Coffee);cout << "----------------------------" << endl;;//制作茶叶doWork(new Tea);system("pause");return EXIT_SUCCESS;
}
虚析构和纯虚析构
这个案例是在子类中有属性开辟到了堆区,因此走子类中的析构代码,如果是多态是走不到的,因此需要加入虚析构或者是纯虚析构,而纯虚析构要有具体的函数实现,不然不能示例化对象,而虚析构是可以实例化对象的,
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <string>
using namespace std;//虚析构和纯虚析构class Animal
{
public:Animal(){cout << "Animal的构造函数调用" << endl;}//虚析构//利用虚析构可以解决 父类指针释放子类对象时不干净的问题//virtual ~Animal()//{// cout << "Animal的析构函数调用" << endl;//}//纯虚析构也能解决问题//无法解析的外部命令是在链接阶段出现的问题//纯虚析构需要有声明也需要实现//有了纯虚析构之后,这个类也属于抽象类,无法实例化对象virtual ~Animal() = 0;//纯虚函数virtual void speak() = 0;
};//纯虚析构的代码实现
Animal::~Animal()
{cout << "纯虚析构函数调用" << endl;
}//猫类
class Cat :public Animal
{
public:Cat(string name){cout << "Cat调用了构造函数" << endl;m_Name = new string(name);}~Cat(){if (m_Name != NULL){cout << "Cat的析构函数调用" << endl;delete m_Name;m_Name = NULL;}}virtual void speak(){cout << *m_Name << "小猫在说话" << endl;}string *m_Name;
};void test01()
{//这里是用父类的指针指向子类对象//父类的指针在析构时候,不会调用子类中的析构函数 //导致了子类中如果又堆区的属性 会出现内存泄露的情况//因此引入了虚析构Animal * animal = new Cat("Tom");animal->speak();delete animal;
}int main()
{test01();system("pause");return EXIT_SUCCESS;
}
总结:
1.虚析构或纯虚析构就是用来解决通过父类指针释放子类对象
2.如果子类中没有堆区数据,可以不写为虚析构或纯虚析构
3.拥有纯虚析构函数的类也属于抽象类
多态案例3—— 电脑组装
案例描述:
电脑主要组成部件为CPU(用于计算),显卡(用于显示),内存条(用于存储)
将每个零件封装出抽象基类,并且提供不同的厂商生产不同的零件,例如Intel厂商和Lenovo厂商创建电脑类提供让电脑工作的函数,并且调用每个零件工作的接口
测试时组装三台不同的电脑进行工作
#include<iostream>
using namespace std;
#include<string>//抽象不同零件类
//抽象计算函数
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 * mem){m_cpu = cpu;//指针接收m_vc = vc;m_mem = mem;}//提供工作的函数void work(){//调用每个零件工作的接口m_cpu->calculate();m_vc->display();m_mem->storage();}//提供析构函数,释放 3个电脑零件~Computer(){if (m_cpu != NULL){delete m_cpu;m_cpu = NULL;}if (m_vc != NULL){delete m_vc;m_vc = NULL;}if (m_mem != NULL){delete m_mem;m_mem = NULL;}}
private:CPU * m_cpu;//CPU的零件指针VideoCard * m_vc;//显卡零件指针Memory * m_mem;//内存零件指针};//具体厂商
//Intel厂商
class IntelCpu :public CPU
{
public:virtual void calculate(){cout << "Intel的CPU开始计算了!" << endl;}
};class IntelVideoCard :public VideoCard
{
public:virtual void display(){cout << "Intel的VideoCard开始显示了!" << endl;}
};class IntelMemory :public Memory
{
public:virtual void storage(){cout << "Intel的Memory开始存储了!" << endl;}
};//Lenovo厂商
class LenovoCpu :public CPU
{
public:virtual void calculate(){cout << "Lenovo的CPU开始计算了!" << endl;}
};class LenovoVideoCard :public VideoCard
{
public:virtual void display(){cout << "Lenovo的VideoCard开始显示了!" << endl;}
};class LenovoMemory :public Memory
{
public:virtual void storage(){cout << "Lenovo的Memory开始存储了!" << endl;}
};void test01()
{//第一台电脑CPU * intelCpu = new IntelCpu;//父类指向子类对象,//需释放VideoCard * intelVCard = new IntelVideoCard;//需释放Memory * intelMem = new IntelMemory;//需释放,//1.直接delete 在 delete computer1; 后//2.提供析构函数在 class Computer 中//创建第一台电脑Computer * computer1 = new Computer(intelCpu, intelVCard, intelMem);//需释放computer1->work();delete computer1;cout << "-----------------------------" << endl;cout << "第二台电脑开始工作" << 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()
{test01();system("pause");return 0;
}
相关文章:

c++学习——多态
多态 **多态的语法****多态的底层原理图****多态案1——计算机类****纯虚函数和抽象类****多态案例2——饮品****虚析构和纯虚析构****多态案例3—— 电脑组装** 多态是C面向对象三大特性之一 多态分为两类 静态多态:函数重载和运算符重载属于静态多态,复用函数名 动…...
Java SPI机制及原理详解
前言 Java SPI (Service Provider Interface) 是一种重要的组件化方式,它可以让程序在运行时动态地装载一些实现模块,从而增强程序的可扩展性和灵活性。本文将详细介绍 Java SPI 的基本概念、原理以及使用方法。 1. 什么是Java SPI Java SPI 是一种标准…...

不压缩打包layui
手动打包 下载layui源码(当前版本2.6.4),并解压缩 下载地址:layui gitee 安装nodejs(v10.24.1) 下载链接 windows-x64 安装cnpm npm install -g cnpm -registryhttps://registry.npm.taobao.org全局安…...
过去、现在及未来
人生最邪恶的地方在于,只能年轻一次 回顾下我毫无规划的,且已经消耗掉的青春 一:过去 19岁,进入大学,兼职、玩儿、暧昧 20-21岁,初创软件公司打杂、恋爱、暧昧 22、23、24岁,上海ÿ…...

leetcode701. 二叉搜索树中的插入操作(java)
二叉搜索树中的插入操作 leetcode701. 二叉搜索树中的插入操作题目描述 递归解题解题思路代码演示 二叉树专题 leetcode701. 二叉搜索树中的插入操作 原题链接: 来源:力扣(LeetCode) 链接:https://leetcode.cn/problem…...
Docker的容器管理操作
1、创建容器 容器创建:就是将镜像加载到容器的过程。 创建容器时如果没有指定容器名称,系统会自动创建一个名称。 新创建的容器默认处于停止状态,不运行任何程序,需要在其中发起一个进程来启动容器。 docker create创建的容器…...

计算机组成原理——中央处理器
文章目录 **一 CPU的功能和基本结构****1 CPU的功能****2 [基本结构](http://t.csdn.cn/bpCt3)****2.1 运算器****2.2 控制器** **二 指令执行过程****1 指令周期****2 指令周期的数据流****2.1 取指周期****2.2 间址周期****2.3 执行周期****2.4 中断周期** **3 指令的执行方案…...
tidb变更大小写敏感问题的总结
作者: sustyle 原文来源: https://tidb.net/blog/2a72bc13 1 背景 近期,我们线上的tidb集群就遇到一个变更忽略大小写的需求,本来以为一个改表工单就解决了,但是业务反馈工单完成后,大小写仍旧敏感&…...

法规标准-UN R158标准解读
UN R158是做什么的? UN R158全名为针对驾驶员识别车辆后方弱势道路使用者,联合国对倒车系统和机动车的统一规定,该法规涉及批准倒车和机动车辆的装置,主要为保证倒车时避免碰撞,方便驾驶员观察了解车辆后部人员和物体…...

160个CrackMe之002
这道题就很简单 有了第一道题目的支持 我们就能做 首先 我们先要下载Msvbvm50.dll Msvbvm50.dll下载_Msvbvm50.dll最新版下载[修复系统丢失文件]-下载之家 然后我们可以运行程序了 比之前那个还简单 就是输入 然后比对 报错或者成功 开始逆向分析 先去常量中进行查找 找…...

3. 响应状态码及Response对象的status_code属性
3. 响应状态码及Response对象的status_code属性 文章目录 3. 响应状态码及Response对象的status_code属性1. 响应状态码2. 响应状态码共分为5种类型2.1 1xx(临时响应)2.2 2xx (成功)2.3 3xx (重定向)2.4 4x…...
MIME 类型列表 03
看表~按照内容类型排列的 MIME 类型列表 类型/子类型扩展名application/envoyevyapplication/fractalsfifapplication/futuresplashsplapplication/htahtaapplication/internet-property-streamacxapplication/mac-binhex40hqxapplication/msworddocapplication/msworddotappl…...

SpringBoot项目登录并接入MFA二次认证
MFA多因素认证(Multi-Factor Authentication ): 一些需要身份认证的服务(如网站),为了提升安全性,通常会在账号密码登录成功后,要求用户进行第二种身份认证,以确保是正确用户登录,避…...

算法与数据结构(三)
一、堆 1,堆结构就是用数组实现的完全二叉树结构 根节点的左孩子的下标为:2i1,右孩子为2i2。两个孩子的父节点为(i-1)/2向下取整 2,完全二叉树中如果每棵子树的最大值都在顶部就是大根堆 从下往上将孩子与父节点进行比较,如果子叶…...

亚马逊云科技出海日,让数字经济出海扩展到更多行业和领域
数字化浪潮之下,中国企业的全球化步伐明显提速。从“借帆出海”到“生而全球化”,中国企业实现了从传统制造业“中国产品”出口,向创新“中国技术”和先导“中国品牌”的逐步升级。 作为全球云计算的开创者与引领者,亚马逊云科技…...

Pb协议的接口测试
【摘要】 Protocol Buffers 是谷歌开源的序列化与反序列化框架。它与语言无关、平台无关、具有可扩展的机制。用于序列化结构化数据,此工具对标 XML ,支持自动编码,解码。比 XML 性能好,且数据易于解析。更多有关工具的介绍可参考…...

2. 分布式文件系统 HDFS
2. 分布式文件系统 HDFS 1. 引入HDFS【面试点】 问题一:如果一个文件中有 10 个数值,一行一个,并且都可以用 int 来度量。现在求 10 个数值的和 思路: 逐行读取文件的内容把读取到的内容转换成 int 类型把转换后的数据进行相加…...
借助金融科技差异化发展,不一样的“破茧”手法
撰稿 | 多客 来源 | 贝多财经 民营银行的诞生顺应了普惠金融的要求,承担着支持民营经济、服务小微的历史使命。经过近年来的发展,19家民营银行形成了特色化、差异化的发展模式,并用各自本领实践普惠金融的初心。 本文从多家民营银行在核心技…...
typescript中type、interface的区别
一、概念定义 interface:接口 在TS 中主要用于定义【对象类型】,可以对【对象】的形状进行描述。type :类型别名 为类型创建一个新名称,它并不是一个类型,只是一个别名。 二,区别 interface: …...

Ingress详解
Ingress Service对集群外暴露端口两种方式,这两种方式都有一定的缺点: NodePort :会占用集群集群端口,当集群服务变多时,缺点明显LoadBalancer:每个Service都需要一个LB,并且需要k8s之外设备支…...

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)
题目:3442. 奇偶频次间的最大差值 I 思路 :哈希,时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况,哈希表这里用数组即可实现。 C版本: class Solution { public:int maxDifference(string s) {int a[26]…...
Linux链表操作全解析
Linux C语言链表深度解析与实战技巧 一、链表基础概念与内核链表优势1.1 为什么使用链表?1.2 Linux 内核链表与用户态链表的区别 二、内核链表结构与宏解析常用宏/函数 三、内核链表的优点四、用户态链表示例五、双向循环链表在内核中的实现优势5.1 插入效率5.2 安全…...
利用ngx_stream_return_module构建简易 TCP/UDP 响应网关
一、模块概述 ngx_stream_return_module 提供了一个极简的指令: return <value>;在收到客户端连接后,立即将 <value> 写回并关闭连接。<value> 支持内嵌文本和内置变量(如 $time_iso8601、$remote_addr 等)&a…...

Xshell远程连接Kali(默认 | 私钥)Note版
前言:xshell远程连接,私钥连接和常规默认连接 任务一 开启ssh服务 service ssh status //查看ssh服务状态 service ssh start //开启ssh服务 update-rc.d ssh enable //开启自启动ssh服务 任务二 修改配置文件 vi /etc/ssh/ssh_config //第一…...
FastAPI 教程:从入门到实践
FastAPI 是一个现代、快速(高性能)的 Web 框架,用于构建 API,支持 Python 3.6。它基于标准 Python 类型提示,易于学习且功能强大。以下是一个完整的 FastAPI 入门教程,涵盖从环境搭建到创建并运行一个简单的…...

深入理解JavaScript设计模式之单例模式
目录 什么是单例模式为什么需要单例模式常见应用场景包括 单例模式实现透明单例模式实现不透明单例模式用代理实现单例模式javaScript中的单例模式使用命名空间使用闭包封装私有变量 惰性单例通用的惰性单例 结语 什么是单例模式 单例模式(Singleton Pattern&#…...

Java面试专项一-准备篇
一、企业简历筛选规则 一般企业的简历筛选流程:首先由HR先筛选一部分简历后,在将简历给到对应的项目负责人后再进行下一步的操作。 HR如何筛选简历 例如:Boss直聘(招聘方平台) 直接按照条件进行筛选 例如:…...

项目部署到Linux上时遇到的错误(Redis,MySQL,无法正确连接,地址占用问题)
Redis无法正确连接 在运行jar包时出现了这样的错误 查询得知问题核心在于Redis连接失败,具体原因是客户端发送了密码认证请求,但Redis服务器未设置密码 1.为Redis设置密码(匹配客户端配置) 步骤: 1).修…...
重启Eureka集群中的节点,对已经注册的服务有什么影响
先看答案,如果正确地操作,重启Eureka集群中的节点,对已经注册的服务影响非常小,甚至可以做到无感知。 但如果操作不当,可能会引发短暂的服务发现问题。 下面我们从Eureka的核心工作原理来详细分析这个问题。 Eureka的…...

实战三:开发网页端界面完成黑白视频转为彩色视频
一、需求描述 设计一个简单的视频上色应用,用户可以通过网页界面上传黑白视频,系统会自动将其转换为彩色视频。整个过程对用户来说非常简单直观,不需要了解技术细节。 效果图 二、实现思路 总体思路: 用户通过Gradio界面上…...