当前位置: 首页 > news >正文

【C++小项目】实现一个日期计算器

目录

Ⅰ. 引入

Ⅱ. 列轮廓

Ⅲ. 功能的实现

构造函数

判断是否相等 == | !=

➡️==:

➡️!=:

判断大小 > | >= | < | <=

➡️>:

➡️<=:

➡️>=:

➡️<:

加减天数 + | += | - | -=

➡️+=:

➡️+:

➡️-:

➡️-=:

自增/自减 ++ | --

➡️前置++

➡️后置++

➡️前置--

➡️后置--

日期减日期

➡️Way1(推荐)

➡️Way2( 这个思路繁杂很多)


Ⅰ. 引入

本篇我们用C++来实现一个日期计算器。

想知道迄今为止你在地球上一共度过了多少天吗?距离寒假还有多少天呢?一百天后会是几月几号呢?

解开这些问题的答案,只需来写一个日期计算器~👻

日期计算器是C++入门以来的第一个小项目,亲自实践一遍,我们在C++上的经验值将⬆️⬆️⬆️

🚩我们将分三步:

Step1:在头文件中把日期类的大体轮廓列出来

Step2:把声明的功能一一实现

Step3:逐个测试。我们写一点,测一点。

这样,就可顺利把日期计算器写出个七七八八。

在遇到较复杂的算法时,我会提供思路。

至于某些锦上添花的功能,我们后续想到了,再添上去。

Ⅱ. 列轮廓

🤔我们先来定义一个日期类,同时看看要实现哪些功能:

#pragma once
#include<iostream>
using namespace std;
​
class Date {
public:Date(int year = 1900, int month = 1, int day = 1);  //构造函数:用于初始化
​void Print();   //打印日期,便于测试
​//功能的具体实现bool operator==(const Date& d);  //判断俩date是否相等bool operator!=(const Date& d);  
​bool operator>(const Date& d);    //date间比较大小bool operator>=(const Date& d);bool operator<(const Date& d);bool operator<=(const Date& d);
​Date operator+(int day);     //加(减)天数,今夕是何年Date& operator+=(int day);Date operator-(int day);Date& operator-=(int day);
​Date& operator++();     //date的自增/自减Date operatoe++(int);Date& operator--();Date operatoe--(int);
​int operator-(const Date& d);  //算两个date间差多少天
​
private:int _year;int _month;int _day;
};

Ⅲ. 功能的实现

构造函数

➡️我们实现一个全缺省的构造函数:

class Date{
public:Date(int year = 1900, int month = 1, int day = 1) {  _year = year;_month = month;_day = day;}private:int _year;int _month;int _day;
}

每次实例化出一个对象,都要调用构造函数,调用频率非常高。

所以,我们干脆就把这短短的几行定义在类里,做内联函数。

❓你可能会疑惑:为啥_year可以直接拿来用,不需要this->year嘛?

后者当然可以写,但没必要。因为我们在使用类的成员函数or成员变量时,this指针会默认加上的。

我们就不用一一手动加啦✌

Print

➡️Print,写在Date.c里:

void Date::Print() {printf("%d-%d-%d\n", _year, _month, _day);
}

❓为啥要加Date::呢?

要知道,类定义了一个全新的作用域。类里类外,是有一层屏障的。

正因为类域的存在,我们不能直接从外部访问类的成员。

因此,把成员函数拿到类外定义时,要指明作用域,即加上Date::

❓我们不是学了cout嘛,为啥不直接cout输出,还得用printf?

这个问题我们先保留着,下一趴再讲。🤪

🔬🧪这俩函数先测试一波:

void Test1() {Date d1(2023, 8, 23);Date d2;d1.Print();d2.Print();
}
int main()
{Test1();return 0;
}

结果:

判断是否相等 == | !=

➡️==:

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指针。只有第二个形参可见。

“d1!=d2; ” 就相当于在调用函数 “d1.operator!=(d2); ”

