手把手教你实现日期类

目录

前言

1.头文件的实现

2.日期类函数各项功能实现

2.1 初始化和打印(比较简单)

2.2日期大小判断

2.3日期的加减运算

3.日期类的输入输出

4.测试代码参考

结束语



前言

前面我们讲解了类的对象的大部分知识,例如拷贝构造,函数重载等知识,本节我们将用所学的知识对日期类进行实现。

注意:本篇博客代码的实现综合了前面所学,同时可能会捎带一点点后面所学内容。

1.头文件的实现

定义日期的类,对公共部分的函数进行声明,私有成员的确定。

函数有日期输入输出,日期判断,日期的大小比较,日期增减。

#pragma once
#include <iostream>
#include <assert.h>
using namespace std;
class Date {friend ostream& operator<<(ostream& out, const Date&d);friend istream& operator>>(istream& in, Date& d);
public:Date(int year = 1, int month = 1, int day = 1);void Print();int Getday(int year, int month) const{assert(month > 0 && month < 13);static int monthDayArray[13] = { -1, 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;}elsereturn monthDayArray[month];}bool CheckDate();bool operator<(const Date& d) const;bool operator<=(const Date& d) const;bool operator>(const Date& d) const;bool operator>=(const Date& d) const;bool operator==(const Date& d) const;bool operator!=(const Date& d) const;// d1 += 天数Date& operator+=(int day);Date operator+(int day) const;// d1 -= 天数Date& operator-=(int day);Date operator-(int day) const;// d1 - d2int operator-(const Date& d) const;// ++d1 -> d1.operator++()Date& operator++();// d1++ -> d1.operator++(0)// 为了区分,构成重载,给后置++,强⾏增加了⼀个int形参// 这⾥不需要写形参名,因为接收值是多少不重要,也不需要⽤// 这个参数仅仅是为了跟前置++构成重载区分Date operator++(int);Date& operator--();Date operator--(int);// 流插⼊,流输入输出// 不建议,因为Date* this占据了⼀个参数位置,使⽤d<<cout不符合习惯//void operator<<(ostream& out);private:int _year;int _month;int _day;
};
ostream& operator<<(ostream& out, const Date&d);
istream& operator>>(istream& in, Date& d);

在这里,我们用了一个数组来存取各月份的天数,避免连续用多个if else选择语句使代码冗杂,痛过闰年判断来进一步决定二月份的天数。

这个获取月份天数我们要频繁调用,所以我们直接定义在类里面,默认内联函数,频繁调用。

2.日期类函数各项功能实现

因为是在.cpp文件,在我们定义的头文件Date类以外,所以类外声明我们要用到 ::  操作符。

即Date:: 

2.1 初始化和打印(比较简单)

bool Date::CheckDate() {if (_month < 1 || _month > 12|| _day < 1 || _day > Getday(_year, _month)){return false;}else{return true;}
}
Date::Date(int year, int month, int day)
{_year = year;_month = month;_day = day;if (!CheckDate()){cout << "⽇期⾮法" << endl;}
}
void Date::Print(){cout << _year << "-" << _month << "-" << _day << endl;
}

这里我们写了个检查日期函数,为了方便判断我们所给定的日期是否是非法的,也使日期类函数功能更加完善。

2.2日期大小判断

判断日期大小,从年月日依次判断,通过代码发现,只要实现了基本的等于和大小判断,其他的判断实现我们都可以用过逻辑运算形式来实现。这样可以减少代码量。

bool Date::operator<(const Date& d) const {if (_year < d._year)return true;else if (_year == d._year) {if (_month < d._month)return true;else if (_month == d._month)return _day < d._day;elsereturn false;}elsereturn false;
}
bool Date::operator<=(const Date& d) const {return *this < d || *this == d;
}
/*
bool Date::operator>(const Date& d) const {if (_year  > d._year)return true;else if (_year == d._year) {if (_month  > d._month)return true;else if (_month == d._month)return _day  > d._day;elsereturn false;}elsereturn false;
}
*/
bool Date::operator>(const Date& d) const {return !(*this < d);
}
bool Date::operator>=(const Date& d) const {return *this > d || *this == d;
}
bool Date::operator==(const Date& d) const {return _year == d._year && _month==d._month&&_day==d._day;
}
bool Date::operator!=(const Date& d) const
{return !(*this == d);
}

2.3日期的加减运算

对于加减运算看起来简单,思路也挺丰富,但是通过代码实现还是有一定的难度的,接下来小编带领大家分析实现。

日期加天数

对于日期加天数,我们要进位并且还要判断是否满年和满该月,然后向前加

