目录
1.日期类的成员
2.日期类的成员函数
2.1构造和析构函数
2.2检查日期合法
2.3日期的打印
2.4操作符重载
2.4.1小于号
2.4.2等于号
2.4.3小于等于号
2.4.4大于号
2.4.5大于等于号
2.4.6不等号
2.4.7加等的实现
2.4.8加的实现
2.4.9减去一个天数的减等实现
2.4.10减去一个天数的减实现
2.4.11两个日期相减的实现
2.4.12前后置++的实现
2.4.13前后置--的实现
2.5流插入/流提取操作符
1.日期类的成员
实现一个日期类,内部的成员自然是年、月、日
class Date
{
private:
int _year;
int _month;
int _day;
};
在日期类中,我们应当是已知每个月份有多少天的,因此我们还需要在日期内中写一个成员函数来获得当月的天数。
//获得天数
int GetMonthDay(int year,int month)
{
static int monthDayArray[13] = { -1, 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 monthDayArray[month];
}
}
此外,我们的日期类还应当能够实现对日期的打印、对日期类的相关计算、输入输出的重载等成员函数。
因此,我们完整的日期类应是如下:
#pragma once
#include <iostream>
using namespace std;
#include <assert.h>
class Date
{
public:
//流插入or输出
friend ostream& operator<<(ostream& out, const Date& d);
friend istream& operator>>(istream& in, Date& d);
//构造
Date(int year = 1900, int month = 1, int day = 1);
//获取月份天数
int GetMonthDay(int year, int month)
{
assert(month > 0 && month < 13);
static int monthDayArray[13] = { -1, 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 monthDayArray[month];
}
}
//检查日期
bool CheckDate();
//打印日期
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;
};
//输入流重载
ostream& operator<<(ostream& out, const Date& d);
//输出流重载
istream& operator>>(istream& in, Date& d);
2.日期类的成员函数
2.1构造和析构函数
由于日期类的成员都是内置类型,因此我们可以显式的写一个构造函数,但不用显式定义析构函数。
Date::Date(int year = 2024, int month = 7, int day = 2)
{
_year = year;
_month = month;
_day = day;
//检查日期合法性
if (!CheckDate())
{
cout << "日期非法" << endl;
}
}
由于我们的日期具有范围,因此我们需要在构造函数中检查日期是否合法。也正是因此,我们需要实现一个检查日期合法性的函数。
2.2检查日期合法
检查日期合法,首先要确保我们输入的数是正数,
//检查日期合法性
bool Date::CheckDate()
{
if (_month < 1 || _month>12
|| _day<1 || _day>GetMonthDay(_year, _month)||_year < 1)
{
return false;
}
else
{
return true;
}
}
2.3日期的打印
void Date::Print() const
{
cout << _year <<'-' << _month <<'-'<<_day;
}
2.4操作符重载
下面我们就需要重载一些对日期类计算有用的操作符
2.4.1小于号
由于我们不想要我们传入的参数会被修改,因此我们需要传递常量。(权限可以缩小)
另外,我们传引用有两个原因
- 可以少一次构造形参的过程,可以提高性能。
- d在函数运行结束后不会销毁,不会返回一个空引用。
因此我们的函数名为:
bool operator<(const Date& d) const
判断一个日期是否小于另一个日期,我们需要分别判断年、月、日是否小于另一个日期。
在判断日的时候,我们可以直接使用原生的<操作符判断。
bool Date::operator<(const Date& d) const
{
//年
if (_year < d._year)
{
return true;
}
else if (_year == d._year)
{ //月
if (_month < d._month)
{
return true;
}
else if (_month == d._month)
{
//日
return _day < d._day;
//if (_day < d._day)
//{
// return true;
//}
//else
//{
// return false;
//}
}
}
}
2.4.2等于号
直接判断年月日是否相等即可
bool Date::operator==(const Date& d) const
{
return _year == d.year
&& _month == d._month
&& _day == d._day;
}
2.4.3小于等于号
我们传入的第一个参数是this,因此我们解引用this即可得到第一个参数的值。
bool Date::operator<=(const Date& d)const
{
return *this < d || *this == d;
}
2.4.4大于号
判断是否大于就是是否小于等于取反
bool Date::operator>(const Date& d)const
{
return !(*this <= d);
}
2.4.5大于等于号
判断是否大于等于就是对判断是否小于取反
bool Date::operator>=(const Date& d)const
{
return !(*this < d);
}
2.4.6不等号
判断是否不相等就是对判等取反
bool Date::operator!=(const Date& d)const
{
return !(*this == d);
}
2.4.7加等的实现
对于加等,是给定一个日期和一个天数,计算日期加上这个天数之后的日期。
这里我们采取的思路是先将原天数加上需要加的天数。
之后我们一直减去当月的天数,并让月份加1,如果月份为13,则年份加1,月份赋为1。一直到天数没有当月天数大为止。
Date& Date::operator+=(int day)
{
//日期加
_day+= day;
//月份加
while (_day > GetMonthDay(_year, _month))
{
if (_day > GetMonthDay(_year, _month))
{
_month++;
_day - GetMonthDay(_year, _month);
if (_month == 13)
{
_month == 1;
_year += 1;
}
}
}
return *this;
}
2.4.8加的实现
首先,我们实现两数相加,是不能改变我们的原数的。
因此,我们的第一个形参为const修饰的变量。
//加
//c=a+b;
Date Date::operator+(int day) const
{
Date tmp = *this;
tmp += day;
return tmp;
}
这里我们采取的思路是创建一个临时变量来保存*this,然后返回tmp加等day的结果即可。
这里需要注意的是,由于这个函数运行结束之后,tmp会先被销毁掉,再进行返回,因此我们如果返回值为引用的话,则会出错。
2.4.9减去一个天数的减等实现
//减去一个天数
//减等
Date& Date::operator-=(int day)
{
//减去一个负数
if (day < 0)
{
return *this += (-day);
}
//减去一个整数
_day -= day;
while (_day < 0)
{
--month;
if (_month == 0)
{
_month = 12;
_year--;
}
_day += GetMonthDay(_year, _month);
}
}
与实现加等类似的是,这里我们也是类似的步骤,通过一个循环来不断的更新年月日。
2.4.10减去一个天数的减实现
//减去一个天数
Date Date::operator-(int day)const
{
Date tmp = *this;
tmp -= day;
return tmp;
}
这里和上面的加等相似。
2.4.11两个日期相减的实现
首先,我们要判断出哪个日期大
之后,我们让小的日期不断加1,直到他们相同。
加了多少次1,两个日期就相隔多少天。
//两个日期相减
Date Date::operator-(const Date& d)const
{
//假设法判断谁大
Date max = *this;
Date min = d;
if (min > max)
{
max = d;
min = *this;
}
//小的日期不断加一天,直到二者相等
//设置一个计数器,计数器的值就是两个日期的差值
int n = 0;
while (min!+ max)
{
min++;
n++;
}
return n;
}
2.4.12前后置++的实现
由于我们重载++操作符时都是这么写的:
Date::operator++()//前
Date::operator++(int)//后
这样便无法判断到底是调用前置++还是后置++了。
因此,我们规定调用后置++时,形参写一个int。
Date::operator++()//前
Date::operator++(int)//后
前置++非常容易实现,这里不再赘述。
//前后置++--
Date& Date::operator++()//前
{
*this += 1;
return *this;
}
Date Date::operator++(int)//后
{
Date tmp = *this;
*this + 1;
return tmp;
}
后置++是先使用后++的。因此我们创建一个临时变量来保存*this,并在返回tmp前对*this+1。
2.4.13前后置--的实现
Date& Date::operator--()//前
{
*this -= 1;
return *this;
}
Date Date::operator--(int)//后
{
Date tmp = *this;
*this - 1;
return tmp;
}
2.5流插入/流提取操作符
观察下面两行代码,我们发现这两个操作符的第二个操作数才是this。
但是成员函数默认第一个操作数为this,这就产生了问题。
因此我们不能够将这两个函数声明为成员函数。
cout << n << endl;
cin << n ;
我们需要将这两个函数声明在类外,之后通过友元在类内访问即可。
//类内
friend ostream& operator<<(ostream& out, const Date& d);
friend istream& operator>>(istream& in, Date& d);
//定义
ostream& operator <<(ostream& out, const Date& d)
{
cout << d._year << '-' << d._month << '-' << d._day;
return out;
}
istream& operator>>(istream& in, Date& d)
{
in >> d._year >> d._month >> d._day;
if (!d.CheckDate())
{
cout << "日期非法" << endl;
}
return in;
}