当前位置: 首页 > news >正文

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面向对象三大特性之一 多态分为两类 静态多态:函数重载和运算符重载属于静态多态&#xff0c;复用函数名 动…...

Java SPI机制及原理详解

前言 Java SPI (Service Provider Interface) 是一种重要的组件化方式&#xff0c;它可以让程序在运行时动态地装载一些实现模块&#xff0c;从而增强程序的可扩展性和灵活性。本文将详细介绍 Java SPI 的基本概念、原理以及使用方法。 1. 什么是Java SPI Java SPI 是一种标准…...

不压缩打包layui

手动打包 下载layui源码&#xff08;当前版本2.6.4&#xff09;&#xff0c;并解压缩 下载地址&#xff1a;layui gitee 安装nodejs&#xff08;v10.24.1&#xff09; 下载链接 windows-x64 安装cnpm npm install -g cnpm -registryhttps://registry.npm.taobao.org全局安…...

过去、现在及未来

人生最邪恶的地方在于&#xff0c;只能年轻一次 回顾下我毫无规划的&#xff0c;且已经消耗掉的青春 一&#xff1a;过去 19岁&#xff0c;进入大学&#xff0c;兼职、玩儿、暧昧 20-21岁&#xff0c;初创软件公司打杂、恋爱、暧昧 22、23、24岁&#xff0c;上海&#xff…...

leetcode701. 二叉搜索树中的插入操作(java)

二叉搜索树中的插入操作 leetcode701. 二叉搜索树中的插入操作题目描述 递归解题解题思路代码演示 二叉树专题 leetcode701. 二叉搜索树中的插入操作 原题链接&#xff1a; 来源&#xff1a;力扣&#xff08;LeetCode&#xff09; 链接&#xff1a;https://leetcode.cn/problem…...

Docker的容器管理操作

1、创建容器 容器创建&#xff1a;就是将镜像加载到容器的过程。 创建容器时如果没有指定容器名称&#xff0c;系统会自动创建一个名称。 新创建的容器默认处于停止状态&#xff0c;不运行任何程序&#xff0c;需要在其中发起一个进程来启动容器。 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变更大小写敏感问题的总结

作者&#xff1a; sustyle 原文来源&#xff1a; https://tidb.net/blog/2a72bc13 1 背景 近期&#xff0c;我们线上的tidb集群就遇到一个变更忽略大小写的需求&#xff0c;本来以为一个改表工单就解决了&#xff0c;但是业务反馈工单完成后&#xff0c;大小写仍旧敏感&…...

法规标准-UN R158标准解读

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

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&#xff08;临时响应&#xff09;2.2 2xx &#xff08;成功&#xff09;2.3 3xx &#xff08;重定向&#xff09;2.4 4x…...

MIME 类型列表 03

看表~按照内容类型排列的 MIME 类型列表 类型/子类型扩展名application/envoyevyapplication/fractalsfifapplication/futuresplashsplapplication/htahtaapplication/internet-property-streamacxapplication/mac-binhex40hqxapplication/msworddocapplication/msworddotappl…...

SpringBoot项目登录并接入MFA二次认证

MFA多因素认证(Multi-Factor Authentication )&#xff1a; 一些需要身份认证的服务&#xff08;如网站&#xff09;&#xff0c;为了提升安全性&#xff0c;通常会在账号密码登录成功后&#xff0c;要求用户进行第二种身份认证&#xff0c;以确保是正确用户登录&#xff0c;避…...

算法与数据结构(三)

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

亚马逊云科技出海日,让数字经济出海扩展到更多行业和领域

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

Pb协议的接口测试

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

2. 分布式文件系统 HDFS

2. 分布式文件系统 HDFS 1. 引入HDFS【面试点】 问题一&#xff1a;如果一个文件中有 10 个数值&#xff0c;一行一个&#xff0c;并且都可以用 int 来度量。现在求 10 个数值的和 思路&#xff1a; 逐行读取文件的内容把读取到的内容转换成 int 类型把转换后的数据进行相加…...

借助金融科技差异化发展,不一样的“破茧”手法

撰稿 | 多客 来源 | 贝多财经 民营银行的诞生顺应了普惠金融的要求&#xff0c;承担着支持民营经济、服务小微的历史使命。经过近年来的发展&#xff0c;19家民营银行形成了特色化、差异化的发展模式&#xff0c;并用各自本领实践普惠金融的初心。 本文从多家民营银行在核心技…...

typescript中type、interface的区别

