运算符重载函数

本文详细介绍了C++中如何通过运算符重载增强Date类的代码可读性,包括成员函数如=,==,<,<=,>,>=,++,--的实现,以及与流(<iostream>)交互的流插入和提取运算符重载函数的用法。
摘要由CSDN通过智能技术生成

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


函数名字为:关键字operator后面接需要重载的运算符符号。


函数原型:返回值类型 operator操作符(参数列表)


 

下面以日期类为例子

我们知道系统的基本类型可以进行,+、-等基本运算,但是用户的自定义类型,我们不能使用系统的基本类型+和-,需要对其进行函数名重载才能使用这些操作。

运算符既可以是成员函数,也可以是非成员函数。因为我们通常将用户自定义类型的数据定义为私有,在类外不能访问私有成员。所以通常,将运算符重载函数,定义为成员函数。特别注意,成员函数的形参列表,形参的个数比实际的个数少一个。因为有一个是这个类本身。

#pragma once

#define _CRT_SECURE_NO_WARNINGS

#include <iostream>
#include <cassert>
using namespace std;

class Date
{
public:

	Date(int year = 1, int month = 1, int day = 1)
	{
		if (month >= 13 || month <= 0
			|| day >= GetMonthDay(year, month) || day <= 0)
		{
			assert(false);
		}
		_year = year;
		_month = month;
		_day = day;
	}

	
	Date& operator=(const Date& d);

	bool operator<(const Date& d) const;
	bool operator==(const Date& d) const;
	bool operator<=(const Date& d) const;

	bool operator>=(const Date& d) const;
	bool operator>(const Date& d) const;
	bool operator!=(const Date& d) const;

	
	Date operator+(int day);

	Date& operator+=(int day);

	int GetMonthDay(int year, int month);

	Date& operator++();

	Date operator++(int);

	Date& operator-=(int day);

	Date operator-(int day);

	Date operator--(int);

	Date& operator--();

	int operator-(const Date& d);

	friend ostream& operator<<(ostream& out, const Date& d);

