多态(虚构的整体,具体的个体)(多态的基本概念/多态的原理剖析/纯虚函数和抽象类/虚析构和纯虚析构)

news2024/11/14 12:07:39

多态的基本概念

#define _CRT_SECURE_NO_WARNINGS 
#include<iostream>
using namespace std;
// 多态的基本概念
// 多态分为静态多态和动态多态
// 静态多态: 函数重载还运算符重载属于静态多态,服用函数名
// 动态多态: 派生派和虚函数实现运行时多态


//静态多态和动态多态的区别
// 静态多态的函数地址早绑定-编译阶段确定函数地址
// 动态多态的函数地址晚绑定-运行阶段确定函数地址


// 动态多态满足条件
// 1.有继承关系
// 2.子类重写父类的虚函数
//    重写就是:函数返回值类型 函数名 参数列表 完全相同

// 动态多态的使用
// 父类的指针或引用执行子类对象


// 动物类
class Animal
{
public:
	virtual void speak()
	{
		cout << "动物在说话" << endl;
	}

};
// 猫类
class Cat :public Animal
{
public:
	void speak()
	{
		cout << "小猫在说话" << endl;
	}
};

// 执行说话的函数

// C++中允许父子之间的类型转换,不需要强制类型转换
void doSpeak(Animal &animal)
{
	animal.speak();
}

void test01()
{
	Cat c;
	// 属于地址早绑定,在编译阶段确定函数地址
	// 如果想执行让猫说话,那么这个函数地址就不能提前绑定。
	// 需要在运行期间绑定,地址晚绑定
	// 此时用到虚函数的概念,也就是在父类中的函数前加virtual
	// 此作用是让被调用的类的说话函数优先执行,起始也就是加virtual降低了本身的优先级
	// 子类中的virtual可写可不写
	doSpeak(c); // 相当于 Animal &animal = c;
}
void doSpeak(Animal* animal)
{
	animal->speak();
}
void test02()
{
	Cat c;
	doSpeak(&c);
}
int main()
{

	test01();// 引用
	test02();// 指针
	system("pause");
	return 0;
}

多态的原理剖析

此时该类中储存指向该函数的指针

#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;
	}
};
int main()
{
	cout << "sizeof(Animal) = " << sizeof(Animal) << endl;

	system("pause");
	return 0;
}

多态案例一---- 计算器类

普通写法

#define _CRT_SECURE_NO_WARNINGS 
#include<iostream>
using namespace std;
// 计算器类普通写法
class Calculate
{
public:

	Calculate(int num1,int num2)
	{
		this->num1 = num1;
		this->num2 = num2;
	}
	int doWork(string operate)
	{
		if (operate == "+")
		{
			return num1 + num2;
		}else if (operate == "-")
		{
			return num1 - num2;
		}else if (operate == "*")
		{
			return num1 * num2;
		}
		// 此种写法如果想增加其它的功能,需要修改源码
		// 在真正的开发中 提倡 开闭原则
		// 开闭原则: 对扩展进行开放,对修改进行关闭
	}
	int num1;
	int num2;
};
// 普通写法
void test01()
{
	Calculate c(10, 20);
	cout << c.num1 << "+" << c.num2 << " = " <<  c.doWork("+") << endl;
	cout << c.num1 << "-" << c.num2 << " = " << c.doWork("-") << endl;
	cout << c.num1 << "*" << c.num2 << " = " << c.doWork("*") << endl;
}
int main()
{
	test01();

	system("pause");
	return 0;
}

多态写法

#define _CRT_SECURE_NO_WARNINGS 
#include<iostream>
using namespace std;
// 计算器类-多态写法

// 多态的好处:
// 1.组织结构清晰
// 2.可读性强
// 3.对于前期和后期扩展以及维护性高

