类(4)

news2024/11/5 6:50:30

1.拷贝构造函数

我们在创建对象得的时候,可否创造一个与已存在对象一摸一样的对象呢?

拷贝构造函数:只有单个形参,该形参是对本类类型对象的引用(一般常用const修饰)

用在已存在的类类型对象创建新对象时由编译器自动调用

拷贝构造函也是特殊的成员函数,其特征如下:

1.拷贝构造函数是构造函数的一个重载形式

2.拷贝构造函数的参数只有一个且必须是类类型对象的引用,使用其他传值方式编译器直接报错,因为会引发无穷递归!

先来解释一下为啥会无限递归

class Date
{
	Date(const Date date)
	{
		_year = date._year;
		_month = date._month;
		_day = date._day;
	}
private:
	int _year;
	int _month;
	int _day;

};

直接这样写·编译器会报错,为啥?

我这个地方调用Date date 的时候我要干嘛?我要把Date这个类的所有内容都要拷贝过来,

那这个地方我把这个类传过来的同时也把这个函数穿过来了!

那我把这个函数穿过来的时候是不是也把这个函数的Date date传过来了!这样不就又形成了一个新的拷贝构造了吗?

这样一直传一直传,无限递归无法停止

那我们有没有一种好的方法能解决这个问题吗?

答案是当然有啊!

可能在学C语言的时候会想到指针(任何指针都是内置类型)

但是我们现在学了C++所以就用引用(取别名)

我们先来看下面这串代码

class Date
{
public:
	Date(int year, int month, int day)
	{
		_year = year;
		_day = day;
		_month = month;
	}
public:
	Date(const  Date& date)
	{
		_year = date._year;
		_month = date._month;
		_day = date._day;
	}
	public :
	int _year;
	int _month;
	int _day;

};
int main(void) {
	class Date d1(2005, 4, 14);
	Date d2(d1);
	return 0;
}

Date d2(d1)和

Date(const  Date& date)
{
    _year = date._year;
    _month = date._month;
    _day = date._day;
}

本质上是在干什么?

我们把this指针加上

Date(const  Date& date)
{
	this->_year = date._year;
	this->_month = date._month;
	this->_day = date._day;
}

这个地方的d2传给了this,而d1传给了date,所以这个操作的本质上是把d2的值赋给d1!

这个地方虽然成员变量是private

在类里面不受访问限定符的限制

其实你会发现这样编译器也能通过

class Date
{
public:
	Date(int year, int month, int day)
	{
		_year = year;
		_day = day;
		_month = month;
	}

	public :
	int _year;
	int _month;
	int _day;

};
int main(void) {
	class Date d1(2005, 4, 14);
	Date d2(d1);
	return 0;
}

这是因为拷贝构造函数如果没有写显示定义,编译器会生成默认的拷贝构造函数

默认的拷贝构造函数对象按内存储存的字节序完成拷贝

这种拷贝叫做浅拷贝,也称值拷贝!

这个地方编译器对内置对象和自定义对象的处理方式和前面学过的构造函数和析构函数有点区别

1.内置类型成员完成值拷贝/浅拷贝

2.自定义类型成员会调用他的拷贝构造

看起来上面的代码好像默认的拷贝构造函数也够用啊!

但是在有些情况下是不适用的

typedef struct Stack
{
	int* a;
	int top;
	int capacity;
}ST;

比如说这个栈当作类去写

s1 ,s2两个类

我拷贝构造函数拷贝过去的同时也把a拷贝过去了。这意味我s1,s2两个的a指向的是同一块空间

当s1析构后a指向的空间被释放了,到s2就再析构把这个空间第二次,但是同一块空间不能释放两次,因此就会出错

像上面的就是浅拷贝,只是值的拷贝,因此有些地方要我们自己去实现深拷贝(这个后面会再介绍)

2.运算符重载

我们平时在比较数的大小的时候,很好比,2>1 显而易见的,但是我们有没有思考过,如果是两个自定义类型的呢? 比如我要比较两个日期的大小,编译器无法直接提供比较大小的方法,这个时候就要我们自己写了,而C++给我们提供了一种很好的方式,就是我们自己来写比较的方法

