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

C++面向对象之多态性

文章目录

      • C++面向对象之多态性
        • 1.静态多态
        • 2.动态多态
        • 3.多态的好处
        • 3.1使用方法
      • 4.纯虚函数
      • 5.虚析构与纯虚析构
        • 5.1问题
        • 5.2解决
      • 6.其他知识点
      • 7.代码
      • 8.测试结果
        • 8.1父类中无虚函数,父类的指针指向子类对象,将调用父类中的函数,无法调用子类中的重写函数,即无法实现多态
        • 8.2父类中的函数由虚函数实现
        • 8.3父类指针对象,无法释放子类中开辟的堆空间数据
        • 8.4将父类的析构函数定义为虚析构函数
        • 8.5将父类中的析构函数定义为纯虚析构函数

C++面向对象之多态性

1.静态多态

通过函数重载和运算符重载实现,在编译时确定函数早绑定

2.动态多态

派生类和虚函数实现运行时多态,运行阶段实现函数晚绑定。

当子类重写了父类的虚函数时,子类中的虚函数表将替换父类中的虚函数,

所以当父类的引用或者指针指向子类对象时,将发生多态

3.多态的好处

结构清晰

可读性很强

利于后期的拓展和维护

3.1使用方法

父类的引用或者指针指向子类的对象

4.纯虚函数

定义格式:virtual 返回值类型 函数名称(参数列表) = 0;

类中有了纯虚函数,称为抽象类,抽象类无法实例化对象

子类必须重写父类中的所有纯虚函数,才能实例化对象,否则也是抽象类

5.虚析构与纯虚析构

5.1问题

多态使用时,如果子类中有属性开辟到了堆区,则父类指针释放时无法调用子类的析构函数

5.2解决

将父类中的析构函数改为虚析构函数或者纯虚析构函数

纯虚析构函数需要先声明,后实现,但是纯虚函数可以只声明

如果子类没有堆区数据,可以不将父类的析构函数写成虚析构或者纯虚析构

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

6.其他知识点

空类(即里面什么代码都没有)的大小通过sizeof测定的结果是1

vfptr(虚函数表指针) ——> vftable(虚函数表,用于记录虚函数的地址)

7.代码

#include<iostream>using namespace std;class Animal {
public:Animal() {cout << "基类中的构造函数被调用!" << endl;}// 虚函数,虚函数将实现晚绑定virtual void speack() {cout << "动物在说话!" << endl;}virtual ~Animal() = 0;			// 纯虚析构函数,纯虚析构声明后,必须定义
};// Animal中的纯虚析构实现部分,可以在这里释放父类开辟的堆空间
Animal::~Animal() {}class Cat :public Animal {public:Cat() {cout << "cat中的构造函数被调用" << endl;}void speack() {cout << "小猫在说话!" << endl;}~Cat() {cout << "cat中的析构函数被调用" << endl;}
};class Dog : public Animal {
public:void speack() {cout << "小狗在说话" << endl;}~Dog() {cout << "dog中的析构函数被调用" << endl;}
};// 地址早绑定,在编译阶段函数地址已经早绑定Animal
void doSpeack(Animal& animal) {animal.speack();
}// 派生类重写基类中的虚函数,当基类的引用或者指针指向派生类时,实现多态
void test01() {Cat cat;Dog dog;doSpeack(cat);doSpeack(dog);}// 基类和派生类的构造函数和析构函数的调用
// 
void test02() {Animal* p_cat = new Cat();			// 开辟内存到堆区,需要手动释放if (p_cat != NULL) {delete p_cat;						// 释放指针p_cat = NULL;}}// --------------------------------------------------------------------------
class CPU {
public:virtual void caculate() = 0;
};class VideoCard {
public:virtual void display() = 0;
};class Memory {
public:virtual void storage() = 0;
};class Computer {
public:Computer(CPU *cpu, VideoCard *videoCard,Memory * memory) {this -> m_cpu = cpu;this -> m_vc = videoCard;this -> m_mem = memory;}// 电脑的工作void work() {m_cpu->caculate();m_vc->display();m_mem->storage();}~Computer() {if (m_cpu != NULL) {delete m_cpu;}if (m_vc != NULL) {delete m_vc;}if (m_mem != NULL) {delete m_mem;}}private:CPU* m_cpu;VideoCard* m_vc;Memory* m_mem;
};
// inter厂商
class InterCPU :public CPU {public:void caculate() {cout << "inter的CPU开始计算了" << endl;}
};class InterVideoCard :public VideoCard {public:void display() {cout << "inter的显卡开始计算了" << endl;}
};
class InterMemory :public Memory {public:void storage() {cout << "inter的内存条开始存储了" << endl;}
};
// lenovoclass lenovoCPU :public CPU {public:virtual void caculate() {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 test03() {// 创建电脑CPU* interCPU = new InterCPU;VideoCard* interCard = new InterVideoCard;Memory* interMemory = new InterMemory;Computer* computer1 = new Computer(interCPU, interCard, interMemory);computer1->work();delete computer1;cout << "---------------------------" << endl;Computer* computer2 = new Computer(new lenovoCPU, new lenovoVideoCard,new lenovoMemory);computer2->work();delete computer2;cout << "---------------------------" << endl;Computer* computer3 = new Computer(new InterCPU, new lenovoVideoCard, new lenovoMemory);computer3->work();delete computer3;
}
int main() {   //test01();//test02();test03();system("pause");return 0;
}

