0. 引1. 基本接口
1.1 默认成员函数
1.1.1 构造函数1.1.2 拷贝构造函数 1.2 获取某年某月天数 2. 一系列运算符重载函数
2.1 `+=` 、`+`、`++`
2.2.1 日期 `+=` 天数 = ?2.2.2 日期 `+` 天数2.2.3 前置++、后置++ 2.2 `-=`、`-`、`--`
2.2.1 日期 `-=` 天数 = 日期2.2.2 日期 `-` 天数2.2.3 前置--、后置-- 2.3 一堆比较 `>`、`>=`、`<`、`<=`、`==`、`!=` 3. 日期 - 日期4. 星期几?附录:
`Date.cpp``test.cpp`
0. 引继C++入门、类和对象上篇中篇后,我们把这些学到的知识都用起来,来写一个日期类。这不禁让我想起了闷热又潮湿的夏季小学期java的第一个作业,写一个万年历,那时我写的真是一塌糊涂啊哈哈。下面我贴出头文件,各位自己写。所有要注意的小点我都写出来了,文章尽量呈现一套自然而然理所当然的思路。开始吧!
#include1. 基本接口 1.1 默认成员函数 1.1.1 构造函数using namespace std; class Date { public: //构造函数 Date::Date(int year = 0, int month = 1, int day = 1); //析构函数、拷贝构造、赋值重载都不用写 //Date(const Date& d) //{ // cout << "Date(const Date& d)" << endl; //} void Print(); int getMonthDay(int year, int month); //运算符重载系列 bool operator>(const Date& d); bool operator>=(const Date& d); bool operator<(const Date& d); bool operator<=(const Date& d); bool operator==(const Date& d); bool operator!= (const Date& d); // d1 += 100; Date& operator+=(int day); // d1 + 100; Date operator+(int day); // d1 -= 100; Date& operator-=(int day); // d1 - 100; Date operator-(int day); // 前置++ Date& operator++(); // 后置++ Date operator++(int); // 前置-- Date& operator--(); //后置 -- Date operator--(int); // 日期 - 日期 int operator-(const Date& d); // 今天是星期几? void PrintWeekday(); private: int _year; int _month; int _day; };
通过对于构造函数、析构函数、拷贝构造这一系列函数特征的学习,我们知道对于日期类,我们并不需要写析构、拷贝构造一类,用默认的就行。只需要自己实现构造函数。
注:
Date::Date(int year, int month, int day )
{
_year = year;
_month = month;
_day = day;
if (year<0
||(month<0 || month >12)
||(day <0 || day >getMonthDay(year,month)))
{
cout << "非法日期:>";
Print(); //在类里,可以直接访问类函数
}
}
这就还需要考虑非法日期的输入:为了判断天数是否合理,我们引入了下一个接口,来获取某年某月的天数 ——
1.1.2 拷贝构造函数可以不写。但后面我为了验证拷贝构造函数的调用,在里面瞎写了一句打印。
1.2 获取某年某月天数这里采用了比较巧妙的用数组存储天数,第几月就对应着相应天数。
注:
int Date::getMonthDay(int year, int month)
{
//静态数组
static int monthDayArray[13] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
int day = monthDayArray[month];
//闰年:四年一闰、百年不闰、四百年再闰
if (month == 2
&& ((year%4==0 && year%100!=0)||( year%400 == 0)))
{
day += 1;
}
return day;
}
2. 一系列运算符重载函数
2.1 += 、+、++
2.2.1 日期 += 天数 = ?
2022.1.21 + 100是几号?这个功能的实现,乍一想好像挺复杂,还要考虑闰年,不同月的天数。但顺着我们正常的计算思维,列写几个例子,其实很简单。✅它其实就是一个不断进位的过程,天满了往月进;月满了往年进、月归1。
那就写个循环直至合法 ——
Date& Date::operator+=(int day)
{
_day += day;
while (_day > getMonthDay(_year, _month))
{
_day -= getMonthDay(_year, _month);
_month++;
if (_month == 13)
{
_year += 1;
_month = 1;
}
}
return *this;//d1没销毁,可以传引用返回
}
int i = 0; i + 100;
i的值并不会改变。那怎么实现运算符+的重载呢?我们就弄一个临时对象来 ——
2.2.2 日期 + 天数// d1 + 100; 不能改变d1
Date Date::operator+(int day)
{
Date ret(*this);//拷贝构造一个
ret += 100; // ret.operator+=(&ret, 100);
return ret;
}
2.2.3 前置++、后置++
在写++的运算符重载函数时,发现这两个函数啊,函数名相同。为了区分前置++和后置++,我们增加一个参数占位,它们俩就构成了函数重载。
实现:前置++,与后置++,区别就在于返回值的不同。
前置++
// 先++后使用
Date& Date::operator++()
{
*this += 1;
return *this;
}
后置++
// 先使用后++
Date Date::operator++(int)
{
Date ret(*this);
*this += 1;
return ret;
}
注:
编译器会把它们转化为 ——
Date d1(2022, 1, 22); ++d1; //d1.operator(&d1); d1++; //d1.operator(&d1, 1);
后置++,这个整数只起到占位作用,没有实在意义,所以传什么随意。
所以你看,**前置++**也保持了它原生的样子。 2.2 -=、-、--
有了2.1节“加”的一系列铺垫,关于“减”那是不在话下。
2.2.1 日期 -= 天数 = 日期怎么减呢?写过“加”了,那思路就顺下来。(在我测试的时候,把几个易错点全测到了,或许女生真的适合去做测试?哈哈,值得表扬的是通过调试都改过来了,也侧面说明我踩雷踩得相当准,我都写在注意里了)
注意:
Date& Date::operator-=(int day)
{
while (_day <= 0)
{
_month--;
if (_month == 0)
{
_year--;
_month = 12;
}
_day += getMonthDay(_year, _month);
}
return *this;
}
在这里要考虑,万一我输入的day是负数?
我们需要把它单拎出来处理一下,-= day等价于+= (-day)。同样的刚刚我们实现的+=运算符重载函数也需要同样处理,代码如下 ——
// +=
Date& Date::operator+=(int day)
{
if (day < 0)
{
return *this -= -day;
}
_day += day;
while (_day > getMonthDay(_year, _month))
{
_day -= getMonthDay(_year, _month);
_month++;
if (_month == 13)
{
_year += 1;
_month = 1;
}
}
return *this;//d1没销毁,可以传引用返回
}
//-=
Date& Date::operator-=(int day)
{
if (day < 0)
{
return *this += -day;
}
_day -= day;
while (_day <= 0)
{
_month--;
if (_month == 0)
{
_year--;
_month = 12;
}
_day += getMonthDay(_year, _month);
}
return *this;
}
2.2.2 日期 - 天数
复用嗷!
Date Date::operator-(int day)
{
Date ret(*this);
ret -= day;
return ret;
}
2.2.3 前置–、后置–
注意事项同++
// 前置--
Date& Date::operator--()
{
*this -= 1;
return *this;
}
//后置 --
Date Date::operator--(int)
{
Date ret(*this);
*this -= 1;
return *this;
}
2.3 一堆比较 >、>=、<、<=、==、!=
事实上,在我们实现了>、==,就可以根据这些符号简单的关系,疯狂复用完成其他所有接口。
相似的逻辑,很自然的就能想到能不能复用。来!
// >
// d1>d2 => d1.operator(&d1, d2)
bool Date::operator>(const Date& d)
{
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 Date::operator==(const Date& d)
{
return _year == d._year
&& _month == d._month
&& _day == d._day;
}
来,开始疯狂复用吧!基本数学知识哈哈
// >=
bool Date::operator>=(const Date& d)
{
return *this > d || *this == d;
}
// <
bool Date::operator<(const Date& d)
{
return !(*this >= d);
}
// <=
bool Date::operator<=(const Date& d)
{
return !(*this > d);
}
// ==
bool Date::operator!=(const Date& d)
{
return !(*this == d);
}
3. 日期 - 日期
这乍一想是挺复杂,又可能是闰年,跨几个月也不定。其实可以暴力求解,找那个较小的日期,加加加到较大的日期。
这里我计算一个,从今天到小边冲实习生那天还有多少天吧!诶,有高考倒计时的感觉了。来!
// 日期 - 日期
// offerDay - today => offerDay.operator(&offerday, today);
int Date::operator-(const Date& d)
{
// 假设
Date min = d;//早
Date max = *this;//晚
int flag = 1;
if (*this < d)
{
min = *this; //早
max = d; // 晚
flag = -1;
}
int count = 0;
while (min < max)
{
min++;
count++;
}
return count*flag;
}
4. 星期几?
void Date::PrintWeekday()
{
Date start(1900, 1, 1); //查询得星期一
int count = *this - start;
cout << "星期" << ((count % 7) + 1) << endl;
}
附录:
测试文件随写随测
Date.cpp#define _CRT_SECURE_NO_WARNINGS 1
#include"Date.h"
int Date::getMonthDay(int year, int month)
{
//静态数组
static int monthDayArray[13] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
int day = monthDayArray[month];
//闰年:四年一闰、百年不闰、四百年再闰
if (month == 2
&& ((year%4==0 && year%100!=0)||( year%400 == 0)))
{
day += 1;
}
return day;
}
//缺省参数不能在声明和定义中同时出现
Date::Date(int year, int month, int day )
{
_year = year;
_month = month;
_day = day;
if (year<0
||(month<0 || month >12)
||(day <0 || day >getMonthDay(year,month)))
{
cout << "非法日期:>";
Print(); //在类里,可以直接访问类函数
}
}
void Date::Print()
{
cout << _year << "-" << _month << "-" << _day << endl;
}
Date& Date::operator+=(int day)
{
if (day < 0)
{
return *this -= -day;
}
_day += day;
while (_day > getMonthDay(_year, _month))
{
_day -= getMonthDay(_year, _month);
_month++;
if (_month == 13)
{
_year += 1;
_month = 1;
}
}
return *this;//d1没销毁,可以传引用返回
}
// d1 + 100; 不能改变d1
Date Date::operator+(int day)
{
Date ret(*this);//拷贝构造一个
ret += 100; // ret.operator+=(&ret, 100);
return ret;
}
// 前置++
Date& Date::operator++()
{
*this += 1;
return *this;
}
//后置++
Date Date::operator++(int)
{
Date ret(*this);
*this += 1;
return ret;
}
bool Date::operator>(const Date& d)
{
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 Date::operator==(const Date& d)
{
return _year == d._year
&& _month == d._month
&& _day == d._day;
}
bool Date::operator>=(const Date& d)
{
//复用
return *this > d || *this == d;
}
bool Date::operator<(const Date& d)
{
// 复用
return !(*this >= d);
}
bool Date::operator<=(const Date& d)
{
// 复用
return !(*this > d);
}
bool Date::operator!=(const Date& d)
{
return !(*this == d);
}
Date& Date::operator-=(int day)
{
if (day < 0)
{
return *this += -day;
}
_day -= day;
while (_day <= 0)
{
_month--;
if (_month == 0)
{
_year--;
_month = 12;
}
_day += getMonthDay(_year, _month);
}
return *this;
}
Date Date::operator-(int day)
{
Date ret(*this);
ret -= day;
return ret;
}
// 前置--
Date& Date::operator--()
{
*this -= 1;
return *this;
}
//后置 --
Date Date::operator--(int)
{
Date ret(*this);
*this -= 1;
return *this;
}
// 日期 - 日期
// offerDay - today => offerDay.operator(&offerday, today);
int Date::operator-(const Date& d)
{
// 假设
Date min = d;//早
Date max = *this;//晚
int flag = 1;
if (*this < d)
{
min = *this; //早
max = d; // 晚
flag = -1;
}
int count = 0;
while (min < max)
{
min++;
count++;
}
return count*flag;
}
void Date::PrintWeekday()
{
Date start(1900, 1, 1); //查询得星期一
int count = *this - start;
cout << "星期" << ((count % 7) + 1) << endl;
}
test.cpp
#define _CRT_SECURE_NO_WARNINGS 1
#include "Date.h"
void test1()
{
Date d1(2002, 3, 7);
d1.Print();
Date d2(2022, 2, 29);
}
//测试+、+=、++
void test2()
{
Date d1(2022, 1, 16);
//Date d2(2022, 1, 16);
//d2 += 100;
//d2.Print();
//++d1;
d1++;
}
//测试这一堆运算符重载函数
void test3()
{
Date d1(2002, 3, 7);
Date d2(2002, 2, 19); //missing lmyy
Date d3(2002, 3, 7);
cout << (d1 == d3) << endl;
cout << (d1 >= d2) << endl;
cout << (d1 < d3) << endl;
cout << (d1 <= d2) << endl;
cout << (d1 != d3) << endl;
}
// 测试-,-=,--
void test4()
{
Date d1(2022, 1, 10);
Date d2(2022, 2, 19);
Date ret2 = d2 - 60;
ret2.Print();
d1 -= 10;
d1.Print();
}
//测试日期 - 日期,星期几
void test5()
{
Date today(2022,1,23);
Date offerDay(2022, 9, 1);
cout << (offerDay - today) << endl;
today.PrintWeekday();
}
int main()
{
//test1();
//test2();
//test3();
//test4();
test5();
return 0;
}