一、概念定义 interface&#xff1a;接口 在TS 中主要用于定义【对象类型】&#xff0c;可以对【对象】的形状进行描述。type &#xff1a;类型别名 为类型创建一个新名称&#xff0c;它并不是一个类型&#xff0c;只是一个别名。 二&#xff0c;区别 interface&#xff1a; …...

Ingress详解

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

KubeSphere 容器平台高可用:环境搭建与可视化操作指南

Linux_k8s篇 欢迎来到Linux的世界&#xff0c;看笔记好好学多敲多打&#xff0c;每个人都是大神&#xff01; 题目&#xff1a;KubeSphere 容器平台高可用&#xff1a;环境搭建与可视化操作指南 版本号: 1.0,0 作者: 老王要学习 日期: 2025.06.05 适用环境: Ubuntu22 文档说…...

51c自动驾驶~合集58

我自己的原文哦~ https://blog.51cto.com/whaosoft/13967107 #CCA-Attention 全局池化局部保留&#xff0c;CCA-Attention为LLM长文本建模带来突破性进展 琶洲实验室、华南理工大学联合推出关键上下文感知注意力机制&#xff08;CCA-Attention&#xff09;&#xff0c;…...

IGP(Interior Gateway Protocol,内部网关协议)

IGP&#xff08;Interior Gateway Protocol&#xff0c;内部网关协议&#xff09; 是一种用于在一个自治系统&#xff08;AS&#xff09;内部传递路由信息的路由协议&#xff0c;主要用于在一个组织或机构的内部网络中决定数据包的最佳路径。与用于自治系统之间通信的 EGP&…...

渗透实战PortSwigger靶场-XSS Lab 14:大多数标签和属性被阻止

<script>标签被拦截 我们需要把全部可用的 tag 和 event 进行暴力破解 XSS cheat sheet&#xff1a; https://portswigger.net/web-security/cross-site-scripting/cheat-sheet 通过爆破发现body可以用 再把全部 events 放进去爆破 这些 event 全部可用 <body onres…...

抖音增长新引擎:品融电商,一站式全案代运营领跑者

抖音增长新引擎&#xff1a;品融电商&#xff0c;一站式全案代运营领跑者 在抖音这个日活超7亿的流量汪洋中&#xff0c;品牌如何破浪前行&#xff1f;自建团队成本高、效果难控&#xff1b;碎片化运营又难成合力——这正是许多企业面临的增长困局。品融电商以「抖音全案代运营…...

Unsafe Fileupload篇补充-木马的详细教程与木马分享(中国蚁剑方式)

在之前的皮卡丘靶场第九期Unsafe Fileupload篇中我们学习了木马的原理并且学了一个简单的木马文件 本期内容是为了更好的为大家解释木马&#xff08;服务器方面的&#xff09;的原理&#xff0c;连接&#xff0c;以及各种木马及连接工具的分享 文件木马&#xff1a;https://w…...

iOS性能调优实战:借助克魔(KeyMob)与常用工具深度洞察App瓶颈

在日常iOS开发过程中&#xff0c;性能问题往往是最令人头疼的一类Bug。尤其是在App上线前的压测阶段或是处理用户反馈的高发期&#xff0c;开发者往往需要面对卡顿、崩溃、能耗异常、日志混乱等一系列问题。这些问题表面上看似偶发&#xff0c;但背后往往隐藏着系统资源调度不当…...

多模态图像修复系统:基于深度学习的图片修复实现

多模态图像修复系统:基于深度学习的图片修复实现 1. 系统概述 本系统使用多模态大模型(Stable Diffusion Inpainting)实现图像修复功能,结合文本描述和图片输入,对指定区域进行内容修复。系统包含完整的数据处理、模型训练、推理部署流程。 import torch import numpy …...

【 java 虚拟机知识 第一篇 】

目录 1.内存模型 1.1.JVM内存模型的介绍 1.2.堆和栈的区别 1.3.栈的存储细节 1.4.堆的部分 1.5.程序计数器的作用 1.6.方法区的内容 1.7.字符串池 1.8.引用类型 1.9.内存泄漏与内存溢出 1.10.会出现内存溢出的结构 1.内存模型 1.1.JVM内存模型的介绍 内存模型主要分…...

elementUI点击浏览table所选行数据查看文档

项目场景&#xff1a; table按照要求特定的数据变成按钮可以点击 解决方案&#xff1a; <el-table-columnprop"mlname"label"名称"align"center"width"180"><template slot-scope"scope"><el-buttonv-if&qu…...