Date& Date::operator+=(int day) {if (day < 0) {return *this -= (-day);}_day += day; // 将传入的天数加到当前日期的天数上while (_day > (Getday(_year, _month))) { // 检查当前日期是否超过了这个月的天数_day -= Getday(_year, _month); // 减去这个月的天数_month++; // 月份加一if (_month == 13) { // 如果月份超过 12_month = 1; // 重置为 1_year++; // 年份加一}}return *this; // 返回当前对象的引用
}

这里的返回是传引用返回,在原来的日期上进行修改,更好的支持链式操作,当然我们也可以通过传值返回,只不过要拷贝一份,加临时变量。

为了方便区分理解,传引用我们定义为+=,传值为+

传值调用法可以借鉴+=的思路,创建一个临时变量temp,在所有成员前面加temp.即可

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

当然一个简便的方法是临时生成一个temp,通过+=函数改变temp,再返回temp。

Date Date::operator+(int day)const {Date temp = *this;temp += day;return temp;
}

日期减天数

我们要采取借位的方法,通过用上一个月份的天数加到_day上,直到>0为止。

Date& Date::operator-=(int day) {if (day < 0) {return *this += (-day);
}_day -= day; // 从当前日期的天数中减去传入的天数while (_day <= 0) { // 检查当前日期的天数是否小于或等于0_month--; // 减少月份if (_month == 0) { // 如果月份变为0,意味着需要回到上一年_month = 12; // 将月份重置为12_year--; // 年份减少}_day += Getday(_year, _month); // 为当前月份添加天数}return *this; // 返回当前对象的引用,
}

同样分为传值和传引用,实现类似于加天数,所以不多加赘述了。

Date Date::operator-(int day) const {Date temp = *this;temp -= day;return temp;
}

 这里额外还有日期的加加减减,其中又分为后置和前置C++祖师爷有自己的规定方法,记住就行,而实现方法就直接调用加减天数即可,因为加减天数只是限制成了一天而已。

在头文件的注释中也提到了规定:


    // ++d1 -> d1.operator++()
    Date& operator++();
    
    // d1++ -> d1.operator++(0)
    // 为了区分,构成重载,给后置++,强行增加了一个int形参
    // 这里不需要写形参名,因为接收值是多少不重要,也不需要用
    // 这个参数仅仅是为了跟前置++构成重载区分

    Date operator++(int);
    Date& operator--();
    Date operator--(int);

Date& Date:: operator++() {*this += 1;return* this;
}
Date Date::operator++(int) {Date temp = *this;temp += 1;return temp;
}Date& Date:: operator--() {*this -= 1;return*this;
}
Date Date::operator--(int) {Date temp = *this;temp -= 1;return temp;
}

 这里同样分为了传值和传引用。

日期-日期

因为日期+日期没有实际意义,所以我们就不用实现了。对于日期-日期,首先我们想到了年月日分别相减再换成天,或者说都换算成天数相减,两者都要计算闰年个数,较为麻烦。

这里我们可以借鉴加加的思想,让小的日期一直+,直到等于大的日期,加的次数就是日期差了。

int Date::operator-(const Date& d) const {int flag = 1;Date max = *this;Date min = d;if (*this <  d) {max = d;min = *this;flag = -1;}int n = 0;while (min!=max) {++min;n++;}return n * flag;
}

这里用了flag=1/-1,是为了满足日期相减的正负,因为大小日期是个函数内的局部,且小到大算出来的n都是正的,n*flag就满足了实际情况。

3.日期类的输入输出

我们如果想自己定义一个输出输入的话,这里就要用到流输入输出,因为是自定义类型输入输出,所以我们要自己创建。

void Date::operator<<(ostream& out)
{out << _year << "年" << _month << "月" << _day << "日" << endl;
}

这种定义实现的时候有个缺陷,因为有默认的this指针,所对应参数就有问题,所以用正常的顺序cout<<就是错的。

Date d(2024, 8, 2);
d << cout;//正确格式

因为Date* this占据了⼀个参数位置,使⽤d<<cout不符合习惯。 

所以我们设置了两个参数,ostream& out, const Date&d,理所当然的我们放在了类外,因而又出现了一个问题,访问不了私有成员,在前面的博客中我们提到了几种解决方法,在这里我们采取友元函数的方法,在函数前面加friend,在类里定义,具体的友元讲解在类的对象完结撒花会提到。

函数的模板定义在头文件有详细注明。

ostream& operator<<(ostream& out, const Date& d)
{out << d._year << "年" << d._month << "月" << d._day << "日" << endl;return out;
}istream& operator>>(istream& in, Date& d)
{while (1){cout << "请依次输入年月日:>";in >> d._year >> d._month >> d._day;if (!d.CheckDate()){cout << "输入日期非法:";d.Print();cout << "请重新输入!!!" << endl;}else{break;}}return in;
}

输入与输出是类似的思路,只是这里设置了循环来控制输入。

