💖作者:小树苗渴望变成参天大树
❤️🩹作者宣言:认真写好每一篇博客
💨作者gitee:gitee
💞作者专栏:C语言,数据结构初阶,Linux,C++
如 果 你 喜 欢 作 者 的 文 章 ,就 给 作 者 点 点 关 注 吧!
文章目录
- 前言
- 总结
前言
今天来写一篇关于完善日期类的博客,把之前学到知识给运用起来,最后在把类和对象中篇收个尾,博客就开始进入类和对象下篇的讲解了,那我们废话不多说,开始进入正文
对于日期类,我们需要写多文件,将声明和定义分离
对于日期类我们有三个成员变量,年月日都是私有的
class date //声明放在date.h里面
{
public:
private:
int _year;
int _month;
int _day;
};
之前将的四个默认成员函数我们只需要写一个构造函数完成初始化即可,其余三个对内置类型都会完成浅拷贝
构造函数:
date(int year = 1, int month = 1, int day = 1)//全缺省的构造函数
{
_year = year;
_month = month;
_day = day;
}
这样就可以设置我们想要的日期了。
对于日期我们可以比较大小,之前在将运算符重载的时候已经讲过了,这里就直接把函数写出来了
日期的比较:
bool date::operator<(const date& d)//定义单独卸载一个文件class.cpp里面
{
if (_year < d._year)
{
return true;
}
if (_year == d._year && _month < d._month)
{
return true;
}
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);
}
日期的大于等于:
bool date::operator>=(const date& d)//小于取反
{
return !(*this < d);
}
日期的不等于:
bool date::operator!=(const date& d)
{
return !(*this == d);
}
这种复用不只适用于日期类呢,其他类也可以这么使用,这几个都是非常简单,接下来在讲一下另一个运算符
++ --运算符:
对于前置的++ --,我们不需要传参数就行了,返回++ --之后的值
date& date::operator++()//前置加加
{
return *this += 1;
}
date& date::operator--()//前置减减
{
return *this -= 1;
}
因为返回的是*this是对象,没有被销毁可以使用引用返回
对于后置++ --,为了和前置区分,多了一个参数,但不做有效参数,相当于一个形式而已:
// 后置++
date date::operator++(int i)//这个i写不写都行,你传过来我也不接收
{
date tmp(*this);
*this += 1;
return tmp;
}
// 后置--
date date::operator--(int)
{
date tmp(*this);
*this -= 1;
return tmp;
}
因为创建了临时对象,所以返回只能使用值返回,虽然会调用拷贝构造,但代价不大,因为前置的和后置的整体差异不大,但前置少了一层拷贝,效率比后置高些,所以尽量能用前置就用前置
接下来我们来介绍一下,有意义的运算符,对于日期加日期没有意义我们就实现,但是日期加减天数有意义,日期减日期也有意义,所以我们来实现一下:
我们在进行一个加天数,是通过这个月有多少天来判断时候需要进到下一个月,所以我们专门写一个函数来获取每个月的天数,在闰年平年的二月我们也做一个判断
int getmonthday(int year,int month)
{
static int arr[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };
if (month == 2 && ((year % 100 != 0 && year % 4 == 0) || year % 400 == 0))
{
return arr[month] + 1;
}
else
{
return arr[month];
}
}
这个函数可以写成员函数也可以不用写,我们可以再数组前面加一个static,因为我们要频繁的调用这个函数。
日期加天数:
date& date::operator+=(int day)
{
_day += day;
while(_day > getmonthday(_year,_month))
{
_day -= getmonthday(_year, _month);
_month += 1;
if (_month == 13)
{
_year += 1;
_month = 1;
}
}
return *this;
}
这么写本身的日期也变成增加之后的日期了,我们需要使用临时变量去进行加减
date date::operator+(int day)
{
date tmp(*this);
tmp._day += day;
while (tmp._day > getmonthday(tmp._year, tmp._month))
{
tmp._day -= getmonthday(tmp._year, tmp._month);
tmp._month += 1;
if (tmp._month == 13)
{
tmp._year += 1;
tmp._month = 1;
}
}
return tmp;
}
我们发现+=和+这么写不太好
+=用+复用:
date& date::operator+=(int day)
{
*this=*this+day;
return *this;
}
+用+=复用:
date date::operator+(int day)
{
date tmp(*this);
tmp += day;
return tmp;
}
大家看这样其中一个代码就简单多了。
日期减天数:
date& date::operator-=(int 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 tmp(*this);
tmp._day -= day;
while (tmp._day <= 0)
{
tmp._month--;
if (tmp._month == 0)
{
tmp._year--;
tmp._month = 12;
}
tmp._day += getmonthday(tmp._year, tmp._month);
}
return tmp;
}
-=用-复用:
date& date::operator-=(int day)
{
*this=*this-day;
return *this;
}
-用-=复用:
date date::operator-(int day)
{
date tmp(*this);
tmp -= day;
return tmp;
}
我们再来写一个关于日期减日期的,算算自己出生了多少天了:
日期减日期:
对于日期相减,大的日期在前面减出来的天数是正数,否则就是负数,这里使用日期的相减要注意的细节还是特别多的,我们复用++来暴力循环,进行判断来解
int date::operator-(const date& d)
{
date max = *this;
date min = d;
int flag = 1;
if (min > max)
{
max = d;
min = *this;
flag = -1;
}
int count=0;
while (min != max)
{
++min;
++count;
}
return count*flag;
}
我们在来写一个函数将日期打印出来的成员函数:
void print()//当成内联函数
{
cout << _year << " " << _month << " " << _day << endl;
}
我们来测试一样之前写的所以功能:
补充程序的细节:
我们也会遇到这种情况,变成这种情况,我们需要在函数体里面加判断,对于+=,-=也是一样的做法:
if (day < 0)
{
*this = *this - (-day);
return *this;
}
if (day < 0)
{
*this = *this + (-day);
return *this;
}
这个判断,不要再复用的函数的里面加。这样就和我们网页的日期计算有差不多的功能了。
初始化错误的日期:
date d1(2023,24,35);
这样显然是不可以的,所有初始化都是通过构造函数来完成的,我们再构造函数里面加以个判断就好了
date(int year = 1, int month = 1, int day = 1)//全缺省的构造函数
{
if (day > 0 && day <= getmonthday(year, month) && month > 0 && month < 13)
{
_year = year;
_month = month;
_day = day;
}
else
{
cout << "非法初始化" << endl;
assert(false);
}
}
完整的代码:
#include"date.h"
int main()
{
date d1(2023, 5, 4);
cout << "测试日期加天数:" << endl;
d1.print();
date d2=d1 + (-400);
d1.print();
d2.print();
printf("\n");
cout << "测试日期减天数:" << endl;
date d3(2023,5,4);
d3.print();
date d4 = d3 - (-400);
d3.print();
d4.print();
printf("\n");
cout << "测试日期加等天数:" << endl;
date d5(2022, 3, 30);
d5.print();
d5 += -400;
d5.print();
printf("\n");
cout << "测试日期减等天数:" << endl;
date d6(2022, 3, 30);
d6.print();
d6 -= -400;
d6.print();
printf("\n");
cout << "测试后置++:" << endl;
date d7(2023, 5, 4);
d7++.print();
d7.print();
printf("\n");
cout << "测试后置减减:" << endl;
date d8(2023, 5, 4);
d8--.print();
d8.print();
printf("\n");
cout << "测试前置加加:" << endl;
date d9(2023, 5, 4);
(++d9).print();
d9.print();
printf("\n");
cout << "测试测试前置减减:" << endl;
date d10(2023, 5, 4);
(--d10).print();
d10.print();
printf("\n");
cout << "测试日期减日期:" << endl;
date d11(2023, 5, 6);
date d12(2003, 3, 25);
int ret = d11 - d12;
cout << ret << endl;
return 0;
}
#include<iostream>
using namespace std;
class date
{
public:
date(int year = 1, int month = 1, int day = 1)//全缺省的构造函数
{
_year = year;
_month = month;
_day = day;
}
//拷贝构造
//赋值重载
//析构函数
void print()//当成内联函数
{
cout << _year << " " << _month << " " << _day << 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);
int date::getmonthday(int year,int month);
// 日期-天数
date operator-(int day);
// 日期-=天数
date& operator-=(int day);
// 前置++
date & operator++();
// 后置++
date operator++(int);
// 后置--
date operator--(int);
// 前置--
date& operator--();
int operator-(const date& d);
private:
int _year;
int _month;
int _day;
};
#include"date.h"
bool date::operator<(const date& d)
{
if (_year < d._year)
{
return true;
}
if (_year == d._year && _month < d._month)
{
return true;
}
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);
}
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);
}
int date::getmonthday(int year,int month)
{
static int arr[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };
if (month == 2 && ((year % 100 != 0 && year % 4 == 0) || year % 400 == 0))
{
return arr[month] + 1;
}
else
{
return arr[month];
}
}
date& date::operator+=(int day)
{
if (day < 0)
{
*this = *this - (-day);
return *this;
}
_day += day;
while(_day > getmonthday(_year,_month))
{
_day -= getmonthday(_year, _month);
_month += 1;
if (_month == 13)
{
_year += 1;
_month = 1;
}
}
return *this;
}
//date date::operator+(int day)
//{
// date tmp(*this);
// tmp._day += day;
// while (tmp._day > getmonthday(tmp._year, tmp._month))
// {
// tmp._day -= getmonthday(tmp._year, tmp._month);
// tmp._month += 1;
// if (tmp._month == 13)
// {
// tmp._year += 1;
// tmp._month = 1;
// }
// }
// return tmp;
//}
date date::operator+(int day)
{
date tmp(*this);
tmp += day;
return tmp;
}
//日期-天数
date date::operator-(int day)
{
date tmp(*this);
tmp -= day;
return tmp;
}
// 日期-=天数
date& date::operator-=(int day)
{
if (day < 0)
{
*this = *this + (-day);
return *this;
}
_day -= day;
while (_day <= 0)
{
_month--;
if (_month == 0)
{
_year--;
_month = 12;
}
_day += getmonthday(_year, _month);
}
return *this;
}
// 前置++
date& date::operator++()
{
return *this += 1;
}
// 后置++
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)
{
date max = *this;
date min = d;
int flag = 1;
if (min > max)
{
max = d;
min = *this;
flag = -1;
}
int count=0;
while (min != max)
{
++min;
++count;
}
return count*flag;
}
总结
对于这个类的实现,综合性特别强,将之前我讲到四个默认的成员函数弄懂,理解这个类不是问题,有许多代表性很强的函数,函数的复用等等。所以大家一定要好好理解这个类,对大家的帮助很大,下篇我将通过这个类再来讲解一个运算符重载,大家再来理解里面的知识和注意的细节。