【c++】类与对象实践:日期类(运算符重载应用)详细版

2024-09-01 01:44

本文主要是介绍【c++】类与对象实践:日期类(运算符重载应用)详细版,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

 文章专栏:c++学习之路

 持续更新~


目录

一、日期类介绍

二、日期类目标功能

1.日期结构设计

2.实现功能的前提函数

3.必须具备实际意义

三、日期类具体实现

🌷头文件->Date.h

🔥逐步解析

1.成员变量

2.构造函数

3.赋值运算符重载 (operator=)

5.自增/自减运算符重载:

6.关系运算符重载:

7.必备方法:

9.流运算符的重载 >>   和<<

🔥代码展示

🌷功能实现 --> Date.cpp

🔥逐步解析:

1.构造函数

 🍬全缺省构造函数

🍬拷贝构造函数

🍬析构函数

2.必备方法

3.赋值运算符重载

3.加减相关的运算符重载

🍬+=重载

🍬+重载

🍬前置++ 和 后置++

🍬 -=、-、前置--、后置--

4.关系运算符

5.计算日期相差天数

6.流重载操作符

五、完整代码

Date.h

Date.cpp

💗感谢阅读!💗


一、日期类介绍

日期函数是用于处理日期数据的函数,通常包括获取当前日期、计算两个日期差值、日期时间比较、日期时间计算等功能。

日期类就是对以上功能的各种实现!!

通过对日期类的学习,我们可以对类和对象有更进一步的认识,同时灵活掌握运算符重载,实现自定义类型的各种运算,但是这些运算必须具备现实意义

比如,计算两个自定义类型Date 之间的差值,实际意义:两个日期相差多少天

Date d1(2023,2,20); //日期类实例化对象
Date d2(2024,5,10);
d2 - d1; //计算两个自定义类型Date 之间的差值,实际意义:两个日期相差多少天

 完成日期类的实现,必须先对成员函数有一定的概念和理解!!

二、日期类目标功能

1.日期结构设计

自定义类型名称:Date
类的属性:
                int _year;
                int  _month;
                int _day;

必要的构造函数,析构函数,拷贝构造函数

2.实现功能的前提函数

运算符重载函数

  •         < 、>、 ==、 <= 、>= 、!=等关系操作符的重载
  •         前置++、后置++、后置-- 、前置--
  •         加+、加等+=、减-、减等-=  

通过以上重载,可以实现日期的加减运算,增加或减少年、月、日来实现新的日期对象,日期的大小比较等等。

工具函数:

获取每个月的天数

int Date::GetMonthDay(int year, int month) const;

3.必须具备实际意义

Date类需要实现对日期有效性的严格检查,确保月份正常,保证闰年的判断,符合各个月份的实际天数。

比如:

  •         月份要在【1,12】区间之内;
  •         天数根据年份、月份确定。

三、日期类具体实现

🌷头文件->Date.h

🔥逐步解析

1.成员变量

私有成员

//年月日int _year;int _month;int _day;
2.构造函数

全缺省构造函数,默认日期为1年1月1日。
!!注意:缺省值,不能在头文件和接口实现文件中同时存在。

拷贝构造函数,复制给定日期对象的所有信息。

Date(int year = 1, int month = 1, int day = 1);//构造函数 + 全缺省Date(const Date& d);							// 拷贝构造函数
3.赋值运算符重载 (operator=)

用于拷贝另一个Date对象的日期信息到当前对象。

	// 赋值运算符重载// d2 = d3 -> d2.operator=(&d2, d3)Date& operator=(const Date& d);

4.算术运算符重载:

        += 和 -= 运算符用于日期增加或减少指定天数。

        一般都是先实现+= 和-=,然后+和 - 运算符 复用 += 和-=。
        +和 - 运算符分别用于返回增加或减少指定天数后的日期对象,以及两个日期之间的天数差。

Date& operator+=(int day);// 日期+=天数Date operator+(int day);// 日期+天数Date operator-(int day);// 日期-天数Date& operator-=(int day);// 日期-=天数
5.自增/自减运算符重载:


前缀和后缀形式的 ++ 与 - -运算符,用于向前或向后移动一天。
可以复用+=  和 -= ,减少代码量!!

Date& operator++();// 前置++Date operator++(int);// 后置++,有特殊处理 形参  Date operator--(int);// 后置-- ,有特殊处理 形参  Date& operator--();// 前置--
6.关系运算符重载:


<、>、>=、<= 和 == 分别用于比较两个日期的大小关系。
!= 判断两个日期是否不相等。

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);// !=运算符重载
7.必备方法:

 Print() 用于输出日期