4.测试代码参考

#include "Date.h"
void test1() {Date d1(2024, 7, 30);d1.Print();++d1;++d1;Date ret = d1++;ret.Print();d1.Print();// Date d2 = d1 + 100;//d2.Print();//d1 += 100;//d1.Print();
}
void test2() {Date d1(2024, 7, 30);Date d2(2024, 7, 30);bool result = (d1 >= d2);d1 -= 100;d1.Print();Date d3 = d1 - 100;d3.Print();--d3;d3.Print();
}
void test3() {Date d(2024, 8, 2);//d << cout;cout << d;Date d1, d2;cin >> d1 >> d2;cout << d1 << d2 << endl;
}
int main() {//Date d2 = d1 + 100;//d2.Print();//test2();/*Date d1(2024, 7, 31);Date d2(2024, 12, 29);cout << d1 - d2 << endl;cout << d2 - d1 << endl;*///test1();
}

可以根据自己的需求进行修改。

结束语

本篇博客到此结束,大家可以根据自己的需求自己添加功能,小编实力有限,所以功能只能实现这么多,大家可以在评论区多多发表自己的观点。

最后给小编点赞支持下吧!!!

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

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

相关文章

优化数据处理效率,解读 EasyMR 大数据组件升级

EasyMR 作为袋鼠云基于云原生技术和 Hadoop、Hive、Spark、Flink、Hbase、Presto 等开源大数据组件构建的弹性计算引擎。此前&#xff0c;我们已就其展开了多方位、多角度的详尽介绍。而此次&#xff0c;我们成功接入了大数据组件的升级和回滚功能&#xff0c;能够借助 EasyMR …

乐乐音乐Kotlin版

简介 乐乐音乐Kotlin版&#xff0c;主要是基于ExoPlayer框架开发的Android音乐播放器&#xff0c;它支持lrc歌词和动感歌词(ksc歌词、krc歌词、trc歌词、zrce歌词和hrc歌词等)、多种格式歌词转换器及制作动感歌词、翻译歌词和音译歌词。 编译环境 Android Studio Jellyfish | …

canvas-视频绘制

通过Canvas元素来实时绘制一个视频帧&#xff0c;并在视频帧上叠加一个图片的功能可以当作水印。 获取Canvas元素&#xff1a; let canvas document.getElementById(canvas) 通过getElementById函数获取页面中ID为canvas的Canvas元素&#xff0c;并将其存储在变量canvas中。 …

【C++】C++11(可变参数模板、lambda表达式、包装器)

文章目录 1. 可变参数模板1.1 介绍1.2 emplace系列接口实现 2. lambda表达式2.1 语法介绍2.2 原理 3. 包装器4. bind 1. 可变参数模板 1.1 介绍 可变参数我们在C语言阶段已经了解过了&#xff0c;C语言中叫做可变参数列表&#xff0c;其中使用 ... 代表可变参数。 C语言中的可…

【给嵌入式新人的几条建议(共勉):三-C语言基础怎么补?】

给嵌入式新人的几条建议&#xff08;共勉&#xff09;&#xff1a;三-C语言基础怎么补&#xff1f; 前言1、先回答一个问题&#xff0c;对C语言的害怕到底在哪&#xff1f;&#xff08;纠正认知&#xff09;2、C语言基础&#xff0c;要补全部吗&#xff1f;No2.1 先看下自己属于…

企业个人信息安全保护实践

在数字化浪潮的推动下&#xff0c;个人信息安全问题日益凸显&#xff0c;企业如何在合规的框架下保护个人信息安全&#xff0c;成为了一项重要课题。结合国家标准的个人信息合规审计要求&#xff0c;以下为企业个人信息安全保护的最佳实践路径。 一、构建合规的个人信息保护体…

【文件解析漏洞】

使用windows2003sever服务器 第一个&#xff1a;目录解析 1、打开网站目录&#xff0c;右键打开资源管理器 新建一个1.asp文件 在1.asp目录下新建一个2.txt&#xff0c;输入asp的语句 2、使用本机访问windows2003的IP地址 访问http://192.168.189.155/1.asp/2.txt即可 第…

论文翻译:Large Language Models in Education: Vision and Opportunities

Large Language Models in Education: Vision and Opportunities 文章目录 教育中的大型语言模型&#xff1a;愿景与机遇摘要1 引言2. 教育与LLMsA. 教育背景B. LLMs背景C. 智能教育D. 教育中的LLMs 3. EduLLMs的关键技术4. LLM赋能教育A. LLMs在教育中的应用B. LLMs下教育的特…

Netty4自学笔记 (3) - Netty NIO Server和Client 样例说明

