运算符重载

对于内置类型,编译器可以帮助我们完成各种操作符的计算,对于自定义类型却无法直接完成计算,因为自定义类型在没有规定时编译器不知道如何计算。

比如日期类比较大小,我们都知道先比年份,年份大的日期大,年份相同比月份,最后在比天。

虽然我们知道这样比较,但编译器压根就不知道这样比较。

由于是自定义类型,我们想要完成这样的比较只能自己去定义一些运算符,这样自定义运算符的方式叫运算符重载。

那是不是对于所有的类型都可以使用运算符重载?

当然不行。如果对于内置类型也能运算符重载,也就是说连基本的加减乘除都可以重新定义,那所有的计算岂不是乱套了,所以内置类型不支持运算符重载。

如何使用运算符重载呢?

函数名字为:关键字operator后面接需要重载的运算符符号。下面来实现日期类大于的比较:

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

可是,这不是两个类之间比较大小嘛,怎么就只有一个形参了呢?

其实作为类成员函数重载时,其形参看起来比操作数数目少1,因为成员函数的第一个参数为隐藏的this。显然,这里的this指针指向的是左操作数,而形参d是右操作数。

对于日期类这种都是int类型的成员,即使我们不写赋值拷贝,编译器也能完成值拷贝,不妨将赋值操作符补充完整:

Date&operator=(const Date d)
{
	this->_year = d._year;
	this->_month = d._month;
	this->_day = d._day;
	return *this;
}

这里返回的是this指针指向的内容,传进来是this指向的内容,返回的也是它,故这里应该用引用返回。

判断两个日期类相等必须是年份相等,月份相等,天也相等,接下来实现相等比较:

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

只要不是大于,那肯定就是小于等于,我们判断小于等于就可以借助上面写过的大于比较,如果是大于就一定不是小于等于,返回假,否则就一定是真。

bool operator<=(Date d)
{
	if (*this > d)
         return false;
	return true;
}

有了以上这些操作符,我们很容易用类似的方法写出小于和大于等于:

bool operator<(Date d)
{
	if (*this > d || *this == d) 
        return false;
	return true;
}

bool operator>=(Date d)
{
	if (*this < d) 
        return false;
	return true;
}

以上就是所有的日期类大小比较。

如果想自定义加减法呢(日期类的乘除法没有意义)

对于加法,我们应该是期望某个日期和天相加(日期类+日期类没有意义)加法的运算规则应该是,满天进月,满月进年。一年12个月好说,可是一个月有多少天是不确定的,而且还需要考虑闰年,所以有必要写一个函数来获取天数,当知道了这个月的天数就可以完成进位,从而实现相加。

int Days(int y, int m)
{
	int arr[13] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
	if (y == 2 && y % 4 == 0 && y % 100 != 0 || y % 400 == 0) 
        return 29;
	return arr[m];
}
Date operator+(int n)
{
	Date tmp = *this;

	tmp._day += n;
	while (tmp._day > Days(tmp._year, tmp._month))
	{
		tmp._day -= Days(tmp._year, tmp._month);
		tmp._month++;
	}
	while (tmp._month > 12)
	{
		tmp._month -= 12;
		tmp._year++;
	}
	return tmp;
}

和内置类型的加法类似,我们不希望改变原来的值,而是返回一个加了之后的值,所以这里得创建临时的Date类,最后返回这个临时变量,而不是返回this

对于减法,既可以认为是日期类-日期类,也可以是日期类-天数,两种都有意义.

可是都是减法编译器能正确调用哪个运算符重载吗?

要知道,编译器会自动匹配参数类型最符合的运算符重载,从而完成我们想要的计算

Date operator-(int n)
{
	Date tmp = *this;

	tmp._day -= n;
	while (tmp._day <=0)
	{
		tmp._day += Days(tmp._year, tmp._month);
		tmp._month--;
	}
	while (tmp._month <=0)
	{
		tmp._month += 12;
		tmp._year--;
	}
	return tmp;
}
int operator-(const Date d)
{
	if (*this < d)
	{
        assert(false);
		return -1;
	}
	Date tmp = d;
	int n = 0;
	while (!(tmp == *this))
	{
		++tmp;
		n++;
	}
	return n;
}

同理,我们也可以完成+=,++等操作。

Date&operator++()
{
	*this=*this + 1;
	return *this;
}
Date&operator--()
{
	*this = *this - 1;
	return *this;
}
Date&operator+=(int n)
{
	*this = *this + n;
	return *this;
}
Date&operator-=(int n)
{
	*this = *this - n;
	return *this;
}

这里的++和--操作是前置++和前置--,如果我们想要的是后置++或后置--呢,operator后面的符号已经完全相同该如何进行区分?

祖师爷进行区分的方式是,将后置++或--里面的参数加上int,这样参数类型和前置++或--操作的不同,使其构成重载。

这样一来,后置++和后置--就能实现了:

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

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

日期类的实现 · 1b0c1ee · Admin/C++测试代码 - Gitee.comicon-default.png?t=N7T8https://gitee.com/zz_9_0/c-test-code/commit/1b0c1eedb2da522fe0068230259ccc061fac9450

至此,一个日期类的基本运算符就实现了。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值