【C++】类与对象的项目实践 — 日期管理工具

在这里插入图片描述

类与对象的实践

  • 项目背景
  • 项目需求
  • 项目实现
    • 1 日期结构设计
    • 2 构造函数
      • 2.1 全缺省构造函数
      • 2.2 拷贝构造函数
      • 2.3 析构函数
    • 3 赋值运算符重载
      • 3.1 =重载
      • 3.2 += 重载
      • +重载
      • 前置++ 和 后置++
    • 4 关系操作符重载
    • 5 工具方法
      • 5.1 计算日期差
      • 5.2 日期转换为字符串
      • 5.3 通过字符串构建对象
  • 完整源代码
    • Date.h
    • Date.cpp
  • Thanks♪(・ω・)ノ谢谢阅读!!!
  • 下一篇文章见!!!

根据我们对C++特性的学习,我们现在可以尝试下一些新玩法,来强化我们对C++的理解。

项目背景

在现代的软件开发中,日期作为一个常见的基础需求,广泛用于各类系统的日程管理,数据分析,交易记录等场景。但是C++库中的时间日期功能比较有限,无法满足复杂的开发需求。为此我们需要开发一款简单高效的“日期类”C++项目。
![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/9f15918ab9814067a9aba1dd289090b4.png

项目需求

  1. 日期结构设计:我们需要实现一个名为“Date”的C++自定义类型,包含年(_year),月(_month),日(_day)。并相应提供构造函数,析构函数,拷贝复制函数等函数。
  2. 日期运算方法:实现日期的加减运算,支持用户通过增加或减少年、月、日来实现新的日期对象。同时,提供比较两个日期大小的方法,包括< 、>、 ==、 <= 、>= 、!=等关系操作符的重载。
  3. 日期有效性检查:Date类需要实现对日期有效性的严格检查,确保月份正常,保证闰年的判断,符合各个月份的实际天数。
  4. 日期格式转换:提供将Date对象转换为“XXXX—YY—ZZ”的方法,同时也支持从标准“XXXX—YY—ZZ”字符串中解析创建Date对象。
  5. 实用工具方法:提供获取当前日期,判断是否为闰年,计算两个日期的天数差等功能。

以上就是该项目的基本需求,请务必确保程序的健壮性与可维护性。

项目实现

1 日期结构设计

该部分我们给出以下框架:

class Date{public:// 获取某年某月的天数int GetMonthDay(int year, int month);//展示日期void show();// 全缺省的构造函数Date(int year = 1900, int month = 1, int day = 1);// 拷贝构造函数// d2(d1)Date(const Date& d);// 析构函数~Date();//---------------------------------------------------------------// 赋值运算符重载// d2 = d3 -> d2.operator=(&d2, d3)Date& operator=(const Date& d);// 日期+=天数Date& operator+=(int day);// 日期+天数Date operator+(int day);// 日期-天数Date operator-(int day);// 日期-=天数Date& operator-=(int day);// 前置++Date& operator++();// 后置++Date operator++(int);// 后置--Date operator--(int);// 前置--Date& operator--();//-------------------------------------------------------------// >运算符重载bool operator>(const Date& d);// ==运算符重载bool operator==(const Date& d);// >=运算符重载bool operator >= (const Date& d);// <运算符重载bool operator < (const Date& d);// <=运算符重载bool operator <= (const Date& d);// !=运算符重载bool operator != (const Date& d);// 日期-日期 返回天数int operator-(const Date& d);//-----------------------------------------------// 转换为字符串“ YYYY-MM-DD ”string toString() const;//通过字符串构建对象static Date fromString(const string& dateStr);private:int _year;int _month;int _day;};

这里给出较为全面的框架:

  1. 成员变量:私有成员变量 _year、_month 和 _day 分别表示年份、月份和日期。

  2. 构造函数:
    全缺省构造函数,默认日期为1900年1月1日。
    拷贝构造函数,复制给定日期对象的所有信息。

  3. 赋值运算符重载 (operator=):用于拷贝另一个Date对象的日期信息到当前对象。

  4. 算术运算符重载:
    += 和 -= 运算符用于日期增加或减少指定天数。
    +和 - 运算符分别用于返回增加或减少指定天数后的日期对象,以及两个日期之间的天数差。

  5. 自增/自减运算符重载:
    前缀和后缀形式的 ++ 与 – 运算符,用于向前或向后移动一天。

  6. 关系运算符重载:
    <、>、>=、<= 和 == 分别用于比较两个日期的大小关系。
    != 判断两个日期是否不相等。

  7. 方法:
    show() 用于输出日期。
    GetMonthDay() 根据年份和月份获取该月的天数,考虑了闰年的特殊情况。

  8. 析构函数:
    简单地将日期成员变量设为0,但在实际应用中这通常不是必要的,因为类的生命周期结束后,系统会自动释放其占用的内存资源。

下面我们逐一实现功能:

2 构造函数

2.1 全缺省构造函数

首先我们需要提供一个全缺省的构造函数,方便对象的实例化。
这里我们提供默认的(1900 -1- 1)作为缺省值

Date::Date(int year , int month , int day ) {_year = year;_month = month;_day = day;
}

2.2 拷贝构造函数

然后我们还需要一个拷贝构造函数,让我们更加灵活的创建对象

Date::Date(const Date& d) {_year = d._year;_month = d._month;_day = d._day;
}

2.3 析构函数

析构函数简单一写即可,因为我们没有开辟空间,不需要考虑复杂问题。

3 赋值运算符重载

这里我们需要实现:
= + - += -= 前置++ 后置++ 前置-- 后置–
加和减原理类似,讲解中只以加为例,详细代码请看结尾全部代码。

3.1 =重载

注意返回值类型,这里传回引用,效率更好。

Date& Date::operator=(const Date& d) {_year = d._year;_month = d._month;_day = d._day;//灵活使用this指针return *this;
}

3.2 += 重载

这里我们先实现+= 之后再实现+,这样可以避免多次创建变量,效率更高。
首先对于+= 我们需要准确知道该月的月份,保证日期的有效性。

int Date::GetMonthDay(int year, int month) {int day[13] = { 0,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;}return day[month];
}

完成+=重载

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

+重载

实现了+=之后我们就好实现+了
注意这里不能传回引用 , 这里是临时变量,传引用会导致错误。

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

前置++ 和 后置++

前置后置这里使用了不同参数来做区分。不得感叹祖师爷的巧妙。

//前置++
Date& Date::operator++() {
//直接返回+=后答案即可return *this += 1;
}
//后置++ 不能传引用
Date Date::operator++(int) {
//创建一个临时变量来储存 ++前的值Date temp(*this);*this += 1;//返回++前的值return temp;
}

4 关系操作符重载

这里十分巧妙,我们只需要实现== > 即可通过巧妙使用完成全部操作符重载:

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

5 工具方法

5.1 计算日期差

这里使用朴素算法,逐渐++到较大日期即可即可

//注意正负
int Date::operator-(const Date& d) {//默认前值大int flag = 1;Date max = *this;Date min = d;if (max < min) {flag = -1;max = d;min = *this;}int day = 0;while (min != max){min++;day++;}return flag * day;
}

5.2 日期转换为字符串

使用库函数轻松实现:

string Date::toString() const {char buffer[11]; // 预留足够的空间存储 "YYYY-MM-DD"snprintf(buffer, sizeof(buffer), "%04d-%02d-%02d", _year, _month, _day);return string(buffer);
}

5.3 通过字符串构建对象

这一步比较复杂:
首先在声明中加入static 保证可以随时调用。
然后需要保证日期的合法性
最后返回类对象

static Date fromString(const string& dateStr);Date Date::fromString(const std::string& dateStr) {int year = 0, month = 0, day= 0;sscanf(dateStr.c_str(), "%d-%d-%d", &year, &month, &day); // 使用sscanf解析字符串Date d(year,month,day);// 在这里应该添加必要的日期合法性检查if (month < 1 || month > 12) {throw std::invalid_argument("月份错误\n");}int maxDays = d.GetMonthDay(year, month);if (day < 1 || day > maxDays) {throw std::invalid_argument("给定月份和年份的日期值无效\n");}return Date(year, month, day);
}

完整源代码

Date.h

#pragma once#include<iostream>
using namespace std;
class Date{public:// 获取某年某月的天数int GetMonthDay(int year, int month);//展示日期void show();// 全缺省的构造函数Date(int year = 1900, int month = 1, int day = 1);// 拷贝构造函数// d2(d1)Date(const Date& d);// 析构函数~Date();// 赋值运算符重载// d2 = d3 -> d2.operator=(&d2, d3)Date& operator=(const Date& d);// 日期+=天数Date& operator+=(int day);// 日期+天数Date operator+(int day);// 日期-天数Date operator-(int day);// 日期-=天数Date& operator-=(int day);// 前置++Date& operator++();// 后置++Date operator++(int);// 后置--Date operator--(int);// 前置--Date& operator--();// >运算符重载bool operator>(const Date& d);// ==运算符重载bool operator==(const Date& d);// >=运算符重载bool operator >= (const Date& d);// <运算符重载bool operator < (const Date& d);// <=运算符重载bool operator <= (const Date& d);// !=运算符重载bool operator != (const Date& d);// 日期-日期 返回天数int operator-(const Date& d);// 转换为字符串“ YYYY-MM-DD ”string toString() const;static Date fromString(const string& dateStr);private:int _year;int _month;int _day;};

Date.cpp

#include"Date.h"void Date::show() {printf("%4d 年 %2d 月 %2d 日\n",_year,_month,_day);
}int Date::GetMonthDay(int year, int month) {int day[13] = { 0,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;}return day[month];
}Date::Date(int year , int month , int day ) {_year = year;_month = month;_day = day;
}Date::Date(const Date& d) {_year = d._year;_month = d._month;_day = d._day;
}Date::~Date() {_year = 0;_month = 0;_day = 0;
}Date& Date::operator+=(int day) {_day += day;while (_day > GetMonthDay(_year, _month)) {_day -= GetMonthDay(_year, _month);_month++;if (_month > 12) {_year++;_month = 1;}}return *this;
}Date& Date::operator=(const Date& d) {_year = d._year;_month = d._month;_day = d._day;return *this;
}Date Date::operator+(int day) {Date temp(*this);temp += day;return temp;
}Date& Date::operator-=(int day) {_day -= day;while (_day < 0) {_month--;if (_month < 1) {_year--;_month = 12;}_day += GetMonthDay(_year,_month);}return *this;
}Date Date::operator-(int day) {Date temp(day);temp -= day;return temp;
}Date& Date::operator++() {return *this += 1;
}Date Date::operator++(int) {Date temp(*this);*this += 1;return temp;
}Date& Date::operator--() {return *this -= 1;
}Date Date::operator--(int) {Date temp(*this);*this -= 1;return temp;
}bool Date::operator==(const Date& d) {return d._year == _year && d._month == _month && d._day == _day;
}bool Date::operator>(const Date& d) {if (_year < d._year) return false;else if (_month < d._month) return false;else if (_day < d._day) return false;else return true;}bool Date::operator >= (const Date& d) {return *this > d || *this == d;
}bool Date::operator < (const Date& d) {return !(*this >= d);
}bool Date::operator <= (const Date& d) {return !(*this > d);
}bool Date::operator != (const Date& d) {return !(*this == d);
}int Date::operator-(const Date& d) {Date max = *this;Date min = d;int flag = 1;if (max < min) {flag = -1;max = d;min = *this;}int day = 0;while (min != max){min++;day++;}return flag * day;
}string Date::toString() const {char buffer[11]; // 预留足够的空间存储 "YYYY-MM-DD"snprintf(buffer, sizeof(buffer), "%04d-%02d-%02d", _year, _month, _day);return string(buffer);
}Date Date::fromString(const std::string& dateStr) {int year = 0, month = 0, day= 0;sscanf(dateStr.c_str(), "%d-%d-%d", &year, &month, &day); // 使用sscanf解析字符串Date d(year,month,day);// 在这里应该添加必要的日期合法性检查if (month < 1 || month > 12) {throw std::invalid_argument("月份错误\n");}int maxDays = d.GetMonthDay(year, month);if (day < 1 || day > maxDays) {throw std::invalid_argument("给定月份和年份的日期值无效\n");}return Date(year, month, day);
}

Thanks♪(・ω・)ノ谢谢阅读!!!

下一篇文章见!!!

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

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

相关文章

云数贸云生活中心:用云生活理念引领社会和谐发展

在数字经济的浪潮下&#xff0c;云数贸云生活中心不仅在科技进步与文明程度上作出了积极贡献&#xff0c;更在推动社会和谐、承担企业社会责任方面展现出了模范作用。通过与“草根互助爱心社区”的紧密合作&#xff0c;云数贸云生活中心正致力于构建一个更加和谐、互助的社会环…

socket通信 smallchat简介

文章目录 前言一、socket的基本操作(1) socket()函数(2) bind()函数(3) listen()、connect()函数(4) accept()函数(5) read()、write()等函数(6) close()函数 二、smallchat代码流程smallchat-server.csmallchat-client.cchatlib.c 参考资料 前言 本文介绍了socket通信的相关A…

六、图像的几何变换

文章目录 前言一、镜像变换二、缩放变换 前言 在计算机视觉中&#xff0c;图像几何变换是指对图像进行平移、旋转、缩放、仿射变换和镜像变换等操作&#xff0c;以改变图像的位置、尺寸、形状或视角&#xff0c;而不改变图像的内容。这些变换在图像处理、模式识别、机器人视觉…

更改WordPress作者存档链接author和用户名插件Change Author Link Structure

WordPress作者存档链接默认情况为/author/Administrator&#xff08;用户名&#xff09;&#xff0c;为了防止用户名泄露&#xff0c;我们可以将其改为/author/1&#xff08;用户ID&#xff09;&#xff0c;具体操作可参考『如何将WordPress作者存档链接中的用户名改为昵称或ID…

猪圈Pigsty-PG私有RDS集群搭建教程

博客 https://songxwn.com/Pigsty-PG-RDS/ 简介 Pigsty 是一个更好的本地自建且开源 RDS for PostgreSQL 替代&#xff0c;具有以下特点&#xff1a; 开箱即用的 PostgreSQL 发行版&#xff0c;深度整合地理、时序、分布式、图、向量、分词、AI等 150 余个扩展插件&#xff…

文件IO的lseek以及目录IO

文件IO之 lseek: 1. lseek off_t lseek(int fd, off_t offset, int whence); 功能: 重新设定文件描述符的偏移量 参数: fd:文件描述符 offset:偏移量 whence: SEEK_SET 文件开头 …

基于scrapy框架的单机爬虫与分布式爬虫

我们知道&#xff0c;对于scrapy框架来说&#xff0c;不仅可以单机构建复杂的爬虫项目&#xff0c;还可以通过简单的修改&#xff0c;将单机版爬虫改为分布式的&#xff0c;大大提高爬取效率。下面我就以一个简单的爬虫案例&#xff0c;介绍一下如何构建一个单机版的爬虫&#…

更快找到远程/自由工作的网站

不要使用Fiver或Upwork。 它们已经饱和了。 下面是10个更快找到远程/自由工作的网站&#xff1a; 1. Toptal 这个网站专门为熟练的自由职业者提供远程工作机会&#xff0c;如Shopify和Priceline等一流公司。 他们只接受软件开发、设计和金融等领域的顶级3%自由职业者。 htt…

2024-02-19(Flume)

1.flume中拦截器的作用&#xff1a;个人认为就是修改或者删除事件中的信息&#xff08;处理一下事件&#xff09;。 2.一些拦截器 Host Interceptor&#xff0c;Timestamp Interceptor&#xff0c;Static Interceptor&#xff0c;UUID Interceptor&#xff0c;Search and Rep…

C++集群聊天服务器 nginx+redis安装 笔记 (中)

一、nginx安装 nginx: download 下载nginx安装包 hehedalinux:~/package$ tar -zvxf nginx-1.24.0.tar.gz nginx-1.24.0/ nginx-1.24.0/auto/ nginx-1.24.0/conf/ nginx-1.24.0/contrib/ nginx-1.24.0/src/ nginx-1.24.0/configure nginx-1.24.0/LICENSE nginx-1.24.0/README…

PLC远程监控在制药行业的应用

PLC远程监控在制药行业的应用 制药行业是一个需要高度控制和精确性的行业&#xff0c;而PLC远程监控技术正是这种需求的完美解决方案。PLC远程监控技术是指将传感器、执行器和其他设备连接到PLC系统中&#xff0c;并使用网络和远程访问技术实现对设备的远程监控和控制。下面我…

HarmonyOS4.0系统性深入开发34栅格布局(GridRow/GridCol)

栅格布局&#xff08;GridRow/GridCol&#xff09; 概述 栅格布局是一种通用的辅助定位工具&#xff0c;对移动设备的界面设计有较好的借鉴作用。主要优势包括&#xff1a; 提供可循的规律&#xff1a;栅格布局可以为布局提供规律性的结构&#xff0c;解决多尺寸多设备的动态…

NAS系统折腾记 | TinyMediaManager刮削电影海报

搭建好了NAS系统和Emby Media Server&#xff0c;接下来就是怎样对下载好的电影/电视剧集等内容进行刮削来展示电影海报墙获得更好的效果了。实际上&#xff0c;Emby Server本身就内置了强大的元数据抓取功能&#xff0c;能够自动从互联网上抓取电影、电视剧的元数据和海报等信…

论UI的糟糕设计:以百度网盘为例

上面这一排鼠标一经过就会弹出来&#xff08;不是点才弹出来&#xff09;&#xff0c;然后挡住你的各种操作&#xff0c; 弹出来时你就必须等它消失&#xff0c;卡一下才能操作。 在用户顺畅地操作内容时&#xff0c;经常就卡一下、卡一下、卡一下…… 1、比如鼠标从下到上&am…

基于YOLOv7算法和Widerface数据集的高精度实时人脸检测系统(PyTorch+Pyside6+YOLOv7)

摘要&#xff1a;基于YOLOv7算法和Widerface数据集的高精度实时人脸检测系统可用于日常生活中检测与定位人脸目标&#xff0c;此系统可完成对输入图片、视频、文件夹以及摄像头方式的目标检测与识别&#xff0c;同时本系统还支持检测结果可视化与导出。本系统采用YOLOv7目标检测…

【springboot+vue项目(十五)】基于Oauth2的SSO单点登录(二)vue-element-admin框架改造整合Oauth2.0

Vue-element-admin 是一个基于 Vue.js 和 Element UI 的后台管理系统框架&#xff0c;提供了丰富的组件和功能&#xff0c;可以帮助开发者快速搭建现代化的后台管理系统。 一、基本知识 &#xff08;一&#xff09;Vue-element-admin 的主要文件和目录 vue-element-admin/ |…

如何确定分库还是 分表?

分库分表 分库分表使用的场景不一样&#xff1a; 分表因为数据量比较大&#xff0c;导致事务执行缓慢&#xff1b;分库是因为单库的性能无法满足要求。 分片策略 1、垂直拆分 水平拆分 3 范围分片&#xff08;range&#xff09; 垂直水平拆分 4 如何解决数据查询问题&a…

【Jvm】性能调优(拓展)Jprofiler如何监控和解决死锁、内存泄露问题

文章目录 Jprofiler简介1.安装及IDEA集成Jprofiler2.如何监控并解决死锁3.如何监控及解决内存泄露(重点)4.总结5.后话 Jprofiler简介 Jprofilers是针对Java开发的性能分析工具(免费试用10天), 可以对Java程序的内存,CPU,线程,GC,锁等进行监控和分析, 1.安装及IDEA集成Jprofil…

车载软件架构 —— Adaptive AUTOSAR软件架构中时间同步、网络管理和软件更新策略

车载软件架构 —— Adaptive AUTOSAR软件架构中时间同步、网络管理和软件更新策略 我是穿拖鞋的汉子&#xff0c;魔都中坚持长期主义的汽车电子工程师&#xff08;Wechat&#xff1a;gongkenan2013&#xff09;。 老规矩&#xff0c;分享一段喜欢的文字&#xff0c;避免自己成…