// C++开发提倡利用多态设计程序架构,因为多态优点很多
class AbstractCalculate
{
public:
	int num1;
	int num2;
	virtual int calculate()
	{
		return 0;
	}
};
class Add :public AbstractCalculate
{
public:
	virtual int calculate()
	{
		return num1 + num2;
	}
};
class Del :public AbstractCalculate
{
public:
	virtual int calculate()
	{
		return num1 - num2;
	}
};
class Cheng :public AbstractCalculate
{
public:
	virtual int calculate()
	{
		return num1 * num2;
	}
};
void test01()
{
	// 多态使用条件
	// 父类指针或引用指向子类对象

	AbstractCalculate* c = new Add;
	c->num1 = 10;
	c->num2 = 20;
	cout << c->num1 << " + " << c->num2 << " = " << c->calculate() << endl;
	// 用完记得销魂
	delete c;

	c = new Del;
	c->num1 = 10;
	c->num2 = 20;
	cout << c->num1 << " - " << c->num2 << " = " << c->calculate() << endl;
	delete c;
}
int main()
{
	test01();
	system("pause");
	return 0;
}

纯虚函数和抽象类

在多态中,通常父类中虚函数的实现时毫无意义的,主要是调用子类重写的内容

因此可以将虚函数改为纯虚函数

当类中有了纯虚函数,这个类称为抽象类

抽象类特点:

1.无法实例化对象

2.子类必须重写抽象类中的纯虚函数,否则也属于抽象类

#define _CRT_SECURE_NO_WARNINGS 
#include<iostream>
using namespace std;

// 纯虚函数和抽象类
class Animal
{
public:
	// 纯虚函数
	// 只要有一个纯虚函数,这类就称为抽象类
	// 抽象类特点
	// 1.无法实例化对象
	// 2.子类必须重写父类中的纯虚函数,否则无法实例化对象
	virtual void func() = 0;

};
class Cat :public Animal
{
public:
	void func()
	{
		cout << "func函数调用" << endl;
	}

};
void test01()
{
	//Animal a;
	//new Animal;  //抽象类是无法实例化对象的

	Cat c;// 子类必须重写父类中的纯虚函数,否则无法实例化对象
	Animal& animal = c;
	animal.func();
}
int main()
{
	test01();
	system("pause");
	return 0;
}

多态案例二:制作饮品

#define _CRT_SECURE_NO_WARNINGS 
#include<iostream>
using namespace std;
class AbstraceMakeDrinking
{
public:
	// 1.煮水
	virtual void zhuShui() = 0;

	// 2.冲泡
	virtual void chongPao() = 0;

	// 3.倒入杯中
	virtual void daoRuBeiZhong() = 0;

	// 4.加入辅料
	virtual void jiaRuFuLiao() = 0;

	void makeDrink()
	{
		zhuShui();
		chongPao();
		daoRuBeiZhong();
		jiaRuFuLiao();
	}
};
class kaFei :public AbstraceMakeDrinking
{
public:
	// 1.煮水
	virtual void zhuShui()
	{
		cout << "煮咖啡水" << endl;
	}

	// 2.冲泡
	virtual void chongPao()
	{
		cout << "冲泡咖啡" << endl;
	}

	// 3.倒入杯中
	virtual void daoRuBeiZhong()
	{
		cout << "导入咖啡杯中" << endl;
	}

	// 4.加入辅料
	virtual void jiaRuFuLiao()
	{
		cout << "加入咖啡辅料" << endl;
	}
};
void test01()
{
	AbstraceMakeDrinking* coffee = new kaFei;
	coffee->makeDrink();
	delete coffee;
}
int main()
{
	test01();
	system("pause");
	return 0;
}

虚析构和纯虚析构

#define _CRT_SECURE_NO_WARNINGS 
#include<iostream>
using namespace std;
#include<string>
// 虚析构和纯虚析构
// 多态使用时,如果子类中有属性开辟到堆区,那么父类指针在释放时
//无法调用到子类的析构代码
// 因为父类引用指向子类对象,故在释放空间时调用的是父类的析构函数
// 故使用多态(虚析构或纯虚析构)

// 虚析构和纯虚析构的共性:
//  1.可以解决父类指针释放子类对象
//  2.都需要具体的函数实现

// 虚析构和纯虚析构的区别:
//   如果是纯虚析构,该类属于抽象类,无法实例化对象

// 总结
// 1.虚析构和纯虚析构就是用来解决父类指针释放子类对象
// 2.如果子类中没有堆区数据,可以不写虚析构或纯虚析构
// 3.拥有纯虚析构也属于抽象类
class Animal
{
public:
	// 纯虚析构
	virtual void speak() = 0;
	Animal()
	{
		cout << "Animal类构造函数的调用" << endl;
	}
	 利用虚析构可以解决 父类指针释放子类对象时不干净的问题
	//virtual ~Animal()
	//{
	//	cout << "Animal类析构函数的调用" << endl;
	//}

	// 纯虚析构(需要声明也需要实现)
	// 有了纯虚析构之后,这个类也属于抽象类,无法实例化对象
	virtual ~Animal() = 0;
};
// 子类中需要析构函数释放空间,但是多态走不到子类中的析构函数,
// 所以需要虚析构和纯虚析构
Animal:: ~Animal()
{
	cout << "Animal类析构函数的调用" << endl;
}
class Cat :public Animal
{
public:
	string* name;
	Cat(string name)
	{
		cout << "Cat类构造函数的调用" << endl;
		this->name = new string(name);
	}
	~Cat()
	{
		cout << "Cat类析构函数的调用" << endl;
		if (name != NULL)
		{
			delete name;
			name = NULL;
		}
	}
	virtual void speak()
	{
		cout << *name << "小猫在说话" << endl;
	}
};
void test01()
{
	// 多态:父类指针或引用指向子类对象
	// 引用:给变量取别名
	Animal *animal = new Cat("Tom");
	animal->speak();
	// 父类指针在析构的时候,不回调用子类中析构函数,
	// 导致子类如果有堆区属性,出现内存泄露
	delete animal;
	animal = NULL;
}
int main()
{
	test01();
	system("pause");
	return 0;
}

    // 父类指针在析构的时候,不回调用子类中析构函数,
    // 导致子类如果有堆区属性,出现内存泄露

// 解决方法,将父类析构函数改为虚析构或纯虚析构

多态案例三: 电脑组装

#define _CRT_SECURE_NO_WARNINGS 
#include<iostream>
using namespace std;
// CPU抽象类
class Cpu
{
public:
	virtual void calculate() = 0;
};
// 显卡抽象类
class DisplayCard
{
public:
	virtual void display() = 0;
};
// 内存抽象类
class Memory
{
public:
	virtual void distory() = 0;
};

// 电脑类
class Computer
{
public:

	// 用来接受每一个零件
	Computer(Cpu *cpu, DisplayCard *card, Memory *memory)
	{
		this->cpu = cpu;
		this->card = card;
		this->memory = memory;
	}
	~Computer()
	{
		if (cpu != NULL)
		{
			delete cpu;
			cpu = NULL;
		}
		if (card != NULL)
		{
			delete card;
			card = NULL;
		}
		if (memory != NULL)
		{
			delete memory;
			memory = NULL;
		}
	}

	// 用来协同每一个零件工作
	void work()
	{
		cpu->calculate();
		card->display();
		memory->distory();
	}
private:
	Cpu* cpu;
	DisplayCard* card;
	Memory* memory;
};

// 不同厂商的CPU
class IntelCpu :public Cpu
{
public:
	virtual void calculate()
	{
		cout << "Intel的CPU开始计算了" << endl;
	}
};
class LevoeCpu :public Cpu
{
public:
	virtual void calculate()
	{
		cout << "Levoe的CPU开始计算了" << endl;
	}
};

// 不同厂商的显卡
class IntelDisplayCard :public DisplayCard
{
public:
	virtual void display()
	{
		cout << "Intel的显卡开始显示了" << endl;
	}
};
class LevoeDisplayCard :public DisplayCard
{
public:
	virtual void display()
	{
		cout << "Levoe的显卡开始显示了" << endl;
	}
};

//不同厂商的内存条
class IntelMemory :public Memory
{
public:
	virtual void distory()
	{
		cout << "Intel的内存条开始存储了 " << endl;
	}
};
class LevoeMemory :public Memory
{
public:
	virtual void distory()
	{
		cout << "Levoe的内存条开始存储了 " << endl;
	}
};


void test01()
{
	// 第一台电脑运行
	cout << "第一台电脑运行--------------------------" << endl;
	Cpu* cpu = new IntelCpu;
	DisplayCard* card = new IntelDisplayCard;
	Memory* memory = new IntelMemory;
	Computer *c = new Computer(cpu,card,memory);
	c->work();
	delete c;

	// 第二台电脑运行
	cout << "第二台电脑运行--------------------------" << endl;
	c = new Computer(new LevoeCpu, new LevoeDisplayCard, new LevoeMemory);
	c->work();
	delete c;
	c = NULL;
}
int main()
{
	test01();
	system("pause");
	return 0;
}

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

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

