这里我们把类的声明放在.h 文件里面,实现放在.cpp文件,这样做的原因是,我们在类里面实现的函数,编译器都会当做内联函数处理的,我们把类的一些成员函数的声明和实现分开,是为了把一些不适合当内联函数给区分开来。
有些成员函数是不会修改到值的,我们都可以加上const修饰,以做到保护代码的作用,防止乱写,我们把const加在声明后面是对隐藏的this指针修饰的。
// >运算符重载 const加在括号外是对隐藏的this指针修饰的
bool operator>(const Date& d)const;
// >运算符重载 const加在括号外是对隐藏的this指针修饰的
bool Date::operator>(const Date& d)const
{
if(_year > d._year)
{
return true;
}
else if(_year == d._year && _month > d._month)
{
return true;
}
else if(_year == d._year && _month == d._month && _day > d._day)
{
return true;
}
return false;
}
日期类的实现
题目内容:
class Date
{
public:
// 获取某年某月的天数
int GetMonthDay(int year, int month);
// 全缺省的构造函数
Date(int year = 1900, int month = 1, int day = 1);
// 拷贝构造函数
// d2(d1)
Date(const Date& d);
// 赋值运算符重载
// d2 = d3 -> d2.operator=(&d2, d3)
Date& operator=(const Date& d);
// 析构函数
~Date();
// 日期+=天数
Date& operator+=(int day);
// 日期+天数
Date operator+(int day);
// 日期-天数
Date operator-(int day);
// 日期-=天数
Date& operator-=(int day);
// 前置++
Date& operator++();
// 后置++
Date operator++(int);
// 后置--
Date operator--(int);
// 前置--
Date& operator--();
// >运算符重载
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 operator-(const Date& d);
private:
int _year;
int _month;
int _day;
};
我们需要先实现一个,可以通过年,月,获取到当个月的天数的函数,以便我们后期一些函数的实现。
// 获取某年某月的天数
int GetMonthDay(int year, int month)
{
static int days[]= {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;
}
这里我们把一年中的每个月的天数用一个数组保存起来,由于数组是0开始的,为了方便我们后面获取天数时,不用加1处理,我们把第一个数置0,后面开始保存我们每个月的天数,当然还要考虑到润年时2月要加1。
// 全缺省的构造函数
Date(int year = 2022, int month = 9, int day = 22)
{
_year = year;
_month = month;
_day = day;
// 我们需要考虑到年份,月份,天数是否合法,需要做个处理,如果非法要打印出来提示
if(!(year >= 1 &&
(month >=1 && month <=12)&&
GetMonthDay(year, month) >= day))
{
std::cout<< "非法" << std::endl;
}
}
接下来是我们的全缺省构造函数,构造函数是调用比较频繁的,我们把他放在类里面,凡是在类里面的函数,编译器都会把他当成内联函数处理。
// 拷贝构造函数
// d2(d1)
Date(const Date& d)
{
_year = d._year;
_month = d._month;
_day = d._day;
}
由于时间类的成员都是内置类型的,我们也可以不写拷贝构造函数,编译器默认生成的,也可以用,那些是需要我们自己写拷贝构造函数呢,例如涉及到内存管理的时候就需要。
// 赋值运算符重载
// d2 = d3 -> d2.operator=(&d2, d3)
//由于我们把赋值运算符声明和实现分开了,所以我们需要在函数名前加上域运算符,以便编译器能找到
Date& Date::operator=(const Date& d)
{
_year = d._year;
_month = d._month;
_day = d._day;
return *this;
}
赋值函数的原型实际为,Date& operator=(Date* this,const Date& d) 隐藏了一个this指针
时间类的成员都是内置类型即int,char,之类的,我们也可以直接用编译器默认生成的赋值运算符重载,这里我们自己写出来是为了更多理解,赋值是把已经创建好的两个类,把右值给左值重新初始化,两个类是出了函数还存在的,所以我们用引用,并且我们是不会更改右值的,所以我们加上const修饰,为什么要返回一个类呢,是因为我们赋值的话,有可能遇到 d0 = d1 = d2;连续赋值,所以一般是返回左值的。
~Date()
{
_year = 0;
_month = 0;
_day = 0;
}
时间类的成员都是内置类型即int,char,之类的,我们也可以直接用编译器默认生成的析构函数,这里我们自己写出来是为了更多理解。
// 日期+=天数
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)
{
_month =1;
++_year;
}
}
//返回+=后的结果是为了 连续的+=情况的处理 d0 += d1 += d2;
return *this;
}
日期加等上一个天数之后的日期,是会改变自身的,如果加上的天数是一个负的,我们直接复用-=运算符重载函数,反之,则直接加上这个天数,通过跟当前的年,月的天数对比,如果大于,则月份加1,如果月份等于13了则年份加1,月份重置为1,一直循环到天数不大于当前的年,月的天数。
// 日期+天数
Date operator+(int day)
{
Date ret(*this);
ret += day;
return ret;
}
日期加天数后的日期,不会改变自身,所以我们可以创建一个临时变量,进行+=运算符重载函数的复用,返回之后的值即可,注意这里返回不能加引用,由于返回的值出了函数就销毁了,所以不能加引用。
// 日期-天数
Date Date::operator-(int 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)
{
_month =12;
--_year;
}
_day+= GetMonthDay(_year, _month);
}
return *this;
}
日期减等日期的,跟日期加等日期的,很相似,只不过把+改为-,++改为--,就可以了。
// 前置++
Date& Date::operator++()
{
*this += 1;
return *this;
}
日期的前置++,复用+=函数,返回即可,由于++的值出了函数后还在,所以可以在返回值上加引用。
// 后置++ 比前置多了一个参数,是为了区分前置++
Date Date::operator++(int)
{
Date tmp(*this);
*this += 1;
return tmp;
}
前置++,跟后置++都是一样的++,所以编译器为了区分他们,做了规定,后置++,要多加个形参,我们调用的时候不需要传参,编译器自己会传参。
日期的后置++,需要创建一个临时变量返回,然后再复用+=函数,改变自身的值,由于后置++比前置++,要多创建一个临时变量,所以能前置就前置。
// 前置--
Date& Date::operator--()
{
return *this -= 1;
}
前置--跟前置++一样的。
// 后置-- 需要多加个形参,编译器规定,为了区分前置和后置
Date Date::operator--(int)
{
Date tmp(*this);
*this -= 1;
return tmp;
}
后置--跟后置--一样的。
// >运算符重载
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 && _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 || *this == d;
}
判断一个日期是否大于等于另外一个日期,这里可以复用上面的大于,和等于函数,这里大于为真,等于也为真,其中一个为真则返回真。
// <运算符重载
bool Date::operator<(const Date& d)
{
return !(*this > d || *this == d);
}
判断一个日期是否小于另外一个日期,我们也是复用到大于和等于函数,只不过对结果取反,如果大于为真,取反后为假,等于也是一样的。
// <=运算符重载
bool Date::operator<=(const Date& d)
{
return *this < d || *this == d;
}
判断一个日期是否小于等于另外一个日期,我们也是利用到小于和等于函数。
// !=运算符重载
bool Date::operator != (const Date& d)
{
if(_year != d._year ||_month != d._month || _day != d._day)
{
return true;
}
return false;
}
判断一个日期不等于另外一个日期,如果年月日,其中一个不等于结果则为真,否则为假。
// 日期-日期 返回天数
int Date::operator-(const Date& d)
{
//这里调用到拷贝构造函数
Date max = *this;
//这里调用到拷贝构造函数
Date min = d;
//如果左值大于右值,则结果为正的,反之则为负的
int flag = 1;
//这里调用到<运算符重载
if(max < d)
{
//这里调用到赋值函数
max = d;
//这里调用到赋值函数
min = *this;
//如果左值大于右值,则结果为正的,反之则为负的
flag = -1;
}
int count = 0;
//这里调用到!=函数重载
while(max != min)
{
//这里调用到++函数重载
++min;
//count变量是为了记录,小的日期++几次到大的日期,最后就是他们的差值
++count;
}
return count*flag;
}
日期减日期,返回差值的天数,这里复用到很多我们之前写的函数重载,我们通过把两个日期把最大的日期,赋值给max,另外一个赋值给min,最后通过一个循环,记录min++几次等于max的时候循环结束,count变量则记录了,min++几次到max的,flag是为了区分结果是正的还是负的。
Date.cpp文件的代码
#pragma once
#include "Date.hpp"
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)
{
_month =1;
++_year;
}
}
return *this;
}
bool Date::operator>(const Date& d)const
{
if(_year > d._year)
{
return true;
}
else if(_year == d._year && _month > d._month)
{
return true;
}
else if(_year == d._year && _month == d._month && _day > d._day)
{
return true;
}
return false;
}
// !=运算符重载
bool Date::operator != (const Date& d)const
{
if(_year != d._year ||_month != d._month || _day != d._day)
{
return true;
}
return false;
}
// 日期-=天数
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);
}
return *this;
}
// 日期-天数
Date Date::operator-(int day)const
{
Date ret(*this);
ret -= day;
return ret;
}
// ==运算符重载
bool Date::operator==(const Date& d)const
{
return _year == d._year &&_month == d._month &&_day == d._day;
}
// >=运算符重载
bool Date::operator>= (const Date& d)const
{
return *this > d || *this == d;
}
// <运算符重载
bool Date::operator<(const Date& d)const
{
return !(*this > d || *this == d);
}
// <=运算符重载
bool Date::operator<=(const Date& d)const
{
return *this < d || *this == d;
}
// 前置++
Date& Date::operator++()
{
*this += 1;
return *this;
}
// 后置++ 比前置多了一个参数,是为了区分前置++
Date Date::operator++(int)
{
Date tmp(*this);
*this += 1;
return tmp;
}
// 后置--
Date Date::operator--(int)
{
Date tmp(*this);
*this -= 1;
return tmp;
}
// 前置--
Date& Date::operator--()
{
return *this -= 1;
}
// 日期-日期 返回天数
int Date::operator-(const Date& d)const
{
//这里调用到拷贝构造函数
Date max = *this;
//这里调用到拷贝构造函数
Date min = d;
//如果左值大于右值,则结果为正的,反之则为负的
int flag = 1;
//这里调用到<运算符重载
if(max < d)
{
//这里调用到赋值函数
max = d;
//这里调用到赋值函数
min = *this;
//如果左值大于右值,则结果为正的,反之则为负的
flag = -1;
}
int count = 0;
//这里调用到!=函数重载
while(max != min)
{
//这里调用到++函数重载
++min;
//count变量是为了记录,小的日期++几次到大的日期,最后就是他们的差值
++count;
}
return count*flag;
}
// 赋值运算符重载
// d2 = d3 -> d2.operator=(&d2, d3)
Date& Date::operator=(const Date& d)
{
_year = d._year;
_month = d._month;
_day = d._day;
return *this;
}
Date.hpp的代码
#pragma once
#include <iostream>
using namespace std;
class Date
{
friend ostream& operator<<(ostream& out,const Date& d);
public:
// 获取某年某月的天数
int GetMonthDay(int year, int month)
{
static int days[]= {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 = 2022, int month = 9, int day = 22)
{
if(year >= 1 &&
(month >=1 && month <=12)&&
GetMonthDay(year, month) >= day)
{
_year = year;
_month = month;
_day = day;
}
else
{
std::cout<< "非法" << std::endl;
}
}
// 拷贝构造函数
// d2(d1)
Date(const Date& d)
{
_year = d._year;
_month = d._month;
_day = d._day;
}
// 赋值运算符重载
// d2 = d3 -> d2.operator=(&d2, d3)
Date& operator=(const Date& d);
// 析构函数
~Date()
{
_year = 0;
_month = 0;
_day = 0;
}
// 日期+=天数
Date& operator+=(int day);
void print()
{
std::cout << _year << "/" << _month << "/" << _day << std::endl;
}
// 日期+天数
Date operator+(int day)const
{
Date ret(*this);
ret += day;
return ret;
}
// 日期-天数
Date operator-(int day)const;
// 日期-=天数
Date& operator-=(int day);
// 前置++
Date& operator++();
// 后置++
Date operator++(int);
// 后置--
Date operator--(int);
// 前置--
Date& operator--();
// >运算符重载
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;
// 日期-日期 返回天数
int operator-(const Date& d)const;
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;
}
main.cpp的代码
通过调用Date类实现一个简易版本的日期计算器
void memu()
{
cout << "************************************************" << endl;
cout << "***** 1.日期减日期 2. 日期加天数 *****" << endl;
cout << "***** 3.日期比大小 4. 日期减天数 *****" << endl;
cout << "***** 0.退出计算器 ----------- *****" << endl;
cout << "************************************************" << endl;
}
int main()
{
Date d1,d2;
int chose = 0;
int day = 0;
do
{
memu();
cout << "请选择你要的计算方式:"<<endl;
cin >> chose;
switch(chose)
{
case 1:
cout<< "请输入日期,年月日间需加空格,以回车键结束"<<endl;
cin >> d1 >> d2;
cout<<d1-d2<<"天"<<endl;
break;
case 2:
cout<< "请输入日期,年月日间需加空格,以回车键结束"<<endl;
cin >> d1 >> day;
cout << d1 - day << endl;
break;
case 3:
cout<< "请输入日期,年月日间需加空格,以回车键结束"<<endl;
cin >> d1 >> d2;
cout << (d1 > d2) << endl;
break;
case 4:
cout<< "请输入日期,年月日间需加空格,以回车键结束"<<endl;
cin >> d1 >> day;
cout << d1 + day << endl;
break;
case 0:
cout<< "退出成功" <<endl;
break;
default :
cout << "输入错误 请重新输入" <<endl;
}
}while(chose);
return 0;
}