8.测试结果

8.1父类中无虚函数,父类的指针指向子类对象,将调用父类中的函数,无法调用子类中的重写函数,即无法实现多态

在这里插入图片描述

8.2父类中的函数由虚函数实现

在这里插入图片描述

父类的指针指向小猫子类,将调用小猫类中的重写函数,实现多态

8.3父类指针对象,无法释放子类中开辟的堆空间数据

在这里插入图片描述

cat类中的析构函数没有被调用,无法释放开辟的堆空间数据

8.4将父类的析构函数定义为虚析构函数

子类中的析构函数被调用
在这里插入图片描述

8.5将父类中的析构函数定义为纯虚析构函数

子类中的析构函数被调用,将父类中的析构函数声明为纯虚析构函数后,必须要实现声明的函数。
在这里插入图片描述

相关文章:

C++面向对象之多态性

文章目录C面向对象之多态性1.静态多态2.动态多态3.多态的好处3.1使用方法4.纯虚函数5.虚析构与纯虚析构5.1问题5.2解决6.其他知识点7.代码8.测试结果8.1父类中无虚函数&#xff0c;父类的指针指向子类对象&#xff0c;将调用父类中的函数&#xff0c;无法调用子类中的重写函数&…...

Android性能优化系列篇:弱网优化

弱网优化1、Serializable原理通常我们使用Java的序列化与反序列化时&#xff0c;只需要将类实现Serializable接口即可&#xff0c;剩下的事情就交给了jdk。今天我们就来探究一下&#xff0c;Java序列化是怎么实现的&#xff0c;然后探讨一下几个常见的集合类&#xff0c;他们是…...

Mysql 插入大批量数据调优方法

Mysql 插入大批量数据调优方法[toc]1、多线程插入&#xff08;单表&#xff09;在数据里做插入操作的时候&#xff0c;整体时间的分配是这样的&#xff1a;链接耗时 &#xff08;30%&#xff09;发送query到服务器 &#xff08;20%&#xff09;解析query &#xff08;20%&#…...

matlab基础

系列文章目录 文章目录系列文章目录前言1 基本用法总结基础语法桌面管理矩阵均匀间隔矢量矩阵创建矩阵索引前言 介绍了matlab的基本用法 1 基本用法 >> save filename.mat % 将当前工作区的所有变量保存为mat文件 >> load filename.mat % 加载文件>> loa…...

自动化测试——多窗口切换和切换frame

这里写目录标题一、多窗口切换1、base.py&#xff1a;公共代码2、切换句柄的方式1&#xff0c;通过for循环3、切换句柄的方式2&#xff0c;通过索引切换4、源代码二、frame窗口1、什么是frame?2、Frame 分类3、判断要定位的元素在不在frame中两种方式方式一&#xff1a;鼠标选…...

C#中,Elasticsearch.Net判断空字符串

之前有个业务需求&#xff0c;由于最开始存储到es里的&#xff0c;是默认空字符串。 后面程序取数据时&#xff0c;发现需要取空字符串的数据时&#xff0c;不好取出来。 字符串的字段如图&#xff1a; 实际数据如图&#xff1a; 我用的是C#语言&#xff0c;使用的是Elastic…...

23种设计模式-适配器模式

适配器模式&#xff08;Adapter Pattern&#xff09;是一种常用的设计模式&#xff0c;它可以将不兼容的接口转换成可兼容的接口&#xff0c;使得原本不能一起工作的类可以协同工作。 在Java中&#xff0c;适配器模式一般有两种实现方式&#xff0c;即类适配器模式和对象适配器…...

深入理解this指向问题

this指向 在运行时绑定&#xff0c;所以this和函数的调用方式和调用的位置有关&#xff0c;和定义的位置没关系 绑定规则 默认绑定&#xff08;非严格模式下this指向全局变量&#xff0c;在严格模式下函数内的this指向undefined&#xff09; 独立函数调用&#xff0c;没有主题 …...