此函数的this指针指向d1,形参的d即d2。

🔬🧪测试一下:

void Test2() {Date d1(2023, 8, 23);Date d2(2000, 1, 1);if (d1 != d2) {cout << "unequal"<<endl;}
}
int main()
{//Test1();Test2();return 0;
}

结果:

判断大小 > | >= | < | <=

日期的大小,听着蛮抽象。其实就是日期的先后:2023年1月1日比2000年1月1日要大(后)。

➡️>:

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

这种算法的思路是:

写完>,先不急着写<,因为>的对立面是<=,那我们可以把这段代码复用到<=👻

➡️<=:

bool Date::operator<=(const Date& d) {return !(*this > d);
}

➡️>=:

bool Date::operator>=(const Date& d) {return *this > d || *this == d;
}

➡️<:

bool Date::operator<(const Date& d) {return !(*this >= d);
}

🔬🧪测试一下:

void Test3() {Date d1(2023, 8, 23);Date d2(2000, 1, 1);cout << (d1 > d2) << endl;cout << (d1 <= d2)<<endl;
}
​
int main()
{//Test1();//Test2();Test3();return 0;
}

结果:

加减天数 + | += | - | -=

➡️+=:

日期加天数要考虑进位的问题。我举个例子,先顺下思路:

2023-12-21往后推40天

61相比当月的31已经溢出了,

怎么判断是否溢出呢?

写个函数GetMonthDay(),取到每月的天数进行比对

GetMonthDay()实现如下:

int Date::GetMonthDay(int year, int month) {int days[13]={ 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};int ret = days[month];
​//考虑闰年的2月是29天的情况//闰年,要么能被4整除&&不能被100~;要么能被400整除
​if (month == 2&& (year % 4 == 0 && year % 100 == 0|| year % 400 == 0)) {ret += 1;}
​return ret;
}

☑️operator+=实现如下:

Date& Date::operator+=(int day) {_day += day;int MaxDay = GetMonthDay(_year, _month);
​while (_day > MaxDay) {_day -= MaxDay;_month++;
​//防止month溢出if (_month == 13) {_month = 1;_year++;}
​MaxDay = GetMonthDay(_year, _month);}
​return *this;
}

➡️+:

有了+=,+就直接复用~👻

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

🤔❓思考:为啥不能这样写?

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

因为:

➡️-:

加要考虑进位,减要考虑借位。

举例:2023-3-2 往前40天

思路:

🌀你可能有点晕:-38为什么要借2月的28?

可以把2023-3-2往前40天视为2023-3-0往前38天。

此时要借位,我们没法从3月借,因为它是空的。只能从2月借。

☑️实现:

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

➡️-=:

同样,复用🥰

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

🔬🧪测试一下:

void Test4() {Date d1(2023, 12, 21);   //+  +=Date d2(d1);(d1 + 40).Print();(d2 += 700).Print();Date d3(d1);   //-  -=Date d4(2023, 3, 2);(d3 -= 400).Print();(d4 - 40).Print();
}

结果:

自增/自减 ++ | --

我们用参数占位来区分前置/后置++:

前置:operator++( )

后置:operator++( int )

❓前置++和后置++的区别是什么?

这俩都能实现自增,但返回值不同。

前置:++d; 先加加,再使用。返回的是加加的值。

后置:d++;先使用,再加加。返回的是加加的值。

假设d=0,d++:返回1,d=1

++d:返回0,同时实现自增,d=1

所以说,后置加加是不能引用返回的。而前置可以。

➡️前置++

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

➡️后置++

Date Date::operator++(int) {Date ret = *this;*this += 1;return ret;
}

➡️前置--

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

➡️后置--

Date Date::operator--(int) {Date ret = *this;*this -= 1;return ret;
}

🔬🧪测试一下:

