C++实现日期类Date(超详细)
个人主页:平行线也会相交💪
欢迎 点赞👍 收藏✨ 留言✉ 加关注💓本文由 平行线也会相交 原创
收录于专栏【C++之路】💌
本专栏旨在记录C++的学习路线,望对大家有所帮助🙇
希望我们一起努力、成长,共同进步。🍓
目录
- 日期类(Date.cpp)成员函数的实现
- 构造函数
- bool类型的运算符重载
- 得到该月有几天GetMonthDay
- 运算符重载+=和+
- 运算符重载-=和-
- 运算符重载前置++和后置++
- 运算符重载前置--后置--
- 两个日期相差几天
- 日期类(Date.h)
- 日期测试
- TestDate1()
- TestDate2()
- TestDate3()
- TestDate4()
- TestDate5()
- TestDate6()
日期类(Date.cpp)成员函数的实现
//构造函数,声明和定义分析不能同时给缺省参数,一般是声明给缺省参数
Date::Date(int year, int month, int day)
{if (month > 0 && month < 13 && day>0 && day <= GetMonthDay(year, month)){_year = year;_month = month;_day = day;}else{cout << "非法日期" << endl;}
}bool Date::operator<(const Date& x)
{if (_year < x._year){return true;}else if (_year == x._year && _month < x._month){return true;}else if (_year == x._year && _month == x._month && _day < x._day){return true;}return false;
}bool Date::operator==(const Date& x)
{return _year == x._year&& _month == x._month&& _day == x._day;
}bool Date::operator<=(const Date& x)
{return *this < x || *this == x;
}bool Date::operator>(const Date& x)
{return !(*this <= x);
}bool Date::operator>=(const Date& x)
{return !(*this < x);
}bool Date::operator!=(const Date& x)
{return !(*this == x);
}int Date::GetMonthDay(int year, int month)
{//由于要频繁调用daysArr,所以我们把daysArr放到静态区static int daysArr[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };//if ((year % 4 == 0) && (year % 100 != 0) || (year % 400 == 0) && month == 2)if (month == 2 && ((year % 4 == 0) && (year % 100 != 0) || (year % 400 == 0))){return 29;}else{return daysArr[month];}return daysArr[month];
}//+=复用+
//Date& Date::operator+=(int day)
//{
// *this = *this + day;
// return *this;
//}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)
{Date tmp(*this);tmp += day;/*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;*///出了作用域后tmp销毁,所以不能用引用返回return tmp;
}Date& Date::operator -=(int day)
{if (day < 0){return *this += -day;}_day -= day;while (_day <= 0){--_month;if (_month == 0){_month = 13;--_year;}_day += GetMonthDay(_year, _month);}return *this;
}Date Date:: operator-(int day)
{Date tmp = *this;//这里是拷贝构造tmp -= day;return tmp;
}//前置++
Date& Date::operator++()
{*this += 1;return *this;
}//后置++
//增加int参数并不是为了接收具体的值,这里仅仅是占位,为了就是跟前置++构成重载
Date Date::operator++(int)
{Date tmp = *this;*this += 1;return tmp;
}//前置--
Date& Date::operator--()
{*this -= 1;return *this;
}//后置--
Date Date::operator--(int)
{Date tmp = *this;*this -= 1;return tmp;
}//两个日期相差几天
int Date::operator-(const Date& d)
{//默认认为第一个日期大,第二个小Date max = *this;Date min = d;int flag = 1;if (*this < d){max = d;min = *this;flag = -1; }int n = 0;while (min != max){++min;++n;}return n * flag;
}
构造函数
Date::Date(int year, int month, int day)
{if (month > 0 && month < 13 && day>0 && day <= GetMonthDay(year, month)){_year = year;_month = month;_day = day;}else{cout << "非法日期" << endl;}
}
bool类型的运算符重载
bool Date::operator<(const Date& x)
{if (_year < x._year){return true;}else if (_year == x._year && _month < x._month){return true;}else if (_year == x._year && _month == x._month && _day < x._day){return true;}return false;
}bool Date::operator==(const Date& x)
{return _year == x._year&& _month == x._month&& _day == x._day;
}bool Date::operator<=(const Date& x)
{return *this < x || *this == x;
}bool Date::operator>(const Date& x)
{return !(*this <= x);
}bool Date::operator>=(const Date& x)
{return !(*this < x);
}bool Date::operator!=(const Date& x)
{return !(*this == x);
}
得到该月有几天GetMonthDay
int Date::GetMonthDay(int year, int month)
{//由于要频繁调用daysArr,所以我们把daysArr放到静态区static int daysArr[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };//if ((year % 4 == 0) && (year % 100 != 0) || (year % 400 == 0) && month == 2)if (month == 2 && ((year % 4 == 0) && (year % 100 != 0) || (year % 400 == 0))){return 29;}else{return daysArr[month];}return daysArr[month];
}
运算符重载+=和+
这里有两种方式来写+=和+的赋值运算符重载。
先来看第一种:+=复用+的方式,请看:
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;
}//+复用+=
Date Date::operator+(int day)
{Date tmp(*this);tmp += day;/*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;*///出了作用域后tmp销毁,所以不能用引用返回return tmp;
}
现在来看第二种写法,+=复用+
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;}}//出了作用域后tmp销毁,所以不能用引用返回return tmp;
}//+=复用+
Date& Date::operator+=(int day)
{*this = *this + day;return *this;
}
现在这两种写法哪一种好呢?对于每种方式的+的赋值运算符重载没啥太大的区别(都要都要创建两个对象,一个是Date tmp(*this);,另外一个就是return tmp);但是对于+=的赋值运算符重载,第一种方式并没有创建对象,而第二种方式的+=的符重运算符重载由于又调用了一次+的赋值运算符重载函数(即多创建了两个对象)。所以最终第一种方式(+复用+=)显然更好一些,第二种方式差就差再+=复用+的时候多创建了两个对象。
运算符重载-=和-
Date& Date::operator -=(int day)
{if (day < 0){return *this += -day;}_day -= day;while (_day <= 0){--_month;if (_month == 0){_month = 13;--_year;}_day += GetMonthDay(_year, _month);}return *this;
}Date Date:: operator-(int day)
{Date tmp = *this;//这里是拷贝构造tmp -= day;return tmp;
}
运算符重载前置++和后置++
//前置++
Date& Date::operator++()
{*this += 1;return *this;
}//后置++
//增加int参数并不是为了接收具体的值,这里仅仅是占位,为了就是跟前置++构成重载,方便区分
Date Date::operator++(int)
{Date tmp = *this;*this += 1;return tmp;
}
运算符重载前置–后置–
//前置--
Date& Date::operator--()
{*this -= 1;return *this;
}//后置--
Date Date::operator--(int)
{Date tmp = *this;*this -= 1;return tmp;
}
两个日期相差几天
//两个日期相差几天
int Date::operator-(const Date& d)
{//默认认为第一个日期大,第二个小Date max = *this;Date min = d;int flag = 1;if (*this < d){max = d;min = *this;flag = -1; }int n = 0;while (min != max){++min;++n;}return n * flag;
}
日期类(Date.h)
class Date
{
public://构造函数Date(int year = 22, int month = 5, int day = 20);//不需要写拷贝构造函数,所以下面可以选择直接注释掉Date (const Date& d){cout << "Date(const Date& d)" << endl;_year = d._year;_month = d._month;_day = d._day;}void Print(){cout << _year << "-" << _month << "-" << _day << endl;}bool operator<(const Date& x);bool operator==(const Date& x);bool operator<=(const Date& x);bool operator>(const Date& x);bool operator>=(const Date& x);bool operator!=(const Date& x);int GetMonthDay(int year, int month);Date& operator+=(int day);Date operator+(int day);Date& operator -=(int day);Date operator-(int day);Date& operator++();//前置++Date operator++(int);//后置++Date& operator--();//前置--Date operator--(int);//后置++//计算两个日期相差多少天int operator-(const Date& d);
private:int _year;int _month;int _day;
};
日期测试
TestDate1()

