日期类(Date)的实现 (C++版)

                   

                       

                                         🌹个人主页🌹:喜欢草莓熊的bear

                                                🌹专栏🌹:C++入门

 

目录

前言

一、Date的头文件,包含函数声明

二、 Date.cpp

2.1 int GetMonthDay(int year, int month)

2.2 bool Check()

2.3 Date& operator+=(int day)

2.4 Date& operator-=(int day)

2.5 Date& operator++()

2.6 Date operator++(int)

2.7 bool operator < (const Date& d)const

2.8 bool operator==(const Date& d)const

2.9 int operator-(const Date& d)const

2.10 ostream& operator<<(ostream& out, const Date& d)

2.11 istream& operator>>(istream& i, Date& d)

三、 完整代码

Date.cpp

总结


前言

hello ,大家又来跟着bear学习了。一起奔向更好的自己

一、Date的头文件,包含函数声明

Date.h

#pragma once
#include<iostream>
#include<cmath>
#include <cassert>
using namespace std;class Date{
public:friend ostream& operator<<(ostream& out, const Date& d);//友源函数的声明friend istream& operator>>(istream& in, Date& d);//友源函数的声明// 获取某年某月的天数int GetMonthDay(int year, int month){assert(month > 0 && month < 13);static int arr[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };int day = arr[month];if (month == 2 && (year % 4 == 0 && year % 100 != 0 || year % 400 == 0))//润年2月多一天{day++;}return day;}// 全缺省的构造函数Date(int year = 1949,int month = 10,int day = 1){_year = year;_month = month;_day = day;if (!Check()){cout << "非法日期输入!";Print();}}void Print()const;//打印函数bool Check();//检查函数// 全缺省的构造函数// 拷贝构造函数// d2(d1)Date(const Date& d){_year = d._year;_month = d._month;_day = d._day;}// 赋值运算符重载// d2 = d3 -> d2.operator=(&d2, d3)//Date& operator=(const Date& d);// 析构函数~Date(){_year = 2024;_month = 1;_day = 1;}// 日期+=天数Date& operator+=(int day);// 日期+天数Date operator+(int day)const;// 日期-天数Date operator-(int day)const;// 日期-=天数Date& operator-=(int day);// 前置++Date& operator++();// 后置++Date operator++(int);// 后置--Date operator--(int);// 前置--Date& operator--();// >运算符重载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;// 日期-日期 返回天数int operator-(const Date& d)const;//void operator<<(ostream& out):private:int _year;int _month;int _day;
};ostream& operator<<(ostream& out, const Date& d);//输出流操作符重载
istream& operator>>(istream& i, Date& d);//输入流操作符重载

二、 Date.cpp

2.1 int GetMonthDay(int year, int month)

GetMonthDay函数的功能是:// 获取某年某月的天数

其中就要考虑到润年的二月比正常的多一天,这里我们的想法是使用一个静态数组来储存每个月的天数。

static int arr[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };

这里多定义一个空间,方便下标和月份对应。 

闰年的判断条件我们在C语言里面就学习过了,那就是能被4整除且不能被100整除 或者 被400整除。转换成代码就是

year % 4 == 0 && year % 100 != 0 || year % 400 == 0

最主要的两个功能已经实现了我们就完整的实现一下这个获取某年某月的天数函数

// 获取某年某月的天数
int GetMonthDay(int year, int month)
{assert(month > 0 && month < 13);static int arr[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };int day = arr[month];if (month == 2 && (year % 4 == 0 && year % 100 != 0 || year % 400 == 0))//润年2月多一天{++day;}return day;
}

 这里使用静态的数组原因就是在调用该函数的时候不用多次申请空间。因为静态是结束是程序周期结束。

还有把month = 2 也是使得程序更加高效。这个函数还是很简单的。

2.2 bool Check()

bool Check()作用:检查日期是否合法,因为不可能出现6月31日的日期。

检查的对象有month 和 day。