GetMonthDay() 根据年份和月份获取该月的天数,考虑了闰年的特殊情况。

8.析构函数:

日期类不存在手动开辟空间的行为,无需再手动析构。

9.流运算符的重载 >>   和<<

两个函数都是全局函数。便于打印自定义类型Date。

为了访问类Date中的私有成员,必须把两个函数设为友元。

ostream& operator<<(ostream& out, const Date& d);
istream& operator>>(istream& in, Date& d);

🔥代码展示

#pragma once
#include<iostream>
using namespace std;//日期类(完结版 + 六个成员函数)//缺省参数,不能声明和定义同时定义class Date
{
public:Date(int year = 1, int month = 1, int day = 1);//构造函数 + 全缺省~Date();										//析构Date(const Date& d);							// 拷贝构造函数void Print();// 获取某年某月的天数int GetMonthDay(int year, int month);// 赋值运算符重载// 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);friend ostream& operator<<(ostream& out, const Date& d);friend istream& operator>>(istream& in, Date& d);private://年月日int _year;int _month;int _day;
};ostream& operator<<(ostream& out, const Date& d);
istream& operator>>(istream& in, Date& d);

🌷功能实现 --> Date.cpp

🔥逐步解析:

1.构造函数

 🍬全缺省构造函数


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

需要注意的是,此时我们已经在头文件Date.h中,构造函数的声明中确定了缺省值!!
因此,在Date.cpp函数定义中,我们就不能再写缺省值!!

第二个注意事项:

日期的定义必须符合现实意义。

Date类需要实现对日期有效性的严格检查,确保月份正常,保证闰年的判断,符合各个月份的实际天数。

比如:

  •         月份要在【1,12】区间之内;
  •         天数根据年份、月份确定。

因此需要对传入的日期进行条件检查!

	//构造函数 + 全缺省
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)){//assert(false);Print();cout << "日期非法" << endl;}
}

🍬拷贝构造函数

拷贝构造函数,让我们更加灵活的创建对象,以及可以传引用返回!提高效率!

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

🍬析构函数

因为我们没有开辟空间,不需要考虑复杂问题。

//析构
Date::~Date()
{}
2.必备方法

便于实现后面的+=、-=

 Print() 用于输出日期

void Date::Print()
{cout << _year << "/" << _month << "/" << _day << endl;
}

GetMonthDay() 根据年份和月份获取该月的天数,考虑了闰年的特殊情况。

// 获取某年某月的天数
int Date::GetMonthDay(int year, int month)
{int dayArr[13] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30,31 };//月份:2月,闰年if (month == 2 && ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0))){return 29;}return dayArr[month];
}
3.赋值运算符重载

返回值:传引用返回,注意this指针需要解引用。

参数类型:const 防止不小心修改参数内容

                   使用引用,提高效率,减少拷贝

函数体: 不要对自己本身进行赋值,直接利用地址相同规避。

// 赋值运算符重载// this = d  
Date& Date::operator=(const Date& d)
{//不对自己赋值//引用返回,直接对左操作数进行修改,减少拷贝if (this != &d){_year = d._year;_month = d._month;_day = d._day;}return *this;
}
3.加减相关的运算符重载

+、 -、 +=、 -=、 前置++、 后置++ 、前置--、 后置–

我们只需要实现+=、-=,然后其他运算符就可以复用 += 、-=来实现,极大节省我们的时间。


🍬+=重载

 日期+=天数

因为是+=,对日期本身进行了修改,所以传引用返回。

// 日期+=天数
// d+= 1000 ---->  d = d+1000,d 的实际内容发生改变
Date& Date::operator+=(int day) 
{// a+=b,a本身变化了,因此最后返回aif (day < 0){return *this -= day;}_day += day;while(_day > GetMonthDay(_year, _month))//天数已经超过当前月份{_day -= GetMonthDay(_year, _month);_month++;if (_month > 12){_year++;_month = 1;}}return *this;
}

🍬+重载

复用+=,可以实现+重载。

d + 1000 ---->  a  = d+1000,d 的实际内容不改变,而是,其他临时变量接收结果。
所以不能传回引用 , 这里是临时变量,函数结束后会自动释放,传引用会导致错误。

// 日期+天数
// d + 1000 ---->  a  = d+1000,d 的实际内容不改变,而是,其他变量接收结果
Date Date::operator+(int day)
{Date temp(*this);temp += day;return temp;
}

🍬前置++ 和 后置++

直接复用+=

为了便于区分前置和后置++,

对于前置++,无参数

