在C++中实现一个日期对象,要求能够实现:
1.算一个日期在x天之后是哪个日子,如2000年1月1日在500天之后是哪天
2.算一个日子在x天之前是哪个日子,如2000年1月1日在500天之前是哪天
3.算两个日期之间相差了有多少天,如2000年1月1日和2008年3月1日之间相差了有多少天
4.要求算给出一个具体的日期算当天是星期几,如2000年1月1日是星期几呢
5.能够实现日期类的各种运算符重载
6.要求判断日期是否合理不能出现非法日期
下面开始具体实现:
第一步对类的初始化和实现
class Date
{
public:
bool Checkdate()//判断日期是否合理
{
if (_year > 0
&& _month > 0 && _month < 13
&& _day>0 && _day < Getmonthday(_year, _month))
{
return true;
}
else
return false;
}
Date(int year = 1, int month = 1, int day = 1)
{
_year = year;
_month = month;
_day = day;
if (!Checkdate())
{
Print();
cout << "非法日期" << endl;
}
}
private:
int _year;
int _month;
int _day;
};
以上是第一步,声明类中的私有成员变量_year,_month,_day,同时写一个检查函数Checkdate()判断是否日期合法,再完成类中的全缺省构造函数Date()。
第二步:声明各种运算符的重载
#pragma once
#include<iostream>
#include<assert.h>
using namespace std;
class Date
{
public:
bool Checkdate()
{
if (_year > 0
&& _month > 0 && _month < 13
&& _day>0 && _day < Getmonthday(_year, _month))
{
return true;
}
else
return false;
}
Date(int year = 1, int month = 1, int day = 1)
{
_year = year;
_month = month;
_day = day;
if (!Checkdate())
{
Print();
cout << "非法日期" << endl;
}
}
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);
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++();
private:
int _year;
int _month;
int _day;//声明
};
在Date.h文件中,进行声明各种运算符重载,其中需要注意的是+=,-=,++,--这四类运算符重载声明时需要带上&(引用),需要引用返回,因为这四类运算符最后返回的都是自己本身直接用引用一个别名会方便很多,而加号减号这些并不是返回自己,加减的运算符返回可以声明另外的变量来进行返回,但是我们在实现这些运算符重载之前得先得到某个月的具体天数,因此需要先实现一个函数
int Getmonthday(int year, int month)
{
static int days[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };
int day = days[month];
if (month == 2
&& ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)))
day += 1;
return day;
}
此函数在我们实现运算符重载时是必不可少的,用来得到具体的1到12月的天数。下面开始第三步在date.cpp文件下实现运算符重载
#include"Date. h"
//任何一个类只需要写一个大于等于或者小于等于就可以了,其他的用比较运算符重载复用即可
void Date::Print()
{
cout << _year << "/" << _month << "/"<<_day << endl;
}
bool Date::operator!=(const Date& d)
{
return !(*this == d);
}
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)||(*this==d);
}
bool Date::operator<=(const Date& d)
{
return !(*this > d);
}
bool Date::operator>(const Date& d)
{
if ((_year > d._year) ||
(_year > d._year && _month > d._month) ||
(_year > d._year && _month > d._month && _day > d._day))
{
return true;
}
else
{
return false;
}
}
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++;
_month = 1;
}
}
return *this;
}
Date Date:: operator+(int day)
{
if (day < 0)
{
return *this += -day;
}
Date ret(*this);
ret += day;//复用了加等号
return ret;
}
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;//这里进行了减号和等号的复用,所以ret可以直接减去day
return ret;
}
//d1-d2
int Date::operator-(const Date& d)
{
int flag = 1;
Date max = *this;//假设第一个大第二个小
Date min = d;
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 ret(*this);
*This -= 1;
return ret;
}
Date& Date::operator++()// 前置++
{
*this += 1;
return *this;
}
以上是date.cpp的完整代码,在date.cpp文件中实现运算符重载中的判断两个日期是否相等,大于,小于,大于等于,小于等于或者是不等于都是bool类型的,返回的都是true或者false,但是我们在实现这些bool类型的大小等这些只需要实现>还有==这两个类型的就可以了,其他的都是这两个类型的复用,如<号,就是>=取反,不等于就是等于号取反等等,还是蛮方便的。
对于第二种运算符重载,Date日期加或者减上一个具体天数,或者是计算两个Date日期的差值天数时,需要注意返回值,同样也是可以用运算符重载的复用的,例如在实现+=和-=之后,+和-可以直接进行前面两个的复用,对于计算两个日期相差的天数的函数需要仔细理解,最后就是前置后置了。到这里第三步基本完成
下面进行第四步:完成test.cpp,也就是测试,一下是test.cpp完整代码。
#include"Date. h"
void Testdate2()
{
Date d1, d2;
int day = 0;
int option = 0;
do {
cout << "*****************************" << endl;
cout << "**** 1.日期加减天数 ******" << endl;
cout << "**** 2.日期减去日期 ******" << endl;
cout << "**** 3.日期->周几 ******" << endl;
cout << "**** -1.退出 ********" << endl;
cout << "********************************" << endl;
cout << "请输入:>";
cin >> option;
if (option == 1)
{
cout << "请依次输入日期和天数(如果是减天数请输入负数):";
cin >> d1 >> day;
cout <<"日期加减天数之后的日期为:" << d1 + day << endl;
}
else if (option == 2)
{
cout << "请依次输入两个日期:";
cin >> d1 >> d2;
cout << "相差的天数是: " << (d1 - d2) << endl;
}
else if (option == 3)
{
cout << "请输入日期:";
cin >> d1;
Date start(1, 1, 1);
int n = d1 - start;
int weekday = 0;//5就是相当于周六
weekday += n;
cout << "周" << weekday % 7 + 1 << endl;
}
} while (option != -1);
}
void Testdate3()
{
Date d5(2002, 3, 1);
Date d9(2030, 1, 5);
cout << d5 << d9;
cin >> d5 >> d9;
cout << d5 << d9;
}
int main()
{
Testdate2();
//cout << i;//1.库里面写好了重载运算符
//cout << d;//2.可以自动识别类型,他们构成了函数重载
//3.两个没有关系,运算符重载:让自定义类型对象可以用运算符,转换成调用这个重载函数
//函数重载:支持函数名相同的函数同时存在
//虽然都用了重载这个词,但是他们之间没有必然的联系
return 0;
上面是test.cpp的完整代码,在testdate2函数中写一个菜单,菜单功能中的1和2就不多解释了,对于菜单功能3,输入一个日期直接显示时周几,具体思想就是先写出公元1年1月1日就是周一,然后算出两个日期之间的天数差后取7的模再加1,例如weekday=0就是代表了周一, 6就是周日了。最后就是处理一些小细节,我们注意到test.cpp中出现了cin>>d5和cou<<d5 ,这些也是需要重载的,那么现在进行第五步。
第五步:以下是date.h的完整代码
#pragma once
#include<iostream>
#include<assert.h>
using namespace std;
class Date
{
friend ostream& operator<<(ostream& out, const Date& d);
friend istream& operator>>(istream& in, Date& d);
public:
bool Checkdate()
{
if (_year > 0
&& _month > 0 && _month < 13
&& _day>0 && _day < Getmonthday(_year, _month))
{
return true;
}
else
return false;
}
int Getmonthday(int year, int month)
{
static int days[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };
int day = days[month];
if (month == 2
&& ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)))
day += 1;
return day;
}
//构造函数会频繁的调用,放在类里面会好一点
Date(int year = 1, int month = 1, int day = 1)
{
_year = year;
_month = month;
_day = day;
if (!Checkdate())
{
Print();
cout << "非法日期" << endl;
}
}
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);
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++();
void Print();
/*operator<<(ostream& out);*/
//cout是ostream类型的对象
private:
int _year;
int _month;
int _day;//声明
};
inline ostream& operator<<(ostream& out, const Date& d)//流插入
{
out << d._year << "年" << d._month << "月" << d._day <<"日"<< endl;
return out;
}
//流提取
inline istream& operator>>(istream& in, Date& d)//in是cin的引用,其中cin是istream类型的对象
{
in >> d._year >> d._month >> d._day;
assert(d.Checkdate());
return in;
}
上面代码中进行了有友元函数的操作,因为cin和cout分别是istream和ostream里面的对象,再分别进行引用成in和out,进行运算符重载,这样就可以直接输入和输出自定义的类型d5了,如果不进行cin和cout的运算符重载只能输入输出内置类型。
最后,这个项目可以完美实现开头提出的要求,完美实现一个日期的项目。