0x0A 体会复用的威力
📚 引入:
比如我们要实现 operator<,因为大于我们已经实现过了,
我们现在来写 <,可以直接把大于改成小于:
…… 既然都能这样了,那为什么不用用神奇的复用呢?
我们已经把 operator> 和 == 实现了,剩下的这些我们都可以复用解决。
技巧:对于类的比较,实现一个 > 和 == 其它直接复用就完事了。
(当然,实现一个 < 和 == 也行,随你便)
这个技巧不仅仅针对于日期类的比较,所有类要实现比较,都可以用这种方式,
除非它们不互斥( >= 取反是 < ,这就是互斥 )。
bool operator>(const Date& d) const; // d1 > d2 bool operator==(const Date& d) const; // d1 == d2
0x0B 判断大于等于 operator>=
💬 Date.h
bool operator>=(const Date& d) const; // d1 >= d2
💬 Date.cpp
/* d1 >= d2 */ bool Date::operator>=(const Date& d) const { return *this > d || *this == d; }
直接复用解决就完事了,这波真是秦始皇被雷劈,嬴麻了。
0x0C 判断小于 operator<
💬 Date.h
bool operator<(const Date& d) const; // d1 < d2
小于,不就是既不大于也不等于嘛。
所以我们直接复用 operator>= 就完事了。
💬 Date.cpp
/* d1 < d2 */ bool Date::operator<(const Date& d) const { return !(*this >= d); }
这里取反就可以了,如果 d1 >= d2 为真,取反后 ! 则返回假。反之返回真。
0x0D 判断小于等于 operator<=
💬 Date.h
bool operator<=(const Date& d) const; // d1 <= d2
💬 Date.cpp
/* d1 <= d2 */ bool Date::operator<=(const Date& d) const { return !(*this > d); }
小于等于,就是 > 取反,没什么好说的。
这里你还可以用 < || == ,也可以的。
0x0E 判断日期是否不相等 operator!=
💬 Date.h
bool operator!=(const Date& d) const; // d1 != d2
不等于和等于逻辑是相反的,直接反 ! 就完事了。
💬 Date.cpp
/* d1 != d2*/ bool Date::operator!=(const Date& d) const { return !(*this == d); }
0x0F 日期减日期 operator-
我们刚才实现的 operator- 是日期减天数的:
/* d1 - 100 */ Date Date::operator-(int day) const { Date ret(*this); // 拷贝构造一个d1 ret -= day; // ret.operator-=(day); return ret; }
❓ 如果我们想要计算一下距离暑假还有多少天呢?
那我们就需要写一个日期减日期版本的 operater-
💬 Date.h
Date operator-(int day) const; // holiday - today
我们现在想的是日期减日期,我们可以让小的天数去加大的天数。
💬 Date.cpp
/* holiday - today */ Date Date::operator-(const Date&d) const { // 我默认认为第一个大,第二个小 Date max = *this; Date min = d; int flag = 1; // 立个flag // 如果第一个小,第二个大 if (*this < d) { max = d; min = *this; flag = -1; // 说明我们立的flag立错了,改成-1 } int count = 0; while (min != max) { min++; count++; } return count * flag; }
我们可以用立 flag 法。
我们先立个flag 假设 —— 第一个日期大,第二个日期小。
flag 为 1 表示第一个大第二个小,flag 为 -1 表示第一个小第二个大。
分别创建 max 和 min 表示第一个日期(d1)和第二个日期(d2)。
然后走一遍判断,核实一下立的 flag 对不对,不对的话就纠正一下。
之后我们用计数器的方式来实现就可以了。
💬 test.cpp
void DateTest8() { Date today(2022, 1, 17); Date holiday(2022, 7, 1); cout << (holiday - today) << endl; cout << (today - holiday) << endl; }
0x10 打印今天是周几 PrintWeekDay
❓ 打印今天是周几什么什么意思?
" 打印今天是周几,就是打印今天是星期几。" —— 节选自《 节选自 <节选> 》
💬 Date.h
void PrintWeekDay() const;
💬 Date.cpp
void Date::PrintWeekDay() const { // 1900.1.1 日开始算 const char* week[] = { "周一", "周二", "周三", "周四", "周五", "周六", "周日" }; Date start(1900, 1, 1); int count = *this - start; cout << week[count % 7] << endl; }
我们拿 1900年1月1号 作为起始点,两个日期相减得到的结果,
%7 作为下标去访问 week 数组里我们已经准备好的周几,打印出来就可以了。
⚡ 这个 start 反正我们就在这用一下而已,后面也用不着了,这里就可以使用匿名对象:
void Date::PrintWeekDay() const { // 1900.1.1 日开始算 const char* week[] = { "周一", "周二", "周三", "周四", "周五", "周六", "周日" }; int count = *this - Date(1900, 1, 1); // 可以使用匿名对象 cout << week[count % 7] << endl; }
💬 test.cpp
void DateTest9() { Date d1(2021, 3, 19); d1.PrintWeekDay(); } int main(void) { DateTest9(); return 0; }
大功告成!!!
Ⅱ. 完整代码
0x00 Date.h
#include <iostream> using namespace std; class Date { public: Date(int year = 1, int month = 1, int day = 1); // 全缺省构造 int GetMonthDay(int year, int month) const ; // 获取某年某月对应的天数 void Print() const; // 打印函数 bool operator>(const Date& d) const; // d1 > d2 bool operator==(const Date& d) const; // d1 == d2 bool operator>=(const Date& d) const; // d1 >= d2 bool operator<(const Date& d) const; // d1 < d2 bool operator<=(const Date& d) const; // d1 <= d2 bool operator!=(const Date& d) const; // d1 != d2 Date& operator+=(int day); // d1 += 100 Date& operator-=(int day); // d1 -= 100 Date operator+(int day) const; // d1 + 100 Date operator-(int day) const; // d1 - 100 Date& operator++(); // ++d1; Date operator++(int); // d1++; Date& operator--(); // --d1; Date operator--(int); // d1--; int operator-(const Date& d) const; // 日期减日期 void PrintWeekDay() const; // 返回星期几 private: int _year; int _month; int _day; };
0x01 Date.cpp
#include "Date.h" /* 获取月对应的天数 */ int Date::GetMonthDay(int year, int month) const { static int monthDatArray[13] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; // 简陋哈希 int day = monthDatArray[month]; // 获取天数 if (month == 2 // 先判断是否为二月 && ((year % 4 == 0 && year % 100 != 0) // 是二月,再判断是否是闰年 || (year % 400 == 0))) { day += 1; // 是闰年,天数+1 } return day; } /* 全缺省构造函数 */ Date::Date(int year, int month, int day) { this->_year = year; this->_month = month; this->_day = day; // 判断日期是否合法 if (!(_year >= 0 && (month > 0 && month < 13) && (day > 0 && _day <= GetMonthDay(year, month)))) { cout << "非法日期: "; this->Print(); // 访问成员函数(this可省略) } } /* 打印函数 */ void Date::Print() const { printf("%d-%d-%d\n", this->_year, this->_month, this->_day); } /* d1 > d2 */ bool Date::operator>(const Date& d) const { 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; } } /* d1 == d2 */ bool Date::operator==(const Date& d) const { return this->_year == d._year && this->_month == d._month && this->_day == d._day; } /* d1 >= d2 */ bool Date::operator>=(const Date& d) const { return *this > d || *this == d; } /* d1 < d2 */ bool Date::operator<(const Date& d) const { return !(*this >= d); } /* d1 <= d2 */ bool Date::operator<=(const Date& d) const { return !(*this > d); } /* d1 != d2*/ bool Date::operator!=(const Date& d) const { return !(*this == d); } /* d1 += 100 */ Date& Date::operator+=(int day) { if (day < 0) { return *this -= -day; } this->_day += day; // 把要加的天数倒进d1里 while (this->_day > GetMonthDay(this->_year, this->_month)) { // 判断天数是否需要进位 this->_day -= GetMonthDay(this->_year, this->_month); // 减去当前月的天数 this->_month++; // 月份+1 if (this->_month == 13) { // 判断月份是否需要进位 this->_month = 1; // 重置月份 this->_year++; // 年份+1 } } return *this; } /* d1 -= 100 */ Date& Date::operator-=(int day) { if (day < 0) { return *this += -day; } this->_day -= day; while (this->_day <= 0) { // 天数为0或小于0了,就得借位,直到>0为止。 this->_month--; // 向月借 if (this->_month == 0) { // 判断月是否有得借 this->_year--; // 月没得借了,向年借 this->_month = 12; // 年-1了,月份置为12月 } this->_day += GetMonthDay(this->_year, this->_month); // 把借来的天数加到_day上 } return *this; } /* d1 + 100 */ Date Date::operator+(int day) const { Date ret(*this); // 拷贝构造一个d1 ret += day; // ret.operator+=(day); return ret; // 出了作用域ret对象就不在了,所以不能用引用返回 } /* d1 - 100 */ Date Date::operator-(int day) const { Date ret(*this); // 拷贝构造一个d1 ret -= day; // ret.operator-=(day); return ret; } /* ++d1 */ Date& Date::operator++() { *this += 1; return *this; } /* d1++ */ Date Date::operator++(int) { Date ret(*this); // 拷贝构造一个d1 *this += 1; return ret; } /* --d1 */ Date& Date::operator--() { *this -= 1; return *this; } /* d1-- */ Date Date::operator--(int) { Date ret(*this); // 拷贝构造一个d1 *this += 1; return ret; } /* 日期减日期 */ int Date::operator-(const Date& d) const { // 我默认认为第一个大,第二个小 Date max = *this; Date min = d; int flag = 1; // 立个flag // 如果第一个小,第二个大 if (*this < d) { max = d; min = *this; flag = -1; // 说明我们立的flag立错了,改成-1 } int count = 0; while (min != max) { min++; count++; } return count * flag; } /* 返回星期几 */ void Date::PrintWeekDay() const { // 1900.1.1 日开始算 const char* week[] = { "周一", "周二", "周三", "周四", "周五", "周六", "周日" }; int count = *this - Date(1900, 1, 1); // 可以使用匿名对象 cout << week[count % 7] << endl; }
0x02 test.cpp
#define _CRT_SECURE_NO_WARNINGS 1 #include "Date.h" void DateTest1() { Date d4(2022, 2, 29); d4.Print(); Date d5(2009, 2, 29); d5.Print(); Date d6(1998, 2, 29); d6.Print(); } void DateTest2() { Date d1(2022, 2, 1); Date d2(2012, 5, 1); cout << (d1 > d2) << endl; Date d3(2022, 3, 15); cout << (d1 > d3) << endl; Date d4(d1); cout << (d1 > d4) << endl; } void DateTest3() { Date d1(2022, 1, 16); d1 += 100; // 让当前天数+100天 d1.Print(); } void DateTest4() { Date d1(2022, 1, 16); Date ret = d1 + 100; d1.Print(); ret.Print(); } void DateTest5() { Date d1(2022, 3, 20); d1 -= 100; // 2021, 12, 10 d1.Print(); } void DateTest6() { Date d1(2022, 1, 17); Date ret = d1 - -100; ret.Print(); } void DateTest7() { Date d1(2022, 3, 20); Date ret1 = d1++; // d1.operator++(&d1, 0); Date ret2 = ++d1; // d1.operator++(&d1); } void DateTest8() { Date today(2022, 1, 17); Date holiday(2022, 7, 1); int ret1 = holiday - today; int ret2 = today - holiday; cout << ret1 << endl; cout << ret2 << endl; } void DateTest9() { Date d1(2022, 3, 19); d1.PrintWeekDay(); } int main(void) { // DateTest1(); // DateTest2(); // DateTest3(); // DateTest4(); // DateTest5(); // DateTest6(); // DateTest7(); // DateTest8(); // DateTest9(); return 0; }