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

【C++】日期类的实现

在上篇博客中我们已经学习了C++中的运算符重载,我们说,操作符只能对于内置类型进行操作,对自定义类型我们需要自己定义函数去实现一系列的操作
那么这篇博客我们就专门把日期这个类单独拿出来写一下它都有哪些有意义的可以重载的运算符,这个函数我们要放到类里面为了访问私有的成员变量,但是函数声明和定义可以分到两个文件中写,只需要标识一下它属于哪个类就行。还有我们之前说过的一点,缺省参数只能声明给,定义不用给,因为编译器怕你给的不一样。
下面一个类当中首先是成员变量年月日我就不说了,下面是构造函数,我们就写一个全缺省的函数,默认不传参数年月日都是一,但是我们要判断传过来的数字是否合法,不合法要做出提醒,可以assert断言,也可以就打印一下。

//声明
Date(int year = 1, int month = 1, int day = 1);
//定义
Date::Date(int year, int month , int day ) {_year = year;_month = month;_day = day;if (_year < 1 || _month < 1 || _month>12 || _day<1 || _day>GetMonthDay(_year, _month)) {cout << _year << "年" << _month << "月" << _day << "日";cout << "日期非法" << endl;}
}

下面比较两个日期的大小和是否相等其实逻辑就比较简单了,写上一个后边的直接赋用就行
比如说

bool Date:: operator==(const Date& n) {return _year == n._year && _month == n._month && _day == n._day;
}bool Date::operator!=(const Date& n) {return !(*this == n);
}

写了等于那么不等于不就是它的相反嘛
下面的大于小于也是同理

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

下面是加减运算,首先日期加日期是没有意义的,但是日期加减天数是有意义的,这个该如何去加减呢?我们可以先把天数加到年月日的日数上,如果合法就不用动了,如果多余本月的该有的天数就进位到月上。为了方便就得有一个得到该年该月的天数的一个函数

int Date :: GetMonthDay(int year, int month) {assert(year >= 1 && month >= 1 && month <= 12);int monthArray[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };if ((month == 2) && (((year % 400) == 0) || ((year % 4) == 0 && (year % 100) != 0))) {return 29;}return monthArray[month];
}

下边就是日期加减一个天数

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

我们先看第一种情况,加等其实是不需要进行拷贝的,而加则需要拷贝两次。第二种情况,加要拷贝两次,而加等要拷贝三次,所以我们可以看出第一种情况更好一些
我们这里的加等还有一个问题,如果我们写的是加等一个负数或者说减等一个负数时就会有问题,这时就会有问题,我们只需要转到相反的就行了,就类似这样:

Date& Date:: operator-=(int day) {if (day < 0) {return *this -= (-day);}

下面就是++了,但是++有前置,有后置,这时我们就规定后置++要在形参上写上一个int,写别的不行

Date& Date::operator++() {*this += 1;return *this;
}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) {int flag = -1;Date min = *this;Date max = d;if (*this > d) {min = d;max = *this;flag = 1;}int n = 0;while (min < max) {++min;++n;}return n*flag;
}

要想效率更高些就要整年整年的加,后面的零碎的天数就从1月1日开始数,大的日期就加上,小的日期就减去

int Date::operator-(const Date& d) {int flag = 1;Date max = *this;Date min = d;if (*this < d) {max = d;min = *this;flag = -1;}int n = 0;int y = min._year;while (y != max._year) {if (y % 4 == 0 && y % 100 != 0 || y % 400 == 0) {n += 366;}else {n += 365;}y++;}int m1 = 1;int m2 = 1;while (m1 < max._month) {n += GetMonthDay(max._year, m1);m1++;}while (m2 < min._month) {n -= GetMonthDay(min._year, m2);m2++;}n = n + max._day - min._day;return n;
}

下面是Date.h中所有代码


#include<iostream>
#include<assert.h>
using namespace std;
class Date {
public:Date(int year = 1, int month = 1, int day = 1);void Print();int GetMonthDay(int year, int month);bool operator==(const Date& n);bool operator!=(const Date& n);bool operator<(const Date& n);bool operator<=(const Date& n);bool operator>(const Date& n);bool operator>=(const Date& n);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;
};

Date.cpp文件中的代码