相关文章

电商走向“未来化”,“含金量”几何?

2018年&#xff0c;史蒂文斯皮尔伯格导演的《头号玩家》一经上映&#xff0c;就带火了虚拟现实概念。电影中&#xff0c;男主角戴上VR眼镜、感知手套&#xff0c;穿上触感套装&#xff0c;从视觉、听觉到触觉&#xff0c;瞬间切换至全新的世界。 电影《头号玩家》剧照 时隔六年…

如何使用ssm实现图书管理借阅系统

TOC ssm301图书管理借阅系统jsp 绪论 1.1 研究背景 当前社会各行业领域竞争压力非常大&#xff0c;随着当前时代的信息化&#xff0c;科学化发展&#xff0c;让社会各行业领域都争相使用新的信息技术&#xff0c;对行业内的各种相关数据进行科学化&#xff0c;规范化管理。…

构建在线教育系统源码:企业培训APP开发的技术指南

在数字化浪潮的推动下&#xff0c;企业培训正从传统课堂转向在线教育模式。构建一个高效、稳定且可扩展的在线教育系统源码&#xff0c;已经成为开发企业培训APP的关键。在本文中&#xff0c;我们将深入探讨构建在线教育系统源码的核心技术&#xff0c;并提供一份开发企业培训A…

免费分享一套SpringBoot+Vue个人理财管理系统【论文+源码+SQL脚本】,帅呆了~~

大家好&#xff0c;我是java1234_小锋老师&#xff0c;看到一个不错的SpringBootVue个人理财管理系统&#xff0c;分享下哈。 项目视频演示 【免费】SpringbootVue个人理财管理系统 Java毕业设计_哔哩哔哩_bilibili 项目介绍 随着信息技术在管理上越来越深入而广泛的应用&am…

记录一次polarDB出现Waiting for table metadata lock

在业务实践中&#xff0c;常见的 DDL 阻塞 原因是由于无法获取到 MDL 锁&#xff0c;即 Waiting for table metadata lock 。借助 metadata_lock 表&#xff0c;可以快速定位到 DDL 阻塞的原因。 元数据锁&#xff08;MDL&#xff09; MDL加锁过程是系统自动控制&#xff0c;无…

京东商品信息快速获取:API返回值实战教程

京东商品信息快速获取通常通过调用京东的API接口来实现&#xff0c;特别是针对商品搜索和商品详情等需求。以下是一个基于京东商品信息API返回值的实战教程&#xff0c;帮助您快速理解和利用这些API返回的数据。 1. 注册与认证 首先&#xff0c;您需要在京东开放平台&#xf…

Python爬虫的这几个实用技巧你都知道吗?

Python爬虫是一种强大的网络数据抓取工具&#xff0c;通过编写Python脚本来自动化地访问网页、提取所需信息并保存到本地。以下是Python爬虫的8大实用技巧&#xff0c;详细讲解如下&#xff1a; 1. 发送HTTP请求 基本方法&#xff1a;使用requests库发送HTTP请求是Python爬虫…

【学术会议征稿】第五届机械工程、智能制造与自动化技术国际学术会议(MEMAT 2024)

第五届机械工程、智能制造与自动化技术国际学术会议&#xff08;MEMAT 2024&#xff09; The 5th International Conference on Mechanical Engineering, Intelligent Manufacturing and Automation Technology 目前&#xff0c;我国自动化技术随着科学技术水平的不断提高已经…

责任链设计模式详解

责任链设计模式详解 一、定义 责任链设计模式&#xff08;Chain of Responsibility Pattern&#xff09;是一种行为设计模式&#xff0c;它允许多个对象有机会处理请求&#xff0c;从而避免请求的发送者和接收者之间的耦合。这种模式将这些对象连接成一条链&#xff0c;并沿着…

麒麟kylin v10 sp3 升级glibc2.28 到 2.31

1. 下载glibc 2.31 wget https://mirrors.aliyun.com/gnu/glibc/glibc-2.31.tar.gz 2.解压 tar -xf glibc-2.31.tar.gz cd glibc-2.31 mkdir build && cd build 3.修改 Makefile 125行添加一行 yum reinstall libxcrypt -y scripts/test-installation.pl 128行修…