对于后置++,设个int形参

// 前置++Date& Date::operator++()
{return *this += 1;
}// 后置++
//先用一个临时变量存储this原先的数值,然后this++,返回临时变量
Date Date::operator++(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 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)
{if (_year == d._year && _month == d._month && _day == d._day){return true;}return false;
}

>重载


// >运算符重载bool Date::operator>(const Date& d)
{if (_year > d._year){return true;}else if (_year == d._year && _month > d._month){return true;}else if (_year == d._year && _month == d._month && _day > d._day){return true;}return false;
}

其他操作符



// >=运算符重载bool Date::operator >= (const Date& d)
{if (*this > d || *this == d){return true;}return false;
}// <运算符重载bool Date::operator < (const Date& d) {if (*this >= d)return false;return true;
}// <=运算符重载bool Date::operator <= (const Date& d) {if (*this > d)return false;return true;
}// !=运算符重载bool Date::operator != (const Date& d) {if (*this == d)return false;return true;
}
5.计算日期相差天数

思想:

找出较小的日期,采用++,利用计数器计算出天数,直到两个日期相等。

那么计数器,就是相差天数!

// 日期-日期 返回天数int Date::operator-(const Date& d) {Date min = *this;Date max = d;if (min > max){swap(min, max);}int day = 0;while (min != max){min++;day++;}return day;
}
6.流重载操作符

需要在类Date的声明中设置为友元!才可以访问私有变量。

ostream& operator<<(ostream& out, const Date& d)
{out << d._year << "年" << d._month << "月" << d._day << "日" << endl;return out;
}istream& operator>>(istream& in, Date& d)
{in >> d._year >> d._month >> d._day;return in;
}

五、完整代码

Date.h

#pragma once
#include<iostream>
using namespace std;//日期类(完结版 + 六个成员函数)//缺省参数,不能声明和定义同时定义class Date
{
public:Date(int year = 1, int month = 1, int day = 1);//构造函数 + 全缺省~Date();										//析构Date(const Date& d);							// 拷贝构造函数void Print();// 获取某年某月的天数int GetMonthDay(int year, int month);// 赋值运算符重载// 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);friend ostream& operator<<(ostream& out, const Date& d);friend istream& operator>>(istream& in, Date& d);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)
{_year = year;_month = month;_day = day;if (_year < 1 ||_month < 1 || _month > 12 ||_day < 1 || _day > GetMonthDay(_year, _month)){//assert(false);Print();cout << "日期非法" << endl;}
}//析构
Date::~Date()
{}
// 拷贝构造函数
Date::Date(const Date& d)
{_year = d._year;_month = d._month;_day = d._day;
} void Date::Print()
{cout << _year << "/" << _month << "/" << _day << endl;
}// 获取某年某月的天数
int Date::GetMonthDay(int year, int month)
{int dayArr[13] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30,31 };//月份:2月,闰年if (month == 2 && ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0))){return 29;}return dayArr[month];
}// 赋值运算符重载// this = d  
Date& Date::operator=(const Date& d)
{//不对自己赋值//引用返回,直接对左操作数进行修改,减少拷贝if (this != &d){_year = d._year;_month = d._month;_day = d._day;}return *this;
}// 日期+=天数
// d+= 1000 ---->  d = d+1000,d 的实际内容发生改变
Date& Date::operator+=(int day) 
{// a+=b,a本身变化了,因此最后返回aif (day < 0){return *this -= day;}_day += day;while(_day > GetMonthDay(_year, _month))//天数已经超过当前月份{_day -= GetMonthDay(_year, _month);_month++;if (_month > 12){_year++;_month = 1;}}return *this;
}// 日期+天数
// d + 1000 ---->  a  = d+1000,d 的实际内容不改变,而是,其他变量接收结果
Date Date::operator+(int day)
{Date temp(*this);temp += day;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 temp(*this);temp -= day;		//复用-=return temp;
}// 前置++Date& Date::operator++()
{return *this += 1;
}// 后置++
//先用一个临时变量存储this原先的数值,然后this++,返回临时变量
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)
{if (_year > d._year){return true;}else if (_year == d._year && _month > d._month){return true;}else if (_year == d._year && _month == d._month && _day > d._day){return true;}return false;
}// ==运算符重载bool Date::operator==(const Date& d)
{if (_year == d._year && _month == d._month && _day == d._day){return true;}return false;
}// >=运算符重载bool Date::operator >= (const Date& d)
{if (*this > d || *this == d){return true;}return false;
}// <运算符重载bool Date::operator < (const Date& d) {if (*this >= d)return false;return true;
}// <=运算符重载bool Date::operator <= (const Date& d) {if (*this > d)return false;return true;
}// !=运算符重载bool Date::operator != (const Date& d) {if (*this == d)return false;return true;
}// 日期-日期 返回天数int Date::operator-(const Date& d) {Date min = *this;Date max = d;if (min > max){swap(min, max);}int day = 0;while (min != max){min++;day++;}return day;
}ostream& operator<<(ostream& out, const Date& d)
{out << d._year << "年" << d._month << "月" << d._day << "日" << endl;return out;
}istream& operator>>(istream& in, Date& d)
{in >> d._year >> d._month >> d._day;return in;
}

