C++ -3- 类和对象 (中) | 拷贝构造函数 赋值运算符重载

文章目录

  • 4.拷贝构造函数
    • 什么是拷贝构造函数?
    • 应用——示例:日期计算器
    • 什么情况下需要自己实现拷贝构造函数?
  • 5.赋值运算符重载
    • 运算符重载(重要)
    • 赋值运算符重载
  • 拷贝构造函数和赋值重载函数


4.拷贝构造函数

什么是拷贝构造函数?

  • 示例:
class Date
{
public:
	//构造函数
	Date(int year=2023,int month=2,int day=27){
		_year = year;
		_month = month;
		_day = day;
	}

	//拷贝构造函数
	Date(Date d)
	{……}
	
private:
	int _year;
	int _month;
	int _day;
};

void TestDate1(){
	Date d1(2023, 4, 1);//调用构造函数
	Date d2(d1);//调用拷贝构造函数
	//or
	Date d2 = d1;//调用拷贝构造函数
}

拷贝初始化构造函数的作用是将一个已知对象的数据成员值拷贝给正在创建的另一个同类的对象

  • 无穷递归Date(Date d){……}
    • 首先,分析传值传参的过程
      在这里插入图片描述

    • 传引用传参没有拷贝的过程,直接传

    • 传值传参:
      内置类型编译器可以直接拷贝(浅拷贝/值拷贝——一个字节一个字节的拷贝)
      自定义类型编译器无法拷贝,需要调用 拷贝构造函数(浅拷贝 or 深拷贝)

    • 为什么会无穷递归:
      在这里插入图片描述

∴ 正确的拷贝构造: 传引用传参

//拷贝构造函数
Date(const Date& d)
{	//……	
}

应用——示例:日期计算器

日期计算器:实现一个函数,获取 X 天后的日期
第一种:

int GetMonthDay(int year, int month)//获取对应年月的天数
{
	if (month > 0 && month < 13)
	{
		int array[] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };
		if (month == 2)
		{

			if ((year % 400 == 0) || ((year % 4 == 0) && (year % 100 != 0)))
			{
				++array[2];
			}
		}

		return array[month];
	}
	else
	{
		cout << "month error" << endl;
		return 0;
	}
}

class Date
{
public:
	//构造函数
	Date(int year = 2023, int month = 2, int day = 27)
	{
		_year = year;
		_month = month;
		_day = day;
	}

	//拷贝构造函数
	Date(const Date& d)
	{
		_year = d._year;
		_month = d._month;
		_day = d._day;
	}

	void Print()
	{
		cout << _year << "/" << _month << "/" << _day << endl;
	}

	//获取 X 天后的日期
	Date& GetAfterXDate1(int x)
	{
		_day = _day + x;
		int monthDay = GetMonthDay(_year, _month);
		while (_day > monthDay)
		{
			_day -= monthDay;
			++_month;

			if (_month > 12)
			{
				++_year;
				_month = 1;
			}
			monthDay = GetMonthDay(_year, _month);

		}
		return *this;//调用拷贝构造
	}

private:
	int _year;
	int _month;
	int _day;
};

void TestDate1()
{
	Date d1(2023, 4, 1);
	d1.GetAfterXDate1(10000);
	d1.Print();
}

第二种:不改变原日期

//获取 X 天后的日期
Date GetAfterXDate2(int x)
{
	Date tmp = *this;//调用拷贝构造
	tmp._day = _day + x;
	int monthDay = GetMonthDay(tmp._year, tmp._month);
	while (tmp._day > monthDay)
	{
		tmp._day -= monthDay;
		++tmp._month;
		if (tmp._month > 12)
		{
			++tmp._year;
			tmp._month = 1;
		}
		monthDay = GetMonthDay(tmp._year, tmp._month);
	}
	return tmp;//调用拷贝构造
}
void TestDate2()
{
	Date d1(2023, 4, 1);
	Date d2 = d1.GetAfterXDate2(10000);
}
  • 拷贝构造函数也是特殊的成员函数,其特征如下:
  1. 拷贝构造函数是构造函数的一个重载形式。
  2. 拷贝构造函数的参数只有一个且必须是类类型对象的引用,使用传值方式编译器直接报错,因为会引发无穷递归调用。
  3. 若未显式定义,编译器会生成默认的拷贝构造函数。 默认的拷贝构造函数对象按内存存储按字节序完成拷贝,这种拷贝叫做 浅拷贝,或者 值拷贝