void Test5() {Date d1(2023, 1, 1);   //++Date d2(d1);(++d1).Print();(d2++).Print();
​Date d3(2023, 1, 1);  //--Date d4(d3);(--d3).Print();(d4--).Print();
}

结果:

日期减日期

距离新年还有多少天呢?

Date(2024,1,1) - Date(2023,8,24) =❓天

➡️Way1(推荐)

我们刚刚不是写了好多功能嘛,复用起来~👻

实现:

int Date::operator-(const Date& d) {Date More = *this;  //先把date标个大小Date Less = d;
​if (Less > More) {More=d;Less=*this;}
​int count = 0;    //用计数法算差值while (Less<More) {Less++;    //复用🥰👻count++;}
​int flag = 1;      //我们不知道是大-小or小-大if (More == d) {    //为了区分结果的正负,引入flagflag = -1;  }
​return count*flag;
}

这种方法虽然思路简单,但是深度复用了代码,效率会下降。

➡️Way2( 这个思路繁杂很多)

(❗这个方法效率会⬆️,但是较复杂,可略过不看!)

Q: 2023-2-13到2024-1-15,要过多少天?、

思路:

Step1:把月、日转化成总天数;

Step2:年与年之间相减,天与天之间相减

Step3:全化成天

实现:

Step1 我们先写一个把月、日转换成天数的函数ConverttoDay( )

如下:

int Date::ConverttoDay(int year, int month, int day) {int MonthtoDay = 0;month -= 1;
​while (month) {MonthtoDay += GetMonthDay(year, month);month--;}
​int ret = MonthtoDay + day;return ret;
}

Step2 实现operator-函数

int Date::operator-(const Date& d) {//先判断日期的大小Date BigDate = *this;Date SmallDate = d;
​if (BigDate < SmallDate) {Date tmp = SmallDate;SmallDate = BigDate;BigDate = tmp;}
​//把月、日都转换成天int BigDay = ConverttoDay(BigDate._year, BigDate._month, BigDate. _day);int SmallDay = ConverttoDay(SmallDate._year, SmallDate._month, SmallDate._day);
​
​int RetofDay = BigDay - SmallDay;  //天之间相减,大天-小天int BigYear = BigDate._year;int SmallYear = SmallDate._year;
​//年之间相减,大年-小年int CountDay = 0;
​while (SmallYear < BigYear) {CountDay += 365;
​if (SmallYear % 4 == 0 && SmallYear % 100 != 0  //考虑闰年|| SmallYear % 400 == 0) {CountDay += 1;}
​SmallYear++;}
​//把两者的天数合一int ret = RetofDay + CountDay;
​int flag = 1;if (*this == BigDate) {flag = -1;}
​return flag * ret;
}

🔬🧪测试一下:

void Test6() {Date d1(2023, 8, 24);Date d2(2024, 1, 1);
​printf("%d\n", d2 - d1);
}

结果:


OK, 到这我们的日期计算器已经完成啦~🥰👻

相关文章:

【C++小项目】实现一个日期计算器

目录 Ⅰ. 引入 Ⅱ. 列轮廓 Ⅲ. 功能的实现 构造函数 Print 判断是否相等 | ! ➡️: ➡️!: 判断大小 > | > | < | < ➡️>&#xff1a; ➡️<&#xff1a; ➡️>&#xff1a; ➡️<&#xff1a; 加减天数 | | - | - ➡️&#xff1a;…...

Ext JS 之Microloader(微加载器)

“Microloader”是 Sencha 数据驱动的 JavaScript 和 CSS 动态加载器的名称。 清单 app.json 用于应用的设置,Sencha Cmd 在构建的时候会读取这个文件。 Sencha Cmd 转换“app.json”的内容并将生成的清单传递给 Microloader 以在运行时使用。 最后,Ext JS 本身也会查阅运…...

【科研】-- 如何将Endnote中参考文献格式插入到Word?

文章目录 如何将Endnote中参考文献格式插入到Word&#xff1f; 如何将Endnote中参考文献格式插入到Word&#xff1f; 1、首先确保Endnote和Word安装正确&#xff0c;正常可以从学校官网中下载到正版软件&#xff0c;下载后在word栏目中会出现EndNote的标签&#xff1b; 2、可…...

Python爬虫实战案例——第二例

某某美剧剧集下载(从搜索片名开始) 本篇文章主要是为大家提供某些电影网站的较常规的下载电影的分析思路与代码思路(通过爬虫下载电影)&#xff0c;我们会从搜索某部影片的关键字开始直到成功下载某一部电影。 地址&#xff1a;aHR0cHM6Ly93d3cuOTltZWlqdXR0LmNvbS9pbmRleC5od…...

深入理解Spring的ImportBeanDefinitionRegistrar接口及其应用

0 导言 ImportBeanDefinitionRegistrar接口在动态注册Bean定义方面发挥着重要作用。本篇博客将深入探讨ImportBeanDefinitionRegistrar接口的作用、用法以及实际应用场景。 1 简介 ImportBeanDefinitionRegistrar接口是Spring Framework中的一个关键接口&#xff0c;位于org…...

【面试题】你理解中JS难理解的基本概念是什么?

前端面试题库 &#xff08;面试必备&#xff09; 推荐&#xff1a;★★★★★ 地址&#xff1a;前端面试题库 作用域与闭包 作用域 作用域是当前的执行上下文&#xff0c;值和表达式在其中“可见”或可被访问。如果一个变量或表达式不在当前的作用域中&#xff0…...

微服务中间件--MQ服务异步通信

MQ服务异步通信 MQ服务异步通信a.消息可靠性1) 生产者消息确认2) 消息持久化3) 消费者消息确认4) 消费者失败重试4.a) 本地重试4.b) 失败策略 b.死信交换机1) 初识死信交换机2) TTL3) 延迟队列a) 安装延迟队列插件b) SpringAMQP使用延迟队列插件 c.惰性队列1) 消息堆积问题2) 惰…...