_month < 1 ||  _month > 12_day < 1 ||  _day > Date::GetMonthDay(_year, _month)
bool Date::Check()//检查日期是否合法
{if (_month < 1 || _month > 12 || _day < 1|| _day > Date::GetMonthDay(_year, _month)){return false;}else{return true;}
}

2.3 Date& operator+=(int day)

Date& operator+=(int day)实现:日期+=天数 ,得到一个新的日期

思路很简单就是进位的思想:满了这个月的天数就进到下一个月。

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

 为了防止有吃饱了没事做的人写负数,所以我们还添加了一个放回措施,加一个负的天数就相当于减掉天数。根据+=我们就可以推到日期+天数这个函数。

// 日期+天数
Date Date::operator+(int day)const
{Date tmp = *this;tmp += day;return tmp;
}

这里面的“  +=  ”就是我们自己写的+=函数,也是+=运算符的重载函数。这里加cosnt是为了应付cosnt类型的数据。 

2.4 Date& operator-=(int day)

Date& operator-=(int day):日期-=天数。

实现思路与+=相似,采用退位的方式。这个月的天数不够就借用前一个月的天数。

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

2.5 Date& operator++()

Date& operator++():前置++运算符的重载实现,前置++特点,先++后引用

Date& operator++()
{*this+=1;return *this;
}

2.6 Date operator++(int)

Date operator++(int):后置++特点先引用后++,为了分清楚前置++还是后置++,祖师爷定义了后置++在运算符重载时会多一个没有任何作用的int 参数(作用知道这个是后置++)

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

     // 后置--   Date operator--(int);      // 前置--    Date& operator--();

大家可以自己实现--的功能,道理一样。不会实现的电疗伺候。

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

2.7 bool operator < (const Date& d)const

bool operator < (const Date& d)const:比较日期的大小

思路:依次比较 先比较年 再比较月 再比较日 。这里我们使用逆向思维成立的为条件。

// d1 < d2
// <运算符重载
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;}return false;
}

 

2.8 bool operator==(const Date& d)const

 bool operator==(const Date& d)const:日期相等

思路还是延续之前的比较大小的。

// ==运算符重载
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);
}// >=运算符重载
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 !(*this == d);
}

2.9 int operator-(const Date& d)const

int operator-(const Date& d)const:实现两个日期相减。

思路1:依靠着进位和退位来计算差值。(不能确定相差的月是哪几个月)。

思路2:直接通过计算来达到相同的日期(有人会说这样效率低下,但是我们的cpu一秒跑很快所以不用担心这些效率)

我们这里采用思路2

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

这个代码大部分都很普通,点睛之笔在这个flag他防止用小日期-大日期得到正天数的麻烦。 

2.10 ostream& operator<<(ostream& out, const Date& d)

ostream& operator<<(ostream& out, const Date& d):输出流操作符重载

我们没有把这两个函数写道类里面,因为类的成员函数会把第一个参数直接给到this指针,这样不方便我们的正常的写作。所以我们就写到了类外面,但是这样我们就使用不了类里面的私有变量了。有一个解决方案,那就是友元函数的声明在类里面。

类的友元函数是定义在类外部,但有权访问类的所有私有(private)成员和保护(protected)成员。尽管友元函数的原型有在类的定义中出现过,但是友元函数并不是成员函数。

友元可以是一个函数,该函数被称为友元函数;友元也可以是一个类,该类被称为友元类,在这种情况下,整个类及其所有成员都是友元。

friend ostream& operator<<(ostream& out, const Date& d);//友元函数的声明ostream& operator<<(ostream& out, const Date& d)//写成友源函数就可以访问到类里面的私有变量了
//这里类型改成ostream是方便多次输出
{out << d._year << "年" << d._month << "月" << d._day << "日" << endl;return out;
}

这里返回类型写成了 ostream是方便多次输出,因为输出流就是这个类型。 

2.11 istream& operator>>(istream& i, Date& d)

istream& operator>>(istream& i, Date& d): //输入流操作符重载