	friend istream& operator>>(istream& in, Date& d);






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

=的运算符重载

Date& Date::operator=(const Date& d) 
{
	if (this != (&d))
	{
		_year = d._year;
		_month = d._month;
		_day = d._day;
	}

	return *this;
}

等号运算符重载的返回值为Date& 类型,使用的是赋值后对象的自引用,可以减少拷贝,提高效率。如果this==&d,说明是自己对自己赋值,不需要进行操作。

==运算符重载

bool Date::operator==(const Date& d) const
{
	return _year == d._year && _month == d._month && _day == d._day;
}

==号运算符的重载判断年、月、日是否相等就可以了。

下面就是<、<=、>=、>等运算符的重载

<运算符的重载

bool Date::operator<(const Date& d) const
{
	if (_year < d._year)
	{
		return true;
	}
	else if (_year == d._year && _month < d._month)
	{
		return true;
	}
	else if (_year == d._year && _month == d._month && _day < d._day)
	{
		return true;
	}
	
	return false;
	
}

<=运算符的重载

在前面,我们已经实现过<、==的运算符重载。只需要复用前面的代码就可以实现<=的运算符重载。

bool Date::operator<=(const Date& d) const
{
	return (*this < d) || (*this == d);
}

>运算符的重载

>的反面就是<=,我们对<=取反就可以完成,>运算符的重载。

bool Date::operator>(const Date& d) const
{
	return !(*this <= d);
}

>=运算符的重载

>=的反面是<,只需要对<取反就可以完成>=的操作了。

bool Date::operator>=(const Date& d) const
{
	return !(*this < d);
}

!=运算符的重载

!=是==的反面

bool Date::operator>(const Date& d) const
{
	return !(*this <= d);
}

+=、+、-=、-运算符的重载

+=运算符的重载

int Date::GetMonthDay(int year,int month)
{
	int Arry[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };
	if (month == 2 && (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0))
	{
		return Arry[month] + 1;
	}
	else
	{
		return Arry[month];
	}
}

Date& Date::operator+=(int day)
{
	if (day < 0)
	{
		return (*this) -= -day;
	}
	else
	{
		_day += day;

		while (_day > GetMonthDay(_year, _month))
		{
			_day -= GetMonthDay(_year, _month);
			++_month;
			if (_month == 13)
			{
				_month = 1;
				++_year;
			}
		}

		return *this;
	}
	
}

如果一个类+=day,我们先将这个类的_day+day,再判断_day的天数,有没有大于这个月的天数,如果大于了,类的月份+1,月份+1后判断,月份是否超过了12,超过了的话将月份置为1,年份+1.循环往复,就可以就出+day后的日期了。

如果+=一个负数的天数,实际上是-=一个整数的天数,我们调用-=就好了。

+运算符的重载

+运算符和+=运算符类似。

比如: int a=3; 

a+3返回结果6,但是a还是3

a+=3,返回6,a变成了6

Date Date::operator+(int day)
{
	Date tmp = (*this);
	tmp += day;
	return tmp;
	
}

-=运算符的重载

Date& Date::operator-=(int day)
{
	if (day < 0)
	{
		return (*this) += -day;
	}
	else
	{
		_day -= day;
		while (_day <= 0)
		{
			--_month;
			if (_month == 0)
			{
				_month = 12;
				--_year;

			}
			_day += GetMonthDay(_year, _month);
		}

		return *this;
	}
	
}

-=运算符的操作和+=的类似,我们先把类的_day-=day;如果得到一个负数,说明日期的_day不足以-day,我们需要向月份借天数,将月份--,然后_day+=借的那个月的天数。月份--之后,我们需要对月份判断是否正确,如果本来月份是1,--变成0,实际上是去年的12月,需要将_month=12,还有减少年份。之后就需要循环判断,直到_day>0为止。

-运算符的重载

-和-=运算符类似

Date Date::operator-(int day)
{
	Date tmp = (*this);
	tmp -= day;
	return tmp;
}

++、--运算符的重载

++运算符的重载

++分为前置++与后置++

前置++运算符的重载

前置++返回的是++后的结果

Date& Date::operator++()
{
	*this = *this + 1;

	return *this;
}

后置++的运算符重载

我们怎么区分前置和后置呢,在形参列表加入一个int就可以说明这个是后置++了。这个int便于编译器区分。

后置++返回的是++之前的结果,++的数据仍然就行了自增。

Date Date::operator++(int)
{
	Date tmp = (*this);
	*this =(*this)+1;

	return tmp;
}

前置--运算符重载函数

Date& Date::operator--()
{
	(*this) -= 1;
	return *this;
}

后置--运算符重载函数

Date Date::operator--(int)
{
	Date tmp = (*this);
	*this -= 1;
	return tmp;
}

那么我们如何计算两个日期相差多少天呢。利用日期-时期。所以需要我们构造日期-日期的运算符重载函数。

int Date::operator-(const Date& d)
{
	Date max=(*this);
	Date min=d;
	int flag = 1;

	if (*this < d)
	{
		max = d;
		min = (*this);
		flag = -1;
	}

	int n = 0;
	while (min != max)
	{
		min++;
		n++;
	}

	return flag*n;
}

两个日期相减,我们需要先找到两个中较大的日期。

小的日期自增到与大的日期相等,自增的次数就是两个日期相差的天数。加一个flag标志用来区分日期相差的正负。

<<流插入运算符重载。我们知道流插入运算符可以打印基本数据类型。用户自定义的类型,能不能使用系统自带的流插入运算符呢?是不行的,需要我们进行函数名重载,便于支持自定义类型的打印。

ostream& operator<<(ostream& out,const Date& d)
{
	out << d._year << "年" << d._month << "月" << d._day << "日" << endl;

	return out;
}

流插入运算符的重载函数。不能作为类的成员函数,因为成员函数的第一个参数默认是类的this指针。但是我们使用流插入运算符是cout<<d<<endl;第一个参数为cout,所以我们不能使用成员函数作为重载函数,那么我们类外不能访问私有成员。该怎么办?我们将函数声明为友元函数,友元函数可以在类外访问私有成员。

在类内加入

为什么返回类型为ostream呢,因为这样可以做到连续的流插入,输出多个结果。

流提取运算符重载函数

我们知道>>可以输入基本的数据类型。但是日期类是我们自定义的类型。我们使用>>输入就需要对>>进行运算符重载。

与流插入运算符的重载函数一样。流提取运算符重载函数,也不能使用成员函数。写在类外将这个函数作为类的友元函数。

istream& operator>>(istream& in, Date& d)
{
	in >> d._year >> d._month >> d._day;

	return in;
}

在类内声明:

对<<、>>进行了运算符重载。我们就可以直接使用其操作了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值