爆火「视频版ControlNet」开源了!靠提示词精准换画风,全华人团队出品

“视频版ControlNet”来了&#xff01; 让蓝衣战神秒变迪士尼公举&#xff1a; 视频处理前后&#xff0c;除了画风以外&#xff0c;其他都不更改。 女孩说话的口型都保持一致。 正在插剑的姜文&#xff0c;也能“下一秒”变猩球崛起了。 这就是由全华人团队打造的最新视频处理…...

常用的数据可视化工具有哪些?要操作简单的

随着数据量的剧增&#xff0c;对分析效率和数据信息传递都带来了不小的挑战&#xff0c;于是数据可视化工具应运而生&#xff0c;通过直观形象的图表来展现、传递数据信息&#xff0c;提高数据分析报表的易读性。那么&#xff0c;常用的操作简单数据可视化工具有哪些&#xff1…...

ssl卸载原理

SSL卸载&#xff0c;也称为SSL解密&#xff0c;是一种将SSL加密数据流卸成非加密的明文数据流的过程。SSL卸载通常在负载均衡器、代理服务器、WAF等设备中实现&#xff0c;可以提高传输效率和安全性。 SSL卸载的原理是将SSL数据流拦截下来&#xff0c;通过设备内置的证书进行解…...

【C语言】动态内存管理,详细!!!

文章目录 前言一、为什么存在动态内存分配二、动态内存开辟函数的介绍1.malloc2.calloc3.realloc4.free 三、动态内存开辟中的常见错误1.误对NULL进行解引用操作2.对于动态开辟的空间进行了越界访问3.对于非动态开辟的内存进行了free操作4.只free掉动态开辟内存的一部分5.多次f…...

2023年国赛 高教社杯数学建模思路 - 案例:退火算法