我们自己来写比较两个日期 的方法

但是这个地方明明写的好像没啥问题,但是为啥这个地方编译器会报错啊!

报错说的是传的参数太多,我们漏掉了this指针啊!

所以我们这个地方改一下就可以了!

​
class Date
{
public:
	bool operator>(const Date& x)
	{
		if (_year == x._year)
		{
			return true;
		}
		else if ((_year == x._year) && (_month > x._month))
		{
			return true;
		}
		else if ((_year == x._year) && (_month == x._month) && (_day > x._day))
		{
			return true;
		}
		return false;
	}
	Date(int year, int month, int day)
	{
		_year = year;
		_day = day;
		_month = month;
	}
public:
	int _year;
	int _month;
	int _day;
};
int main(void) {
	class Date d1(2005, 4, 14);
	class Date d2(2001, 1, 2);
	if (d1 > d2)
	{
		printf("true");
}
	else
	{
		printf("false");
	}
	return 0;
}

​
int a = (int)(d1.operator>(d2));
int b = d1 > d2;
int c = operator>(d1, d2);

这个地方

d1>d2本质上是啥

a b c本质上是同样的东西

但是c的这种方式我们不能直接显示写

operator>函数中的实际是这样的

	bool operator>(const Date& x)
	{
		if (this->_year == x._year)
		{
			return true;
		}
		else if ((this->_year == x._year) && (this->_month > x._month))
		{
			return true;
		}
		else if ((this->_year == x._year) && (this->_month == x._month) && (this->_day > x._day))
		{
			return true;
		}
		return false;
	}

所以d1>d2

本质上是将d1的地址当作this指针传过去,把d2的别名传过去给了x

 操作符重载的要求是至少有一个类成员

不然你重载出来2>3 还是true 就太离谱了!

接下来我们要开始引入,6个默认成员函数之一的赋值重载

3.赋值重载函数

赋值重载函数本质上和上面的操作符重载是差不多的(因为操作符函数重载本质上也是operator函数嘛!)

但是这个地方本质上还是有一定区别的

class Date
{
public:
	void operator=(const Date& x)
	{
		if (_year == x._year)
		{
			return ;
		}
		else if ((_year == x._year) && (_month > x._month))
		{
			return ;
		}
		else if ((_year == x._year) && (_month == x._month) && (_day > x._day))
		{
			return ;
		}
		return ;
	}
	Date(int year, int month, int day)
	{
		_year = year;
		_day = day;
		_month = month;
	}
public:
	int _year;
	int _month;
	int _day;
};
int main(void) {
	class Date d1(2005, 4, 14);
	class Date d2(2001, 1, 2);
	class Date d3(2000, 1, 1);
	d1 = d2;
	d1 = d2 = d3;
	return 0;
}

这个地方我们自己写了一个operator赋值函数我们发现d1=d2这个地方没有问题

但是d1=d2=d3这个地方就出问题了,为啥?

首先我们要知道,这条语句的执行顺序是从右到左的,

d2=d3先进行赋值

正常我们普通变量赋值

比如a=b最后得到的结果是b

但是这个地方我们的d1 d2 d3 是自定义类型

它们的赋值是通过赋值函数重载进行的,d2=d3

通过operator这个函数我们知道,结果是void(这个结果的返回值是void)

然后d1=void

这个地方就出错了,我们稍微改一下就可以了

把operator=这个函数的返回值改成Date就可以了!

但是这还不是最优解,最优解就是传别名

传值拷贝返回效率太低了

这样就不是d1=void 而是d1=d2了。

当然了,这个地方我们自己不写,编译器也会自动生成

但是赋值重载函数和一般重载函数的区别在于

赋值运算符只能重载成类的的成员函数,不能重载成全局函数

