什么是日期类?
用C++来实现一个日期类Date,包括年(_year)、月(_month)、日(day),来实现对日期的自增(++),自减(–),加上特定天数(+days),减去指定天数(-days),输入输出的实现,以及通过输入两个特定的日期,来计算相隔的天数。其中会用到构造函数、拷贝构造函数、析构函数,以及多类运算符的重载。
日期类实现思路
在设计日期类过程中,有一个月份相对特殊,那就是二月。可以通过判断是否闰年来确定二月的天数,为了后面实现的方便与简洁,可以将12个月的天数存储于一个一维数组中。在运算符重载中,对this指针的迷惑可以查看 this指针的详解。重载中会巧妙运用引用&及const关键字,程序中会降低一些算法的复杂度,具体实现将在函数调用中详细介绍。
函数调用模块
①构造函数及非法日期判断(以1900-1-1日为下限)
// 全缺省参数构造函数
Date(int year = 1997, int month = 11, int day = 4)
:_year(year)
, _month(month)
, _day(day)
{
//检查合法
if (year >= 0
&& _month > 0 && _month < 13
&& _day > 0 && _day <= GetMonthDay(year, month))
{
_year = year;
_month = month;
_day = day;
}
else
{
cout << "Date Invalid" << endl;
}
}
②拷贝构造函数(注意函数参数为const Date&类型)
//拷贝构造函数:Date d3(d1)或者 Date d3 = d1
Date::Date(const Date& d)
{
_year = d._year;
_month = d._month;
_day = d._day;
}
③析构函数(可以在里面打印"~Date",什么都不做也可以,对于动态开辟内存,在析构函数中free)
~Date()
{
;
}
④ 判断是否闰年(4年一闰,逢百年不闰,400年一闰与获取某年某月的指定天数(判断闰年后月份已经确定,可存储于数组中方便调用)
//获取当月天数
int Date::GetMonthDay(int year, int month)
{
//方法一:十二个if、else语句
//方法二:switch分支语句
//此处方法三:
static const int days[13] = {0, 31,28, 31,30, 31,30, 31,31,30, 31,30, 31 };//润年二月多一天
//4年一润百年不润400年一润且此处至于二月有关
if ((month == 2)&&((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)))
{
return 29;
}
return days[month];
}
⑤赋值运算符 = 重载(分两种情况:1.自己给自己赋值,但是无意义,建议不使用 2.自己给别人赋值)
//赋值操作符重载
Date& Date::operator=(const Date& d)
{
if (this != &d)
{
_year = d._year;
_month = d._month;
_day = d._day;
}
return *this;
}
⑥取地址操作符重载
//取地址操作符重载
Date* operator&()
{
return this;
}
⑦重载 + days(加上指定天数)的重载(当+days大于该月总天数时,用days减去该月天数,月份month+1,差值即为新月份的天数。若遇到年末,即month = 12时,年份year++,月份month置1,否则month++)
Date Date::operator+(int day)
{
Date ret(*this);
if (day<0)
return ret - abs(day);
ret._day += day;
while (ret._day > GetMonthDay(ret._year, ret._month))
{
ret._day -= GetMonthDay(ret._year,ret._month);
if (12 == ret._month)
{
ret._year++;
_month = 1;
}
else
{
_month += 1;
}
}
return ret;
}
Date& Date::operator+=(int day)
{
if (day<0)
{
return *this - abs(day);
}
_day += day;
while (_day > GetMonthDay(_year, _month))
{
_day -= GetMonthDay(_year, _month);
if (12 == _month)
{
_year++;
_month = 1;
}
else
{
_month += 1;
}
}
return *this;
}
⑧重载 - days (减去指定天数)的重载(与+days类似,用该月天数-days,其差值若小于0,且在年初,则年份year–,置月份month=12,否则month–)
//(与+days类似,用该月天数-days,
//其差值若小于0,且在年初,则年份year--,置月份month=12,否则month--)
Date Date::operator-(int day)
{
Date ret(*this);
if (day < 0)
return ret + abs(day);
ret._day -= day;
while (ret._day <= 0)
{
if (ret._month == 1)
{
ret._year--;
ret._month = 12;
}
else
{
ret._month--;
}
ret._day += GetMonthDay(ret._year,ret._month);
}
return ret;
}
Date& Date::operator-=(int day)
{
if (day < 0)
return *this + abs(day);
_day -= day;
while (_day <= 0)
{
if (_month == 1)
{
_year--;
_month = 12;
}
else
{
_month--;
}
_day += GetMonthDay(_year,_month);
}
return *this;
}
⑨前置 ++ 的重载(+1操作应该考虑天数为月末,月份为年末时的特殊情况,通过判断月末与年末,对指定的月份+1或年份+1,并置新月份=1)
//( + 1操作应该考虑天数为月末,月份为年末时的特殊情况,
//通过判断月末与年末,对指定的月份 + 1或年份 + 1,并置新月份 = 1)
Date& Date::operator++()// ++d => d.operator++(&d)
{
_day++;
if (_day > GetMonthDay(_year, _month))
{
_day -= GetMonthDay(_year, _month);
_month++;
if (_month > 12)
{
_year++;
_month = 1;
}
}
return *this;
}
⑩后置 ++ 的重载(后置++与前置++类似,返回值略有差异,可以拷贝构造一个临时的函数来保存this指针保存的内容,最终返回临时的函数)
//(后置++与前置++类似,返回值略有差异,
//可以拷贝构造一个临时的函数来保存this指针保存的内容,最终返回临时的函数)
Date Date::operator++(int)// d++ => d.operator(&d, 0)
{
Date ret(*this);
_day++;
if (_day > GetMonthDay(_year, _month))
{
_day -= GetMonthDay(_year, _month);
_month++;
if (_month > 12)
{
_year++;
_month = 1;
}
}
return ret;
}
⑪前置 – 的重载(-1操作应该考虑天数为月初,月份为年初时的特殊情况,通过判断月末与年末,对指定的月份-1或年份-1,并置新月份=12)
// (-1操作应该考虑天数为月初,月份为年初时的特殊情况,
//通过判断月末与年末,对指定的月份-1或年份-1,并置新月份=12)
Date& Date::operator--() // --d
{
_day--;
if (_day <= 0)
{
if (_month == 1)
{
_year--;
_month = 12;
}
else
{
_month--;
}
_day += GetMonthDay(_year, _month);
}
return *this;
}
⑫后置 – 的重载(与前置–类似,可以使用拷贝构造函数构造一个临时的函数,最终返回临时函数即可)
//(与前置--类似,可以使用拷贝构造函数构造一个临时的函数,最终返回临时函数即可)
Date Date::operator--(int) // d--
{
Date ret(*this);
if (_day <= 0)
{
if (_month == 1)
{
_year--;
_month = 12;
}
else
{
_month--;
}
_day += GetMonthDay(_year, _month);
}
return ret;
}
⑬关系运算符的重载
//日期类关系操作符重载
bool Date::operator>(const Date& d)
{
if (_year > d._year)
{
return true;
}
else if (_year == d._year)
{
if (_month > d._month)
{
return true;
}
else if (_month == d. _month)
{
if (_day > d._day)
{
return true;
}
}
}
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);
}
bool Date::operator<=(const Date& d)
{
return !(*this > d);
}
// d1 >= d2
bool Date::operator>=(const Date& d)
{
return *this > d || *this == d;
}
bool Date::operator!=(const Date& d)
{
return !(*this == d);
}
⑭输出运算符 << 的重载(模拟cout输出)
// 重载输出 <<
ostream& operator<<(ostream& _cout, const Date& d)
{
_cout << d._year << "-" << d._month << "-" << d._day << endl;
return _cout;
}
⑮ 输入运算符 >> 的重载(模拟cin输入)
//重载输入>>
istream& operator>>(istream& _cin, Date& d)
{
_cin >> d._year;
_cin >> d._month;
_cin >> d._day;
return _cin;
}
⑯两个日期相隔天数 - 的重载(这里可以运用一个巧妙的方法,将当前对象拷贝构造为Max,引用对象拷贝构造为Min,如果Max<Min,调用库函数交换,并用一个状态量flag标记。再利用while循环,只要Max与Min不相等,Max–,计数器Count++,Count即为最终的相隔天数)
//(这里可以运用一个巧妙的方法,将当前对象拷贝构造为Max,引用对象拷贝构造为Min,
//如果Max<Min,调用库函数交换,并用一个状态量flag标记。再利用while循环,
//只要Max与Min不相等,Max--,计数器days++,days即为最终的相隔天数)
int Date::operator-(const Date& d)
{
int flag = 1;
Date Max(*this);
Date Min(d);
if ((*this) < d)
{
std::swap(Max, Min);
flag = -1;
}
int days = 0;
while (Max != Min)
{
--Max;
++days;
}
return days*flag;
}
参考代码
Date.h
#pragma once
#include<iostream>
#include<Windows.h>
#include<cmath>
using namespace std;
//日期类实现操作符重载
class Date
{
public:
// 全缺省参数构造函数
Date(int year = 1997, int month = 11, int day = 4)
:_year(year)
, _month(month)
, _day(day)
{
//检查合法
if (year >= 0
&& _month > 0 && _month < 13
&& _day > 0 && _day <= GetMonthDay(year, month))
{
_year = year;
_month = month;
_day = day;
}
else
{
cout << "Date Invalid" << endl;
}
}
//析构函数
~Date()
{
;
}
//拷贝构造函数:Date d3(d1)或者 Date d3 = d1
Date(const Date& d)
{
_year = d._year;
_month = d._month;
_day = d._day;
}
//赋值操作符重载
Date& operator=(const Date& d)
{
if (this != &d)
{
_year = d._year;
_month = d._month;
_day = d._day;
}
return *this;
}
//取地址操作符重载
Date* operator&()
{
return this;
}
//关系操作符重载
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);
//获取当月天数
int GetMonthDay(int year, int month);
//返回自身加引用,返回临时值返回
Date operator+(int day);
Date& operator+=(int day);
Date operator-(int day);
Date& operator-=(int day);
int operator-(const Date& d);
Date& operator++();
Date operator++(int);
Date& operator--();
Date operator--(int);
//重载输出<<
friend ostream& operator<<(ostream& _cout, const Date& d);
//重载输入>>
friend istream& operator>>(istream& _cin, Date& d);
private:
int _year;
int _month;
int _day;
};
Date.cpp
#include "Date.h"
//获取当月天数
int Date::GetMonthDay(int year, int month)
{
//方法一:十二个if、else语句
//方法二:switch分支语句
//此处方法三:
static const int days[13] = {0, 31,28, 31,30, 31,30, 31,31,30, 31,30, 31 };//润年二月多一天
//4年一润百年不润400年一润且此处至于二月有关
if ((month == 2)&&((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)))
{
return 29;
}
return days[month];
}
//日期类关系操作符重载
bool Date::operator>(const Date& d)
{
if (_year > d._year)
{
return true;
}
else if (_year == d._year)
{
if (_month > d._month)
{
return true;
}
else if (_month == d. _month)
{
if (_day > d._day)
{
return true;
}
}
}
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);
}
bool Date::operator<=(const Date& d)
{
return !(*this > d);
}
// d1 >= d2
bool Date::operator>=(const Date& d)
{
return *this > d || *this == d;
}
bool Date::operator!=(const Date& d)
{
return !(*this == d);
}
//日期类操作符重载
// d1 + 100
//当+days大于该月总天数时,用days减去该月天数,月份month+1,差值即为新月份的天数。
//若遇到年末,即month = 12时,年份year++,月份month置1,否则month++)
Date Date::operator+(int day)
{
Date ret(*this);
/*if (day<0)
return ret - abs(day);
ret._day += day;
while (ret._day > GetMonthDay(ret._year, ret._month))
{
ret._day -= GetMonthDay(ret._year,ret._month);
if (12 == ret._month)
{
ret._year++;
_month = 1;
}
else
{
_month += 1;
}
}*/
//改进:
ret += day;
return ret;
}
Date& Date::operator+=(int day)
{
if (day<0)
{
return *this - abs(day);
}
_day += day;
while (_day > GetMonthDay(_year, _month))
{
_day -= GetMonthDay(_year, _month);
if (12 == _month)
{
_year++;
_month = 1;
}
else
{
_month += 1;
}
}
return *this;
}
//(与+days类似,用该月天数-days,
//其差值若小于0,且在年初,则年份year--,置月份month=12,否则month--)
Date Date::operator-(int day)
{
Date ret(*this);
/*if (day < 0)
return ret + abs(day);
ret._day -= day;
while (ret._day <= 0)
{
if (ret._month == 1)
{
ret._year--;
ret._month = 12;
}
else
{
ret._month--;
}
ret._day += GetMonthDay(ret._year,ret._month);
}*/
//改进:
ret -= day;
return ret;
}
Date& Date::operator-=(int day)
{
if (day < 0)
return *this + abs(day);
_day -= day;
while (_day <= 0)
{
if (_month == 1)
{
_year--;
_month = 12;
}
else
{
_month--;
}
_day += GetMonthDay(_year,_month);
}
return *this;
}
//(这里可以运用一个巧妙的方法,将当前对象拷贝构造为Max,引用对象拷贝构造为Min,
//如果Max<Min,调用库函数交换,并用一个状态量flag标记。再利用while循环,
//只要Max与Min不相等,Max--,计数器days++,days即为最终的相隔天数)
int Date::operator-(const Date& d)
{
int flag = 1;
Date Max(*this);
Date Min(d);
if ((*this) < d)
{
std::swap(Max, Min);
flag = -1;
}
int days = 0;
while (Max != Min)
{
--Max;
++days;
}
return days*flag;
}
//( + 1操作应该考虑天数为月末,月份为年末时的特殊情况,
//通过判断月末与年末,对指定的月份 + 1或年份 + 1,并置新月份 = 1)
Date& Date::operator++()// ++d => d.operator++(&d)
{
/*_day++;
if (_day > GetMonthDay(_year, _month))
{
_day -= GetMonthDay(_year, _month);
_month++;
if (_month > 12)
{
_year++;
_month = 1;
}
}*/
//该进:
*this += 1;
return *this;
}
//(后置++与前置++类似,返回值略有差异,
//可以拷贝构造一个临时的函数来保存this指针保存的内容,最终返回临时的函数)
Date Date::operator++(int)// d++ => d.operator(&d, 0)
{
Date ret(*this);
/*_day++;
if (_day > GetMonthDay(_year, _month))
{
_day -= GetMonthDay(_year, _month);
_month++;
if (_month > 12)
{
_year++;
_month = 1;
}
}*/
*this += 1;
return ret;
}
// (-1操作应该考虑天数为月初,月份为年初时的特殊情况,
//通过判断月末与年末,对指定的月份-1或年份-1,并置新月份=12)
Date& Date::operator--() // --d
{
/*_day--;
if (_day <= 0)
{
if (_month == 1)
{
_year--;
_month = 12;
}
else
{
_month--;
}
_day += GetMonthDay(_year, _month);
}*/
*this -= 1;
return *this;
}
//(与前置--类似,可以使用拷贝构造函数构造一个临时的函数,最终返回临时函数即可)
Date Date::operator--(int) // d--
{
Date ret(*this);
/*_day--;
if (_day <= 0)
{
if (_month == 1)
{
_year--;
_month = 12;
}
else
{
_month--;
}
_day += GetMonthDay(_year, _month);
}*/
*this -= 1;
return ret;
}
// 重载输出 <<
ostream& operator<<(ostream& _cout, const Date& d)
{
_cout << d._year << "-" << d._month << "-" << d._day << endl;
return _cout;
}
//重载输入>>
istream& operator>>(istream& _cin, Date& d)
{
_cin >> d._year;
_cin >> d._month;
_cin >> d._day;
return _cin;
}
Main.cpp
#include "Date.h"
void FunTest()
{
Date date1(2015, 3, 31);
Date date2(date1);
Date date3(2017, 12, 1);
Date date4(date3);
Date date5(2012, 2, 2);
Date date6(date5);
Date date7(2017, 2, 19);
Date date8(2015, 8, 8);
Date date9;
cout<<"date1:"<<date1<<endl;
cout<<"date2:"<<date2<<endl;
cout<<"date3:"<<date3<<endl;
cout<<"date4:"<<date4<<endl;
cout<<"date5:"<<date5<<endl;
cout<<"date6:"<<date6<<endl;
cout<<"date7:"<<date7<<endl;
cout<<"date8:"<<date8<<endl;
cout<<"date9:"<<date9<<endl;
cout << "前置++:" << ++date1 << endl;
cout << "后置++:" << date2++ << endl;
cout << "前置--:" << --date3 << endl;
cout << "后置--:" << date4-- << endl;
cout << "加指定天数:" << date5 + 24 << endl;
cout << "减指定天数:" << date6 - 5 << endl;
cout << "两个日期相差的天数:" << date7 - date8 << endl;
cin>>date9;
}
int main()
{
FunTest();
system("pause");
return 0;
}
效果样例:
结语
初识C++的大门,希望自己在这条路上越走越远!