什么情况下需要自己实现拷贝构造函数?

  • 编译器默认的拷贝构造函数 能完成“值拷贝”(浅拷贝)
    所以,日期类(都是内置类型)没有自己实现拷贝构造函数的必要

  • 什么情况下需要自己实现拷贝构造函数?
    在这里插入图片描述

  • sum. 自己实现了析构函数释放空间(意味着设计资源管理),则需要自己实现拷贝构造函数


5.赋值运算符重载

运算符重载(重要)

运算符重载:让【自定义类型】可以使用运算符

例如: 内置类型可以直接比大小;自定义类型不可以直接比大小

//内置类型
int a = 1,b = 2; a==b; a>b;

//自定义类型
class Date { 	//…… } 
Date d1;Date d2; 
d1==d2;? d1<d2;?

运算符重载具有特殊函数名的函数,也具有其返回值类型,函数名字以及参数列表,其返回值类型与参数列表与普通的函数类似。

函数名字为:关键字 operator 后面接需要重载的运算符符号
函数原型:返回值类型 operator操作符(参数列表)

  • 将运算符重载函数放在全局:
bool operator==(const Date& d1,const Date& d1)
{
	return d1._day == d2._day
		&& d1._month == d2._month
		&& d1._year == d2._year;
}
  • 将运算符重载函数放入类:
    • 这里需要注意的是,左操作数是this,指向调用函数的对象
    • 操作符使用时包含几个操作数,运算符重载函数就含有几个参数
bool operator==(Date* this, const Date& d2)
!这里需要注意的是,左操作数是this,指向调用函数的对象
----------------------------------------------
// ==运算符重载
bool Date::operator==(const Date& d)
{
	return _day == d._day
		&& _month == d._month
		&& _year == d._year;
}
// >运算符重载
bool Date::operator>(const Date& d)
{
	if (_year < d._year)
		return false;
	if (_year > d._year)
		return true;
	if (_month < d._month)
		return false;
	if (_month > d._month)
		return true;
	if (_day < d._day)
		return false;
	if (_day > d._day)
		return true;
		
	return false;
}

注意:

  • 不能通过连接其他符号来创建新的操作符:比如operator@
  • 重载操作符必须有一个 类型 参数
  • 用于内置类型的运算符,其含义不能改变,例如:内置的整型+,不能改变其含义
  • 作为类成员函数重载时,其形参看起来比操作数数目少1,因为成员函数的第一个参数为隐藏的this
  • .* / :: / sizeof / ?: / .注意以上5个运算符不能重载。

赋值运算符重载

1.赋值运算符重载的特性

赋值运算符 “=”,可以连续赋值,例如:

int i = 1,j = 0,k = 0;
j = k = i;//连续赋值

∴ 赋值运算符重载函数应该有 返回值

// 赋值运算符重载
// d2 = d3 -> d2.operator=(&d2, d3)
Date& Date::operator=(const Date& d)
{
	if (*this == d)//如果时自己给自己赋值就不用进行下列操作了
		return *this;
	_day = d._day;
	_month = d._month;
	_year = d._year;
	return *this;
}
  1. 赋值运算符只能重载成类的成员函数不能重载成全局函数

原因:赋值运算符如果不显式实现,编译器会生成一个默认的。此时用户再在类外自己实现一个全局的赋值运算符重载,就和编译器在类中生成的默认赋值运算符重载冲突了,故赋值运算符重载只能是类的成员函数。


拷贝构造函数和赋值重载函数

默认生成的拷贝函数/赋值重载函数

  1. 内置类型浅拷贝
  2. 自定义类型,调用这个成员的拷贝构造函数/赋值重载函数

对比↕

默认生成的构造函数/析构函数

