前面将类学的差不多,接下来我们就来实现一下日期类。这个日期类包含运算符重载和前面学
的C++的语法知识。
首先我们先建立一个日期类的头文件和源文件:
一.日期类的头文件实现:
首先我们要知道我们有闰年,还有每个月的天数也不一样,所有这里在写类时,就要注意哪
些年是闰年,哪些月有31天,哪些月是30天。
首先类中有三个私有的成员变量,年,月,日。
接下来就完成判断,哪些月的天数是30天和31天,再去判断哪些年是闰年,这样就导致2月是29
天。
所以这里我们就在类里去写一个函数,用来获取每个月的天数。
这里的Getmonthday函数,我们需要一个静态的数组来存贮每个月的天数,因为我们将这个数组
放到静态区去,这样频繁调用的话就不会再去创造空间,就直接可以用了。
为什么创建13个数组成员,因为数组开始为0,而没有0月,所以就用-1这个值来填这个位置,当
后面就是你是几月,就直接返回那个月的天数。
接下来就算判断是否为闰年还有2月了,如果是就返回29天。
这样整个的获取月的天数的函数就写好了。
写完这个就要将打印日期的声明和拷贝构造函数的声明也写到头文件中去,这样做到声明和定义
分离。
这样头文件的基本盘就写完了。
为什么其他函数的声明和定义是分开的呢,而Getmonthday不是呢,因为Getmonthday在后面会
使用的很频繁,这样不分开就算默认是内敛函数了
二.日期类运算符+的重载:
对于日期类的加,我们如果直接加的话就特别麻烦,你要知道这个月有多少天,每次都去进1,然
然后再去找当前这个月有多少天,所以就导致整个非常混乱并且不好实现。
我们利用这个逻辑,比如我们要加的天数,我们直接加上去,然后我们再判断如果加完的天数,如
果大于本月的天数那么我们就进入一个循环,先用加完的天数减去本月的天数,然后月加一,如果
还是比加完月的月的天数大,就继续走上述循环,如果比其小了,就可以结束循环了。如果一开始
就没有超过那就更好了。
有了这样的思路我们就来实现一下代码,每个成员函数的第一个参数其实是隐藏的this指针。
C++类和对象(上)-CSDN博客
这里我们就可以回顾一下关于this指针的介绍。
看一下完整的代码:
如果月加到13了,就手动让其跳动到一月并且年也加一
这里也是一个构造函数,这里为什么要引进一个tmp的临时变量呢,就是因为这里是+,不会改变
原来的日期,这里要用传值返回不用引用返回,因为出了作用域临时对象的生命周期就结束了,所
以这里用传值返回。
这里就是错的,因为,这个加并不会改变他的值,所以要重新创建一个类来接收加完的值。
这两个写法是一样的
这样就正确了,我们看一下40天过后是不是11月21日
可以看出来是正确的。
三.日期类运算符+=的重载:
上面写了+的运算符重载,其实现在就是改变原来的值,而上面的是自己不改变。
这里就是传引用返回,因为改变了其原本的值,所以直接用传引用返回,节省的传值返回的拷贝的
一个步骤
看一下运行结果:
既然加等写出来了,那么加的运算符重载就还有一个写法:
四.日期类运算符-的重载:
这里用的思路是,原本的天数,减去往前推的天数,如果是小于0,就月往前推一个月,再用往前
推的那个月的天数去加那个小于0的天数,直到天数变为正即可,如果月数减到了0,那么就手动
减去一年,再手动将月调成12即可。
五.日期类运算符-=的重载:
上面讲完减的运算符重载,其实-=跟+=的性质差不多,现在直接展示如何实现的:
六.日期类运算符<的重载:
这里就是如果年小就返回真,如果年相等就来比月,如果月小就返回真。如果月也相当,就返回天
的比较结果,如果天小就返回真,如果天大就返回假。其他情况并为一种就为假。
七.日期类运算符==的重载:
这里为什么先写==的运算符重载呢,因为再写后面的运算符这样就可以更简洁写出后面的运算符
重载。
八.日期类运算符重载<=的重载:
将上面两个<和<=的运算符重载写好后,可以直接赋用,使得<=的代码更加简洁高效。
因为前面的运算符已经写好了,所以直接赋用将两个参数传过去就行。
九.日期类运算符重载>的重载:
也就是取反一下,如果确实是小于等于那就为假,如果不是小于等于取反那就为真。
十.日期类运算符重载>=的重载:
总的来说这些大于等于的运算符先写两个出来然后其他的赋用一下就行了,非常的方便。
十一.日期类运算符重载++的重载:





