c++(六)

news2024/11/18 13:28:41

c++(六)

  • 多态
    • 概念
    • 在c++中是如何实现多态
      • 静态多态(绑定)
      • 动态多态(绑定)
    • 动态多态的实现原理
    • 动态内存分配中遇到的问题
  • 重载、重定义、重写的区别
  • 抽象类
  • 接口类---抽象类
  • 空类对象的内存大小
  • explicit
  • final
    • 修饰类
    • 修饰成员函数

在这里插入图片描述

多态

概念

多种状态(一个事物的多种状态或形态)

<1>水在不同的温度下呈现的不同状态
<2>买票
学生票;
成人票;
老年票;
军人;

在c++中是如何实现多态

绑定:就是把函数调用语句与对应的代码块进行了绑定!。

静态多态(绑定)

编译的时候,就知道执行的是哪一个函数体
调用函数时,函数名是一样的,当我们传入不同参数的时候,执行的是不同的函数体(函数重载、运算符重载)

动态多态(绑定)

在运行的时候,才知道执行的是哪一个函数体

案例:如果要求两个子类的周长和面积之和,就得写两个函数来实现,传入不同的对象
在这里插入图片描述

在这里插入图片描述

#include <iostream>
using namespace std;
class Shape
{
public:
	Shape(int s = 0, int c = 0) :s(s), c(c)
	{
		cout << "Shape构造" << endl;
	}
	~Shape()
	{
		cout << "Shape析构" << endl;
	}
	int getC()
	{
		cout << "周长:" << this->c << endl;
		return this->c;
	}
	int getS()
	{
		cout << "面积:" << this->s << endl;
		return this->s;
	}
private:
protected:
	int s;
	int c;
};
class Rect:public Shape
{
public:
	Rect(int a = 0, int b = 0) :a(a), b(b)
	{
		cout << "Rect构造" << endl;
	}
	~Rect()
	{
		cout << "Rect析构" << endl;
	}
	int getC()
	{
		this->c = (this->a + this->b) * 2;
		return this->c;
	}
	int getS()
	{
		this->s = this->a * this->b;
		return this->s;
	}
	void show()
	{
		cout << "周长:" << this->c << ",面积:" << this->s << endl;
	}
private:
protected:
	int a;
	int b;
};
class Circle:public Shape
{
public:
	Circle(int r = 0) :r(r)
	{
		cout << "Circle构造" << endl;
	}
	~Circle()
	{
		cout << "Circle析构" << endl;
	}
	int getC()
	{
		this->c = 2 * 3.14 * this->r;
		return this->c;
	}
	int getS()
	{
		this->s = 3.14 * this->r * this->r;
		return this->s;
	}
	void show()
	{
		cout << "周长:" << this->c << ",面积:" << this->s << endl;
	}
private:
protected:
	int r;
};
void Rcs(Rect & demo)
{
	cout << demo.getC()+ demo.getS()<< endl;
}
void Ccs(Circle& demo)
{
	cout << demo.getC() + demo.getS() << endl;
}
int main()
{
	//矩形对象
	Rect rect(2,3);
	Rcs(rect);
	
	//圆形对象
	Circle circle(3);
	Ccs(circle);


}

解决:用父类统一管理子类
在这里插入图片描述
问题:通过父类的引用操作子类的对象时,并没有执行子类的函数,执行的是子类从父类继承过来的函数
在这里插入图片描述
解决:目的:执行子类重定义的函数,将父类对应的函数写成虚函数
虚函数的格式:

virtual 返回值类型 函数名(参数列表){}

未加victual之前,不能访问子类重定义函数的原因:
将子类对象强制赋值给父类的引用,父类的引用所访问的范围小,访问不到子类的函数
在这里插入图片描述

