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

C++之日期类的实现

C++之日期类Date的实现

  • 一、引言
  • 二、日期类核心功能概述
  • 三、日期类的具体实现
    • Date.h
    • Date.cpp
    • Test.cpp
  • 四、日期类的实现结果
  • 五、日期类的系统测试

一、引言

在 C++ 面向对象编程的学习路径中,“日期类(Date C#lass)” 是绕不开的经典实践案例。它不像数据结构那样需要复杂的逻辑设计,却完美契合了面向对象的核心思想 ——封装、复用与抽象,同时还能让开发者深入理解运算符重载、构造函数有效性检查、成员函数设计等关键技术点。
日常生活中,日期的计算无处不在:从日程管理 App 的 “距离截止日还有 X 天”,到金融系统的 “存款计息天数计算”,再到考勤系统的 “月度工作日统计”,背后都离不开对日期合法性校验、日期增减、日期差值计算等核心操作的支持。如果直接用零散的函数处理这些逻辑,不仅代码冗余度高,还容易出现 “日期越界”“闰年判断错误” 等隐蔽 Bug。
而一个设计良好的日期类,能将 “年、月、日” 这组关联数据与 “日期校验、加减、比较” 等操作封装成一个独立的模块,既保证了数据的安全性(通过访问控制隐藏内部细节),又让代码具备极高的复用性 —— 无论在哪个项目中需要处理日期,直接实例化日期类即可调用现成的接口。本文将基于一份完整的日期类实现代码,拆解其设计思路与技术细节,帮助读者掌握面向对象编程中 “类设计” 的核心方法。

二、日期类核心功能概述

本文的日期类代码围绕 “日期的合法性管理” 与 “日期的运算操作” 两大核心需求展开,覆盖了日常开发中 90% 以上的日期处理场景。其核心功能可划分为以下 4 个模块,每个模块都对应明确的业务需求与技术实现:

功能模块核心需求具体实现(成员 / 全局函数)
日期合法性校验确保初始化 / 输入的日期有效(如 2 月不超过 29 天、月份不超过 12)1. 构造函数:初始化时校验日期合法性 2. operator>>:输入时校验日期合法性 3. GetMonthDay:获取当月天数(含闰年判断)
日期比较运算判断两个日期的大小关系(如 “2024-05-20” 是否早于 “2024-06-01”)1. operator<:小于 2. operator==:等于 3. 复用上述两个函数实现<=/>/>=/!=
日期增减运算计算 “日期 + N 天”“日期 - N 天”,或实现日期的自增 / 自减1. 带天数增减:operator+=/operator+、operator-=/operator- 2. 自增自减:前置++/ 后置++、前置–/ 后置–
日期差值计算计算两个日期之间的天数差(如 “2024-01-01” 到 “2024-01-10” 相差 9 天)operator-(参数为const Date&,返回 int 类型天数)
日期 IO 操作支持用cout输出日期、用cin输入日期(符合 C++ 流操作习惯)1. 全局函数operator<<:流插入(输出)2. 全局函数operator>>:流提取(输入)

从设计逻辑上看,该日期类遵循了 “最小功能复用” 原则 —— 例如operator<=直接复用operator<和operator==的逻辑,operator+复用operator+=的逻辑,既减少了代码冗余,又避免了重复开发带来的 Bug。同时,通过static修饰daysArry(月份天数数组),让该数组仅在程序启动时初始化一次,提升了GetMonthDay函数的调用效率,这些细节都体现了 “高效、健壮” 的类设计思路。

三、日期类的具体实现

Date.h

#pragma once
#include <iostream>
using namespace std;
class Date
{friend ostream& operator<<(ostream& out, const Date& d);//对象访问私有 友元函数 不能写在类里面friend istream& operator>>(istream& in, Date& d);
public:Date(int year = 1, int month = 1, int day = 1);//构造函数//Date& operator=(const Date& d)//赋值重载//{//	_year = d._year;//	_month = d._month;//	_day = d._day;//	return *this;//}//Date(const Date& d)//拷贝构造//{//	_year = d._year;//	_month = d._month;//	_day = d._day;//}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);//声明,重载运算符“!=”static int GetMonthDay(int year, int month);//子函数,获取一年多少天 static静态的在类外边也能调用了//2023年12月是2024年1月Date& operator+=(int day);//计算日期加天数后的值Date operator+(int day);//计算加某天后的日期(但不能改变自己)Date& operator++();//前置++Date operator++(int);//后置++Date& operator-=(int day);//计算日期减天数后的值Date operator-(int day);//计算减某天后的日期(但不能改变自己)Date& operator--();//前置--Date operator--(int);//后置--int operator-(const Date& d);//现在的天数减过去的天数//void operator<<(ostream& out);  //函数重载支持自动识别类型 错误的,因为流插入不能写成成员函数 d1 << cout不符合习惯void Print() const  //const修饰的是*this  成员函数后面加const以后,普通和const对象都可以调{cout << _year << "-" << _month << "-" << _day << endl;}
private:int _year;int _month;int _day;
};ostream& operator<<(ostream& out, const Date& d);//全局函数 cout << d1即d1.operator<<(cout)
istream& operator>>(istream& in, Date& d);//流提取

Date.h这段代码是C++日期类(Date)的头文件定义,通过封装年、月、日私有成员,声明了构造函数、日期比较(<、==、>等)、增减运算(+=、+、++等)、天数差计算等成员函数,同时借助友元函数实现了流输入输出(<<、>>),形成了完整的日期类接口设计。

Date.cpp

#include "Date.h"//Date::Date(int year, int month, int day)//构造函数, 声明和定义分离,声明给参数
//{
//	_year = year;
//	_month = month;
//	_day = day;
//}
// 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)//获取某一年某一月的天数
{static int daysArry[] = { 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)))//判断月份是2月时是否是闰年{return 29;}return daysArry[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;//*this = *this + day;//return *this; 复用“operator+”函数 
}Date Date::operator+(int day)//计算日期加天数,但不改变自己  tmp出作用域销毁不能用&返回
{Date tmp(*this);//拷贝构造一个自己,默认拷贝构造系统默认生成tmp += day; //复用“operator+=”函数/*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++()//前置++
{*this += 1;return *this;
}Date Date::operator++(int)//后置++  加int不是为了接收具体的值,仅仅为了占位和前置++构成重载
{Date temp = *this;*this += 1;return temp;
}Date& Date::operator-=(int day)//计算日期减天数后的值
{if (day < 0){return *this += -day;}_day -= day;while (_day <= 0){--_month;if (_month == 0){_month == 12;--_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;
}Date Date::operator--(int)//后置--
{Date temp = *this;*this -= 1;return temp;
}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;}ostream& operator<<(ostream& out, const Date& d)  //流插入 全局函数
{out << d._year << "年" << d._month << "月" << d._day << "日" << endl;return out;
}istream& operator>>(istream& in, Date& d)
{int year, month, day;in >> year >> month >> day;if (month > 0 && month < 13 && day > 0 && day <= Date::GetMonthDay(year, month)){d._year = year;d._month = month;d._day = day;}else{cout << "非法日期" << endl;}return in;
}

Date.cpp这段代码是日期类(Date)的实现文件,实现了头文件中声明的构造函数(含日期合法性校验)、各类运算符重载(比较、增减、自增自减、日期差值计算等)、获取月份天数函数,以及流输入输出的友元函数,完成了日期类的核心功能逻辑。

Test.cpp

#include "Date.h"void Test()
{Date d1(2025,9,29);d1 += 100;d1.Print();Date d2(2025, 9, 29);d2.Print();//Date d3(d2+100);Date d3 = d2 + 100; //拷贝构造,因为d3刚开始不存在d3.Print();++d1;d1.Print();d1++;d1.Print();d1 -= -20;d1.Print();d2 += -20;d2.Print();d3--;d3.Print();cout << d3 - d2 << endl;//d1 << cout; //d1.operator<<(out);cout << d2;cout << d2 << d1; //先返回d2 在返回d1 因此返回类型用ostream&cin >> d1;cout << d1;Date d4(2025, 4, 78);cout << d4;
}int main()
{Test();return 0; 
}

Test.cpp这段代码是日期类(Date)的测试代码,通过定义Test函数创建多个Date对象,调用日期增减(+=、-=)、自增自减(++、–)、日期差值计算、流输入输出等方法,验证日期类的各项功能,并在main函数中执行测试。

四、日期类的实现结果

在这里插入图片描述

五、日期类的系统测试

#include "Date.h"  
// 测试函数:验证日期类各项功能,所有测试用例均使用合法日期
void Test()
{// 1. 测试日期 += 运算(2025年9月29日加100天,结果为2026年1月6日,均为合法日期)Date d1(2025, 9, 29);  // 初始日期合法(9月有30天,29日有效)d1 += 100;d1.Print();  // 输出结果:2026-1-6// 2. 测试默认构造与打印(初始日期合法)Date d2(2025, 9, 29);  // 与d1初始日期一致,合法d2.Print();  // 输出结果:2025-9-29// 3. 测试日期 + 运算(不改变原对象d2,结果合法)Date d3 = d2 + 100;  // d2+100为2026年1月6日,拷贝构造d3(合法)d3.Print();  // 输出结果:2026-1-6// 4. 测试前置++与后置++(日期自增1天,均合法)++d1;  // d1从2026-1-6变为2026-1-7(合法)d1.Print();  // 输出结果:2026-1-7d1++;  // d1从2026-1-7变为2026-1-8(合法)d1.Print();  // 输出结果:2026-1-8// 5. 测试日期 -= 负数(等价于 += 正数,日期合法)d1 -= -20;  // 等价于d1 +=20,2026-1-8加20天为2026-1-28(1月有31天,合法)d1.Print();  // 输出结果:2026-1-28d2 += -20;  // 等价于d2 -=20,2025-9-29减20天为2025-9-9(合法)d2.Print();  // 输出结果:2025-9-9// 6. 测试后置--(日期自减1天,合法)d3--;  // d3从2026-1-6变为2026-1-5(合法)d3.Print();  // 输出结果:2026-1-5// 7. 测试两个日期差值计算(d3=2026-1-5,d2=2025-9-9,差值为119天)cout << d3 - d2 << endl;  // 输出结果:119// 8. 测试流插入运算符<<(输出合法日期)cout << d2;  // 输出结果:2025年9月9日cout << d2 << d1;  // 依次输出:2025年9月9日、2026年1月28日// 9. 测试流提取运算符>>(手动输入合法日期,示例输入:2024 12 31)cout << "请输入合法日期(格式:年 月 日):";cin >> d1;  // 输入合法日期(如2024 12 31),d1更新为该日期cout << d1;  // 输出输入的合法日期// 10. 测试构造函数合法性校验(使用合法日期初始化,无报错)Date d4(2025, 4, 30);  // 4月有30天,30日为合法日期(原代码4月78日修正为4月30日)cout << d4;  // 输出结果:2025年4月30日
}int main()
{Test();  // 执行所有测试用例return 0;
}

运行结果
在这里插入图片描述

写在最后:日期类的实现是 C++ 面向对象编程学习中极具代表性的实践。从类的封装、构造函数的合法性校验,到各类运算符的重载,每一个环节都紧密围绕面向对象的核心思想展开。通过对日期类的编写与测试,我们不仅掌握了对象创建、成员函数设计等基础技能,更深入理解了运算符重载在简化代码逻辑、提升代码可读性方面的关键作用。它是一座桥梁,帮助我们从对面向对象概念的初步认知,迈向更灵活、更高效的代码编写实践,为后续复杂类的设计与开发筑牢了根基。希望小伙伴们能够动动发财的小手,亲自实现一个日期类代码喔~ 编程就是在不断实操中提升,只有亲手敲代码,才能真正把知识变成自己的技能,在解决问题的过程里收获成长(ง •_•)ง
在这里插入图片描述

http://www.dtcms.com/a/457300.html

相关文章:

  • 构建AI智能体:五十七、LangGraph + Gradio:构建可视化AI工作流的趣味指南
  • Create/Assemble/Link x64 Windows
  • 网站建设与管理案例教程第三版答案中国货源大全网
  • 织梦建网站建设收费网站
  • Delphi字段值含有空格
  • 【第五章:计算机视觉-项目实战之生成式算法实战:扩散模型】2.CV黑科技:生成式算法理论-(3)经典扩散模型DDPM算法流程讲解
  • 牛客算法_哈希
  • Product Hunt 每日热榜 | 2025-10-08
  • 重庆建站公司官网国外有名的网站
  • 【论文阅读】Visual Planning: Let’s Think Only with Images
  • 河南教育平台网站建设为中小型企业构建网站
  • 开放指令编辑创新突破!小米开源 Lego-Edit 登顶 SOTA:用强化学习为 MLLM 编辑开辟全新赛道!
  • Vue 与 React 深度对比:底层原理、开发体验与实际性能
  • 平台网站建设协议电话网站域名到期
  • Spring Gateway 全面解析:从入门到进阶实践​
  • 江西九江网站建设注册登记
  • 建个微网站多少钱tv网站建设
  • Docker 说明与安装
  • Docker 镜像结构与相关核心知识总结
  • 容器技术与 Docker 入门部署
  • linux学习笔记(20)线程
  • Vue3后台表单快速开发
  • 前端技术栈 —— 创建React项目
  • 推荐一个 GitHub 开源项目信息卡片生成工具,支持Docker快速部署和API调用
  • 元宇宙的工业制造应用:重构生产、研发与供应链
  • 做美足网站违法吗北京网站建设哪家比较好
  • 2025版本的idea解决Git冲突
  • 深入浅出 HarmonyOS ArkTS:现代跨平台应用开发的语法基石
  • Spring boot 3.0整合RocketMQ不兼容的问题
  • 淮安制作企业网站莱芜金点子最新招聘