void TestDate1()
{Date da1(23, 5, 20);da1 += 100;da1.Print();Date da2(23, 5, 20);Date da3(da2 + 100);da2.Print();da3.Print();//用一个已经存在的对象初始化另一个对象,即拷贝构造函数//拷贝构造的意义就是赋值初始化Date da4 = da2;//等价于Date da4(da2);//均为拷贝构造函数,是等价的//而赋值重载的意义纯粹的就是拷贝//已经存在的两个对象之间进行复制拷贝,即运算符重载函数da4 = da1;
}
这里指的注意的是Date da4 = da2;是等价于Date da4(da2);,因为这里实在用一个已经存在的对象初始化另外一个对象,所以这里调用的是拷贝构造函数,而不是调用=的赋值运算符重载。
如下如:


TestDate2()
{Date da1(2021, 5, 21);//无论前置还是后置++都需要++//前置++就返回++以后的对象,后置++就返回++之前的对象//编译器这里成全一个同时委屈一个,为了区分这里的重载++da1;//da1.operator++()da1++;//da1.operator++(0)Date da2(2024, 5, 20);Date da3(2023, 3, 14);bool ret1 = da2 < da3;//自定义类型转换为对应的函数int i = 0, j = 2;bool ret2 = i < j;//内置类型编译器知道怎么比较,故编译器会自动处理内置类型的重载
}
TestDate3()
//测试日期类的-=
void TestDate3()
{Date da1(2023, 5, 20);da1 -= 50;da1.Print();Date da2(2023, 5, 21);da2 -= 88;da2.Print();Date da3(2023, 5, 25);da3 -= 100;da3.Print();Date da4(2024, 5, 20);da4 -= 10000;da4.Print();
}
TestDate4()
void TestDate4()
{Date d1(2020, 5, 20);d1 += 100;d1.Print();Date da2(2023, 5, 21);da2 += -100;da2.Print();Date da3(2023, 5, 5);da3 -= -100;da3.Print();
}
TestDate5()
void TestDate5()
{Date da1(2023, 5, 5);Date ret1 = da1--;//调用da1.operator(&da1,0);ret1.Print();da1.Print();Date da2(2023, 5, 5);Date ret2 = --da2;//调用da1.operator++(&da1);ret2.Print();da2.Print();
}
TestDate6()
void TestDate6()
{Date da1(2023, 5, 20);Date da2(2022, 5, 21);Date da3(1949, 10, 1);Date da4(2023, 5, 20);cout << da1 - da2 << endl;cout << da2 - da1 << endl;cout << da3 - da4 << endl;cout << da4 - da3 << endl;
}
好了,以上就是用C++来实现日期类。
就到这里,再见啦各位!!!