#include"Date.h"
Date::Date(int year, int month , int day ) {_year = year;_month = month;_day = day;if (_year < 1 || _month < 1 || _month>12 || _day<1 || _day>GetMonthDay(_year, _month)) {cout << _year << "年" << _month << "月" << _day << "日";cout << "日期非法" << endl;}
}void Date::Print() {cout << _year << "年" << _month << "月" << _day << "日" << endl;
}int Date :: GetMonthDay(int year, int month) {assert(year >= 1 && month >= 1 && month <= 12);int monthArray[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };if ((month == 2) && (((year % 400) == 0) || ((year % 4) == 0 && (year % 100) != 0))) {return 29;}return monthArray[month];
}bool Date:: operator==(const Date& n) {return _year == n._year && _month == n._month && _day == n._day;
}bool Date::operator!=(const Date& n) {return !(*this == n);
}bool Date:: operator<(const Date& n) {if (_year < n._year) {return true;}if (_year == n._year && _month < n._month) {return true;}if (_year == n._year && _month == n._month && _day < n._day) {return true;}return false;
}bool Date::operator<=(const Date& n) {return ((*this < n) || (*this == n));
}bool Date::operator>(const Date& n) {return !(*this <= n);
}bool Date:: operator>=(const Date& n) {//return *this > n || *this == n;return !(*this < n);
}Date& Date:: operator+=(int day) {if (day < 0) {return *this -= (-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;return tmp;
}Date& Date:: operator-=(int day) {if (day < 0) {return *this -= (-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-(int day) {Date tmp(*this);tmp -= day;return tmp;
}Date& Date::operator++() {*this += 1;return *this;
}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) {
//	int flag = -1;
//	Date min = *this;
//	Date max = d;
//	if (*this > d) {
//		min = d;
//		max = *this;
//		flag = 1;
//	}
//	int n = 0;
//	while (min < max) {
//		++min;
//		++n;
//	}
//	return n*flag;
//}
int Date::operator-(const Date& d) {int flag = 1;Date max = *this;Date min = d;if (*this < d) {max = d;min = *this;flag = -1;}int n = 0;int y = min._year;while (y != max._year) {if (y % 4 == 0 && y % 100 != 0 || y % 400 == 0) {n += 366;}else {n += 365;}y++;}int m1 = 1;int m2 = 1;while (m1 < max._month) {n += GetMonthDay(max._year, m1);m1++;}while (m2 < min._month) {n -= GetMonthDay(min._year, m2);m2++;}n = n + max._day - min._day;return n;
}

相关文章:

【C++】日期类的实现

在上篇博客中我们已经学习了C中的运算符重载&#xff0c;我们说&#xff0c;操作符只能对于内置类型进行操作&#xff0c;对自定义类型我们需要自己定义函数去实现一系列的操作 那么这篇博客我们就专门把日期这个类单独拿出来写一下它都有哪些有意义的可以重载的运算符&#xf…...

带残差连接的ResNet18

目录 1 模型构建 1.1 残差单元 1.2 残差网络的整体结构 2 没有残差连接的ResNet18 2.1 模型训练 2.2 模型评价 3 带残差连接的ResNet18 3.1 模型训练 3.2 模型评价 4 与高层API实现版本的对比实验 总结 残差网络&#xff08;Residual Network&#xff0c;ResNet&#xff09;…...

【深入解析git和gdb:版本控制与调试利器的终极指南】

【本节目标】 1. 掌握简单gdb使用于调试 2. 学习 git 命令行的简单操作, 能够将代码上传到 Github 上 1.Linux调试器-gdb使用 1.1.背景 程序的发布方式有两种&#xff0c;debug模式和release模式release模式不可被调试&#xff0c;debug模式可被调试Linux gcc/g出来的二进制…...

CGAN原理讲解与源码

1.CGAN原理 生成器&#xff0c;输入的是c和z&#xff0c;z是随机噪声&#xff0c;c是条件&#xff0c;对应MNIST数据集&#xff0c;要求规定生成数字是几。 输出是生成的虚假图片。 生成器生成的图片被判别器认为是真实图片&#xff0c;那么标签就是1 其实判别器模型输出的是…...

C#实体类与XML互转以及List和DataTable转XML的使用

引言 在C#开发中&#xff0c;数据的存储和传输是非常常见的需求。使用XML作为数据格式有很多优点&#xff0c;例如可读性强、易于解析等。而实体类、List和DataTable是表示数据模型的常用方式。本文将介绍如何在C#中实现实体类、List和DataTable与XML之间的相互转换&#xff0c…...

uniapp的vue3的模版的setup函数内使用uniapp内置方法

vue2使用方式直接在method同级使用就行,但是在vue3的setup函数内直接使用会报错,本人找了好久,发现vue3需要导入uniapp模块才能使用,具体如下 使用uniapp上拉加载更多方法 <script>import {onReachBottom} from dcloudio/uni-apponReachBottom(() > {console.log(&qu…...

UI自动化的基本知识

一、UI自动化测试介绍 1、什么是自动化测试 概念&#xff1a;由程序代替人工进行系统校验的过程 1.1自动化测试能解决的问题&#xff1f; 回归测试 (冒烟测试) 针对之前老的功能进行测试 通过自动化的代码来实现。 针对上一个版本的问题的回归 兼容性测试 web实例化不同的浏…...

python实现C++简易自动压行

突发奇想&#xff0c;想要将自己的c压行之后交上去。但是苦于手动压行效率太低&#xff0c;在网上搜索压行网站没有找到&#xff0c;突然发现压行不就是检查检查去个换行符吗。于是心血来潮&#xff0c;用python实现了一个简易压行程序。 首先&#xff0c;宏定义等带#的文件不…...

京东数据分析(京东大数据采集):2023年线上珍珠市场销售数据采集

在珠宝首饰市场&#xff0c;从黄金到钻石&#xff0c;如今年轻人的新风潮又转向了珍珠。珍珠热潮并非刚刚兴起&#xff0c;早在前两年&#xff0c;抖音、快手等短视频台的珍珠开蚌直播内容&#xff0c;就掀起了一波珍珠热潮。 此后&#xff0c;随着珍珠饰品被越来越多社交平台的…...

亚信科技AntDB数据库与库瀚存储方案完成兼容性互认证

近日&#xff0c;亚信科技AntDB数据库与苏州库瀚信息科技有限公司自主研发的RISC-V数据库存储解决方案进行了产品兼容测试。经过双方团队的严格测试&#xff0c;亚信科技AntDB数据库与库瀚数据库存储解决方案完全兼容、运行稳定。除高可用性测试外&#xff0c;双方进一步开展TP…...

现代C++之万能引用、完美转发、引用折叠

现代C之万能引用、完美转发、引用折叠 0.导语1.问题引入2.引入万能引用3.万能引用出现场合4.理解左值与右值4.1 精简版4.2 完整版4.3 生命周期延长4.4 生命周期延长应用5.区分万能引用6.表达式的左右值性与类型无关7.引用折叠和完美转发7.1 引用折叠之本质细节7.2 示例与使用7.…...

ELK日志收集系统-filbeat

filebeat日志收集工具 elk&#xff1a;filebeat日志收集工具和logstash相同 filebeat是一个轻量级的日志收集工具&#xff0c;所使用的系统资源比logstash部署和启动时使用的资源要小的多 filebeat可以运行在非Java环境&#xff0c;它可以代理logstash在非java环境上收集日志…...

Python小知识

个人学习笔记&#xff0c;用于记录使用过程中好用的技巧、好用的库。 1 小知识 1.1 相对路径 1.2 打包Exe文件 命令&#xff1a; pyinstaller -F main.py其中-F&#xff1a;覆盖之前打包的文件 mian.py&#xff1a;需要打包的Python文件 PS&#xff1a;使用pyinstaller 5.1…...

如何在Ubuntu系统上安装Redis

Redis的下载 Redis安装包分为windows版和Linux版当前示例中介绍的是Linux版本Linux的下载地址&#xff1a;Index of /releases/ (redis.io)本次下载的压缩包为&#xff1a;redis-6.2.14.tar.gzRedis的安装 将压缩包通过ssh远程工具上传到Linux服务器中解压压缩包 tar -zxvf red…...

Vue2问题:如何全局使用less和sass变量?

前端功能问题系列文章&#xff0c;点击上方合集↑ 序言 大家好&#xff0c;我是大澈&#xff01; 本文约2400字&#xff0c;整篇阅读大约需要4分钟。 本文主要内容分三部分&#xff0c;如果您只需要解决问题&#xff0c;请阅读第一、二部分即可。如果您有更多时间&#xff…...

Java 基础学习(四)操作数组、软件开发管理

1 操作数组 1.1.1 System.arraycopy 方法用于数组复制 当需要将一个数组的元素复制到另一个数组中时&#xff0c;可以使用System.arraycopy方法。它提供了一种高效的方式来复制数组的内容&#xff0c;避免了逐个元素赋值的繁琐过程。相对于使用循环逐个元素赋值的方式&#x…...

git仓库如何撤销提交,恢复提交,重置版本命令

撤销提交&#xff1a; 要撤销最近一次提交&#xff08;未推送到远程仓库&#xff09;&#xff0c;可以使用以下命令&#xff1a; git reset HEAD^该命令将会把最后一次提交的修改从当前主分支中移除&#xff0c;并将这些修改的状态保留在本地工作目录中。 如果想要取消所有的…...

Java 基础学习(三)循环流程控制与数组

1 循环流程控制 1.1 循环流程控制概述 1.1.1 什么是循环流程控制 当一个业务过程需要多次重复执行一个程序单元时&#xff0c;可以使用循环流程控制实现。 Java中包含3种循环结构&#xff1a; 1.2 for循环 1.2.1 for循环基础语法 for循环是最常用的循环流程控制&#xff…...

别太担心,人类只是把一小部分理性和感性放到了AI里

尽管人工智能&#xff08;AI&#xff09;在许多方面已经取得了重大进展&#xff0c;但它仍然无法完全复制人类的理性和感性。AI目前主要侧重于处理逻辑和分析任务&#xff0c;而人类则具有更复杂的思维能力和情感经验。 人类已经成功地将一些可以数据化和程序化的理性和感性特征…...

最新AIGC创作系统ChatGPT系统源码+DALL-E3文生图+图片上传对话识图/支持OpenAI-GPT全模型+国内AI全模型

一、AI创作系统 SparkAi创作系统是基于ChatGPT进行开发的Ai智能问答系统和Midjourney绘画系统&#xff0c;支持OpenAI-GPT全模型国内AI全模型。本期针对源码系统整体测试下来非常完美&#xff0c;可以说SparkAi是目前国内一款的ChatGPT对接OpenAI软件系统。那么如何搭建部署AI…...

在软件开发中正确使用MySQL日期时间类型的深度解析

在日常软件开发场景中&#xff0c;时间信息的存储是底层且核心的需求。从金融交易的精确记账时间、用户操作的行为日志&#xff0c;到供应链系统的物流节点时间戳&#xff0c;时间数据的准确性直接决定业务逻辑的可靠性。MySQL作为主流关系型数据库&#xff0c;其日期时间类型的…...

conda相比python好处

Conda 作为 Python 的环境和包管理工具&#xff0c;相比原生 Python 生态&#xff08;如 pip 虚拟环境&#xff09;有许多独特优势&#xff0c;尤其在多项目管理、依赖处理和跨平台兼容性等方面表现更优。以下是 Conda 的核心好处&#xff1a; 一、一站式环境管理&#xff1a…...

【HarmonyOS 5.0】DevEco Testing:鸿蒙应用质量保障的终极武器

——全方位测试解决方案与代码实战 一、工具定位与核心能力 DevEco Testing是HarmonyOS官方推出的​​一体化测试平台​​&#xff0c;覆盖应用全生命周期测试需求&#xff0c;主要提供五大核心能力&#xff1a; ​​测试类型​​​​检测目标​​​​关键指标​​功能体验基…...

Qt Widget类解析与代码注释

#include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this); }Widget::~Widget() {delete ui; }//解释这串代码&#xff0c;写上注释 当然可以&#xff01;这段代码是 Qt …...

解决Ubuntu22.04 VMware失败的问题 ubuntu入门之二十八

现象1 打开VMware失败 Ubuntu升级之后打开VMware上报需要安装vmmon和vmnet&#xff0c;点击确认后如下提示 最终上报fail 解决方法 内核升级导致&#xff0c;需要在新内核下重新下载编译安装 查看版本 $ vmware -v VMware Workstation 17.5.1 build-23298084$ lsb_release…...

django filter 统计数量 按属性去重

在Django中&#xff0c;如果你想要根据某个属性对查询集进行去重并统计数量&#xff0c;你可以使用values()方法配合annotate()方法来实现。这里有两种常见的方法来完成这个需求&#xff1a; 方法1&#xff1a;使用annotate()和Count 假设你有一个模型Item&#xff0c;并且你想…...

涂鸦T5AI手搓语音、emoji、otto机器人从入门到实战

“&#x1f916;手搓TuyaAI语音指令 &#x1f60d;秒变表情包大师&#xff0c;让萌系Otto机器人&#x1f525;玩出智能新花样&#xff01;开整&#xff01;” &#x1f916; Otto机器人 → 直接点明主体 手搓TuyaAI语音 → 强调 自主编程/自定义 语音控制&#xff08;TuyaAI…...

HarmonyOS运动开发:如何用mpchart绘制运动配速图表

##鸿蒙核心技术##运动开发##Sensor Service Kit&#xff08;传感器服务&#xff09;# 前言 在运动类应用中&#xff0c;运动数据的可视化是提升用户体验的重要环节。通过直观的图表展示运动过程中的关键数据&#xff0c;如配速、距离、卡路里消耗等&#xff0c;用户可以更清晰…...

Java求职者面试指南:计算机基础与源码原理深度解析

Java求职者面试指南&#xff1a;计算机基础与源码原理深度解析 第一轮提问&#xff1a;基础概念问题 1. 请解释什么是进程和线程的区别&#xff1f; 面试官&#xff1a;进程是程序的一次执行过程&#xff0c;是系统进行资源分配和调度的基本单位&#xff1b;而线程是进程中的…...

解析奥地利 XARION激光超声检测系统:无膜光学麦克风 + 无耦合剂的技术协同优势及多元应用

在工业制造领域&#xff0c;无损检测&#xff08;NDT)的精度与效率直接影响产品质量与生产安全。奥地利 XARION开发的激光超声精密检测系统&#xff0c;以非接触式光学麦克风技术为核心&#xff0c;打破传统检测瓶颈&#xff0c;为半导体、航空航天、汽车制造等行业提供了高灵敏…...