#include <iostream>
using namespace std;
class Shape
{
public:
	Shape(int s = 0, int c = 0) :s(s), c(c)
	{
		cout << "Shape构造" << endl;
	}
	~Shape()
	{
		cout << "Shape析构" << endl;
	}
	virtual int getC()
	{
		cout << "周长:" << this->c << endl;
		return this->c;
	}
	virtual int getS()
	{
		cout << "面积:" << this->s << endl;
		return this->s;
	}
private:
protected:
	int s;
	int c;
};
class Rect:public Shape
{
public:
	Rect(int a = 0, int b = 0) :a(a), b(b)
	{
		cout << "Rect构造" << endl;
	}
	~Rect()
	{
		cout << "Rect析构" << endl;
	}
	int getC()
	{
		this->c = (this->a + this->b) * 2;
		return this->c;
	}
	int getS()
	{
		this->s = this->a * this->b;
		return this->s;
	}
	void show()
	{
		cout << "周长:" << this->c << ",面积:" << this->s << endl;
	}
private:
protected:
	int a;
	int b;
};
class Circle:public Shape
{
public:
	Circle(int r = 0) :r(r)
	{
		cout << "Circle构造" << endl;
	}
	~Circle()
	{
		cout << "Circle析构" << endl;
	}
	int getC()
	{
		this->c = 2 * 3.14 * this->r;
		return this->c;
	}
	int getS()
	{
		this->s = 3.14 * this->r * this->r;
		return this->s;
	}
	void show()
	{
		cout << "周长:" << this->c << ",面积:" << this->s << endl;
	}
private:
protected:
	int r;
};
void Scs(Shape & demo)
{
	cout << demo.getC()+ demo.getS()<< endl;
}
int main()
{
	//矩形对象
	Rect rect(2,3);
	Scs(rect);
	
	//圆形对象
	Circle circle(3);
	Scs(circle);


}

在这里插入图片描述

动态多态的实现原理

有虚函数一定能实现动态多态吗?不一定

多态的实现:
<1>一个父类,有多个子类
<2>父类中有虚函数,子类重写父类的虚函数
<3>用父类对象的指针或者引用去操作子类的对象并调用虚函数的受,才会触发动态多态(决定性因素)

将父类的对应的函数写成虚函数,在子类中进行重写,通过父类对象的指针/引用去操作子类对象就可以调用到子类的函数了

指针所能访问的空间的大小:由指针指向的数据类型大小决定

int *p; //4字节
shape *p;// 8个字节

在这里插入图片描述
为什么添加virtual就可以访问子类的函数?

虚函数表:保存虚函数的地址(函数指针数组)

什么时候有虚函数表?

一个类中一旦有了虚函数,那么这个类中就有了一个虚函数表,保存这个类中所有虚函数的地址,如果这个类被子类继承了,子类中也会有一张虚函数表

父类的虚函数表和子类的虚函数表一样吗?

<1>如果子类不重写父类的虚函数,那么父类和子类的虚函数表是一样的
<2>如果子类重写了父类的虚函数,那么子类虚函数表中对应的就是子类重写之后的虚函数地址

在这里插入图片描述

  1. 父类有虚函数,那么被子类继承之后,子类中对应的函数也是虚函数!子类中对应函数的virtual关键字可加可不加!
  2. 父类中有函数是虚函数,如果子类有重定义的话,此时被称为重写(覆盖–就是子类中的函数把从父类中继承来的给覆盖了。子类中有且只有一个这样子的函数!!!)!!!!
  3. 重写就必须保证 子类中的函数首部与父类中函数的首部是一模一样的,首部指的是:函数类型 函数名(参数列表)。

动态内存分配中遇到的问题

问题:把new出来的子类对象,赋值给了父对象类型的指针,在整个操作过程中,都是通过父类的指针来操作,使用delete去释放空间的时候,只执行了父类的析构函数,并没有子类的析构函数,可能会造成内存泄漏的问题(在子类的构造函数去new空间了)
在这里插入图片描述

在这里插入图片描述

解决:目标:执行子类的析构函数
将父类的析构函数写成虚函数,子类的析构自然也是虚函数!

在这里插入图片描述

#include <iostream>
using namespace std;
class Shape
{
public:
	Shape(int s = 0, int c = 0) :s(s), c(c)
	{
		cout << "Shape构造" << endl;
	}
	virtual ~Shape()
	{
		cout << "Shape析构" << endl;
	}
	virtual int getC()
	{
		cout << "周长:" << this->c << endl;
		return this->c;
	}
	virtual int getS()
	{
		cout << "面积:" << this->s << endl;
		return this->s;
	}
private:
protected:
	int s;
	int c;
};
class Rect :public Shape
{
public:
	Rect(int a = 0, int b = 0) :a(a), b(b)
	{
		cout << "Rect构造" << endl;
	}
	~Rect()
	{
		cout << "Rect析构" << endl;
	}
	int getC()
	{
		this->c = (this->a + this->b) * 2;
		return this->c;
	}
	int getS()
	{
		this->s = this->a * this->b;
		return this->s;
	}
	void show()
	{
		cout << "周长:" << this->c << ",面积:" << this->s << endl;
	}
private:
protected:
	int a;
	int b;
};
class Circle :public Shape
{
public:
	Circle(int r = 0) :r(r)
	{
		cout << "Circle构造" << endl;
	}
	~Circle()
	{
		cout << "Circle析构" << endl;
	}
	int getC()
	{
		this->c = 2 * 3.14 * this->r;
		return this->c;
	}
	int getS()
	{
		this->s = 3.14 * this->r * this->r;
		return this->s;
	}
	void show()
	{
		cout << "周长:" << this->c << ",面积:" << this->s << endl;
	}
private:
protected:
	int r;
};
void Scs(Shape* demo)
{
	cout << demo->getC() + demo->getS() << endl;
}
int main()
{

	Shape* p = new Circle(4);
	Scs(p);
	delete p;


}