  1. 内置类型不处理
  2. 自定义类型,调用它的默认构造函数

END

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Vue2 API-源码解析

目录 Vue.extend(option) delimiters functional Vue.component(id, Function | Object) Vue.directive( id, [definition] ) Vue.filter( id, function) Vue.nextTick() Vue.set() Vue.delete(target, index/key) Vue.compile(template) Vue.observable(object) …

一文讲解系统性能分析之|iowait是什么?

我们对系统性能进行优化时&#xff0c;一般会使用 top 命令来查看系统负载和系统中各个进程的运行情况&#xff0c;从而找出影响系统性能的因素。如下图所示&#xff1a; top top 命令会输出很多系统相关的信息&#xff0c;如&#xff1a;系统负载、系统中的进程数、CPU使用率…

四十六、docker-compose部署

一个项目肯定包含多个容器&#xff0c;每个容器都手动单独部署肯定费时费力。docker-compose可以通过脚本来批量构建镜像和启动容器&#xff0c;快速的部署项目。 使用docker-compose部署主要是编写docker-compose.yml脚本。 一、项目结构 不论是Dockerfile还是docker-compo…

实验室汇报汇报汇报

1、kafka是什么 Producer&#xff1a;即生产者&#xff0c;消息的产生者&#xff0c;是消息的入口&#xff1b;Consumer&#xff1a;消费者&#xff0c;即消息的消费方&#xff0c;是消息的出口&#xff1b;Broker&#xff1a;中间代理&#xff0c;即一个broker就是一个server。…

接口优化的常见方案实战总结

一、背景 针对老项目&#xff0c;去年做了许多降本增效的事情&#xff0c;其中发现最多的就是接口耗时过长的问题&#xff0c;就集中搞了一次接口性能优化。本文将给小伙伴们分享一下接口优化的通用方案。 &#xfeff; &#xfeff; &#xfeff;&#xfeff; 二、接口优化…

设计模式-结构型模式之装饰模式

3. 装饰模式3.1. 模式动机一般有两种方式可以实现给一个类或对象增加行为&#xff1a;继承机制使用继承机制是给现有类添加功能的一种有效途径&#xff0c;通过继承一个现有类可以使得子类在拥有自身方法的同时还拥有父类的方法。但是这种方法是静态的&#xff0c;用户不能控制…

java基础——迭代器,数据结构,List,Set ,TreeSet集合,Collections工具类

迭代器&#xff0c;数据结构,List,Set ,TreeSet集合,Collections工具类 第一章 Iterator迭代器 1.1 Iterator接口 在程序开发中&#xff0c;经常需要遍历集合中的所有元素。针对这种需求&#xff0c;JDK专门提供了一个接口java.util.Iterator。 想要遍历Collection集合&…

链表基础知识

1.链表必知必会 什么是链表? 链表是一种通过指针串联在一起的线性结构&#xff0c;每一个节点由两部分组成&#xff0c;一个是数据域一个是指针域&#xff08;存放指向下一个节点的指针&#xff09;&#xff0c;最后一个节点的指针域指向null&#xff08;空指针的意思&#…

【好刊推荐】知名出版社影响因子7+被踢出SCI,投稿前如何选期刊?

今年3月Hindawi旗下的19本期刊被SCIE剔除&#xff0c;其中有一本影响因子7&#xff0c;以下从期刊各个指标方面分析一下具体原因&#xff1a; 期刊剔除&#xff1a;影响因子7 期刊简介 期刊名称&#xff1a; OXIDATIVE MEDICINE AND CELLULAR LONGEVITY ISSN / eISSN&#…

数据结构——堆和优先队列

文章目录前言堆堆的引入堆的定义堆的储存结构优先队列优先队列简介优先队列的基础操作入队出队优先队列的实现堆的应用堆排序TOP-K问题什么是TOP-K问题TOP-K问题的排序解法TOP-K问题的堆解法总结前言 堆是一个比较基础&#xff0c;且实现起来难度也不算太大的一个数据结构。而…

可选择的Elasticsearch好用的可视化客户端工具

前言 常言道&#xff1a;工欲善其事&#xff0c;必先利其器。对于我们开发和测试同学来说&#xff0c;在日常的工作中有一款趁手的工具那真实如虎添翼啊&#xff0c;工作效率可是蹭蹭蹭的往上长&#xff0c;节省下来的时间摸摸鱼该有多好啊。最近我们系统开始使用elasticsearc…

Spring注解开发

定义bean 我们先直接通过一张图来理解注解在Spring开发中如和定义bean&#xff1a; 那么我们既然加了注解&#xff0c;相当于定义了bean可是Spring的配置文件怎么知道他的存在&#xff0c;于是我们引入component-scan进行包扫描即为了让Spring框架能够扫描到写在类上的注解&…

Lego- 美团接口自动化测试实战(详细解析)

目录&#xff1a;导读 一、概述 1.1 接口自动化概述 1.2 提高 ROI 1.3 Lego 的组成 二、脚本设计 2.1 Lego 的做法 2.2 测试脚本 2.3 配置文件 三、用例设计 3.1 一些思考 3.2 Lego 接口自动化测试用例 3.3 参数化 3.4 前后置动作 3.5 执行各部分 四、网站功能 …

八百字讲清楚——BCEWithLogitsLoss二分类损失函数

BCEWithLogitsLoss是一种用于二分类问题的损失函数&#xff0c;它将Sigmoid函数和二元交叉熵损失结合在一起。 假设我们有一个大小为NNN的二分类问题&#xff0c;其中每个样本xix_ixi​有一个二元标签yi∈0,1y_i\in {0,1}yi​∈0,1&#xff0c;并且我们希望预测每个样本的概率…

Seal AppManager发布:基于平台工程理念的全新应用部署管理体验

4月12日&#xff0c;数澈软件Seal&#xff08;以下简称“Seal”&#xff09;宣布推出新一代应用统一部署管理平台 Seal AppManager&#xff0c;采用平台工程的理念&#xff0c;降低基础设施操作的复杂度为研发和运维团队提供易用、一致的应用管理和部署体验&#xff0c;进而提升…

28岁,他是如何成为上市公司测试总监的

现在的大环境下&#xff0c;各行各业都开始内卷起来&#xff0c;测试也不例外&#xff0c;企业要求也越来越高&#xff0c;“会代码”逐渐成为测试工程师的一个标签。你要想拿到一个不错的薪资&#xff0c;必不可少的一个技能—自动化测试&#xff0c;自动化测试难吗&#xff1…

【2023最新】超详细图文保姆级教程:App开发新手入门(5)

上文回顾&#xff0c;我们已经完成了一个应用的真机调试&#xff0c;本章我们来了解一下如何引入YonBuilder移动开发的&#xff08;原生&#xff09;移动插件, 并利用移动插件完成一个简单的视频播放器。 8. 「移动插件」的使用 8.1 什么是 「移动插件」&#xff1f; 用通俗…

HDLBits-Modules 题解【Verilog模块例化】(中文翻译+英文原文,可顺带学习英文)

Moudule 概念介绍 到目前为止&#xff0c;你已经熟悉了一个模块&#xff0c;它是一个通过输入和输出端口与其外部交互的电路。更大、更复杂的电路是通过将较小的模块和其他连接在一起的部分&#xff08;例如赋值语句和always块&#xff09;组合而成的更大模块来构建的。因为模…

对决:Kubernetes vs Docker Swarm - 谁才是最优秀的容器编排方案?

✅创作者&#xff1a;陈书予 &#x1f389;个人主页&#xff1a;陈书予的个人主页 &#x1f341;陈书予的个人社区&#xff0c;欢迎你的加入: 陈书予的社区 文章目录一、介绍1. 什么是Kubernetes2. 什么是Docker Swarm3. 为什么需要容器编排&#xff1f;二、 架构比较1. Kubern…

C++【栈队列(3种)反向迭代器】

文章目录一、容器适配器二、栈&#xff08;一&#xff09;栈定义&#xff08;二&#xff09;栈使用接口&#xff08;三&#xff09;栈模拟实现(1) 栈模拟实现解析(2) 栈模拟实现代码(3) 栈模拟结果三、队列&#xff08;一&#xff09;普通队列&#xff08;1&#xff09;普通队列…