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

08.5【C++ 初阶】实现一个相对完整的日期类--附带源码

文章目录

  • 前言
  • 分析
  • Date.h
  • Date.cpp
  • 一些测试代码:(main.cpp)
  • 全文总结


前言

本文是对之前学习知识的小小总结实践。


分析

功能分析:

  • 日期类简单的记录我们的日期时间,包括年、月、日
  • 支持日期类对象之间的拷贝赋值
  • 两日期类对象相减得到天数差
  • 日期类对象减特定天数得到新日期
  • 日期类对象支持cout打印
  • 日期类对象支持cin输入赋值
  • 日期类对象之间的各种相互比较的运算符
  • 日期类对象的自增、自减
  • 获得日期类对象某年某月的有多少天
  • 简单打印日志类时间
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);//其他的一些重载,TODO..//简单打印日期类时间void Print() const;//日期类之间比较的运算符bool operator<(const Date& x) const;bool operator==(const Date& x) const;bool operator<=(const Date& x) const;bool operator>(const Date& x) const;bool operator>=(const Date& x) const;bool operator!=(const Date& x) const;int GetMonthDay(int year, int month);// 日期类加天数运算符Date& operator+=(int day);Date operator+(int day) const;Date& operator-=(int day);Date operator-(int day) const;//日期类自增自减Date& operator++();Date operator++(int);Date& operator--();Date operator--(int);//日期类减日期类的天数差int operator-(const Date& d) const;
private:int _year;int _month;int _day;
};ostream& operator<<(ostream& out, const Date& d);
istream& operator>>(istream& in, Date& d);

我们实现的是一个简单的日期类,它的不涉及资源的管理,所以一些资源拷贝、复制、销毁的关键成员函数,像:析构、拷贝、赋值重载,我们都无需手动实现,而是交给编译器自动生成,自动生成的浅拷贝已经可以满足。

我们需要手动写的,就是特定的初始化方式,即构造函数,还有一些日期之间的常见运算对应的运算符重载。我们就采用类声明定义分离的方式去实现。


Date.h

#include<iostream>
#include<cassert>
using std::ostream;
using std::istream;
using std::cout;
using std::cin;
using std::endl;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);//其他的一些重载,TODO..//简单打印日期类时间void Print() const;//日期类之间比较的运算符bool operator<(const Date& x) const;bool operator==(const Date& x) const;bool operator<=(const Date& x) const;bool operator>(const Date& x) const;bool operator>=(const Date& x) const;bool operator!=(const Date& x) const;int GetMonthDay(int year, int month);// 日期类加天数运算符Date& operator+=(int day);Date operator+(int day) const;Date& operator-=(int day);Date operator-(int day) const;//日期类自增自减Date& operator++();Date operator++(int);Date& operator--();Date operator--(int);//日期类减日期类的天数差int operator-(const Date& d) const;   //日期减日期也并不会修改对象本身的值,所以加上const禁止函数内部修改本身的值.
private:int _year;int _month;int _day;
};ostream& operator<<(ostream& out, const Date& d);
istream& operator>>(istream& in, Date& d);

Date.cpp