<1>在设计类的时候,为什么建议把析构函数写成虚函数
防止内存泄漏
<2>为什么不执行子类的析构函数就可能会存在内存泄漏的问题
在子类的构造函数去new空间了

重载、重定义、重写的区别

重载:同一个作用域内,函数功能相似,函数名相同、参数不同,与返回值无关的一组函数
重定义:在继承关系中,子类重定义父类的函数,函数名相同即可
重写(覆盖):在继承关系中,子类重写父类的虚函数
备注:函数首部必须一样
首部:返回值类型 函数名(形式参数列表)

抽象类

在设计类的时候,发现这个类确实需要这样子的一个操作函数,但是在父类中不知道该怎么实现,它的所有的子类都要实现这个函数,并且所有的子类实现这个函数的效果是不一样的,这种情况下,就可以把这个函数写成纯虚函数

virtual 返回值类型 函数名(形参列表) = 0;

在这里插入图片描述
注意:抽象类是不能创建对象的
在这里插入图片描述

作用:就是用来被继承的,在子类中去实现这个纯虚函数(每一个子类都要去实现这个纯虚函数)
如果子类没有实现这个纯虚函数,子类也变成了抽象类

#include <iostream>
using namespace std;
class Shape //抽象类
{
public:
	Shape(int s = 0, int c = 0) :s(s), c(c)
	{
		cout << "Shape构造" << endl;
	}
	virtual ~Shape()
	{
		cout << "Shape析构" << endl;
	}
	virtual int getC() = 0;//纯虚函数
	
	virtual int getS() = 0;
	
private:
protected:
	int s;
	int c;
};
class Rect :public Shape
{
public:
	Rect(int a = 0, int b = 0) :a(a), b(b)
	{
		cout << "Rect构造" << endl;
	}
	~Rect()
	{
		cout << "Rect析构" << endl;
	}
	int getC()
	{
		this->c = (this->a + this->b) * 2;
		return this->c;
	}
	int getS()
	{
		this->s = this->a * this->b;
		return this->s;
	}
	void show()
	{
		cout << "周长:" << this->c << ",面积:" << this->s << endl;
	}
private:
protected:
	int a;
	int b;
};
class Circle :public Shape
{
public:
	Circle(int r = 0) :r(r)
	{
		cout << "Circle构造" << endl;
	}
	~Circle()
	{
		cout << "Circle析构" << endl;
	}
	int getC()
	{
		this->c = 2 * 3.14 * this->r;
		return this->c;
	}
	int getS()
	{
		this->s = 3.14 * this->r * this->r;
		return this->s;
	}
	void show()
	{
		cout << "周长:" << this->c << ",面积:" << this->s << endl;
	}
private:
protected:
	int r;
};
void Scs(Shape* demo)
{
	cout << demo->getC() + demo->getS() << endl;
}
int main()
{

	Shape* p = new Circle(4);
	Scs(p);
	delete p;


}

在这里插入图片描述

接口类—抽象类

接口类其实就是抽象类的应用
当抽象类不能实例化对象时,抽象类中的成员变量也就不能初始化,其构造函数也就不能被执行

接口类:类中只有成员函数,没有数据成员,并且成员函数必须是纯虚函数
作用:就是用来被继承的,描述一些能力、协议

#include <iostream>
using namespace std;
//接口类
class fly_land
{
public:
	virtual void fly() = 0;//纯虚函数
	virtual void land() = 0;
};
class Bird :public fly_land
{
public:
	void fly()
	{
		cout << "bird  fly ....." << endl;
	}
	void land()
	{
		cout << "bird land....." << endl;
	}
};
class Plane :public fly_land
{
public:
	void fly()
	{
		cout << "plane fly....." << endl;
	}
	void land()
	{
		cout << "plane land....." << endl;
	}
};
void dosomething(fly_land& demo)
{
	demo.fly();
}
int main()
{
	Bird bird;
	dosomething(bird);

	Plane plane;
	dosomething(plane);
}

在这里插入图片描述

