【c++】——类和对象(中)——实现完整的日期类

作者:chlorine

专栏:c++专栏

我的花一定会开。

【学习目标】

  • 拷贝复制——赋值运算符重载

目录

🎓运算符重载(-><=...)

🎓日期&天数

🎓前置++和后置++重载


我们完成了赋值运算符重载章节的学习,对operator关键字的使用有了一定的了解,接下来我们要来实现相对完整的日期类

#include<iostream>
using namespace std;
class Date
{
public:Date(int year, int month, int day){_year = year;_month = month;_day = day;}Date(const Date& d){_year = d._year;_month = d._month;_day = d._day;}bool operator<(const Date& d){if (_year < d._year){return true;}else if (_year == d._year && _month < d._month){return true;}else if (_year == d._year && _month == d._month && _day < d._day){return true;}else{return false;}}void print(){cout << _year << "-" << _month << "-" << _day << endl;}private:int _year;int _month;int _day;
};
int main()
{Date d1(2023, 10, 5);Date d2(2023, 11, 5);int ret=d1<d2;cout << ret << endl;Date d3(d1);d1.print();d2.print();d3.print();return 0;
}

我们要对以上的代码进行声明定义分离。

拷贝构造需要写嘛?赋值重载需要写嘛?析构需要写嘛?——都不需要

唯一要写的就是——构造!

让我们回顾一下类的俩种定义方式:

  • 1. 声明和定义全部放在类体中,需注意:成员函数如果 在类中定义 ,编译器可能会将其当成 内联函数 处理。
  • 类声明放在 .h 文件中,成员函数定义放在 .cpp 文件中,注意: 成员函数名前需要加类名 ::

声明和定义分离,不能同时(声明和定义)都给构造函数缺省参数。

注意:成员函数名前需要加类名::

所以我们对于构造函数的声明定义,应以下形式:

好嘞,接下来真正的来实现了。

🎓运算符重载(-><=...)

对于我们d1的日期大于另一个日期,就返回true,但是如果小于呢,如果小于等于,等于,大于等于呢.....我们每次都要改下面一段代码嘛?未必也太麻烦了吧

bool Date::operator<(const Date& d)
{if (_year < d._year){return true;}else if (_year == d._year && _month < d._month){return true;}else if (_year == d._year && _month == d._month && _day < d._day){return true;}else{return false;}
}
bool Date::operator==(const Date& d)
{return _year == d._year&& _month ==d._month&& _day == d._day;
}

我们首先写了 (< 和 ==)运算符的运算符重载函数,接下来我们要对 (> >= <= )进行操作。因为==和<可以完成后续的操作符的函数写照。

  • 首先我们看看<=

我们先可以形成 d1<=d2

//d1<=d2
bool Date::operator<=(const Date& d)

d1是this指针,d2是d,所以我们就可以想到,<=不就是 <和=的结合嘛?

//d1<=d2
bool Date::operator<=(const Date& d)
{return *this < d || *this == d;
}

 

那么接下来的 >= 和 > 不就由任而解了嘛~

那我就将完整代码给你们看看。

//.h文件中声明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);
  //.cpp文件中定义
bool Date::operator<(const Date& d)
{if (_year < d._year){return true;}else if (_year == d._year && _month < d._month){return true;}else if (_year == d._year && _month == d._month && _day < d._day){return true;}else{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);
}

完美的进行了一波复用。这个代码不仅支持日期类,也支持任意类型的复用。

重载一个<和=,或者重载一个>和=,都是可以用复用,因为它们本身都存在互斥关系。

其实这里我们讲述一个通用的方法,以后会有更多类型使用复用。

🎓日期&天数

日期类还有另一种方式的。

日期+日期 显然没有意义的,有日期-日期有意义,日期+-天数也是有意义的。接下来我们实现这段函数重载。

如果我想算一下从今天2023/11/14,那么一百天是哪一天?

