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

这篇具有很好参考价值的文章主要介绍了C++ -3- 类和对象 (中) | 拷贝构造函数 & 赋值运算符重载。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。


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){……}
    • 首先,分析传值传参的过程
      C++ -3- 类和对象 (中) | 拷贝构造函数 & 赋值运算符重载

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

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

    • 为什么会无穷递归:
      C++ -3- 类和对象 (中) | 拷贝构造函数 & 赋值运算符重载

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

//拷贝构造函数
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. 若未显式定义,编译器会生成默认的拷贝构造函数。 默认的拷贝构造函数对象按内存存储按字节序完成拷贝,这种拷贝叫做 浅拷贝,或者 值拷贝

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

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

  • 什么情况下需要自己实现拷贝构造函数?
    C++ -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个运算符不能重载。

应用示例:

顺序表:运算符重载之后,就可以向访问内置类型的数组一样直接访问,并且可以防止越界👇

class List
{
public:
	int& operator[](int i) const
	{
		assert(i < _capacity);
		return _a[i];
	}
private:
	int* _a;
	int _size;
	int _capacity;
};

void Test()
{
	List list;
	list[0];
}

赋值运算符重载

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文章来源地址https://www.toymoban.com/news/detail-418055.html

到了这里,关于C++ -3- 类和对象 (中) | 拷贝构造函数 & 赋值运算符重载的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【C++初阶】类与对象:6大默认成员函数------拷贝构造和赋值运算符重载

      拷贝构造函数: 只有单个形参,该形参是对本类类型对象的引用(一般常用const修饰) ,在用已存在的类类型对象创建新对象时由编译器自动调用。 1. 拷贝构造函数是 构造函数的一个重载形式 ; 2. 拷贝构造函数的 参数只有一个且必须是类类型对象的引用 ,使用传值方式编

    2024年02月03日
    浏览(33)
  • 【C++学习】类和对象 | 拷贝构造 | 探索拷贝构造函数为什么需要引用传参 | 深拷贝 | 初识运算符重载

    上一篇文章我们开始学习类内的默认成员函数, 这里是传送门,有兴趣可以去看看:http://t.csdn.cn/iXdpH 这篇文章我们继续来学习类和对象的知识。 目录 写在前面: 1. 拷贝构造 2. 拷贝构造函数为什么需要引用传参? 3. 深拷贝 4. 初识运算符重载 写在最后: 我们在创建一个对

    2024年02月11日
    浏览(37)
  • 【C++】:拷贝构造函数和赋值运算符重载

    拷贝构造函数是特殊的构造函数。 是用一个已经存在的对象,赋值拷贝给另一个新创建的已经存在的对象 。 本质:用同类型的对象拷贝初始化 。 拷贝构造函数也是 特殊的成员函数 ,其特征如下: 2.1 拷贝构造函数是构造函数的一个重载形式。 2.2 拷贝构造函数的 函数名域

    2024年04月28日
    浏览(29)
  • C++拷贝构造函数与赋值运算符重载

    顾得泉: 个人主页 个人专栏: 《Linux操作系统》 《C++从入门到精通》  《LeedCode刷题》 键盘敲烂,年薪百万!        在现实生活中,可能存在一个与你一样的自己,我们称其为双胞胎。        那在创建对象时,可否创建一个与已存在对象一某一样的新对象呢?  

    2024年02月22日
    浏览(34)
  • 【C++】C++入门—初识构造函数 , 析构函数,拷贝构造函数,赋值运算符重载

    如果一个类中什么成员都没有,简称为空类。 空类中真的什么都没有吗? 并不是 任何类在什么都不写时,编译器会自动生成以下6个默认成员函数。 默认成员函数:用户没有显式实现,编译器会生成的成员函数称为默认成员函数 我们实现了,编译器就不会生成了 构造函数是

    2024年02月21日
    浏览(35)
  • 【C++基础(六)】类和对象(中) --拷贝构造,运算符重载

    💓博主CSDN主页:杭电码农-NEO💓   ⏩专栏分类:C++初阶之路⏪   🚚代码仓库:NEO的学习日记🚚   🌹关注我🫵带你学习C++   🔝🔝 本章重点: 本篇文章将详细讲解拷贝构造函数 和运算符重载,并介绍const成员的概念 拷贝构造函数和运算符重载 是类和对象中六大默认成员函数

    2024年02月14日
    浏览(30)
  • 【C++】类和对象(中)之拷贝构造与运算符、操作符重载

    👀 樊梓慕: 个人主页  🎥 个人专栏: 《C语言》《数据结构》《蓝桥杯试题》《LeetCode刷题笔记》《实训项目》《C++》 🌝 每一个不曾起舞的日子,都是对生命的辜负 我们继续学习默认成员函数,本篇文章博主带来的是拷贝构造函数与运算符、操作符重载的讲解,并且还有

    2024年02月05日
    浏览(38)
  • c++类和对象(拷贝构造、运算符重载、初始化列表、静态成员、友元等)

    拷贝构造函数的特征: 1、拷贝构造函数是构造函数的一个重载形式; 2、拷贝构造函数的参数只有一个且必须是同类类型对象的引用, 使用传值方式编译器直接报错 ,因为会引发无穷递归调用。 在c++中自定义类型 传值传参 的时候要调用拷贝构造函数。 3、若未显式定义,

    2024年02月15日
    浏览(27)
  • 【C++】:拷贝构造函数与赋值运算符重载的实例应用之日期类的实现

    🔑日期类的实现,将按以下声明依次进行,其中因为Print函数比较短,直接放到类里面让其变成内联函数 🔑而我们实现日期类经常要用到某月有多少天,在这里先把获得某月有多少天的函数实现出来。实现时先检查传参有没有问题,在注意把数组设置成静态的,出了作用域

    2024年02月08日
    浏览(49)
  • c++拷贝构造与赋值运算符重载

    目录 目录:         1:拷贝构造         2:赋值运算符重载                  前言:在上一章我们已经学习过了,构造与析构这两个默认成员函数了,接下来让我们一起来学习另外两个重要的默认成员函数。         首先让我们来讲一下默认成员函数这个概念,所谓

    2024年02月08日
    浏览(40)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包