空类对象的内存大小

默认构造函数、析构函数、默认拷贝构造函数、赋值运算符函数、取值运算符函数 const 修饰的取值运算符
空类占内存大小:1字节
在这里插入图片描述
在这里插入图片描述

explicit

作用:修饰构造函数的,对应的构造函数被称为 转换构造函数!!!!
意义:防止构造函数单参数的时候进行自动类型的转换

在这里插入图片描述

final

作用:修饰类和类中的成员函数

修饰类

作用:不能被继承
在这里插入图片描述

修饰成员函数

作用:无法重写
在这里插入图片描述

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

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

相关文章

串口调试助手中文乱码 解决方案

输出乱码 一般&#xff0c;当串口调试助手输出乱码时&#xff0c;可能有以下几个原因&#xff1a; 波特率设置错误&#xff1a;串口通信需要保证发送和接收的设备使用相同的波特率。请检查串口调试助手和目标设备的波特率设置是否一致。 数据位、停止位或校验位设置错误&…

java Web开发中采用Servlet登录验证,中文用户名始终提示“用户名密码错误”以及输出中文乱码问题

采用Servlet登录验证&#xff0c;中文乱码问题解决 在Java Web开发中&#xff0c;往往采用Servlet完成前后端直接的控制和处理&#xff0c;例如&#xff1a;用户登录验证功能。 在采用如下Servle源码t完成用户名登录验证时&#xff0c;只要用户名涉及中文&#xff0c;对于正确…

kafka-偏移量图解

生产者偏移量&#xff1a;生产者发送消息时写入到哪个位置&#xff08;主题的每个分区会存储一个 leo 即将写入消息的偏移量&#xff09;&#xff0c;每次写完消息 leo 会 1 消费者偏移量&#xff1a;消费者从哪个位置开始消费消息&#xff0c;小于等于 leo&#xff0c;每个组…

电脑怎么清理c盘垃圾文件 电脑运行内存不足怎么清理

和Windows系统电脑文件分区不同&#xff0c;苹果电脑并不分区&#xff0c;默认只有C盘&#xff0c;当C盘垃圾文件过多&#xff0c;电脑运行内存不足时&#xff0c;手动清理电脑垃圾文件毫无头绪&#xff0c;可以尝试使用苹果电脑清理软件——CleanMyMac来清理 。 一、电脑怎么…

Stable Diffusion WebUI详细使用指南

Stable Diffusion WebUI&#xff08;AUTOMATIC1111&#xff0c;简称A1111&#xff09;是一个为高级用户设计的图形用户界面&#xff08;GUI&#xff09;&#xff0c;它提供了丰富的功能和灵活性&#xff0c;以满足复杂和高级的图像生成需求。由于其强大的功能和社区的活跃参与&…

618局外人抖音:别人挤压商家“拼价格”,它默默联合商家“抢用户”?

文&#xff5c;新熔财经 作者&#xff5c;宏一 “618”来临之际&#xff0c;各电商平台和短视频平台早已打响了“促销大战”。不过&#xff0c;今年各大平台都更积极适应新的消费形式&#xff0c;调整了“大促动作”。 比如淘宝、京东带头取消了沿用十年之久的预售机制&…

【JS红宝书学习笔记】第4章 变量、作用域和内存

第4章 变量、作用域和内存 1. 原始值和引用值&#xff08;面试题&#xff09; ECMAScript 变量可以包含两种不同类型的数据&#xff1a;原始值和引用值。原始值&#xff08;primitive value&#xff09;就是最简单的数据&#xff08;Undefined、Null、Boolean、Number、Strin…

windows上安装miniforge和jupyterlab

1&#xff0c;下载miniforge3 GitHub - conda-forge/miniforge: A conda-forge distribution. 下载下来后傻瓜式安装就可以了 配置环境变量&#xff0c;在系统环境变量的path添加下列就行了&#xff0c;根据自己的路径修改 2&#xff0c;创建虚拟环境 conda create -n test …

1比1万地形图符号库分享

我们在《1:2.5万、1:5万、1:10万军用地形图图式》一文中&#xff0c;为大家分享过军用地形图式。 还在《超实用三调符号库分享下载》一文中&#xff0c;为大家分享过三调符号库。 现在再为你分享一个&#xff11;比&#xff11;万的地形图符号库&#xff0c;请在文末查看符号…

四象限桌面怎么制作 结合桌面便签更高效

