cpp_9.3类和对象中(九) --- 赋值运算重载符

1 变量之间的赋值

int main()
{
	int a = 10;
	int b = 20;
	a = b;
	return 0;
}

2 引入赋值运算重载符

  • 调用赋值运算符重载函数:
  • 如果一个类没有显式实现赋值运算符重载函数,则编译器会生成一份默认的完成对象之间的赋值操作
int main()
{
	Date d0;
	Date d1(2020, 10, 12);
	Date d2(d1);
	Date d3(2020, 10, 13);

	d1 = d3;
	return 0}

完整的代码:

#if 0
class Date
{
public:
	// 成员函数在类内实现,编译器可能会将其当成内联函数来处理
	Date(int year = 1900, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}

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

		cout << "Date(Date&):" << this << endl;
	}

	void PrintDate()
	{
		cout << _year << "-" << _month << "-" << _day << endl;
	}

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

int main()
{
	Date d0;
	Date d1(2020, 10, 12);
	Date d2(d1);
	Date d3(2020, 10, 13);

	// 调用赋值运算符重载函数
	// 如果一个类没有显式实现赋值运算符重载函数,则编译器会生成一份默认的
	// 完成对象之间的赋值操作
	d1 = d3;


	int a = 10;
	int b = 20;
	a = b;

	return 0;
}
#endif

C++为了增强代码的可读性引入了运算符重载,运算符重载是具有特殊函数名的函数,也具有其返回值类型,函数名字以及参数列表,其返回值类型与参数列表与普通的函数类似。

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

3 如果类中涉及到资源管理时,赋值运算符重载函数必须要显式实现出来

#if 0
class String
{
public:
	String(const char* str = "")
	{
		_str = (char*)malloc(strlen(str) + 1);
		strcpy(_str, str);
	}

	String(const String& s)
	{
		cout << "String(const String& s):" << this << endl;
	}


	// String类没有实现自己的拷贝构造函数,则编译器会生成一份
	~String()
	{
		if (_str)
		{
			free(_str);
			_str = nullptr;
		}
	}
private:
	char* _str;
};


void TestString()
{
	String s1("hello");
	String s2("world");

	// 调用拷贝构造,构造一个新对象s3
	String s3(s2);

	// 拷贝构造构造
	String s4 = s3;

	// 编译器生成的赋值运算符重载是按照浅拷贝的方式实现的
	// 如果类中涉及到资源管理时,会导致以下两个后果:
	// 存在两个后果:
	// 1. 浅拷贝:造成后果一份资源释放多次引起代码崩溃
	// 2. s1原来的空间丢失了--内存泄漏
	s1 = s2;
}

int main()
{
	TestString();
	return 0;
}
#endif

注意

  • 不能通过连接其他符号来创建新的操作符:比如operator@
    在这里插入图片描述

  • 重载操作符必须有一个类类型或者枚举类型的操作数

  • 用于内置类型的操作符,其含义不能改变,例如:内置的整型+,不能改变其含义

  • 作为类成员的重载函数时,其形参看起来比操作数数目少1成员函数的操作符有一个认的形参this,限定为第一个形参

  • .* 、:: 、sizeof 、?: 、. 注意以上5个运算符不能重载。

class Date
{
public:
	// 成员函数在类内实现,编译器可能会将其当成内联函数来处理
	Date(int year = 1900, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}

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

		cout << "Date(Date&):" << this << endl;
	}
	void PrintDate()
	{
		cout << _year << "-" << _month << "-" << _day << endl;
	}
	
	//原先的写法
	bool IsLess(const Date& d)
	{
		if ((_year < d._year) ||
			(_year == d._year && _month < d._month) ||
			(_year == d._year && _month == d._month && _day < d._day))
		{
			return true;
		}
		return false;
	}
	
	// 针对原始方法优化的赋值运算符函数
	// 对于自定义类型,编译器不知道如何进行相应运算符的操作
	// 因此需要对该运算符进行重载,相当于告诉编译器针对该中类型的对象如何进行此运算符操作
	//<
	bool operator<(const Date& d)
	{
		if ((_year < d._year) ||
			(_year == d._year && _month < d._month) ||
			(_year == d._year && _month == d._month && _day < d._day))
		{
			return true;
		}
		return false;
	}

	// ==
	bool operator==(/*Date* const this, */const Date& d)
	{
		return _year == d._year &&
			   _month == d._month &&
			   _day == d._day;
	}
	
	//!=
	bool operator!=(const Date& d)
	{
		return !(*this == d);
	}

	// 注意:不能臆造运算符来进行重载
	//void operator@()
	//{
	//}
	
	//+=
	Date& operator+=(int days)
	{
		//Date temp(*this);
		//temp._day += days;
		//return temp;
		_day += days;
		return *this;
	}
	
	//+
	Date operator+(int days)
	{
		Date temp(*this);
		temp._day += days;
		return temp;
	}

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

enum Data
{ONE, TWO, THREE};

//死循环,因为自己调用了自己
//int operator+(Data a, int b)
//{
//	return a + b;
//}

int main()
{
	Date d1(2020, 10, 12);
	Date d2(2020, 10, 13);

	//变量比较
	int a = 10;
	int b = 20;
	if (a < b)
	{
		cout << "a < b" << endl;
	}
	else
	{
		cout << "a >= b" << endl;
	}
	
	//原始方法比较
	if (d1.IsLess(d2))
	{
		cout << "d1 < d2" << endl;
	}
	else
	{
		cout << "d1 >= d2" << endl;
	}
	
	//写了赋值运算符函数之后比较
	if (d1 < d2)
	{
		cout << "d1 < d2" << endl;
	}
	else
	{
		cout << "d1 >= d2" << endl;
	}


	//!=
	if (d1 != d2)
	{
		cout << "d1 != d2" << endl;
	}
	else
	{
		cout << "d1 == d2" << endl;
	}

	a + 10;
	d1 += 10;
	d2 = d1 + 2;
	return 0;
}

4 易出错地方

int operator+(Data a, int b)
{
	return a + b;
}

在这里插入图片描述

赋值运算符主要有四点: 参数类型、 返回值、检测是否自己给自己赋值、 返回*this

  • 一个类如果没有显式定义赋值运算符重载,编译器也会生成一个,完成对象按字节序的值拷贝。(按字节拷贝就是原封不动的拷贝过去,其实就是浅拷贝)

往期链接:
cpp_9.2类和对象中(八) — 拷贝构造函数
cpp_9.1 类和对象中(七)—构造函数中,无参对象如何调用?底层如何实现?
cpp_8.2类和对象中(六) — 析构函数
cpp_8.1类和对象中(五) — 构造函数链接描述
cpp_8 类和对象上(四) — this遗留
cpp_7.1 类和对象上(三) — this
cpp_7类与对象上(二) — 类对象的存储方式
cpp_6.1类与对象上(一)— 类的引入

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值