我们首先要知道,每一个月份的天数是不一样的,特别是2月得考虑平年闰年,闰年29天,平年28天,闰年的判断规则是(四年一润,百年不润,再400年润)挺复杂的,获取每个月的天数,首先我们得完成。

int Date::GetMonthDay(int year, int month)
{int daysArr[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };if ((month==2)&&((_year % 4 == 0 && _year % 100 != 0 )|| (_year % 400 == 0))){return 29;}else{return daysArr[month];}
}

那我们接下来就写一下下面函数

//d+100Date& operator+(int day);

Date& Date::operator+(int day)
{_day += day;while (_day > GetMonthDay(_year, _month)){_day -= GetMonthDay(_year, _month);++_month;if (_month == 13){++_year;_month = 1;}}return *this;
}

直到_day小于当月的天数,就给月份+1,如果月份=13,就给年份+1.

结果是2024/2/22

但是这样写的话,是不是给d1本身改变了?如何不让其本身改变呢?就像i=10,i+100中的i会不会变?——不会变,因为会有返回值,但是这里的d1改变了。其实这里我们对d1+100,严格上完成的是+=,+=有返回值。所以不改变原来的值。

+不能改变自己

  • 如何用+来进行保存d1的原本的值呢?——临时变量tmp
  • 如何利用临时变量呢?——拷贝构造

大家有没有发现这里是个大杂烩,前面的知识进行融会贯通,这里就考察了拷贝构造,d1+100,d1是this,那么就将this拷贝给tmp,然后将tmp+day,返回tmp临时变量,不用引用返回,出了函数就销毁了。

//d1+day
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;if (tmp._month == 13){++tmp._year;tmp._month = 1;}}return tmp;
}

这就实现了用+来保留d1的原有值,不改变它的值,创建临时变量进行拷贝构造,就可以用+来实现。这里我还要增加一个点,这里+=和+我们有没有联想到上面的复合运用?如果用+=复合+,又如何用+复合+=?

//+=复用+
Date& Date::operator+=(int day)
{*this = *this + day;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;if (tmp._month == 13){++tmp._year;tmp._month = 1;}}return tmp;
}
//+复用+=
Date Date::operator+(int day)
{Date tmp(*this);tmp += day;return tmp;
}Date& Date::operator+=(int day)
{_day += day;while (_day > GetMonthDay(_year, _month)){_day -= GetMonthDay(_year, _month);++_month;if (_month == 13){++_year;_month = 1;}}return *this;
}

按上面的代码,更推荐的是第二种。


🎓前置++和后置++重载

  • 前置++:返回++之后的对象(默认前置++,参数增加int)
  • 后置++:返回++之前的对象

这样就可以吗?运算符重载和函数重载都用了重载的词,但是不一样的,运算符重载是自定义类型,函数重载是函数名相同参数不同。这里是无法进行函数重载的,因为函数名相同参数也相同。为了让它们重载呢?我们就在后置++增加一个int参数,int参数并不是接收具体的值,仅仅是占位。

//前置++
Date& Date::operator++()
{*this+= 1;return *this;
}//后置++
Date Date::operator++(int)
{Date tmp=*this;*this += 1;return tmp;
}

以示区分。前置++,后置++。内置类型的前置后置++效率没有什么问题,自定义类型的前置后置++有区别,看上面前置和后置的代码,而且编译器自动默认前置,而且后置创建了临时变量。

前置++和后置++都是一元运算符,为了让前置++与后置++形成能正确重载

  • 前置++:返回+1之后的结果  注意:this指向的对象函数结束后不会销毁,故以引用方式返回提高效率。
  • C++规定:后置++重载时多增加一个int类型的参数,但调用函数时该参数不用传递,编译器自动传 递  
  • 后置++:注意:后置++是先使用后+1,因此需要返回+1之前的旧值,故需在实现时需要先将this保存一份, 然后给this+1   而temp是临时对象,因此只能以值的方式返回,不能返回引用。

我的花一定会开的。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/191014.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

如何使用`open-uri`模块