与上面同理写成友元函数

friend istream& operator>>(istream& in, Date& d);//友元函数的声明istream& operator>>(istream& in ,Date& d)//这里类型改成istream是方便多次输入
{while (1){cout << "请输入日期 > :";in >> d._year >> d._month >> d._day;if (!d.Check()){cout << "非法日期!";d.Print();cout << "重新输入日期";}else{break;}}return in;
}

三、 完整代码

Date.cpp

Date.cpp
#define _CRT_SECURE_NO_WARNINGS
#include"Date.h"
// 日期+=天数
Date& Date::operator+=(int day)
{if (day < 0){return *this -= (-day);}_day += day;while (_day > GetMonthDay(_year, _month)){_day -= GetMonthDay(_year, _month);++_month;if (_month == 13){++_year;_month = 1;}}return *this;
}bool Date::Check()//检查日期是否合法
{if (_month < 1 || _month > 12 || _day < 1|| _day > Date::GetMonthDay(_year, _month)){return false;}else{return true;}
}void Date::Print()const
{cout << _year << "/" << _month << "/" << _day << endl;
}// 日期+天数
Date Date::operator+(int day)const
{Date tmp = *this;tmp += day;return tmp;
}// 日期-天数
Date Date::operator-(int day)const
{Date tmp = *this;tmp -= day;return tmp;
}// 日期-=天数
Date& Date::operator-=(int day)
{if (day < 0){return *this += (-day);}_day -= day;while (_day <= 0){--_month;if (_month == 0){_year--;_month = 12;}_day += GetMonthDay(_year, _month);}return *this;
}
// 前置++
Date& Date::operator++()
{*this += 1;return *this;
}
// 后置++
Date Date::operator++(int)
{Date tmp = *this;*this += 1;return tmp;
}
// 后置--
Date Date::operator--(int)
{Date tmp = *this;*this -= 1;return tmp;
}
// 前置--
Date& Date::operator--()
{*this -= 1;return *this;
}
// >运算符重载
bool Date::operator>(const Date& d)const
{return !(*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);
}// d1 < d2
// <运算符重载
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;}return false;
}// <=运算符重载
bool Date::operator <= (const Date& d)const
{return *this < d || *this == d;
}
// 
// !=运算符重载
bool Date::operator != (const Date& d)const
{return !(*this == d);
}
// 
// 日期-日期 返回天数
int Date::operator-(const Date& d)const
{int flag = 1;Date max = *this;Date min = d;if (max < min){max = d;min = *this;flag = -1;}int n = 0;while (min != max){++min;++n;}return n*flag;
}//void operator<<(ostream& out)//this是当前类的类型。
//{
//	out << _year << "年" << _month << "月" << _day << "日" << endl;
//}ostream& operator<<(ostream& out, const Date& d)//写成友源函数就可以访问到类里面的私有变量了
//这里类型改成ostream是方便多次输出
{out << d._year << "年" << d._month << "月" << d._day << "日" << endl;return out;
}istream& operator>>(istream& in ,Date& d)//这里类型改成istream是方便多次输入
{while (1){cout << "请输入日期 > :";in >> d._year >> d._month >> d._day;if (!d.Check()){cout << "非法日期!";d.Print();cout << "重新输入日期";}else{break;}}return in;
}

test.cpp

#define _CRT_SECURE_NO_WARNINGS
#include"Date.h"
int main()
{/*Date s1(200, 10, 3);s1.Print();*//*Date s2(2005, 10, 1);s2.Print();*///cout << s1 - s2 << endl;//s1 -= 20;// s1.Print();测试减法//s1 += 20;//s1.Print();测试加法//Date s2 = ++s1;//测试前置++//s2.Print();//s1.Print();//s1 << cout;//和我们平常写的太不一样,放弃。//cout << s2 << s1 << endl;//这样就非常适合我们平常的写作习惯了Date d1;cin >> d1;cout << d1 + 50;return 0;
}

 

总结

感谢大家的支持,我会继续努力创造出更好的博客。

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