文章目录 1 退火算法原理1.1 物理背景1.2 背后的数学模型 2 退火算法实现2.1 算法流程2.2算法实现 建模资料 ## 0 赛题思路 &#xff08;赛题出来以后第一时间在CSDN分享&#xff09; https://blog.csdn.net/dc_sinor?typeblog 1 退火算法原理 1.1 物理背景 在热力学上&a…...

jenkins 日志输出显示时间戳的方式

网上很多方式比较片面&#xff0c;最新版插件直接使用即可无需更多操作。 使用方式如下&#xff1a; 1.安装插件 Timestamper 2.更新全局设置 系统设置-找到 Timestamper 勾选 Enabled for all Pipeline builds 也可修改时间戳格式。 帮助信息中显示 When checked, timesta…...

geacon_pro配合catcs4.5上线Mac、Linux

我的个人博客: xzajyjs.cn 一些链接 Try师傅的catcs4.5项目: https://github.com/TryGOTry/CobaltStrike_Cat_4.5&#xff0c;最新版解压密码见&#xff1a;https://www.nctry.com/2708.html geacon_pro: https://github.com/testxxxzzz/geacon_pro BeaconTool.jar: https:/…...

vue 实现腾讯地图搜索选点功能(附加搜索联想功能)

注意&#xff1a;开发环境、正式环境需在腾讯地图配置ip地址白名单、域名白名单 封装map组件&#xff1a; <template><iframe width"100%" style"border: none;width: 100%;height: 100%;" :src"map_src"></iframe> </t…...

解密长短时记忆网络(LSTM):从理论到PyTorch实战演示

目录 1. LSTM的背景人工神经网络的进化循环神经网络&#xff08;RNN&#xff09;的局限性LSTM的提出背景 2. LSTM的基础理论2.1 LSTM的数学原理遗忘门&#xff08;Forget Gate&#xff09;输入门&#xff08;Input Gate&#xff09;记忆单元&#xff08;Cell State&#xff09;…...

17.1.2 【Linux】systemd使用的unit分类

systemd 有什么好处&#xff1f; 平行处理所有服务&#xff0c;加速开机流程&#xff1a; 旧的 init 启动脚本是“一项一项任务依序启动”的模式&#xff0c;因此不相依的服务也是得要一个一个的等待。但目前我们的硬件主机系统与操作系统几乎都支持多核心架构了&#xff0c;s…...

vue离线缓存资源文件

本文章主要是解决大文件,实时请求资源浪费网络资源的问题 从而有效的将解决用户体验的问题 话不多说上才艺 ⬇️⬇️⬇️⬇️⬇️⬇️⬇️ 找到项目中的 index.html 文件,并在 html 标签中加入 manifest"manifest.appcache" 安装 appcache-manifest 包 npm ins…...

2023华为杯研赛数学建模A题B题C题D题E题F题资料 华为杯

本次比赛我们将会全程更新华为杯研赛赛题思路模型及代码&#xff0c;大家查看文末名片获取 之前华为杯相关的资料和助攻可以查看 2022华为杯数学建模研赛选题建议和思路分析_方形件组批优化问题_UST数模社_的博客-CSDN博客 我们华为杯更新的流程如下&#xff1a; A题思路&a…...

星际争霸之小霸王之小蜜蜂(六)--让子弹飞

目录 前言 一、添加子弹设置 二、创建子弹 三、创建绘制和移动子弹函数 四、让子弹飞 五、效果 总结 前言 小蜜蜂的基本操作已经完成了&#xff0c;现在开始编写子弹的代码了。 一、添加子弹设置 在我的预想里&#xff0c;我们的小蜜蜂既然是一只猫&#xff0c;那么放出的子弹…...

测试微信模版消息推送

进入“开发接口管理”--“公众平台测试账号”&#xff0c;无需申请公众账号、可在测试账号中体验并测试微信公众平台所有高级接口。 获取access_token: 自定义模版消息&#xff1a; 关注测试号&#xff1a;扫二维码关注测试号。 发送模版消息&#xff1a; import requests da…...