十二.日期类运算符重载--的重载:
前面的代码小问题:
这里如果+=一个负数的话就会出错,所以我们在这里不仅要考虑的是给的是正数还是负数。
因为传过来的是负数,所以是往前推算时间,所以直接就赋用-=然后将传的值给正即可。
这样就正确了。
然而-=也要修改:
十三.日期减日期的实现:
思路一:就是往前借日期去减
这里问题就出来了,如果往前借12个月,有的月是30天有的月是31天,所以就很难计算。所以
这种办法就会很麻烦。
思路二:
就是做一个横向的减法:
这个方法比上面的更加简单,但是代码实现起来也有点复杂
思路三:
我们赋用前面的逻辑,我们做了比较大小,所以我们就先用假设法去做一个谁大谁小,然后去累加
再定义一个计数器,不断累加,直到两者的天数相等即可。这个不断累加确实计算麻烦,但是cpu
的计算能力很强,和上面的时间差不了多少。
思路三的实现:
因为我们不知道this接受的是大日期还是小日期,所以用一个flag去做一个标志,如果this是小日期
那么相差的天数就是负的。
也就是还有108天过年。
结果也就是正确的。
十四.检查日期的正确与否:
日期类的整个大逻辑也是实现好了,但是如果3月有30天,但我给日期的时候给错了,给了31天,
虽然电脑能计算出来但是是错误的,所以我们在构造日期类的时候要做一个检查,不能让错误的日
期继续算。
这里如果检查出来为假 就取反变为真去走if语句里面的逻辑,然后打印一下非法日期,这里不用给
参数,直接有this指针去检查。
这里直接检查出了非法日期。
十五.日期类重载输出流:
在前面都是封装好了一个类去运行,我们这里想要自己去输入一个日期,并不想要封装好的怎么办
这里我们就需要重载一下输入输出流。
之前我们说过C++的cout将常见的内置类型都写好了,所以不用像C语言那样用什么%d去输入输出
所以在这个日期类我们自己来重载一下输入输出流。
这里cout是ostream的类型,所以这里用out引用一下。out就是cout
这里就出错了,没办法匹配上
因为这里有两个参数,还有一个隐含的this指针,所以应该是d1传给this指针,而cout传给out的引
用,这里我们倒过来写一下,看看能否运行成功。
这样就成功运行了,但是这样写明显变得倒反天罡,变得很难看,所以不能这么写。
当年写成日期类里面的成员函数时,都会有默认的this指针,我们将运算符重载函数写成成员函数
的目的就是访问私有变量,那我们如果不想要这个this指针,我们就写成全局变量,让cout传给第
一个参数,日期类传给第二个参数。但是这样不能访问私有变量了,这里直接剧透,我们在类和对
象下会学习友元函数,我们将输出流的运算符重载函数定义成友元函数,这样我就可以访问里面的
私有的成员变量。
但这里还有一个问题我们无法连续调用这个运算符重载:
因为这个cout是从左向右结合的先与d1结合再与d2结合,但这里输出流的函数重载无返回值,所以
匹配不上,所以这里我们要改一下返回的类型,我们也要返回一下out,这样就能连续匹配调用
了;
这里流对象是不支持拷贝的,所以必须使用引用返回
这样就可以连续调用了。
十六.日期类重载输入流:
这里就不是ostream了,这里就是istream了。
这里我们来测试一下:
这里优化一下,检查我们输入的日期是否是非法日期,如果非法就重新输入。
十七.取地址运算符的重载:
1 const成员函数:
权限可以缩小但是权限不能放大。
接下来我们看个例子:


2 取地址运算符重载:
