当前位置: 首页 > 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.lryc.cn/news/626256.html

相关文章:

  • JVM垃圾回收(GC)深度解析:原理、调优与问题排查
  • 算法——快速幂
  • 猫头虎AI分享|字节开源了一款具备长期记忆能力的多模态智能体:M3-Agent 下载、安装、配置、部署教程
  • Python 与 VS Code 结合操作指南
  • 深入理解抽象类
  • css过渡属性
  • 从繁琐到优雅:Java Lambda 表达式全解析与实战指南
  • 05高级语言逻辑结构到汇编语言之逻辑结构转换 while (...) {...} 结构
  • 实现Johnson SU分布的参数计算和优化过程
  • Windows系统维护,核心要点与解决方案
  • 行业分析---领跑汽车2025第二季度财报
  • 基于决策树模型的汽车价格预测分析
  • 中科米堆CASAIM自动化三维测量设备测量汽车壳体直径尺寸
  • 浅看架构理论(二)
  • 【habitat学习二】Habitat-Lab 快速入门指南(Quickstart)详解
  • python每日学习14:pandas库的用法
  • MySQL 从入门到精通 11:触发器
  • noetic版本/ubuntu20 通过moveit控制真实机械臂
  • 基于单片机智能手环/健康手环/老人健康监测
  • Kubernetes 的 YAML 配置文件-apiVersion
  • 【AI】算法环境-显卡、GPU、Cuda、NVCC和cuDNN的区别与联系
  • Redis-缓存-击穿-分布式锁
  • ZooKeeper 一致性模型解析:线性一致性与顺序一致性的平衡
  • ISIS高级特性
  • Linux下编译ARPACK
  • 基于提示词工程和MCP构建垂直Agent应用
  • 《P1550 [USACO08OCT] Watering Hole G》
  • Apache Doris 4.0 AI 能力揭秘(一):AI 函数之 LLM 函数介绍
  • uniapp 5+App项目,在android studio模拟器上运行调试
  • 大数据数据库 —— 初见loTDB