简易版抽奖活动的设计技术方案

1.前言 本技术方案旨在设计一套完整且可靠的抽奖活动逻辑,确保抽奖活动能够公平、公正、公开地进行,同时满足高并发访问、数据安全存储与高效处理等需求,为用户提供流畅的抽奖体验,助力业务顺利开展。本方案将涵盖抽奖活动的整体架构设计、核心流程逻辑、关键功能实现以及…...

【SpringBoot】100、SpringBoot中使用自定义注解+AOP实现参数自动解密

在实际项目中,用户注册、登录、修改密码等操作,都涉及到参数传输安全问题。所以我们需要在前端对账户、密码等敏感信息加密传输,在后端接收到数据后能自动解密。 1、引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId...

LeetCode - 394. 字符串解码

题目 394. 字符串解码 - 力扣&#xff08;LeetCode&#xff09; 思路 使用两个栈&#xff1a;一个存储重复次数&#xff0c;一个存储字符串 遍历输入字符串&#xff1a; 数字处理&#xff1a;遇到数字时&#xff0c;累积计算重复次数左括号处理&#xff1a;保存当前状态&a…...

电脑插入多块移动硬盘后经常出现卡顿和蓝屏

当电脑在插入多块移动硬盘后频繁出现卡顿和蓝屏问题时&#xff0c;可能涉及硬件资源冲突、驱动兼容性、供电不足或系统设置等多方面原因。以下是逐步排查和解决方案&#xff1a; 1. 检查电源供电问题 问题原因&#xff1a;多块移动硬盘同时运行可能导致USB接口供电不足&#x…...

如何在看板中有效管理突发紧急任务

在看板中有效管理突发紧急任务需要&#xff1a;设立专门的紧急任务通道、重新调整任务优先级、保持适度的WIP&#xff08;Work-in-Progress&#xff09;弹性、优化任务处理流程、提高团队应对突发情况的敏捷性。其中&#xff0c;设立专门的紧急任务通道尤为重要&#xff0c;这能…...

1.3 VSCode安装与环境配置

进入网址Visual Studio Code - Code Editing. Redefined下载.deb文件&#xff0c;然后打开终端&#xff0c;进入下载文件夹&#xff0c;键入命令 sudo dpkg -i code_1.100.3-1748872405_amd64.deb 在终端键入命令code即启动vscode 需要安装插件列表 1.Chinese简化 2.ros …...

【论文阅读28】-CNN-BiLSTM-Attention-(2024)

本文把滑坡位移序列拆开、筛优质因子&#xff0c;再用 CNN-BiLSTM-Attention 来动态预测每个子序列&#xff0c;最后重构出总位移&#xff0c;预测效果超越传统模型。 文章目录 1 引言2 方法2.1 位移时间序列加性模型2.2 变分模态分解 (VMD) 具体步骤2.3.1 样本熵&#xff08;S…...

视频行为标注工具BehaviLabel(源码+使用介绍+Windows.Exe版本)

前言&#xff1a; 最近在做行为检测相关的模型&#xff0c;用的是时空图卷积网络&#xff08;STGCN&#xff09;&#xff0c;但原有kinetic-400数据集数据质量较低&#xff0c;需要进行细粒度的标注&#xff0c;同时粗略搜了下已有开源工具基本都集中于图像分割这块&#xff0c…...

保姆级教程:在无网络无显卡的Windows电脑的vscode本地部署deepseek

文章目录 1 前言2 部署流程2.1 准备工作2.2 Ollama2.2.1 使用有网络的电脑下载Ollama2.2.2 安装Ollama&#xff08;有网络的电脑&#xff09;2.2.3 安装Ollama&#xff08;无网络的电脑&#xff09;2.2.4 安装验证2.2.5 修改大模型安装位置2.2.6 下载Deepseek模型 2.3 将deepse…...