相关文章:
C++实现日期类Date(超详细)
个人主页:平行线也会相交💪 欢迎 点赞👍 收藏✨ 留言✉ 加关注💓本文由 平行线也会相交 原创 收录于专栏【C之路】💌 本专栏旨在记录C的学习路线,望对大家有所帮助🙇 希望我们一起努力、成长&…...
实验室检验系统源码,集检验业务、质量控制、报告、统计分析、两癌等模块于一体
云 LIS 系统针对区域化 LIS 而设计,依托底层云架构,将传统的 LIS 功能模块进行“云化”。 该系统是集检验业务、科室管理、质量控制、报告、统计分析、两癌等模块于一体的数据检验信息平台。通过计算机联网,实现各类仪器数据结果的实时自动接…...
学习RHCSA的day.03
目录 2.6 Linux系统的目录结构 2.7 目录操作命令 2.8 文件操作命令 2.6 Linux系统的目录结构 1、Linux目录结构的特点 分区加载于目录结构: 使用树形目录结构来组织和管理文件。整个系统只有一个位于根分区的一个根目录(树根)、一棵树。…...
电子邮件协议(SMTP,MIME,POP3,IMAP)
SMTP 关键词: 电子邮件协议:SMTP简单邮件传输协议,负责将邮件上传到服务器,采用TCP的25端口,C/S工作。仅传送ASCII码文本 详细介绍: SMTP是一种提供可靠且有效的电子邮件传输的协议。SMTP是建立在FTP文件传输服务上…...
Golang笔记:使用embed包将静态资源嵌入到程序中
文章目录 目的使用演示//go:embed 指令在WebServer中应用总结 目的 Golang编译程序默认是静态编译,会把相关的库都打包到一起,这在分发部署使用时非常方便。不过如果项目中用到的外部的静态资源文件,通常就需要将这些资源和程序一起拷贝分发…...
ImportError: cannot import name ‘OldCsv‘ from ‘pyflink.table.descriptors‘
我最近开始使用flink用于数据处理。 当我尝试执行table api 用于计数时 我不能导入OldCsv and FileSystem from pyflink.table.descriptors. I have also downloaded apache-flink using: pip install apache-flink [rootmaster flink]# pip3 list | grep flink apache-fli…...
YouCompleteMe(YCM)安装
vim在各个linux版本中是个比较好编辑器,反正nano我是用不惯。但这个ycm的安装也是不断的在变,现在的安装比之前要简单的多,基本个几命令就搞定了,而且 也不用关心系统里有没有vim,ycm已经可以自动安装。具体安装步骤如下ÿ…...
day33_css
今日内容 零、 复习昨日 一、CSS 零、 复习昨日 见代码 一 、引言 1.1CSS概念 层叠样式表(英文全称:Cascading Style Sheets)是一种用来表现HTML(标准通用标记语言的一个应用)或XML(标准通用标记语言的一个子集)等文…...
10个最流行的向量数据库【AI】
矢量数据库是一种将数据存储为高维向量的数据库,高维向量是特征或属性的数学表示。 每个向量都有一定数量的维度,范围从几十到几千不等,具体取决于数据的复杂性和粒度。 推荐:用 NSDT场景设计器 快速搭建3D场景。 矢量数据库&…...
vite3+vue3 项目打包优化二 —— 依赖分包策略
在没有配置构建工具的分包功能时,构建出来的文件将无比巨大且是独立的一个 js 和 css 文件(如下图),这样本地加载文件时会存在巨大的压力。 默认情况下,浏览器重复请求相同名称的静态资源时,会直接使用缓存…...
中国社科院与美国杜兰大学金融管理硕士——与时间赛跑,充分利用每一分钟
不管你愿不愿意,时间总是在不经意间流去。林清玄在《和时间赛跑》中写道:“虽然我知道人永远跑不过时间,但是可以比原来快跑几步。那几步虽然很小很小,但作用却很大很大”。是的,我们需要与时间赛跑,充分利…...
什么是Dirichlet分布?
Dirichlet分布是一种概率分布,用于描述多维随机变量的概率分布。它是一个连续分布,通常用于处理具有多种可能取值的离散型随机变量。在LDA模型中,Dirichlet分布通常被用作先验分布,用来表示主题的概率分布和单词的概率分布。 Dir…...
web前端开发需要哪些技术?学前端顺序千万千万不要搞错啦!
宝子们,下午好,之前给大家分享了前端岗位的前景规划,小源看的出来,还是有不少宝子想入行前端的! 那除了会面试,还要有充足丰富的知识储备,需要什么技术,怎么样做才能找到高薪工作呢&…...
【AFNetWorking源码(二)AFURLSessionManger和AFHTTPSessionManager】
前言 学习了Mananger的初始化和以GET请求为例的过程,发现整个过程离不开AFHTTPSessionManager和AFURLSessionManger的某些方法。这两个是AFN的重要的网络通信模块内容,对它们作揖详细的学习。 AFURLSessionManager和AFHTTPSessionManager都是AFNetwork…...
编程不头秃,Google「AI程序员」来了,聊天就能敲代码
上周 Google 在 I/O 大会宣布了一个能够辅助编程的聊天机器人 Codey,现在它终于上线 Google Colab 啦! 🌟 Codey 是基于 Google 目前最新的大语言模型 PaLM 2 运行,有着强大的语言理解和编程能力。 Codey 有这些功能࿱…...
【数据结构与算法】基础数据结构
文章目录 数组概述动态数组二维数组局部性原理越界检查 链表概述单向链表单向链表(带哨兵)双向链表(带哨兵)环形链表(带哨兵) 队列概述链表实现环形数组实现 栈概述链表实现数组实现应用 双端队列概述链表实…...
k8s系列(四)——资源对象
k8s系列四——资源对象 pod概念 思考:为什么k8s会引出pod这个概念,容器不能解决么? 我的理解:一组密切相关的服务使用容器的话,如果他们的镜像不在一个容器里的话,那么就需要配置反向代理进行通信…...
JavaScript如何使用for循环
JavaScript 是一门非常有趣的编程语言,它可以让我们在浏览器中创建交互式的 Web 应用程序。在 JavaScript 中,我们可以使用 for 循环来迭代一个数组或对象,从而执行一系列的操作。下面是一些关于 for 循环的有趣的用法和例子。 为什么要使用…...
(浙大陈越版)数据结构 第三章 树(上) 3.1 树和树的表示
目录 3.1.1 引子(顺序查找) 什么是树 查找 3.1.2 引子 二分查找例子(BinarySearch) 二分查找 3.1.3 引子 二分查找实现 二分查找代码 二分查找的启示 3.1.4 树的定义 一些基本术语: 3.1.5 树的表示 3.1.1 引子(顺序查找…...
平抑风电波动的电-氢混合储能容量优化配置(Matlab代码实现)
💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…...
CVPR 2025 MIMO: 支持视觉指代和像素grounding 的医学视觉语言模型
CVPR 2025 | MIMO:支持视觉指代和像素对齐的医学视觉语言模型 论文信息 标题:MIMO: A medical vision language model with visual referring multimodal input and pixel grounding multimodal output作者:Yanyuan Chen, Dexuan Xu, Yu Hu…...
前端倒计时误差!
提示:记录工作中遇到的需求及解决办法 文章目录 前言一、误差从何而来?二、五大解决方案1. 动态校准法(基础版)2. Web Worker 计时3. 服务器时间同步4. Performance API 高精度计时5. 页面可见性API优化三、生产环境最佳实践四、终极解决方案架构前言 前几天听说公司某个项…...
《从零掌握MIPI CSI-2: 协议精解与FPGA摄像头开发实战》-- CSI-2 协议详细解析 (一)
CSI-2 协议详细解析 (一) 1. CSI-2层定义(CSI-2 Layer Definitions) 分层结构 :CSI-2协议分为6层: 物理层(PHY Layer) : 定义电气特性、时钟机制和传输介质(导线&#…...
定时器任务——若依源码分析
分析util包下面的工具类schedule utils: ScheduleUtils 是若依中用于与 Quartz 框架交互的工具类,封装了定时任务的 创建、更新、暂停、删除等核心逻辑。 createScheduleJob createScheduleJob 用于将任务注册到 Quartz,先构建任务的 JobD…...
【SQL学习笔记1】增删改查+多表连接全解析(内附SQL免费在线练习工具)
可以使用Sqliteviz这个网站免费编写sql语句,它能够让用户直接在浏览器内练习SQL的语法,不需要安装任何软件。 链接如下: sqliteviz 注意: 在转写SQL语法时,关键字之间有一个特定的顺序,这个顺序会影响到…...
Rust 异步编程
Rust 异步编程 引言 Rust 是一种系统编程语言,以其高性能、安全性以及零成本抽象而著称。在多核处理器成为主流的今天,异步编程成为了一种提高应用性能、优化资源利用的有效手段。本文将深入探讨 Rust 异步编程的核心概念、常用库以及最佳实践。 异步编程基础 什么是异步…...
Springboot社区养老保险系统小程序
一、前言 随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱,社区养老保险系统小程序被用户普遍使用,为方…...
Java + Spring Boot + Mybatis 实现批量插入
在 Java 中使用 Spring Boot 和 MyBatis 实现批量插入可以通过以下步骤完成。这里提供两种常用方法:使用 MyBatis 的 <foreach> 标签和批处理模式(ExecutorType.BATCH)。 方法一:使用 XML 的 <foreach> 标签ÿ…...
无人机侦测与反制技术的进展与应用
国家电网无人机侦测与反制技术的进展与应用 引言 随着无人机(无人驾驶飞行器,UAV)技术的快速发展,其在商业、娱乐和军事领域的广泛应用带来了新的安全挑战。特别是对于关键基础设施如电力系统,无人机的“黑飞”&…...
CSS | transition 和 transform的用处和区别
省流总结: transform用于变换/变形,transition是动画控制器 transform 用来对元素进行变形,常见的操作如下,它是立即生效的样式变形属性。 旋转 rotate(角度deg)、平移 translateX(像素px)、缩放 scale(倍数)、倾斜 skewX(角度…...