【吊打面试官系列-MySQL面试题】什么是基本表?什么是视图?

大家好&#xff0c;我是锋哥。今天分享关于【什么是基本表&#xff1f;什么是视图&#xff1f;】面试题&#xff0c;希望对大家有帮助&#xff1b; 什么是基本表&#xff1f;什么是视图&#xff1f; 基本表是本身独立存在的表&#xff0c;在 SQL 中一个关系就对应一个表。 视图…

【含开题报告+文档+PPT+源码】闲置二手市场小程序的设计与实现

开题报告 闲置二手市场平台的背景可以追溯到互联网的普及和电子商务的兴起。随着互联网技术的不断发展&#xff0c;人们的消费观念也在不断变化&#xff0c;越来越多的人开始关注二手商品的价值和优势。同时&#xff0c;大用户群体也在不断增加&#xff0c;他们对于经济实惠的…

利用顺序栈输出对应的二进制数,找迷宫出口详解(数据结构作业04)

目录 利用顺序栈输出对应的二进制数 代码&#xff1a; 运行结果&#xff1a; 找迷宫出口 代码&#xff1a; 图解&#xff1a; 运行结果&#xff1a; 利用顺序栈输出对应的二进制数 键盘输入一个十进制正整数89&#xff0c;用C语言设计一个算法&#xff0c;利用顺序栈…

MambaAD 实验部分讲解

4 实验 4.1 设置&#xff1a;数据集、指标和细节 数据集&#xff08;6个&#xff09; 1.MVTec-AD&#xff1a; 包含5种类型的纹理和10种类型的对象&#xff0c;总共5,354张高分辨率图像。 实验&#xff1a; 3,629张正常图像被指定为训练。 剩下的 1,725 张图像被保留用于测试…

网络基础擅长组建乐队

让我们荡起双桨 来说说网络吧 现有计算机要进行协作&#xff0c;网络的产生是必然的 局域网&#xff1a;计算机数量更多了, 通过交换机和路由器连接在一起 广域网&#xff1a;将远隔千里的计算机都连在一起 交换机路由器等设备就应运而生 计算机是人的工具&#xff0c;人要协…

美国游戏发展趋势

美国拥有一些最大、最具影响力的游戏开发工作室&#xff0c;是游戏行业的全球领导者。凭借丰富地创新历史&#xff0c;美国游戏开发不断发展&#xff0c;受到尖端技术、消费者偏好和市场动态的影响。已经出现了几个趋势&#xff0c;这些趋势定义了该国游戏发展的方向&#xff0…

node高版本报错: digital envelope routines::unsupported

node高版本报错&#xff1a; digital envelope routines::unsupported 解决方案&#xff1a; package.json中&#xff0c;启动命令前加上&#xff1a; set NODE_OPTIONS--openssl-legacy-provider &&

WPF 手撸插件 八 操作数据库一

1、本文将使用SqlSugar创建Sqlite数据库&#xff0c;进行入门的增删改查等操作。擦&#xff0c;咋写着写着凌乱起来了。 SqlSugar官方文档&#xff1a;简单示例&#xff0c;1分钟入门 - SqlSugar 5x - .NET果糖网 2、环境SqlSugar V5.0版本需要.Net Framework 4.6 &#xff0…

Qt源码-Qt多媒体音频框架

Qt 多媒体音频框架 一、概述二、音频设计1. ALSA 基础2. Qt 音频类1. 接口实现2. alsa 插件实现 一、概述 环境详细Qt版本Qt 5.15操作系统Deepin v23代码工具Visual Code源码https://github.com/qt/qtmultimedia/tree/5.15 这里记录一下在Linux下Qt 的 Qt Multimedia 模块的设…

Windows 11 version 24H2 LTSC 2024 中文版、英文版 (x64、ARM64) 下载 (updated Oct 2024)