#include"Date.h"//实现一下构造出对象需求的基本成员函数.
Date::Date(int year, int month, int day)
{//首先我们需要判断日期的合法性.也因此,我们并不将赋初值的操作放在初始化列表.if ((month > 0 && month <= 12) && (day > 0 && day <= GetMonthDay(year, month)))   //根据不同年份,2月的天数略有差距,所以写一个函数,更好的判断我们的日期天数,当给的数值合法,我们才正常的构造.{_year = year;_month = month;_day = day;}else{cout << "非法日期:" << "year=" << year << ", month=" << month << ", day=" << day << endl;assert(false);}
}int Date::GetMonthDay(int year, int month)
{int DayArr[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };int day = DayArr[month];if (month == 2 && ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0))  //如果是2月并且是闰年,那么将天数加一.{day++;}return day;
}//早早写出打印的函数,可以阶段性的测试我们的代码正确性.
void Date::Print() const
{cout << "该对象数据:" << "_year=" << _year << ", _month=" << _month << ", _day=" << _day << endl;
}//2.然后先实现operator==和operator<,为什么?---后面的运算符重载可以复用逻辑.
bool Date::operator==(const Date& x) const      //首先这个函数逻辑的内部不可以去改动内部的变量,其次我们的传入用作比较的Date对象也不可以被改动,所以均是const的.
{//if (x._day == _day && x._month == _month && x._year == _year)//{//	return true;//}//return false;return x._day == _day && x._month == _month && x._year == _year;
}bool Date::operator<(const Date& x) const      //同样,这个函数逻辑的内部不可以去改动内部的变量,其次我们的传入用作比较的Date对象也不可以被改动,所以均是const的.
{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;
}//3.然后复用已经实现的逻辑,去实现其他的一些运算符重载.
bool Date::operator<=(const Date& x) const
{//if (*this < x || *this == x) return true;//return false;return *this < x || *this == x;
}bool Date::operator>(const Date& x) const
{return !(*this <= x);
}bool Date::operator>=(const Date& x) const
{return !(*this < x);
}bool Date::operator!=(const Date& x) const
{return !(*this == x);
}//4.然后实现日期类加天数的运算符重载函数
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 > 12){_month = 1;_year++;}}return *this;   //为什么要返回它自己?  --  因为+=的逻辑本身就是自己去加.
}Date Date::operator+(int day) const
{Date tmp(*this);     //这里是用拷贝构造去创建出一个临时的对象,至于为什么我们没有实现还有拷贝构造,因为浅拷贝使用编译器自动生成的就完全够用.tmp += day;return tmp;      //这里又为什么要重新构造一个临时变量去返回?  --  因为+本来就是创造一个临时变量,像1 + 1,如果我们不用一个变量去接住它,那么答案2我们是拿不到的,//这种运算符重载的灵活体现,更加加深了我们类的抽象程度,使得其更加贴近内置类型.
}Date& Date::operator-=(int day)
{if (day < 0)    //同样如果减等于一个负数,相当与加该负数的绝对值.{return *this += (-day);}_day -= day;while(_day <= 0){_month--;//_day += GetMonthDay(_year, _month);           //放在这里是错的,因为有可能减到0,减到0,访问的日期就是0.if (_month == 0){_month = 12;_year--;}_day += GetMonthDay(_year, _month);}return *this;
}Date Date::operator-(int day) const
{Date tmp(*this);tmp -= day;return tmp;
}//5.然后实现一些自增自减运算符.
Date& Date::operator++()
{*this += 1;return *this;       //	前置++表达式的返回值,是++之后的值,所以返回的是对象自己(引用).
}
Date Date::operator++(int) // 后置++,这个 int参数只用于编译器区分类型,不用于任何实际操作。
// 在函数内部,你不需要使用这个参数(通常省略其名字以避免未使用参数的警告)。编译器在遇到 obj++时,会自动传递一个 0(或其他任意整数值)给这个虚拟参数。
{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;
}//6.然后实现日期类减日期类的天数差
int Date::operator-(const Date& d) const
{Date max = *this;Date min = d;int flag = 1;if (*this < d){max = d;min = *this;flag = -1;}int n = 0;while (max != min){n++;min++;}return n * flag;
}//7.让我们的类支持<<和>>.
ostream& operator<<(ostream& out, const Date& d)
{out << "该对象数据:" << "_year=" << d._year << ", _month=" << d._month << ", _day=" << d._day << endl;return out;         //为什么重载之后还需要返回out呢?因为有这种使用场景:  cout << d << "你好兄弟";   就相当于: (cout << d) << "你好兄弟";
}
istream& operator>>(istream& in, Date& d)
{int year, month, day;in >> year >> month >> day;if ((month > 0 && month <= 12) && (day > 0 && day <= d.GetMonthDay(year, month)))   //根据不同年份,2月的天数略有差距,所以写一个函数,更好的判断我们的日期天数,当给的数值合法,我们才正常的构造.{d._year = year;d._month = month;d._day = day;}else{cout << "非法日期:" << "year=" << year << ", month=" << month << ", day=" << day << endl;assert(false);}return in;
}