原因:我们如果在全局写一个赋值重载函数会导致我们在调用的时候到底是调用全局的,还是类的成员函数,当然我们可能说,我们不写类的那个成员函数不就可以了吗?但是复制重载函数是那6个成员函数之一啊!你不写编译器也会自动生成!

那么赋值运算符重载函数和拷贝构造函数有啥区别呢?

赋值运算符重载函数是作用与两个已存在已声明的函数

而拷贝构造函数本质上就带有声明的属性

默认生成赋值重载跟拷贝构造行为一样

1.内置类型成员 值拷贝  浅拷贝

2.自定义类型成员会去调用他的赋值重载

最后一个问题,我们在使用前置++和后置++去进行操作符重载,该怎么区分呢?

一般都是将后置++的参数多一个参数,从而构成函数重载

这个地方的这个参数a没有实际作用,只是为了和前置++做区分而做出的函数重载!因此也可以只写一个int

//前置++
Date& operator ++()
{
	*this += 1;
	return *this;
}
//后置++
Date& operator ++(int a)
{
	Date tmp(*this);
	*this += 1;
	return tmp;
}

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

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

相关文章

‌【元素周期表】氢

化学式:H₂ 外观:无色透明 分子量:2.01588 吸入少量氢气对人体没有危害,甚至还可能对人体有益。但是不能吸入大量氢气,否则可能会对身体造成影响。 氢在生活中的主要用途包括以下几个方面‌: ‌医疗保健…

【06】A-Maven项目SVN设置忽略文件

做Web项目开发时,运用的是Maven管理工具对项目进行管理,在项目构建的过程中自动生成了很多不需要SVN进行管理的文件,SVN在对源码进行版本管理时,需要将其忽略,本文给出了具体解决方案。 SVN设置忽略Maven项目中自动生成…

【Windows】X-DOC:无需NAS使用Windows也能安装Jellyfin玩私人影音媒体平台

【Windows】X-DOC:无需NAS使用Windows也能安装Jellyfin玩私人影音媒体平台 1、前言2、Jellyfin服务搭建2.1 Jellyfin简介2.2 Jellyfin下载2.3 Jellyfin安装2.4 Jellyfin设置2.5 Jellyfin使用 3、终端访问3.1 浏览器访问 4、内网穿透 1、前言 下载收藏高清电影、电视…

海的记忆篇章:海滨学院班级回忆录项目

摘要 随着信息技术在管理上越来越深入而广泛的应用,管理信息系统的实施在技术上已逐步成熟。本文介绍了海滨学院班级回忆录的开发全过程。通过分析海滨学院班级回忆录管理的不足,创建了一个计算机管理海滨学院班级回忆录的方案。文章介绍了海滨学院班级回…

Unity 使用Netcode实现用户登录和登出

Unity之NetCode for GameObjets 基本使用 说明思路相关API代码实现Tips 说明 最近项目需要联机,项目方案选用Unity提供的NetCode for GameObjets(以下简称NGO),踩了不少坑,本文不介绍基础使用,围绕双端&…

C++(类和对象-运算符重载)

运算符重载概念: 对已有的运算符重新进行定义,赋予其另一种功能,以适应不同的数据类型 运算符重载的同时也可以发生函数重载 1.加号运算符重载 1.1加号运算符重载的本质 1.2运算符重载也可以发生函数重载 总结1:对于内置的数据类型…

Flink CDC 同步 Mysql 数据

文章目录 一、Flink CDC、Flink、CDC各有啥关系1.1 概述1.2 和 jdbc Connectors 对比 二、使用2.1 Mysql 打开 bin-log 功能2.2 在 Mysql 中建库建表准备2.3 遇到的坑2.4 测试 三、番外 一、Flink CDC、Flink、CDC各有啥关系 Flink:流式计算框架,不包含 …

Sigrity Power SI VR noise Metrics check模式如何进行电源噪声耦合分析操作指导

SSigrity Power SI VR noise Metrics check模式如何进行电源噪声耦合分析操作指导 Sigrity Power SI的VR noise Metrics check模式本质上是用来评估和观测器件的电源网络的耦合对于信号的影响,输出S参数以及列出具体的贡献值。 以下图为例