首先&#xff0c;我们需要使用open-uri模块来打开网页&#xff0c;并使用Nokogiri模块来解析网页内容。然后&#xff0c;我们可以使用Nokogiri的css方法来选择我们想要的元素&#xff0c;例如标题&#xff0c;作者&#xff0c;内容等。最后&#xff0c;我们可以使用open-uri模块…

线圈寿命预测 数据集讲解

来自-郭师兄 1.这个是线圈数据的阻抗、电抗等数据&#xff0c;我想根据这个个数据进行线圈寿命预测也就是RUL预测&#xff0c;请问有什么思路吗。 最简单的思路&#xff1a; 数据通过某种方法进行压缩表征到一维再通过 同时需要标签。 确定一个特征 使用降维方法如同PCA来构…

互联网Java工程师面试题·微服务篇·第二弹

目录 18、什么是 Spring 引导的执行器&#xff1f; 19、什么是 Spring Cloud&#xff1f; 20、Spring Cloud 解决了哪些问题&#xff1f; 21、在 Spring MVC 应用程序中使用 WebMvcTest 注释有什么用处&#xff1f; 22、你能否给出关于休息和微服务的要点&#xff1f; 23、…

Vue.js中的状态管理:理解和使用Vuex

目录 前言 Vue.js 样式绑定 Vue.js class class 属性绑定 实例 1 实例 2 实例 3 实例 4 数组语法 实例 5 实例 6 Vue.js style(内联样式) 实例 7 实例 8 实例 9 Vue.js 组件 全局组件 全局组件实例 局部组件 局部组件实例 Prop Prop 实例 动态 Prop Pro…

Makefile应用

Makefile实例 在c.c里面&#xff0c;包含一个头文件c.h&#xff0c;在c.h里面定义一个宏&#xff0c;把这个宏打印出来。 c.c&#xff1a; #include <stdio.h> #include <c.h>void func_c() {printf("This is C %d\n", C); }c.h #define C 1然后上传…

ubuntu开机系统出错且无法恢复。请联系系统管理员。

背景&#xff1a; ubuntu22.04.2命令行&#xff0c;执行自动安装系统推荐显卡驱动命令&#xff0c;字体变大&#xff0c;重启后出现如下图错误&#xff0c;无法进入系统&#xff0c;无法通过CTRLALTF1-F3进入TTY模式。 解决办法&#xff1a; 1.首先要想办法进入系统&#xff…

Python 日志记录器logging 百科全书 之 日志回滚

Python 日志记录器logging 百科全书 之 日志回滚 前言 在之前的文章中&#xff0c;我们学习了关于Python日志记录的基础配置。 本文将深入探讨Python中的日志回滚机制&#xff0c;这是一种高效管理日志文件的方法&#xff0c;特别适用于长时间运行或高流量的应用。 知识点&…

飞天使-django创建一个初始项目过程

创建django项目 运行项目 运行命令 pyhont manage.py runserver 然后访问 http://127.0.0.1:8000/&#xff0c; 则可以打开本地新建的项目 虚拟环境的部署-mac 在一台计算机上可以通过虚拟环境实现多个版本Django的开发环境 安装虚拟环境工具&#xff1a;如果你的系统中没有安…

Qt执行带参sql

//准备执行的sql语句&#xff0c;此为带参的sql语句query.prepare("update employee set Name:Name, Gender:Gender,Height:Height,"" Birthday:Birthday, Mobile:Mobile, Province:Province,"" City:City, Department:Department, Education:Educati…

202311.13 windows通过vscode ssh远程连接到Ubuntu 连接失败 waiting for server log

关闭VScode时没有关闭终端的Ubuntu进程&#xff1f; 导致重启后不能正常连接到Ubuntu了 Windows 系统自带的cmd终端通过ssh 可以连接 应该是vscode里对Ubuntu 的服务器端配置出了问题 参考&#xff1a;记录 VSCode ssh 连接远程服务器时出错及解决方法 在Windows 的vscode里面执…

