行业知识
【C++初阶】五、类和对象(日期类的完善、流运算符重载函数、const成员、“&”取地址运算符重载)
=========================================================================
���关代码gitee自取:
C语言学习日记: 加油努力 (gitee.com)
=========================================================================
接上期:
【C++初阶】四、类和对象
(构造函数、析构函数、拷贝构造函数、赋值运算符重载函数)-CSDN博客
=========================================================================
一 . 日期类的完善
此次日期类的成员函数,采用声明和定义(实现)分离的方式实现
成员函数声明和定义(实现)分离的好处:
将成员函数的声明写在头文件中,方便我们查看这个类中有哪些成员函数,
其具体实现再到成员函数实现文件(.cpp文件)中查看
(详细解释在图片的注释中,代码分文件放下一标题处)
Date构造函数 -- 全缺省构造函数优化
- 当实例化对象时,所给的初始化参数可能不合理(比如给了负数的日期),
需要进行特殊处理(报错) - 注意:
全缺省构造函数的缺省参数只能在声明或实现中给,
不能两边都给缺省参数,不然编译器不知道要使用哪边的缺省参数,
而且两边的缺省参数给得还可能不一样,
所以这里选择在声明中给缺省参数,实现时并没有给图示:
测试:
---------------------------------------------------------------------------------------------
Print函数 -- 打印日期函数
图示:
---------------------------------------------------------------------------------------------
GetMonthday“辅助”函数 -- 获取当前月份日期函数
- 因为考虑到各月份日期可能不一样,二月还需要考虑闰年还是平年,
所以可以单独写一个函数处理月份的情况,方便后续成员函数的实现 - assert断言:防止year(年份)或month(月份)传错
- 一年有12个月,定义一个有13个元素的数组,
不使用第一个元素,之后的12个元素分别为1~12月各个月的对应日期(平年) - 再单独判断2月的情况,如果year是闰年,再修改2月的日期为29天
- 最后通过数组下标返回对应月的日期
图示:
---------------------------------------------------------------------------------------------
operator==函数 -- “==”运算符重载函数
- 通过隐藏的this指针来依次判断两日期的年、月、日是否相同并返回结果
图示:
---------------------------------------------------------------------------------------------
operator!=函数 -- “!=”运算符重载函数
- 复用“==”运算符重载函数,对其结果取反,就能实现“!=”运算符重载函数了
图示:
---------------------------------------------------------------------------------------------
operator>函数 -- “>”运算符重载函数
- 先比较年份,“年大就大”;
如果年份相等,“月大就大”;
如果年份相等,月份也相等,“天大就大”;
大就返回true - 除此以外,就是两日期小于等于的情况了,返回false
图示:
---------------------------------------------------------------------------------------------
operator>=函数 -- “>=”运算符重载函数
- 复用“>”和“==”运算符重载函数即可实现">="运算符重载函数
图示:
---------------------------------------------------------------------------------------------
operator(const Date& y); //大于//“>=”运算符重载函数:bool operator>=(const Date& y); //大于等于//“ y._day){return true;}//上面已经写出了所有大于的情况,执行到这说明是小于等于:return false; //返回false}//“>=”运算符重载函数:bool Date::operator>=(const Date& y) //大于等于{//直接复用“>”和“==”运算符重载函数即可:return *this > y || *this == y;/** *this即左值对象,y即右值对象* 通过复用“>”和“==”运算符重载函数判断并返回结果即可,*“>=” --> “>” 或 “==”*/}//“= y);/** *this即左值对象,y即右值对象* 通过复用“>=”运算符重载函数即可,* 如果不是“>=”,那就是“”运算符重载函数即可,* 如果不是“>”,那就是“”(或“ GetMonthDay(_year, _month))/** 先通过GetMonthDay函数获得当月的天数,* 再比较相加后的天数是否超过了当月的天数,* 只要超过了则进行进位,进位到月:* (while循环到没超过为止)*/{//天数减去一轮当前月天数:_day -= GetMonthDay(_year, _month);//减去的一轮当前月天数进位到月中:++_month;//如果当前月进位后超过了12个月:if (_month == 13){//将一轮月份进位到年:++_year;//将月份重置为1月:_month = 1;}}return *this;}//“+”运算符重载函数:Date Date::operator+(int day){Date tmp(*this);/** 为了实现加法,加了后不改变d1对象(+=才会改变)* 先通过*this(即d1)拷贝出一个tmp,* 对tmp进行加法操作就不会改变d1对象了*//** 复用 “+=运算符重载” ,只要 += 到d1的拷贝tmp上即可,* 就不会改变到d1对象,通过tmp返回d1的加法结果:*/tmp += day;//通过tmp返回d1的加法结果:return tmp;/** 这里tmp是d1的拷贝,出了函数就销毁了,* 所以需要传值返回拷贝一份回主函数*/}“+”运算符重载函数:d1 + 100(整数) ,计算d1日期的100天后的日期://Date Date::operator+(int day) // “+” 不会改变d1对象////为了防止拷贝返回,使用引用返回//{//Date tmp(*this); ///*//* 为了实现加法,加了后不改变d1对象(+=才会改变)//* 先通过*this(即d1)拷贝出一个tmp,//* 对tmp进行加法操作就不会改变d1对象了//*///////思路:当月天数满了进位到月,月满了则进位到年:////tmp._day += day; //先将要加的天数加到当前的天数上//////开始进位(如果需要的话)://while (tmp._day > GetMonthDay(tmp._year, tmp._month))///*//* 先通过GetMonthDay函数获得当月的天数,//* 再比较相加后的天数是否超过了当月的天数,//* 只要超过了则进行进位,进位到月://* (while循环到没超过为止)//*///{////天数减去一轮当前月天数://tmp._day -= GetMonthDay(tmp._year, tmp._month);//////减去的一轮当前月天数进位到月中://++tmp._month;//////如果当前月进位后超过了12个月://if (tmp._month == 13)//{////将一轮月份进位到年://++tmp._year;//////将月份重置为1月://tmp._month = 1;//}//}////return tmp;///*//* 这里tmp是d1的拷贝,出了函数就销毁了,//* 所以需要传值返回拷贝一份回主函数//*///}“+=”运算符重载函数://Date& Date::operator+=(int day)//{////复用“+”运算符重载函数://*this = *this + day;///*//* 这里的*this(左值对象)和day(右值对象),//* 都是已经存在的对象,把已经存在的对象赋值给//* 另一个已经存在的对象上,需要使用到赋值运算符重载函数//* //* 使用“+”运算符重载函数将day日期加到*this日期上,//* 再使用赋值运算符重载函数把加上的日期赋值给*this,//* 完成“+”运算符重载函数的复用//*///////返回“+=”结果://return *this;//}/**一:* 如果先实现了“+”运算符重载函数,* 可以复用“+”运算符重载函数实现“+=”运算符重载函数* *二:* 如果先实现了“+=”运算符重载函数,* 那就可以复用“+=”运算符重载函数实现“+”运算符重载函数* * 第一种方法的“+”需要进行两次对象拷贝,* “+=”通过复用“+”实现,需要三次对象拷贝,* 所以该方法总共需要五次拷贝* * 第二种方法的“+=”不需要进行对象拷贝,* “+”中需要两次对象拷贝,该方法总共需要两次拷贝* * 所以还是通过第二种方法实现“+=”和“+”比较好,* 而且实现加法最好使用“+=”,而不是“+”,* 因为“+=”不需要进行拷贝,“+”需要拷贝两次对象*///“-=”运算符重载函数:Date& Date::operator-=(int day){/** 可能有坏蛋右值传了个负数过来,* 如:d1 -= -100;* 这时就要进行特殊处理了:*/if (day min* 那么 n*flag = 相差天数(正)*1 ,返回正日期* 如果我们假设错了:max
Test.cpp -- 测试文件:
//包含日期类头文件:#include "Date.h"//优化全缺省构造函数:void TestDate1(){Date d1;//打印d1日期:d1.Print();//全缺省构造函数的完善://初始化的日期可能不合法(月份):Date d2(2023, 13, 1);d2.Print();//初始化的日期可能不合法(日期):Date d3(2010, 2, 29); //2月可能没有29天d3.Print();}//测试 “-” 和 “+”(日期-+整型):void TestDate2(){//创建一个日期类对象:d1Date d1(2023, 10, 24);d1.Print();//测试“-”运算符重载函数:Date ret1 = d1 - 100; //隔几个月ret1.Print(); //打印结果Date ret2 = d1 - 10000; //跨越闰年ret2.Print(); //打印结果//测试“+”运算符重载函数:Date ret3 = d1 + 100; //隔几个月ret3.Print(); //打印结果Date ret4 = d1 + 10000; //跨越闰年ret4.Print(); //打印结果}//测试“前置++”和“后置++”:void TestDate3(){//创建一个日期类对象:d1Date d1(2023, 10, 24);d1.Print();++d1; //d1.operator++() -- “前置++”d1.Print(); //2023/10/25Date d2 = d1++;//d1.operator++(int) -- “后置++”d2.Print(); //先取到d1:2023/10/25,再++d1.Print(); //2023/10/26}//测试“日期-日期”运算符重载函数:void TestDate4(){//创建一个日期类对象:d1Date d1(2023, 10, 24);d1.Print();//创建一个日期类对象:d2Date d2(2024, 2, 10);d2.Print();//打印两日期相差的日期:cout
- 复用“>”和“==”运算符重载函数即可实现">="运算符重载函数
- 先比较年份,“年大就大”;
- 复用“==”运算符重载函数,对其结果取反,就能实现“!=”运算符重载函数了
- 通过隐藏的this指针来依次判断两日期的年、月、日是否相同并返回结果
- 因为考虑到各月份日期可能不一样,二月还需要考虑闰年还是平年,
下一篇:为什么要介绍自己?