事业单位联考(综合应用A类)典型例题教案

【联考A类】根据材料2&#xff0c;请你概括C市B县旅游质监所投诉处理科小王在接待投诉时存在的主要问题&#xff0c;并指出问题的具体表现。&#xff08;35分&#xff09;要求&#xff1a;准确、全面、分条作答。字数在300字以内。材料2&#xff1a;某日&#xff0c;几位游客家…...

frp内网穿透实验

Frp (Fast Reverse Proxy) 是比较流行的一款。FRP 是一个免费开源的用于内网穿透的反向代理应用&#xff0c;它支持 TCP、UDP 协议&#xff0c; 也为 http 和 https 协议提供了额外的支持。你可以粗略理解它是一个中转站&#xff0c; 帮你实现 公网 ←→ FRP(服务器) ←→ 内网…...

认识JavaScript中的防抖函数

&#x1f468; 作者简介&#xff1a;大家好&#xff0c;我是Taro&#xff0c;前端领域创作者 ✒️ 个人主页&#xff1a;唐璜Taro &#x1f680; 支持我&#xff1a;点赞&#x1f44d;&#x1f4dd; 评论 ⭐️收藏 文章目录前言一、防抖是什么&#xff1f;1. deounce-v1的基本…...

macOS 13.3 Beta 2 (22E5230e)With OpenCore 0.8.9正式版 and winPE双引导分区原版镜像

原文地址&#xff1a;http://www.imacosx.cn/112340.html&#xff0c;转载需注明出处镜像特点完全由黑果魏叔官方制作&#xff0c;针对各种机型进行默认配置&#xff0c;让黑苹果安装不再困难。系统镜像设置为双引导分区&#xff0c;全面去除clover引导分区&#xff08;如有需要…...

JetPack—DataStore核心原理与使用

简介 首先&#xff0c;DataStore是Jetpack一部分&#xff0c;是一种数据存储解决方案。其次&#xff0c;DataStore使用协程及flow以异步、一致的方式实现数据的存储。最后是DataStore的实现&#xff0c;分为Preferences DataStore和Proto DataStore&#xff1a;Preferences Da…...

热烈祝贺|酒事有鲤盛装亮相2023中国(山东)精酿啤酒产业发展创新论坛暨展览会

酒事有鲤&#xff08;济南&#xff09;品牌管理有限公司是一家致力于将世界顶级精酿啤酒技术和理念与“ 在地”文化有机融合&#xff0c;做世界认 可的多元化好啤酒&#xff0c;通过精致 舒适的家门口酒馆&#xff0c;让啤酒的 世界观更为完整。 中国生物发酵产业协会联合齐鲁…...

深度强化学习DLR

1 强化学习基础知识 强化学习过程&#xff1a;⾸先环境(Env)会给智能体(Agent)⼀个状态(State)&#xff0c;智能体接收到环境给的观测值之后会做出⼀个动作(Action)&#xff0c;环境接收到智能体给的动作之后会做出⼀系列的反应&#xff0c;例如对这个动作给予⼀个奖励(Reward…...

Android Handler机制(四) Message源码分析

一. 简介 接上一篇文章:Android Handler机制(三) Looper源码分析 ,我们来继续分析一下Message源码 这一系列文章都是为了深入理解Handler机制. Message 作为消息传递的载体&#xff0c;源码主要分为以下 几个部分: 1. 操作数据相关&#xff0c;类似 getter()和 setter()这种…...

【Git】git命令(全)

Git1、本地操作2、版本管理3、远端仓库4、分支管理5、缓存stash6、遗留rebase7、标签管理8、解决冲突9、参考教程10、示例代码1、本地操作 Linux安装git&#xff1a;yum install git查看git版本 git version查看git设置 git config --list设置git属性 git config --global初始…...

软考论文-成本管理(1)

成本管理 1.成本管理的主要内容&#xff1f; 规划成本&#xff1a;制定一个成本管理的计划。估算成本&#xff1a;根据项目范围说明书&#xff0c;项目管理计划和wbs等文档&#xff0c;采用xxx方法进行估算成本成本预算&#xff1a;可以算工作包的费用&#xff0c;制定预算和…...

Java 多线程 --- 锁的概念和类型划分

Java 多线程 --- 锁的概念和类型划分锁的概念乐观锁与悲观锁公平锁与非公平锁什么是可重入锁独占锁与共享锁轻量级锁和重量级锁自旋锁 (Spinlock)锁的概念 锁可以将多个线程对共享数据的并发访问转换为串行访问, 这样一个共享数据一次只能被一个线程访问, 该线程访问结束后其他…...