Windows 11 version 24H2 & LTSC 2024 中文版、英文版 (x64、ARM64) 下载 (updated Oct 2024) Windows 11, version 24H2&#xff0c;企业版 arm64 x64 请访问原文链接&#xff1a;https://sysin.org/blog/windows-11/ 查看最新版。原创作品&#xff0c;转载请保留出处。…

20年408数据结构

第一题&#xff1a; 解析&#xff1a;这种题可以先画个草图分析一下&#xff0c;一下就看出来了。 这里的m(7,2)对应的是这图里的m(2,7),第一列存1个元素&#xff0c;第二列存2个元素&#xff0c;第三列存3个元素&#xff0c;第四列存4个元素&#xff0c;第五列存5个元素&#…

C嘎嘎入门篇:类和对象番外(时间类)

前文&#xff1a; 小编在前文讲述了类和对象的一部分内容&#xff0c;其中小编讲述过运算符重载这个概念以及一个时间类&#xff0c;当时小编讲的没有那么细致&#xff0c;下面小编将会讲述时间类来帮助各位读者朋友更好的去理解运算符重载&#xff0c;那么&#xff0c;代码时刻…

江西精装世家新型环保材料有限公司:环保家装理念已深入人心!

在现代社会&#xff0c;随着环保意识的觉醒&#xff0c;越来越多的人开始重视家居环境的健康与可持续性。江西精装世家新型环保材料有限公司&#xff0c;作为家装行业的佼佼者&#xff0c;正是这一绿色潮流的引领者。该公司将环保理念深深融入家装实践之中&#xff0c;为消费者…

奥斯卡影帝阿尔帕西诺自传出版:儿子和女友为他提供了写自传的灵感

女友努尔阿尔法拉&#xff08;Noor Alfallah&#xff09;何许人也&#xff1f; 许多人在听到阿尔帕西诺将在80岁出头再次成为父亲的消息时感到震惊&#xff0c;但一年后&#xff0c;帕西诺已经证明他喜欢再次成为他和努尔阿夫拉的女儿罗曼的父亲&#xff1b;甚至激发了一个即将…

数字电表读数检测图像数据集,数据集总共3300左右张图片,标注为voc格式

数字电表读数检测图像数据集&#xff0c;数据集总共3300左右张图片&#xff0c;标注为voc格式 数字电表读数检测数据集 (Digital Meter Reading Detection Dataset) 数据集概述 该数据集是一个专门用于训练和评估数字电表读数检测模型的数据集。数据集包含约3300张图像&#…

高速机器人的点动与直线运动

工业机器人中的点动和直线运动非常之重要&#xff0c;接下来说一下他们的实现过程。 点动&#xff1a; 点动包括两个部分&#xff0c;第一个点动是每一个关节电机的点动&#xff0c;第二个是机器末端向xyz的三个方向进行点动处理。 第一个点动是非常简单的&#xff0c;即把对…

购物清单 | 双十一加购率最高好物合集,数码购物车必备!

​双十一来临&#xff0c;小伙伴们肯定已经被种草了很多很多清单&#xff0c;开始买买买了&#xff01;但是&#xff0c;作为一个数码博主&#xff0c;怎么能少了数码产品&#xff01;今天我给大家准备了一份数码人专属的购物清单&#xff0c;快来看看吧&#xff01; 运动耳机…

Android阶段学习思维导图

前言 记录下自己做的一个对Android原生应用层的思维导图&#xff0c;方便个人记忆扩展&#xff1b;这里只露出二级标题。 后语 虽然有些内容只是初步了解&#xff0c;但还是记录了下来&#xff1b;算是对过去一段学习的告别。

005集—— 用户交互之CAD窗口选择图元实体(CAD—C#二次开发入门)

如下图&#xff1a;根据提示选择若干图形要素&#xff0c;空格或右键结束选择&#xff0c;返回图元的objectid&#xff0c;以便进一步操作图元实体。 代码如下&#xff1a; using Autodesk.AutoCAD.DatabaseServices; using Autodesk.AutoCAD.EditorInput; using Autodesk.Aut…