java Boss直聘爬虫数据分析

摘要 本报告利用Java和Selenium爬虫技术获取数据&#xff0c;并使用ECharts库对薪资数据进行可视化分析&#xff0c;旨在探究不同经验和学历的薪资分布情况。 数据来源 数据来源于Boss直聘&#xff0c;使用Java结合Selenium库进行数据抓取。 数据总数&#xff1a;约2000家企…

虚幻引擎(Unreal Engine)技术使得《黑神话悟空传》大火,现在重视C++的开始吃香了,JAVA,Go,Unity都不能和C++相媲美!

虚幻引擎&#xff08;Unreal Engine&#xff09;火了黑神话游戏。 往后&#xff0c;会有大批量的公司开始模仿这个赛道&#xff01; C 的虚拟引擎技术通常指的是使用 C 语言开发的游戏引擎&#xff0c;如虚幻引擎&#xff08;Unreal Engine&#xff09;等。以下是对 C 虚拟引…

[WUSTCTF2020]spaceclub(我把输入的字符切片研究了)

上sublime txt 每一行的长短对应一个二进制位&#xff0c;长空格是1&#xff0c;短空格是0&#xff0c;全部替换掉得到 上python脚本 import binasciiwith open(attachment_5.txt, r) as file:lines file.readlines() # 逐行读取文本内容output # 初始化输出字符串# 遍历…

【C++题解】1145. 数列求和

欢迎关注本专栏《C从零基础到信奥赛入门级&#xff08;CSP-J&#xff09;》 问题&#xff1a;1145. 数列求和 类型&#xff1a;递归基础 题目描述&#xff1a; 有一数列如下&#xff1a; 1 2 4 7 11 16 22 …… 试求该数列前 N 项之和。 输入&#xff1a; 一个整数 N &…

STM32G474定时器触发1次引起ADC转换直至DMA请求传输完所有通道的数据

STM32G474使用定时器1触发1次ADC转换&#xff0c;然后交给DMA循环执行&#xff0c;实现多通道ADC转换和多通道数据传输。若定时器1停止工作&#xff0c;则ADC转换也会随之停止&#xff0c;当然也不会再有DMA数据传输。 1、ADC触发信号分配 2、DMA多路复合器分配&#xff0c;指…

微信表情包格式推荐要求:240*240 +gif

微信表情包格式要求&#xff1a;240*240 gif

2024了,Neo4j能显示节点图片吗?

经过一番调研&#xff0c;答案是官方的是不能的.但有一个中文版可以显示网络图片作为节点背景 如通义千问说说&#xff1a; Neo4j 图数据库本身并不直接支持在节点中存储和显示图片。但是&#xff0c;你可以通过几种方式间接实现这一功能&#xff1a;1. 存储图片URL 最简单的…

K8S持久化存储数据

环境&#xff1a; Ubuntu-1:192.168.114.110作为主 Ubuntu-2:192.168.114.120作为从1&#xff0c;node节点1 Ubuntu-3:192.168.114.130作为从2&#xff0c;node节点2 持久化volumeMounts pod里面&#xff1a;emptyDir和hostPath。存储在node&#xff0c;NFS...&#xff0c;Clo…

微软Win11 24H2最新可选更新补丁26100.1591发布!

系统之家于8月28日发出最新报道&#xff0c;微软面向Win11 24H2用户推出八月最新的可选更新KB5041865&#xff0c;系统更新后版本号升至26100.1591。本次更新进行了多项改进&#xff0c;还优化了小组件面板。接下来&#xff0c;跟随小编一起深入了解这次更新的详细内容吧。 更新…

RSA非对称性加密02: 加密redis的连接密码(下)-私钥加密,公钥解密

全文目录,一步到位 1.前言简介1.1 专栏传送门1.1.2 上文传送门 2. 使用方式2.1 使用druid自带的RSA加密工具2.1.1 引入druid依赖2.1.2 原yml配置(对比使用)2.1.2 新yml配置 2.2 springboot的redis配置类2.2.1 例如在RedisConfig中2.2.2 设置序列化与反序列化代码示例如下: 2.3 …