红色旅游AR互动体验将景区推向更广泛的市场

AR技术的出现使得各展厅观众可以在虚拟和现实的层面进行互动&#xff0c;利用AR和VR技术&#xff0c;将展览地点扩展到特定的虚拟领域&#xff0c;实现了"无触觉"交互体验&#xff0c;增强现实技术和展馆的对接更加激发人们了解新事物的兴趣。 一、AR景区&#xff1a…

WordPress 文档主题模板Red Line -v0.2.2

此主题作为框架&#xff0c;做承载第三方页面之用&#xff0c;例如飞书文档等&#xff0c; 您可以将视频图片等资源放第三方文档上&#xff0c;通过使用此主题做目录用。 此主题使用前后端分离开发&#xff0c;也使用了一些技术尽量不影响正常的SEO&#xff0c;还望注意。 源码…

【Spring Boot】035-Spring Boot 整合 MyBatis Plus

【Spring Boot】035-Spring Boot 整合 MyBatis Plus 【Spring Boot】010-Spring Boot整合Mybatis https://blog.csdn.net/qq_29689343/article/details/108621835 文章目录 【Spring Boot】035-Spring Boot 整合 MyBatis Plus一、MyBatis Plus 概述1、简介2、特性3、结构图4、相…

如何计算掩膜图中多个封闭图形的面积

import cv2def calMaskArea(image,idx):mask cv2.inRange(image, idx, idx)contours, hierarchy cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)for contour in contours:area cv2.contourArea(contour)print("图形的面积为", area) image是…

从0到0.01入门React | 009.精选 React 面试题

🤍 前端开发工程师(主业)、技术博主(副业)、已过CET6 🍨 阿珊和她的猫_CSDN个人主页 🕠 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 🍚 蓝桥云课签约作者、已在蓝桥云课上架的前后端实战课程《Vue.js 和 Egg.js 开发企业级健康管理项目》、《带你从入…

【OpenCV实现图像:用OpenCV图像处理技巧之巧用直方图】

文章目录 概要前置条件统计数据分析直方图均衡化原理小结 概要 图像处理是计算机视觉领域中的重要组成部分&#xff0c;而直方图在图像处理中扮演着关键的角色。如何巧妙地运用OpenCV库中的图像处理技巧&#xff0c;特别是直方图相关的方法&#xff0c;来提高图像质量、改善细…

如何使用iPhone邮件客户端管理QQ邮箱?

如何使用iPhone邮件客户端管理QQ邮箱&#xff1f; 解决方案 之前按照QQ邮箱的提示&#xff0c;一直配置失败 解决方案 需要POP3/IMAP/SMTP/Exchange/CardDAV 授权码 然后登陆密码就是授权码 参考文章&#xff1a;参考

nmap原理与使用

kali的命令行中可以直接使用 nmap 命令&#xff0c;打开一个「终端」&#xff0c;输入 nmap 后回车&#xff0c;可以看到 nmap 的版本&#xff0c;证明 nmap 可用。 一、端口扫描 扫描主机的「开放端口」&#xff0c;在nmap后面直接跟主机IP&#xff08;默认扫描1000个端口&am…

arcgis提取栅格有效边界

方法一&#xff1a;【3D Analyst工具】-【转换】-【由栅格转出】-【栅格范围】 打开一幅栅格数据&#xff0c;利用【栅格范围】工具提取其有效边界&#xff08;不包含NoData值&#xff09;&#xff1a; 方法二&#xff1a;先利用【栅格计算器】将有效值赋值为1&#xff0c;得到…

什么是状态机?

什么是状态机&#xff1f; 定义 我们先来给出状态机的基本定义。一句话&#xff1a; 状态机是有限状态自动机的简称&#xff0c;是现实事物运行规则抽象而成的一个数学模型。 先来解释什么是“状态”&#xff08; State &#xff09;。现实事物是有不同状态的&#xff0c;例…