Vue computed watch

computed watch watch current prev

恋爱脑学Rust之智能指针Rc,RefCell和Weak指针

小明和小丽为了维系彼此的关系,一起探索了智能指针的奥秘。通过 Rc、RefCell 和 Weak 的帮助,他们得以克服情感中遇到的种种困境。 第一章:Rc 智能指针的共生 小明和小丽搬进了一个共同的小屋,他们彼此相爱,决定共用…

Matlab车牌识别课程设计报告(附源代码)

Matlab车牌识别系统 分院(系) 信息科学与工程 专业 学生姓名 学号 设计题目 车牌识别系统设计 内容及要求: 车牌定位系统的目的在于正确获取整个图像中车牌的区域, 并识别出车牌号。通过设计实现车牌识别系…

Java 文件操作与IO流

文件 文件有两个概念,在广义来看就是操作系统上对硬件和软件资源抽象为文件。 在侠义上来看,就是我们保存在硬盘上的文件 在这里我们讨论的是狭义的文件,在外面的硬盘上的文件细分又可以分为二进制文件和文本文件,文本文件可以通…

C++ 优先算法 —— 有效三角形的个数(双指针)

目录 题目:有效三角形个数 1. 题目解析 2. 算法原理 解法一: 暴力枚举 解法二: 双指针算法 3. 代码实现 暴力枚举 双指针算法 题目:有效三角形个数 1. 题目解析 题目截图: 题目的意思就是在一个数组中&#x…

前端拖拽库方案之react-beautiful-dnd

近期,知名 React 拖拽库 react-beautiful-dnd 宣布了项目弃用的决定,未来将不再维护。这一决定源于其存在的缺陷与局限性,促使作者转向开发一个更加现代化的拖拽解决方案——Pragmatic drag and drop(下面会介绍)&…

《高频电子线路》—— 调制

文章内容来源于【中国大学MOOC 华中科技大学通信(高频)电子线路精品公开课】,此篇文章仅作为笔记分享。 调制 调制的原因 第一个原因 是为了要做出切实可行的天线。 无线电波能够从天线发射出去,以及正常的接收,需要…

第二十四章 v-model原理及v-model简化表单类组件封装

目录 一、v-model 原理 二、表单类组件封装 三、v-model简化组件封装代码 一、v-model 原理 原理:v-model本质上是一个语法糖。例如应用在输入框上,就是 value属性 和 input事件 的合写。 作用:提供数据的双向绑定 ① 数据变&#x…

机器学习中的数据可视化:常用库、单变量图与多变量图绘制方法

《博主简介》 小伙伴们好,我是阿旭。专注于人工智能、AIGC、python、计算机视觉相关分享研究。 ✌更多学习资源,可关注公-仲-hao:【阿旭算法与机器学习】,共同学习交流~ 👍感谢小伙伴们点赞、关注! 《------往期经典推…

SELS-SSL/TLS

一、了解公钥加密(非对称加密) 非对称加密中,用于加密数据的密钥与用于解密数据的密钥不同。私钥仅所有者知晓,而公钥则可自由分发。发送方使用接收方的公钥对数据进行加密,数据仅能使用相应的私钥进行解密。 你可以将…

Kubernetes中的secrets存储

华子目录 2.secrets2.1secrets功能介绍2.2secrets的创建2.2.1从文件创建2.2.2编写yaml文件 2.3secret的使用案例2.3.1将secret挂载到volume中2.3.2设置子目录映射secret密钥2.3.3将secret设置为环境变量2.3.4存储docker register的认证信息spec.imagePullSecrets[] 2.secrets …

软件设计师笔记-数据结构

数据结构 数据元素的集合及元素间的相互关系和构造方法。 线性表的存储结构 顺序存储链式存储 单链表节点 typedef struct node { int data; struct node *link; }NODE, *LinkList; 双向链表 每个节点有两个指针,分别指出直接前驱和直接后继。 循环链表 尾…