在繁忙的工作中&#xff0c;我们经常面临各种任务和项目的挑战&#xff0c;如何高效地管理这些任务成为提升工作效率的关键。这时候&#xff0c;四象限时间管理法就显得尤为重要。 四象限&#xff0c;即将工作按照紧急与重要程度分为四类&#xff1a;紧急且重要、紧急不重要、…

怎么从视频中提取音频?这里有三种提取妙招

怎么从视频中提取音频&#xff1f;在数字媒体日益丰富的今天&#xff0c;视频内容成为了信息传播的重要形式。但有时我们可能只需要视频中的音频部分&#xff0c;用于制作播客、音乐剪辑或语音分析等。幸运的是&#xff0c;技术的发展为我们提供了多种从视频中高效提取音频的方…

今日好料推荐(大数据湖体系规划)

今日好料推荐&#xff08;大数据湖体系规划&#xff09; 参考资料在文末获取&#xff0c;关注我&#xff0c;获取优质资源。 大数据湖体系规划 一、大数据湖简介 大数据湖&#xff08;Data Lake&#xff09;是一个集中式的存储库&#xff0c;用于存储来自各种来源的结构化和…

人工智能应用-实验5-BP 神经网络分类手写数据集

文章目录 &#x1f9e1;&#x1f9e1;实验内容&#x1f9e1;&#x1f9e1;&#x1f9e1;&#x1f9e1;代码&#x1f9e1;&#x1f9e1;&#x1f9e1;&#x1f9e1;分析结果&#x1f9e1;&#x1f9e1;&#x1f9e1;&#x1f9e1;实验总结&#x1f9e1;&#x1f9e1; &#x1f9…

服务器内存与CPU要占用多少才合理?

一 通常服务器内存占用多少合理&#xff1f;cpu占用多少才合理&#xff1f; 1 通常配置范围建议&#xff1a; 建议CPU使用率不高于80%&#xff1b;内存使用率不高于80%&#xff1b; 注意&#xff1a;具体情况还需要根据服务器的实际负载和应用场景来判断。 2 内存使用率&…

【方法】如何禁止查看压缩包里的内容?

使用压缩文件&#xff0c;可以让文件更方便存储和传输&#xff0c;那对于重要的文件&#xff0c;如何防止随意查看压缩包的内容呢&#xff1f;我们可以试试以下两个方法。 方法1&#xff1a; 最常见的便是给压缩包设置“打开密码”&#xff0c;这样只有通过密码才能查看文件内…

MyBatis系统学习 - 使用Mybatis完成查询单条,多条数据,模糊查询,动态设置表名,获取自增主键

上篇博客我们围绕Mybatis链接数据库进行了相关概述&#xff0c;并对Mybatis的配置文件进行详细的描述&#xff0c;本篇博客也是建立在上篇博客之上进行的&#xff0c;在上面博客搭建的框架基础上&#xff0c;我们对MyBatis实现简单的增删改查操作进行重点概述&#xff0c;在MyB…

产品推荐 | 基于Xilinx Zynq-7015 FPGA的MYC-C7Z015核心板

一、产品概述 基于 Xilinx Zynq-7015&#xff0c;双Cortex-A9FPGA全可编程处理器&#xff1b;PS部分(ARM)与PL部分(FPGA)之间采用AXI高速片上总线通信&#xff0c;吉比特级带宽&#xff0c;突破传统ARMFPGA架构的通信瓶颈&#xff0c;通过PL部分(FPGA)灵活配置丰富的外设接口&…

windows 安装 使用 nginx

windows 安装 使用 nginx nginx官网下载地址&#xff1a;https://nginx.org/en/download.html 下载稳定版本即可 下载压缩包解压到即可 进入文件夹中&#xff0c;打开命令行窗口&#xff0c;执行启动命令 start nginx.exe验证&#xff08;默认是80端口&#xff09;&#x…

产品经理-原型绘制(五)

1. 概念 用线条、图形描绘出的产品框架&#xff0c;也称为线框图&#xff0c;是需求和功能的具体化表现 2. 常用工具 Axure 3. 类别 3.1 草图原型 手绘图稿&#xff0c;修改方便&#xff0c;规划的早期使用 3.2 低保真原型 简单交互&#xff0c;无设计图&#xff0c;无需…

【Docker】2、配置SSL证书远程访问Docker

1、使用 openssl 生成 ca 1、创建文件夹 mkdir -p /root/dockercd /root/docker2、创建 RSA 私钥 会提示 2 次输入证书密码&#xff0c;至少 4 位&#xff0c;创建后会生成一个 ca-key.pem 文件 openssl genrsa -aes256 -out ca-key.pem 4096得到 ca-key.pem 文件 3、创建…