「这是我参与2022首次更文挑战的第21天,活动详情查看:2022首次更文挑战」
这篇文章会更深入的学习常见的运算符重载,当然还有一些需要后面的知识铺垫,比如流提取、流插入运算符。
💨Date.h
#pragma once
#include<iostream>
#include<assert.h>
#include<stdbool.h>
using namespace std;
class Date
{
public:
//获取某年某月的天数
int GetMonthDay(int year, int month)
{
assert(month > 0 && month < 13);
//默认平年
int monthDays[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 29;
}
return monthDays[month];
}
Date(int year = 0, int month = 1, int day = 1)
{
_year = year;
_month = month;
_day = day;
//判断日期是否合法
if (_year < 0 || _month <= 0 || _month >= 13 || _day <= 0 || _day > GetMonthDay(_year, _month))
{
cout << _year << "/" << _month << "/" << _day << "->";
cout << "非法日期" << endl;
}
}
void Print() const
{
cout << _year << "/" << _month << "/" << _day << endl;
}
bool 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;
else
return false;
}
bool operator==(const Date& d) const
{
return _year == d._year && _month == d._month && _day == d._day;
}
bool operator>=(const Date& d) const
{
return *this > d || *this == d;//复用operator>、operator==
}
bool operator<(const Date& d) const
{
return !(*this >= d);//复用operator>=,再取反
}
bool operator<=(const Date& d) const
{
return !(*this > d);//复用operator>,再取反
}
bool operator!=(const Date& d) const
{
return !(*this == d);//复用operator==,再取反
}
Date operator+(int day) const;
Date operator-(int day) const;
Date& operator+=(int day);
Date& operator-=(int day);
Date& operator++();
Date operator++(int);
Date& operator--();
Date operator--(int);
int operator-(const Date& d) const;
private:
int _year;
int _month;
int _day;
};
💨Date.cpp
#include"Date.h"
Date Date::operator+(int day) const
{
//Date temp(*this);
//temp._day += day;
//while (temp._day > GetMonthDay(temp._year, temp._month))
//{
// temp._day -= GetMonthDay(temp._year,temp._month);
// ++temp._month;
// if (temp._month == 13)
// {
// ++temp._year;
// temp._month = 1;
// }
//}
//return temp;
//相同逻辑太多,直接复用operator+= (这个比较好)
Date temp = *this;
temp += day;
return temp;
}
Date& Date::operator+=(int day)
{
if (day < 0)//d1 + -100;
{
return *this -= -day;//+= -100到-= 100
}
_day += day;
//日期不合法,需要进位
while (_day > GetMonthDay(_year, _month))
{
_day -= GetMonthDay(_year, _month);
++_month;
if (_month == 13)
{
++_year;
_month = 1;
}
}
return *this;
//相同逻辑太多,直接复用operator+
//*this = *this + day;
//return *this;
}
Date Date::operator-(int day) const
{
Date temp = (*this);
temp -= day;
return temp;
}
Date& Date::operator-=(int day)
{
if (day < 0)
{
return *this += -day;
}
_day -= day;
while (_day < 1)
{
--_month;
if (_month == 0)
{
--_year;
_month = 12;
}
_day += GetMonthDay(_year, _month);
}
return *this;
}
Date& Date::operator++()
{
*this += 1;//复用operator+=
return *this;//返回++后的值
}
Date Date::operator++(int)
{
Date temp = *this;
*this += 1;//复用operator+=
return temp;//返回++前的值
}
Date& Date::operator--()
{
*this -= 1;//复用operator-=
return *this;//返回--后的值
}
Date Date::operator--(int)
{
Date temp(*this);
*this -= 1;//复用operator-=
return temp;//返回--前的值
}
int Date::operator-(const Date& d) const
{
//比较大小
Date max = *this, min = d;
int flag = 1;
if (*this < d)
{
max = d;
min = *this;
flag = -1;
}
int n = 0;
while (min != max)
{
++min;//利用operator++()
++n;
}
return n * flag;
}
💨Test.cpp
#include"Date.h"
void TestDate1()
{
Date d1(2021, 10, 11);//ok
Date d2(2021, 2, 29);//err
Date d3(2020, 2, 29);//ok
Date d4(2020, 13, 29);//err
}
void TestDate2()
{
Date d1(2021, 10, 11);
Date ret;
ret = d1 + 100;
ret.Print();
ret = d1 += 100;
ret.Print();
d1.Print();
ret = d1 + -100;
ret.Print();
}
void TestDate3()
{
Date d1(2021, 10, 11);
Date ret;
ret = d1 - 11;
ret.Print();
ret = d1 -= 11;
ret.Print();
d1.Print();
ret = d1 - -11;
ret.Print();
}
void TestDate4()
{
Date d1(2021, 10, 11);
Date ret;
ret = ++d1;
ret.Print();
d1.Print();
ret = d1++;
ret.Print();
d1.Print();
}
void TestDate5()
{
Date d1(2021, 10, 11);
Date ret;
ret = --d1;
ret.Print();
d1.Print();
ret = d1--;
ret.Print();
d1.Print();
}
void TestDate6()
{
Date d1(2023, 10, 11);
Date d2(2022, 10, 11);
cout << d1 - d2 << endl;
cout << d2 - d1 << endl;
}
int main()
{
//TestDate1();//日期合法
//TestDate2();//+、+=、+ -(负)
//TestDate3();//-、-=、- -(负)
//TestDate4();//++x、x++
//TestDate5();//--x、x--
TestDate6();//d1 - d2
return 0;
}
📝说明
日期的不合法,构造函数有无责任 ❓
有的,构造函数不仅仅是完成初始化工作,还要判断数据是否合法。
除了上面说的 5 个运算符不能重载之外,其余的运算符有重载的意义 ❓
一个类到底要重载哪些运算符,是看你需要哪些运算符,并且要考量重载的运算符有无价值。
运算符重载 | 函数重载 ❓
虽然它们都用了重载这个词,但是它们之间没有关联。
operator+ | operator+= ❓
对于大量重复的代码我们可以利用复用来提高代码质量 (它俩必须得实现一个)。
operator+复用operator+=不需要声明 ❓
operator+ 是在 operator+= 之前,所以需要声明,但是我们的 Date.cpp 文件中的第一行,已经把 Date.h 的声明都展开了,所以这里的先后位置可随意。
Date d3 = d1 + -100 & Date d3 = d1 - -100 ❓
显然我们并未考虑到这种情况,所以这里我们还可以把复用用到极致。
运算符前置++和后置++怎么进行重载(同前置- -和后置- -) ❓
它们的共同点都是需要 ++ 的,但是它们的返回值不同:前置++ 的返回值是 ++ 以后的;后置++ 的返回值是 ++ 之前的。
这两个运算符都是单操作数,也就是只能有一个 this 指针,按正常的运算符重载规则是无法区分前置与后置的,所以编译器为了能区分这种情况,这里就做了一个特殊的处理 —— 给后置++ 增加一个 int 参数 (这个参数仅仅是为了区分,你给多少它都不会用),这样它们就能构成函数重载。
日期 - 日期 ❓
常规思路是日减、月减、年减,补它们中间的位,但是实际上实现较难。
思路一:把某月某日映射到 365 天
思路二 (最优):先比较两日期的大小,然后让小的++,当小的等于大的时,那么加了多少次就是它们相差的天数
比较运算符重载 ❓
常规思路是写好一个比较运算符重载之后就复制代码改符号。
利用复用的思路是实现 operator> 和 operator== 就行了。