目录
前言:
结合了前面的内容的学习,本篇来对之前的内容像运算符重载等进行应用,完成日期类的实现,具体功能大致包括对日期的加减比较,显示日期等。
1.显示日期
调用成员函数打印日期:
cpp
void Date::Print() const
{
cout << _year << "/" << _month << "/" << _day << endl;
}
对流插入<<进行重载,完成对日期类的打印:
定义文件中:
cpp
ostream& operator<<(ostream& out, const Date& d)
{
out << d._year << "/" << d._month << "/" << d._day << endl;
return out;
}
声明文件中:
cpp
friend ostream& operator<<(ostream& out, const Date& d);
为什么这里要用友元函数:
由于我们要使用的格式为例如,cout<<d1,如果放到成员函数中,由于对象调用成员函数会传对象的地址并在成员函数中用this指针接收,所以第一个参数只能是Date* this,也只能d1<<cout这样调用。
但是我们如果仅仅定义为一个普通函数就没法访问到类中的私有成员变量了,而且不能为了一个函数就让成员函数放为私有的,所以我们这里使用友元函数,既可以访问成员变量,也可以调整参数的顺序。
2.构造函数与获取某年某月的日期的函数
声明文件中:
cpp
Date(int year = 1900, int month = 1, int day = 1);
int GetMonthDay(int year, int month) const;
注意构造函数的缺省要在声明中给(如果声明和定义的缺省值不同,编译器无法确定,放在声明中也减少了其他源文件重复定义)。
定义文件中:
cpp
int Date::GetMonthDay(int year, int month) const
{
assert(month > 0 && month < 13);
int MonthArray[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;//闰年
}
else
{
return MonthArray[month];
}
}
Date::Date(int year, int month, int day)
{
if (year > 0 && (month > 0 && month < 13) && (day > 0 && day <= GetMonthDay(month, day)))
{
_year = year;
_month = month;
_day = day;
}
else
{
cout << "初始化日期非法" << endl;
}
}
1.因为有闰年平年之分,还有不同的月的天数不同,所以我们要定义一个函数来获取具体到哪年哪月的具体的天数。
2.获取天数用一个数组来确定,方便下标与内容对应,多加一位;其次就是单独判断闰年的二月是29天,如果是,那就直接返回,如果不是,就返回对应下标的天数。
3.构造函数判断一下日期的合法性。
3.日期比较
cpp
bool Date::operator==(const Date& d) const
{
return _year == d._year
&& _month == d._month
&& _day == d._day;
}
bool Date::operator<(const Date& d) const
{
return (_year < d._year)
|| ((_year == d._year) && (_month < d._month))
|| ((_year == d._year) && (_month == d._month) && (_day < d._day));
}
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);
}
可以先实现等于和小于的逻辑,其它的逻辑直接复用即可。
4.日期加减天数
cpp
Date& Date::operator+=(int day)
{
if (day < 0)
{
*this -= -day;//+=一个负的,就是让它走-=一个正的逻辑
return *this;
}
_day += day;
while (_day > GetMonthDay(_year,_month))
{
_day -= GetMonthDay(_year, _month);
++_month;
if (_month ==13)
{
_year++;
_month = 1;
}
}
return *this;
}
Date Date::operator+(int day) const
{
Date tmp(*this);
tmp += day;//复用,变得更简单
//tmp._day += day;
//while (tmp._day < GetMonthDay(tmp._year, tmp._month))
//{
// tmp._day -= GetMonthDay(tmp._year, tmp._month);
// ++tmp._month;
// if (tmp._month == 13)
// {
// tmp._year++;
// tmp._month = 1;
// }
//}
return tmp;
}
Date& Date::operator-=(int day)
{
Date tmp(*this);
if (day < 0)
{
*this += -day;//-=一个负的天数,就是走+=一个正的天数的逻辑
return *this;
}
_day -= day;
while (_day <= 0)//不够减,往上一个月借
{
--_month;
if (_month == 0)
{
--_year;
_month = 12;
}
_day += GetMonthDay(_year, _month);
}
return *this;
}
Date Date::operator-(int day) const
{
Date tmp(*this);
tmp -= day;
return tmp;
}
1.首先区分+=和-=与+和-的区别,+=和-=是会对原内容进行修改,也就是对对象进行修改,所以用引用返回,直接返回this指针,还能减少返回时产生的拷贝;而对于+和-来说,不能改变原有的对象,所以先调用编译器默认生成的拷贝构造来对对象进行一次拷贝(这里只有浅拷贝,不会出错),然后再对拷贝的对象复用+=或者-=的逻辑,再返回这个拷贝的对象即可,所以这里需要用一个返回值接收这个结果才能看出来。
2.要注意如果对天数进行操作时,天数为-怎么办。如果为负,在+=里面,就是要转换为-=了,所以写一句*this-=-day即可转换成去调用,因为day本身就是负的,所以就去调用*this-=day了;在-=则相反。
3.在+=中,我们要还要判断,当天数+的超过了这个月的天了,我们就要往下个月加了,如果加到下个月还多,那就再往下个月加,所以使用一个循环来实现,如果月加到了13,就要加到下一年去,并且让月再从一月开始,+也要考虑这个问题,但是我们复用了+=的逻辑,就不考虑了。
4.在-=中,我们要判断如果天数减的变为了负的,那就要往上一个月去借,然后让天数加上这个月的天数,如果借的还不够,继续借,所以使用循环来实现,注意如果月减到了0,就要往上一年借,并让月从12开始。-直接复用即可。
5.也可以先完成+-的逻辑,+=与-=再复用:
cpp//如果先实现了+的逻辑,+=也可复用+的逻辑 //*this=*this+day;但是这个会先调operator+的函数,再调自动生成的operator赋值函数,所以建议使用第一种
这样就多了拷贝了,所以建议先实现+=与-=。
5.日期减日期
日期减日期可以有两种方法,可以先获取两个日期距离所在年的1月1日有多少天,再计算两个日期相差多少年,要考虑闰平年,然后再计算总共相差多少天即可。
或者使用下面的方法:
cpp
int Date::operator-(const Date& d) const
{
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 n * flag;
}
flag用来确定正负,n用来计算相差多少天。先假设左边的日期大,然后比较,如果右边大,交换顺序,并且右边大减出来肯定是负的,所以再让flag设为-1,然后让n计数,看相差多少天,然后返回天数*正反号即可。
6.前置后置++与--
cpp
Date& Date::operator++()
{
*this += 1;
return *this;
}
Date Date::operator++(int)
{
Date tmp(*this);
*this += 1;
return tmp;
}
Date& Date::operator--()
{
*this -= 1;
return *this;
}
Date Date::operator--(int)
{
Date tmp(*this);
*this -= 1;
return tmp;
}
1.前置复用之前+=与-=的逻辑,直接返回这个修改后的对象;而后置是先拷贝,再对原对象进+=和-=的复用,再返回没有改变的拷贝的对象,这样接收返回值的时候,接收的就是没有改变的对象,但是原来的对象已经修改了,就起到了后置的效果。
2.编译器为了区分前置后置,在调用后置的时候,会传一个参数,可能是一个整形0,可能是其他的,所以重载的时候写一个int参数,这是编译器自动传的,不用我们自己传,自己传也行。
7.完整代码
定义文件:
cpp
#define _CRT_SECURE_NO_WARNINGS
#include "Date.h"
int Date::GetMonthDay(int year, int month) const
{
assert(month > 0 && month < 13);
int MonthArray[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;//闰年
}
else
{
return MonthArray[month];
}
}
Date::Date(int year, int month, int day)
{
if (year > 0 && (month > 0 && month < 13) && (day > 0 && day <= GetMonthDay(month, day)))
{
_year = year;
_month = month;
_day = day;
}
else
{
cout << "初始化日期非法" << endl;
}
}
void Date::Print() const
{
cout << _year << "/" << _month << "/" << _day << endl;
}
bool Date::operator==(const Date& d) const
{
return _year == d._year
&& _month == d._month
&& _day == d._day;
}
bool Date::operator<(const Date& d) const
{
return (_year < d._year)
|| ((_year == d._year) && (_month < d._month))
|| ((_year == d._year) && (_month == d._month) && (_day < d._day));
}
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);
}
Date& Date::operator+=(int day)
{
if (day < 0)
{
*this -= -day;//+=一个负的,就是让它走-=一个正的逻辑
return *this;
}
_day += day;
while (_day > GetMonthDay(_year,_month))
{
_day -= GetMonthDay(_year, _month);
++_month;
if (_month ==13)
{
_year++;
_month = 1;
}
}
return *this;
}
Date Date::operator+(int day) const
{
Date tmp(*this);
tmp += day;//复用,变得更简单
//tmp._day += day;
//while (tmp._day < GetMonthDay(tmp._year, tmp._month))
//{
// tmp._day -= GetMonthDay(tmp._year, tmp._month);
// ++tmp._month;
// if (tmp._month == 13)
// {
// tmp._year++;
// tmp._month = 1;
// }
//}
return tmp;
}
Date& Date::operator-=(int day)
{
Date tmp(*this);
if (day < 0)
{
*this += -day;//-=一个负的天数,就是走+=一个正的天数的逻辑
return *this;
}
_day -= day;
while (_day <= 0)//不够减,往上一个月借
{
--_month;
if (_month == 0)
{
--_year;
_month = 12;
}
_day += GetMonthDay(_year, _month);
}
return *this;
}
Date Date::operator-(int day) const
{
Date tmp(*this);
tmp -= day;
return tmp;
}
int Date::operator-(const Date& d) const
{
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 n * flag;
}
Date& Date::operator++()
{
*this += 1;
return *this;
}
Date Date::operator++(int)
{
Date tmp(*this);
*this += 1;
return tmp;
}
Date& Date::operator--()
{
*this -= 1;
return *this;
}
Date Date::operator--(int)
{
Date tmp(*this);
*this -= 1;
return tmp;
}
ostream& operator<<(ostream& out, const Date& d)
{
out << d._year << "/" << d._month << "/" << d._day << endl;
return out;
}
声明文件:
cpp
#pragma once
#include <iostream>
#include <assert.h>
using namespace std;
class Date
{
friend ostream& operator<<(ostream& out, const Date& d);
public:
Date(int year = 1900, int month = 1, int day = 1);
int GetMonthDay(int year, int month) const;
void Print() 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;
bool operator!=(const Date& d) const;
Date& operator+=(int day);
Date operator+(int day) const;
Date& operator-=(int day);
Date operator-(int day) const;
int operator-(const Date& d) const;
Date& operator++();
Date operator++(int);
Date& operator--();
Date operator--(int);
private:
int _year;
int _month;
int _day;
};
这样的成员函数没对成员变量进行修改的都加上了const修饰,方便不是const的对象和const的对象都能调用。
8.测试
cpp
#define _CRT_SECURE_NO_WARNINGS
#include "Date.h"
void TestDate1()
{
Date d1(2024, 4, 4);
Date d2(2023, 4, 4);
Date ret1=++d1;
cout << d1;
cout << ret1;
Date ret2=d1++;
cout << d1;
cout << ret2;
cout << endl;
Date ret3=d1--;
cout << d1;
cout << ret3;
Date ret4=--d1;
cout << d1;
cout << ret4;
d1.Print();
}
void TestDate2()
{
Date d1(2024, 4, 4);
Date d2(2023, 4, 4);
Date ret1=d1 + 100;
cout << d1;
cout << ret1;
d1 += 100;
cout << "d1此时为:" << d1;
Date ret2=d2 - 100;
cout << d2;
cout << ret2;
d2 -= 100;
cout << "d2此时为:" << d2;
cout << (d1 - d2) << endl;;
cout << (d2 - d1) << endl;;
}
void TestDate3()
{
Date d1(2024, 4, 4);
Date d2(2023, 4, 4);
cout << (d1 > d2) << endl;
cout << (d1 < d2) << endl;
cout << (d1 >= d2) << endl;
cout << (d1 <= d2) << endl;
cout << (d1 != d2) << endl;
cout << (d1 == d2) << endl;
}
int main()
{
TestDate3();
return 0;
}