一些测试代码:(main.cpp)


#include"Date.h"//测试构造函数的逻辑正确性
void test()
{Date d(1901, 12, 1);//Date d1(1901, 2, 29);Date d2(2000, 2, 29);Date d3(2000, 2, 29);d.Print();//d1.Print();d2.Print();}//测试operator==和operator<
void test1()
{Date d(1901, 12, 1);//Date d1(1901, 2, 29);Date d2(2000, 2, 29);Date d3(2000, 2, 29);cout << (d2 == d3);cout << (d2 < d3);cout << (d < d3);
}//测试其他运算符重载函数
void test2()
{Date d(1901, 12, 1);//Date d1(1901, 2, 29);Date d2(2000, 2, 29);Date d3(2000, 2, 29);cout << (d2 < d3);cout << (d2 <= d3);cout << (d > d3);cout << (d >= d3);cout << (d != d3);
}//测试我们日期类加天数的运算符重载函数
void test3()
{Date d(1901, 12, 1);d.Print();Date d1 = d + 100;d1.Print();Date d2 = d - 100;d2.Print();d.Print();d += 666;d.Print();d -= 666;d.Print();//d -= 654;   //测试_year的逻辑对不对.//d.Print();//d -= 654;//d.Print();//d -= 654;//d.Print();
}//测试自增自减的功能
void test4()
{Date d(1901, 12, 1);d.Print();Date d1;d1.Print();d1 = d++;d1.Print();d1 = d--;d1.Print();d1 = ++d;d1.Print();d1 = --d;d1.Print();
}//测试日期类减日期类的天数差的功能.
void test5()
{Date d(1901, 12, 1);Date d1(2000, 2, 29);cout << d1 - d << endl;cout << d - d1 << endl;
}//测试我们类适配的cin和cout.
void test6()
{Date d(1901, 12, 1);cout << d;cin >> d;cout << d;//该对象数据:_year=1901, _month=12, _day=1//2000 12 25//该对象数据:_year = 2000, _month = 12, _day = 25
}int main()
{test6();return 0;
}

全文总结

实践简单类,知行合一有益身体健康。


本文章为作者的笔记和心得记录,顺便进行知识分享,有任何错误请评论指点:)。

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

相关文章:

  • implement libtime on Windows
  • MyCAT基础概念
  • Python函数总结
  • week2-[一维数组]最大元素
  • 单细胞格式转换 rds 转成 h5ad
  • transformer模型初理解
  • Transformer、BERT、BEiT等模型相关八股及代码【自用】
  • HJ4 字符串分隔
  • 神经网络训练过程详解
  • 电流采样实现方法
  • JavaScript 代码保护与混淆
  • Vue2+Vue3前端开发_Day1
  • 端口映射原理操作详解教程:实现外网访问内网服务,本地路由器端口映射公网ip和软件端口映射域名2种方法
  • Qwen2.5-vl源码解读系列:LLM的Embedding层
  • MySQL常用函数
  • 首届机器人足球运动会技术复盘:从赛场表现看智能机器人核心技术突破
  • Wireshark获取数据传输的码元速率
  • 中科米堆CASAIM提供机加工件来料自动化测量尺寸方案
  • Origin绘制气泡图|科研论文图表教程(附数据格式模板)
  • 【HarmonyOS】H5 实现在浏览器中正常跳转 AppLinking 至应用
  • Java基础 8.19
  • 基于SpringBoot的停车场管理系统【2026最新】
  • C文件/Linux内核级文件理解
  • 软考网工选择题-1
  • 路由器详解
  • Windows 8.1 补丁 KB2919355 安装方法 详细步骤
  • 【Netty4核心原理⑫】【异步处理双子星 Future 与 Promise】
  • 【AI】算法环境-显卡、GPU、Cuda、NVCC和cuDNN的区别与联系
  • Stimulsoft 发布 2025.3 版本:支持在报表计算中解释运行 C# 脚本
  • Apache ShenYu网关与Nacos的关联及如何配合使用