python程序员狂飙上头——京海市大嫂单推人做个日历不过分吧?

嗨害大家好鸭&#xff01;我是小熊猫~ 这个反黑剧其实火了很久了&#xff0c; 但是我现在才有空开始看 该说不说&#xff0c;真的很上头&#xff01;&#xff01;&#xff01; 大嫂简直就像是干枯沙漠里的玫瑰 让人眼前一亮哇~~ 我小熊猫此时此刻就成为大嫂的单推人&…...

Docker 运行 Kafka 带 SASL 认证教程

Docker 运行 Kafka 带 SASL 认证教程 Docker 运行 Kafka 带 SASL 认证教程一、说明二、环境准备三、编写 Docker Compose 和 jaas文件docker-compose.yml代码说明&#xff1a;server_jaas.conf 四、启动服务五、验证服务六、连接kafka服务七、总结 Docker 运行 Kafka 带 SASL 认…...

大数据零基础学习day1之环境准备和大数据初步理解

学习大数据会使用到多台Linux服务器。 一、环境准备 1、VMware 基于VMware构建Linux虚拟机 是大数据从业者或者IT从业者的必备技能之一也是成本低廉的方案 所以VMware虚拟机方案是必须要学习的。 &#xff08;1&#xff09;设置网关 打开VMware虚拟机&#xff0c;点击编辑…...

ESP32读取DHT11温湿度数据

芯片&#xff1a;ESP32 环境&#xff1a;Arduino 一、安装DHT11传感器库 红框的库&#xff0c;别安装错了 二、代码 注意&#xff0c;DATA口要连接在D15上 #include "DHT.h" // 包含DHT库#define DHTPIN 15 // 定义DHT11数据引脚连接到ESP32的GPIO15 #define D…...

Nuxt.js 中的路由配置详解

Nuxt.js 通过其内置的路由系统简化了应用的路由配置&#xff0c;使得开发者可以轻松地管理页面导航和 URL 结构。路由配置主要涉及页面组件的组织、动态路由的设置以及路由元信息的配置。 自动路由生成 Nuxt.js 会根据 pages 目录下的文件结构自动生成路由配置。每个文件都会对…...

论文浅尝 | 基于判别指令微调生成式大语言模型的知识图谱补全方法(ISWC2024)

笔记整理&#xff1a;刘治强&#xff0c;浙江大学硕士生&#xff0c;研究方向为知识图谱表示学习&#xff0c;大语言模型 论文链接&#xff1a;http://arxiv.org/abs/2407.16127 发表会议&#xff1a;ISWC 2024 1. 动机 传统的知识图谱补全&#xff08;KGC&#xff09;模型通过…...

python报错No module named ‘tensorflow.keras‘

是由于不同版本的tensorflow下的keras所在的路径不同&#xff0c;结合所安装的tensorflow的目录结构修改from语句即可。 原语句&#xff1a; from tensorflow.keras.layers import Conv1D, MaxPooling1D, LSTM, Dense 修改后&#xff1a; from tensorflow.python.keras.lay…...

比较数据迁移后MySQL数据库和OceanBase数据仓库中的表

设计一个MySQL数据库和OceanBase数据仓库的表数据比较的详细程序流程,两张表是相同的结构,都有整型主键id字段,需要每次从数据库分批取得2000条数据,用于比较,比较操作的同时可以再取2000条数据,等上一次比较完成之后,开始比较,直到比较完所有的数据。比较操作需要比较…...

uniapp 实现腾讯云IM群文件上传下载功能

UniApp 集成腾讯云IM实现群文件上传下载功能全攻略 一、功能背景与技术选型 在团队协作场景中&#xff0c;群文件共享是核心需求之一。本文将介绍如何基于腾讯云IMCOS&#xff0c;在uniapp中实现&#xff1a; 群内文件上传/下载文件元数据管理下载进度追踪跨平台文件预览 二…...

DBLP数据库是什么?

DBLP&#xff08;Digital Bibliography & Library Project&#xff09;Computer Science Bibliography是全球著名的计算机科学出版物的开放书目数据库。DBLP所收录的期刊和会议论文质量较高&#xff0c;数据库文献更新速度很快&#xff0c;很好地反映了国际计算机科学学术研…...

React从基础入门到高级实战:React 实战项目 - 项目五:微前端与模块化架构

React 实战项目&#xff1a;微前端与模块化架构 欢迎来到 React 开发教程专栏 的第 30 篇&#xff01;在前 29 篇文章中&#xff0c;我们从 React 的基础概念逐步深入到高级技巧&#xff0c;涵盖了组件设计、状态管理、路由配置、性能优化和企业级应用等核心内容。这一次&…...