目录
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;
}