全文详见个人独立博客&#xff1a;Netty4自学笔记 (3) - Netty NIO Server和Client 样例说明 Netty4自学笔记 (3) - Netty NIO Server和Client 样例说明更新节奏缓慢&#xff0c;因为每晚学习注意力不够集中&#xff0c;学习进展缓慢。本还给自己找了一大堆其他理由&#xff0…

适用于个人使用的十大数据恢复工具:综合指南

有许多数据恢复工具和软件可用于帮助恢复丢失或损坏的文件。通过了解您的需求并考虑这里探讨的工具&#xff0c;您将能够选择最佳的数据恢复软件&#xff0c;并希望找回您丢失的宝藏。在本综合指南中&#xff0c;我们将探索个人使用的十大数据恢复工具&#xff0c;重点介绍它们…

自定义CustomRatingBar控件

通过自定义RatingBar的样式实现⭐️⭐️⭐️指示器的方式功能过于受限&#xff0c;而且显示的样式阴影会受到影响。 系统自带显示&#xff1a; 自定义样式&#xff1a; 因此简单自一个符合要求的 CustomRatingBar 支持设置星星数量支持设置星星Rating(float)支持设置空显示…

NICE Seminar(2023-07-16)|演化算法的理论研究到底有什么用?(南京大学钱超教授)

模式定理&#xff08;Schema Theorem&#xff09; 模式定理&#xff08;Schema Theorem&#xff09;是遗传算法&#xff08;Genetic Algorithm, GA&#xff09;的重要理论基础&#xff0c;由约翰霍兰德&#xff08;John Holland&#xff09;在1975年提出。它描述了具有特定模式…

CSS mask-image 实现边缘淡出过渡效果

使用场景 在生产环境中&#xff0c;遇到一个需求&#xff0c;需要在一个深色风格的大屏页面中&#xff0c;嵌入 Google Maps。为了减少违和感&#xff0c;希望地图四边能够淡出过渡。 这里的“淡出过渡”&#xff0c;关键是淡出&#xff0c;而非降低透明度。 基于 Google Ma…

Tecplot安装error找不到指定模块之解决方案

最近有小伙伴反应&#xff0c;在安装Tecplot 2023版本时&#xff0c;参考教程来操作很顺利&#xff0c;但是在开启软件后&#xff0c;有一个error弹窗&#xff0c;内容如下&#xff1a; 随后用中英文翻译&#xff1a;找不到指定模块 同时&#xff0c;软件内部的Tool工具栏打不…

大路灯护眼灯有必要买吗?五款护眼大路灯推荐

大路灯护眼灯有必要买吗&#xff1f;许多消费者对护眼大路灯的了解不够&#xff0c;总是被不专业产品“耍”得团团转。就比如市面上很多声称用了眼睛就不近视的产品&#xff0c;实际上它们毫无专业技术沉淀&#xff0c;还疏于调校光线稳定性、光线均匀度等上百项核心参数&#…

基于IOT架构的数据采集监控平台!

LP-SCADA数据采集监控平台是蓝鹏测控推出的一款聚焦于工业领域的自动化数据采集监控系统&#xff0c; 助力数字工厂建设的统一监控平台。 为企业提供从下到上的完整的生产信息采集与集成服务&#xff0c;从而为企业综合自动化、工厂数字化及完整的"管控一体化”的解决方案…

校园水电费管理小程序的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;学生管理&#xff0c;教师管理&#xff0c;宿舍信息管理&#xff0c;学生缴费管理&#xff0c;教师缴费管理&#xff0c;系统管理 微信端账号功能包括&#xff1a;系统首页&#xff0c;我的 开发系统…

抖音视频素材一般都从哪里找?抖音视频素材库分享

在浏览抖音时&#xff0c;你是否曾被那些内容丰富、制作精良的视频所吸引&#xff1f;这些视频背后的秘密其实非常简单——高质量的视频素材。优质素材能够让你的视频更加出彩。然而&#xff0c;许多抖音内容创作者在初期可能会困惑&#xff1a;这些视频素材究竟从哪里获取呢&a…

linux uos悬浮窗口置顶问题

问题背景 公司软件有一个功能&#xff0c;在PPT播放时&#xff0c;我们软件悬浮窗口需要在WPS幻灯片上层显示&#xff0c;方便客户操作按钮。在window 上我们设置了窗口的topmost 所以能够显示在最前面。如下图所示&#xff1a; 但是在软件适配国产操作系统Linux统信和麒麟在w…

推动未来的引擎:人工智能大模型的现状与发展

推动未来的引擎&#xff1a;人工智能大模型的现状与发展 一、引言 随着人工智能技术的迅速发展&#xff0c;人工智能大模型作为其中的重要组成部分&#xff0c;正逐渐成为推动科技进步的重要引擎。无论是在自然语言处理、计算机视觉&#xff0c;还是智能推荐等领域&#xff0…