💗感谢阅读!💗


这篇关于【c++】类与对象实践:日期类(运算符重载应用)详细版的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1125596

相关文章

Spring Boot @RestControllerAdvice全局异常处理最佳实践

《SpringBoot@RestControllerAdvice全局异常处理最佳实践》本文详解SpringBoot中通过@RestControllerAdvice实现全局异常处理,强调代码复用、统... 目录前言一、为什么要使用全局异常处理?二、核心注解解析1. @RestControllerAdvice2

Python设置Cookie永不超时的详细指南

《Python设置Cookie永不超时的详细指南》Cookie是一种存储在用户浏览器中的小型数据片段,用于记录用户的登录状态、偏好设置等信息,下面小编就来和大家详细讲讲Python如何设置Cookie... 目录一、Cookie的作用与重要性二、Cookie过期的原因三、实现Cookie永不超时的方法(一)

Spring事务传播机制最佳实践

《Spring事务传播机制最佳实践》Spring的事务传播机制为我们提供了优雅的解决方案,本文将带您深入理解这一机制,掌握不同场景下的最佳实践,感兴趣的朋友一起看看吧... 目录1. 什么是事务传播行为2. Spring支持的七种事务传播行为2.1 REQUIRED(默认)2.2 SUPPORTS2

Python实现对阿里云OSS对象存储的操作详解

《Python实现对阿里云OSS对象存储的操作详解》这篇文章主要为大家详细介绍了Python实现对阿里云OSS对象存储的操作相关知识,包括连接,上传,下载,列举等功能,感兴趣的小伙伴可以了解下... 目录一、直接使用代码二、详细使用1. 环境准备2. 初始化配置3. bucket配置创建4. 文件上传到os

Java中的雪花算法Snowflake解析与实践技巧

《Java中的雪花算法Snowflake解析与实践技巧》本文解析了雪花算法的原理、Java实现及生产实践,涵盖ID结构、位运算技巧、时钟回拨处理、WorkerId分配等关键点,并探讨了百度UidGen... 目录一、雪花算法核心原理1.1 算法起源1.2 ID结构详解1.3 核心特性二、Java实现解析2.

SpringBoot整合liteflow的详细过程

《SpringBoot整合liteflow的详细过程》:本文主要介绍SpringBoot整合liteflow的详细过程,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋...  liteflow 是什么? 能做什么?总之一句话:能帮你规范写代码逻辑 ,编排并解耦业务逻辑,代码

Python中re模块结合正则表达式的实际应用案例

《Python中re模块结合正则表达式的实际应用案例》Python中的re模块是用于处理正则表达式的强大工具,正则表达式是一种用来匹配字符串的模式,它可以在文本中搜索和匹配特定的字符串模式,这篇文章主... 目录前言re模块常用函数一、查看文本中是否包含 A 或 B 字符串二、替换多个关键词为统一格式三、提

从入门到精通C++11 <chrono> 库特性

《从入门到精通C++11<chrono>库特性》chrono库是C++11中一个非常强大和实用的库,它为时间处理提供了丰富的功能和类型安全的接口,通过本文的介绍,我们了解了chrono库的基本概念... 目录一、引言1.1 为什么需要<chrono>库1.2<chrono>库的基本概念二、时间段(Durat

C++20管道运算符的实现示例

《C++20管道运算符的实现示例》本文简要介绍C++20管道运算符的使用与实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 目录标准库的管道运算符使用自己实现类似的管道运算符我们不打算介绍太多,因为它实际属于c++20最为重要的

Java MQTT实战应用

《JavaMQTT实战应用》本文详解MQTT协议,涵盖其发布/订阅机制、低功耗高效特性、三种服务质量等级(QoS0/1/2),以及客户端、代理、主题的核心概念,最后提供Linux部署教程、Sprin... 目录一、MQTT协议二、MQTT优点三、三种服务质量等级四、客户端、代理、主题1. 客户端(Clien