本章目标
1.掌握日期类的实现
2.了解剩下两个默认函数
一. 日期类的实现
对于日期类来说 其成员变量包括年 月 日这三个
它的通常操作有
日期加天数 计算多少天后是什么时间 是周几
日期减天数 计算多少天前是什么时间 是周几
日期减日期 计算两个日期之间相差多少天 相差多少周
日期加日期没有什么意义 这里不做实现
我们都知道 每个月的天数都不尽相同 并且还有闰年这个影响因素 所以说我们首先要实现一个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 ; // 日 };
这里稍微了解下就好 基本不会用到这两个操作符
总结
本文主要讲解日期类的实现以及两个简单的默认构造函数
由于作者水平有限 出现错误在所难难免 希望大佬们看到之后能及时指正
如果本文帮助到了你 别忘了一键三连啊
阿尼亚 哇酷哇酷!