时间类的实现
在现实生活中,我们常常需要计算某一天的前/后xx天是哪一天,算起来十分麻烦,为此我们不妨写一个程序,来减少我们的思考时间。
1.基本实现过程
为了实现时间类,我们需要将代码写在3个文件中,以增强可读性,我们将这三个文件命名为date.h date.cpp test.cpp.
这是date.h文件
#pragma once
#include<iostream>
using namespace std;
class Date
{
//友元
friend void operator<<(ostream& out, const Date& d);
public:
Date(int year = 1, int month = 1, int day = 1);
void print();
//inline
int getmonday(int year, int month)
{
//把12个月先准备好
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;
}
return monthDayArray[month];
}
//判断日期大小的函数
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);
//d1+=
Date& operator+=(int day);
Date operator+(int day);
// d1 -=
Date& operator-=(int day);
// d1 - 100
Date operator-(int day);
// d1 - d2
int operator-(const Date& d);
// ++d1 -> d1.operator++();
Date& operator++();
// d1++ -> d1.operator++(0);
Date operator++(int);
Date& operator--();
Date operator--(int);
//void operator<<(ostream& out);
private:
int _year;
int _month;
int _day;
};
void operator<<(ostream& out, const Date& d);
这是date.cpp文件
#define _CRT_SECURE_NO_WARNINGS
#include"date.h"
Date::Date(int year, int month, int day)
{
_year = year;
_month = month;
_day = day;
}
void Date::print()
{
cout << _year << "-" << _month << "-" << _day << endl;
}
//d1+=50
Date& Date::operator+=(int day) //this -> d1;day->50
{
if (day < 0)
{
return *this -= (-day);
}
_day += day; //等价于this->_day += day;
while (_day > getmonday(_year, _month))
{
_day -= getmonday(_year, _month);
//月进位
++_month;
if (_month == 13)
{
++_year;
_month = 1;
}
}
return *this;
}
Date Date::operator+(int day)
{
Date tmp(*this);
tmp += day;
return tmp;
}
// d1 -= 天数
Date& Date::operator-=(int day)
{
if (day < 0)
{
return *this += (-day);
}
_day -= day;
while (_day <= 0)
{
// 借位
--_month;
if (_month == 0)
{
--_year;
_month = 12;
}
_day += getmonday(_year, _month);
}
return *this;
}
Date Date::operator-(int day)
{
Date tmp = *this;
tmp -= day;
return tmp;
}
// d1 < d2
bool Date::operator>(const Date& d)
{
if (_year > d._year)
{
return true;
}
else if (_year == d._year && _month > d._month)
{
return true;
}
else if (_year == d._year && _month == d._month)
{
return _day > d._day;
}
return false;
}
//d1<d2
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 _year == d._year
&& _month == d._month
&& _day == d._day;
}
bool Date::operator!=(const Date& d)
{
return !(*this == d);
}
//顺便说一下前置++和后置++怎末写
// ++d1 -> d1.operator++();
Date& Date::operator++()
{
*this += 1;
return *this;
}
// d1++ -> d1.operator++(0);//这个数多少都行,没影响的,就是++,跟你传的数没关系
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;
}
//求日期差多少天
//d1-d2
//this->d1,d->d2 (d是d2别名)
int Date::operator-(const Date& d)
{
//不知道d1d2谁大谁小,为了避免弄错先后关系,我们比较一下
int flag = 1;
Date max = *this;
Date min = d;
if (*this < d)
{
max = d;
min = *this;
flag = -1;
}
int n = 0;
while (min != max)
{
++n;
++min;
}
return n * flag;
}
void operator<<(ostream& out, const Date& d)
{
out << d._year << "年" << d._month << "月" << d._day << "日" << endl;
}
这是test.cpp文件
#include"Date.h"
#include<math.h>
void testdate1()
{
Date d1(2024, 11, 14);
Date d2 = d1 + 50;
//d1 += 50;
d1.print();
d2.print();
Date d3(2024, 11, 14);
Date d4 = d3 + 5000;
d3 += 5000;
d3.print();
d4.print();
}
void testdate2()
{
Date d1(2024, 11, 16);
Date d2 = d1 - 50;
//d1 -= 50;
d1.print();
d2.print();
Date d3(2024, 11, 16);
Date d4 = d3 - 5000;
d3 -= 5000;
d3.print();
d4.print();
Date d5(2024, 11, 16);
d5 += -100;
d5.print();
}
void testdate3()
{
Date d1(2024, 11, 16);
Date d2(2024, 11, 16);
Date d3(2024, 10, 17);
cout << (d1 > d2) << endl;
cout << (d1 >= d2) << endl;
cout << (d1 == d2) << endl;
cout << (d1 > d3) << endl;
cout << (d1 >= d3) << endl;
cout << (d1 == d3) << endl;
}
void testdate4()
{
//打印时,不要放在一坨,否则由于我们的++操作,可能导致程序本身没大问题,但是打印会出问题,导
致我们看不到我们想要的结果
Date d1(2024, 11, 16);
d1.print();
Date d4 = d1++; //等价于Date d4 = d1.operator++(1);这里实参传什么值都可以,只要是int就
行,仅仅参数匹配
d4.print();
Date d3 = ++d1; //等价于Date d3 = d1.operator++();
d3.print();
cout << endl;
Date d6(2024, 11, 16);
d6.print();
Date d7 = ++d6;
d7.print();
Date d8 = d6++;
d8.print();
//通过对比两组实验结果,我们发现,前置++和后置++区别很大,
//第一组,我们让后置++在前置++前面,会发现:由于后置++是先使用后++,故打印出16日,之后变为
17,而前置++是先++后使用,此时,17+1==18,故打印出来是18日
//同理,可解释第二组的结果,这里不在赘述,由此可见,选取哪种++方式,要视情况而定
}
void testdate5()
{
Date d1(2025, 3, 3);
Date d2(2025, 1, 14);
cout <<"还有" << abs(d1 - d2) <<"放假!"<< endl; //abs是临时起意为了解决实际问题而加的
int i = 100;
//cout << d1 << "和" << i;
cout << d1; //这里之所以能输出年月日字样,是因为我们定义了<<运算符,是设置的一种输出流,
不要和正常的cout<<弄混
//d1 << cout;
}
int main()
{
//testdate1();
//testdate2();
//testdate3();
//testdate4();
testdate5();
return 0;
}
代码结果这里就不过多展示了!
2.代码优化
这里有一个小问题~~
上述testdate5中,cout<<d1没有问题,但是当我们在想连续输出其他值时,会出现报错,我们看<ostream>里面的cout,为什么可以连续输出,因为其在输出第一个值之后,返回值仍为cout,但是,反观我们写的函数,没有返回值了!故我们需要在对其精进一下!
精进代码如下:
我们将date.cpp的输入流和输出流这样改一下!
ostream& operator<<(ostream& out, const Date& d)
{
out << d._year << "年" << d._month << "月" << d._day << "日" << endl;
return out;
}
istream& operator>>(istream& in, Date& d)
{
cout << "请依次输入年月日:>";
in >> d._year >> d._month >> d._day;
return in;
}
date.h也改一下:(这里将前面用不到的函数删去了!)
#pragma once
#include<iostream>
using namespace std;
class Date
{
//友元
friend ostream& operator<<(ostream& out, const Date& d);
friend istream& operator>>(istream& in, Date& d);
public:
private:
int _year;
int _month;
int _day;
};
// 流插入
ostream& operator<<(ostream& out, const Date& d);
// 流提取
istream& operator>>(istream& in, Date& d);
test.cpp也改一下:
void testdate6()
{
Date d1(2024, 2, 29);
Date d2(2023, 2, 29);
cin >> d1 >> d2;
cout << d1 << d2;
}
int main()
{
testdate6();
return 0;
}
如此一来,我们得到了我们想输出的日期!
可是,这个日期真的对吗?我们的编译器似乎太服从我们了,不管对错他都输出,但是,为了保证我们输出结果的正确性,应该加上一组日期判断,不符合常理的就让用户重新输!
3.提高正确性
我们做出如下改造:
在date.cpp文件中在定义一个函数,用于检查日期是否合理:
bool Date::checkdate()const //为什么加const下一篇博客讲
{
if (_month < 1 || _month > 12 || _day < 1 || _day > getmonday(_year, _month))
{
return false;
}
else
{
return true;
}
}
date.cpp的流提取也要改一下:
istream& operator>>(istream& in, Date& d)
{
while (1)
{
cout << "请依次输入年月日:>";
in >> d._year >> d._month >> d._day;
if (d.checkdate()) //得到结果为1
{
break;
}
else //得到结果为0
{
cout << "输入的日期非法,请重新输入" << endl;
}
}
return in;
}
这样我们就得到了一个功能相对健全的时间程序!