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之外设备支…...

docker详细操作--未完待续
docker介绍 docker官网: Docker:加速容器应用程序开发 harbor官网:Harbor - Harbor 中文 使用docker加速器: Docker镜像极速下载服务 - 毫秒镜像 是什么 Docker 是一种开源的容器化平台,用于将应用程序及其依赖项(如库、运行时环…...
day52 ResNet18 CBAM
在深度学习的旅程中,我们不断探索如何提升模型的性能。今天,我将分享我在 ResNet18 模型中插入 CBAM(Convolutional Block Attention Module)模块,并采用分阶段微调策略的实践过程。通过这个过程,我不仅提升…...

全球首个30米分辨率湿地数据集(2000—2022)
数据简介 今天我们分享的数据是全球30米分辨率湿地数据集,包含8种湿地亚类,该数据以0.5X0.5的瓦片存储,我们整理了所有属于中国的瓦片名称与其对应省份,方便大家研究使用。 该数据集作为全球首个30米分辨率、覆盖2000–2022年时间…...
【论文笔记】若干矿井粉尘检测算法概述
总的来说,传统机器学习、传统机器学习与深度学习的结合、LSTM等算法所需要的数据集来源于矿井传感器测量的粉尘浓度,通过建立回归模型来预测未来矿井的粉尘浓度。传统机器学习算法性能易受数据中极端值的影响。YOLO等计算机视觉算法所需要的数据集来源于…...
C++八股 —— 单例模式
文章目录 1. 基本概念2. 设计要点3. 实现方式4. 详解懒汉模式 1. 基本概念 线程安全(Thread Safety) 线程安全是指在多线程环境下,某个函数、类或代码片段能够被多个线程同时调用时,仍能保证数据的一致性和逻辑的正确性…...

3-11单元格区域边界定位(End属性)学习笔记
返回一个Range 对象,只读。该对象代表包含源区域的区域上端下端左端右端的最后一个单元格。等同于按键 End 向上键(End(xlUp))、End向下键(End(xlDown))、End向左键(End(xlToLeft)End向右键(End(xlToRight)) 注意:它移动的位置必须是相连的有内容的单元格…...
Fabric V2.5 通用溯源系统——增加图片上传与下载功能
fabric-trace项目在发布一年后,部署量已突破1000次,为支持更多场景,现新增支持图片信息上链,本文对图片上传、下载功能代码进行梳理,包含智能合约、后端、前端部分。 一、智能合约修改 为了增加图片信息上链溯源,需要对底层数据结构进行修改,在此对智能合约中的农产品数…...

RSS 2025|从说明书学习复杂机器人操作任务:NUS邵林团队提出全新机器人装配技能学习框架Manual2Skill
视觉语言模型(Vision-Language Models, VLMs),为真实环境中的机器人操作任务提供了极具潜力的解决方案。 尽管 VLMs 取得了显著进展,机器人仍难以胜任复杂的长时程任务(如家具装配),主要受限于人…...
Go语言多线程问题
打印零与奇偶数(leetcode 1116) 方法1:使用互斥锁和条件变量 package mainimport ("fmt""sync" )type ZeroEvenOdd struct {n intzeroMutex sync.MutexevenMutex sync.MutexoddMutex sync.Mutexcurrent int…...
MySQL 索引底层结构揭秘:B-Tree 与 B+Tree 的区别与应用
文章目录 一、背景知识:什么是 B-Tree 和 BTree? B-Tree(平衡多路查找树) BTree(B-Tree 的变种) 二、结构对比:一张图看懂 三、为什么 MySQL InnoDB 选择 BTree? 1. 范围查询更快 2…...