作者:@小萌新
专栏:@初阶C++
作者简介:大二学生 希望能和大家一起进步
本篇博客目标: 完成Date类的实现 梳理剩下两个默认函数
好困 跑个步去
睡醒啦! 继续肝
日期类的实现
- 本章目标
- 一. 日期类的实现
- 1.1 Getmonthday的实现
- 1.2 构造函数和打印函数
- 1.3 日期类的运算函数
- == 符号
- > 符号
- <= 符号
- < 符号
- >= 符号
- 1.4 日期类的加减天数的实现
- +=天数
- +天数
- -=天数
- -天数
- 1.5 自增自减
- 前置++ 前置--
- 后置++ 后置--
- 1.6 日期减日期
- 二. 普通对象 const对象取地址
- 总结
本章目标
- 掌握日期类的实现
- 了解剩下两个默认函数
一. 日期类的实现
对于日期类来说 其成员变量包括年 月 日这三个
它的通常操作有
日期加天数 计算多少天后是什么时间 是周几
日期减天数 计算多少天前是什么时间 是周几
日期减日期 计算两个日期之间相差多少天 相差多少周
日期加日期没有什么意义 这里不做实现
我们都知道 每个月的天数都不尽相同 并且还有闰年这个影响因素 所以说我们首先要实现一个Getmonthday的函数
它的主要作用是得到某年某月的具体天数
1.1 Getmonthday的实现
思路分析: 首先每个月的天数都不同 我们可以创建一个数组 来填上所有月数对应的天数 类似于这
样子
int monthDayArr[13] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
当然 我们这里的月份肯定是1~12月 所以为了更严谨可以在前面加个断言
assert(month > 0 && month < 13);
当然还有一个影响月天数的原因就是是否是闰年
所以说还需要再写以一个判断是否是润年的函数
四年润 百年不润 四百年润
bool isleapyear(int year)
{
if ((year%4==0 && year%100 !=0) || (year%400==0))
{
return true;
}
else
{
return false;
}
}
然后我们整体代码表示如下
public:
int Getmonthday(int year,int month)
{
assert(month > 0 && month < 13);
int monthDayArr[13] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
// 判断是否是闰年 如果是闰年 二月的天数就是28
if (month==2 && isleapyear(year))
{
return 29;
}
// 否则就返回这个月的天数
else
{
return monthDayArr[month];
}
}
想想看 还有没有什么值得优化的地方
这个获取月份的数组 我们是不是要经常使用啊
每次都要创建销毁数组未免也太浪费内存了 我们可以用static关键字修饰下这个数组 将其中的内容
存放到静态区来进行更好的资源管理
1.2 构造函数和打印函数
我们实现了得到月份功能后迫不及待想试验一下了
那么试验前我们首先要对对象进行初始化 然后打印其数据看看是否正确
这两步在前面的博客中已经做过详细讲解 这里不再赘述
构造函数代码如下
Date(int year = 1,int month =1,int day =1)
{
// 判断年月日输入是否正确
assert(year >= 1);
assert(month >= 1 && month <= 12);
assert(day >= 0 && day <= 31);
// 赋值 这里用this指针也可以
this->_year = year;
_month = month;
_day = day;
}
打印函数代码如下
void Print()
{
cout << _year << "-" << _month << "-" << _day << endl;
}
下面我们来测试下三种情况
1 闰年的二月份
2 非闰年的二月份
3 错误的日期
我们可以发现 这三个场景都符合我们的预期
1.3 日期类的运算函数
== 符号
这个很简单 依次判断三个值是否相等就可以
bool operator == (const Date& d)
{
return _year == d._year
&& _month == d._month
&& _day == d._day;
}
> 符号
实现大于号的思路很简单
如果首先判断年 如果年大于就大于
如果年相同判断月 如果月大于就大于
最后判断日 如果日大于就大于
但是我们判断完年之后是否可以直接返回一个bool类型呢?
很显然不可以
这个时候我们换一个思路 如果小于等于就返回false
代码表示如下
bool operator > (const Date& d)
{
bool operator > (const Date& d)
{
if (_year>d._year)
{
return true;
}
if (_month>d._month && _year == d._year)
{
return true;
}
if (_day<d._day && _month == d._month && _day == d._day)
{
return true;
}
return false;
}
<= 符号
这里很简单 不大于不就是小于等于嘛?
所以这里直接上代码
bool operator <= (const Date& d)
{
return !(*this > d);
}
< 符号
不大于的同时不等于 就是小于
return (*this) <= d && !((*this) == d);
>= 符号
不小于就是大于等于
bool operator >= (const Date& d)
{
return !((*this) < d);
}
1.4 日期类的加减天数的实现
+=天数
加上天数之后赋值 这个时候我们的返回值要改变
这里有个难点就是我们我们增加的天数万一很多怎么办
万一跨越了月份呢?
万一跨越了年份呢?
这里我们先从最简单的加上一天看起
如果只加上一天 并且加上这一天之后不会超过这个月天数的大小(想想看 怎么知道这个月有多少天)
那么就直接返回就可以了
如果说大于这个月份的天数呢?
是不是就要往后面的月份进位了啊
如果月份大于十二了呢?
是不是就要往后面的年进位了啊
按照这个思路我们来写代码
Date& operator += (int day)
{
assert(day >= 0);
// 第一步 日期先加上
_day = _day + day;
while (_day>Getmonthday(_year,_month))
{
_day -= Getmonthday(_year, _month);
_month += 1;
if (_month>12)
{
_month -= 12;
_year += 1;
}
}
}
我们来验证下我们的思路
完全正确
+天数
这里跟+=天数的区别 就是一个改变自身的值 一个不改变自身的值
使用一个中间值就好了
代码表示如下
Date& operator + (int day)
{
// 拷贝构造
Date ret =(*this);
ret += day; // 复用
return ret;
}
-=天数
和+=天数的思路差不多 转换下几个符号就可以了
代码表示如下
Date& operator -= (int day)
{
assert(day >= 0);
// 第一步 日期先加上
_day = _day - day;
while (_day <= 0)
{
_month -= 1;
if (_month < 1)
{
_month = 12;
_year -= 1;
}
_day += Getmonthday(_year, _month);
}
return *this;
}
-天数
这个思路也很相似 不过多赘述
Date& operator + (int day)
{
// 拷贝构造
Date ret = (*this);
ret -= day; // 复用
return ret;
}
1.5 自增自减
由于 前置++ 和 后置++的特殊性 我们无法判断哪个是前置 哪个是后置
所以说C++中引入了以一个这样子的标准
C++规定:将括号中带有int的规定为后置++,不带int的为前置++ 。(int后面可以加参数,也可以不加)
其实也就是前置效率高那么一点点 所以C++就改变后置的类型去了
前置++ 前置–
这个很简单 使用下+=1 -=1就可以了
Date& operator ++ ()
{
// 复用+=
(*this) += 1;
return *this;
}
Date& operator -- ()
{
// 复用-=
(*this) -= 1;
return *this;
}
后置++ 后置–
这个也很类似
使用下临时变量 返回临时变量就可以
Date& operator ++ (int x)
{
Date ret = *this;
ret += 1;
return ret;
}
Date& operator ++ (int x)
{
Date ret = *this;
ret += 1;
return ret;
}
1.6 日期减日期
这个实现思路很简单
我们只需要选出两个中的较大值 然后让其中的较小值不停++ (并且设置一个计数器)
等到它们相等的时候就好了
代码表示如下
int operator - (const Date& d)
{
if (*this == d)
{
return 0;
}
Date min = *this;
Date max = d;
int count = 0;
// 有可能相差天数为负数
int flag = 1;
if (*this>d)
{
max = *this;
min = d;
flag = -1;
}
while (!(max==min))
{
++min;
count= count+1;
}
return count*flag;
}
我们可以发现 可以运行
那么这就是日期计算器的全部内容啦
工程源代码如下
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<assert.h>
using namespace std;
bool isleapyear(int year)
{
if ((year%4==0 && year%100 !=0) || (year%400==0))
{
return true;
}
else
{
return false;
}
}
class Date
{
public:
Date(int year = 1,int month =1,int day =1)
{
// 判断年月日输入是否正确
assert(year >= 1);
assert(month >= 1 && month <= 12);
assert(day >= 0 && day <= 31);
// 赋值 这里用this指针也可以
this->_year = year;
_month = month;
_day = day;
}
void Print()
{
cout << _year << "-" << _month << "-" << _day << endl;
}
int Getmonthday(int year,int month)
{
assert(month > 0 && month < 13);
static int monthDayArr[13] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
// 判断是否是闰年 如果是闰年 二月的天数就是28
if (month==2 && isleapyear(year))
{
return 29;
}
// 否则就返回这个月的天数
else
{
return monthDayArr[month];
}
}
bool operator == (const Date& d)
{
return _year == d._year
&& _month == d._month
&& _day == d._day;
}
bool operator > (const Date& d)
{
// 我们大于能直接判断嘛?
// 显然不能 所以说我们这里如果小于就返回false
/*if (_year > d._year)
{
}*/
if (_year<d._year)
{
return false;
}
if (_month<d._month)
{
return false;
}
if (_day<d._day)
{
return false;
}
// 最后还有一种全部相等的情况
if (*this == d)
{
return false;
}
return true;
}
bool operator <= (const Date& d)
{
return !(*this > d);
}
bool operator < (const Date& d)
{
return (*this) <= d && !((*this) == d);
}
bool operator >= (const Date& d)
{
return !((*this) < d);
}
Date& operator += (int day)
{
assert(day >= 0);
// 第一步 日期先加上
_day = _day + day;
while (_day>Getmonthday(_year,_month))
{
_day -= Getmonthday(_year, _month);
_month += 1;
if (_month>12)
{
_month -= 12;
_year += 1;
}
}
return *this;
}
Date& operator + (int day)
{
// 拷贝构造
Date ret =(*this);
ret += day; // 复用
return ret;
}
Date& operator -= (int day)
{
assert(day >= 0);
// 第一步 日期先加上
_day = _day - day;
while (_day <= 0)
{
_month -= 1;
// 这里首先要判断month是否越界
if (_month < 1)
{
_month = 12;
_year -= 1;
}
_day += Getmonthday(_year, _month);
}
return *this;
}
Date& operator - (int day)
{
// 拷贝构造
Date ret = (*this);
ret -= day; // 复用
return ret;
}
Date& operator ++ ()
{
// 复用+=
(*this) += 1;
return *this;
}
Date& operator -- ()
{
// 复用-=
(*this) -= 1;
return *this;
}
Date& operator ++ (int x)
{
Date ret = *this;
ret += 1;
return ret;
}
Date& operator -- (int x)
{
Date ret = *this;
ret -= 1;
return ret;
}
int operator - (const Date& d)
{
if (*this == d)
{
return 0;
}
Date min = *this;
Date max = d;
int count = 0;
// 有可能相差天数为负数
int flag = 1;
if (*this>d)
{
max = *this;
min = d;
flag = -1;
}
while (!(max==min))
{
++min;
count= count+1;
}
return count*flag;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Date d1(2001,7,5);
Date d2(2022,11,4);
//d1.Print();
int ret = d1.Getmonthday(2001,2);
cout << ret << endl;
//d1 -= 1000;
//d1.Print();
int ret = d1 - d2;
cout << ret << endl;
return 0;
}
大佬们想到什么有趣的功能也可以加上去
二. 普通对象 const对象取地址
class Date
{
public :
Date* operator&()
{
return this;
}
const Date* operator&()const
{
return this;
}
private :
int _year ; // 年
int _month ; // 月
int _day ; // 日
};
这里稍微了解下就好 基本不会用到这两个操作符
总结
本文主要讲解日期类的实现以及两个简单的默认构造函数
由于作者水平有限 出现错误在所难难免 希望大佬们看到之后能及时指正
如果本文帮助到了你 别忘了一键三连啊
阿尼亚 哇酷哇酷!