【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 Security简介、使用与最佳实践

《SpringSecurity简介、使用与最佳实践》SpringSecurity是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架,本文给大家介绍SpringSec... 目录一、如何理解 Spring Security?—— 核心思想二、如何在 Java 项目中使用?——

防止Linux rm命令误操作的多场景防护方案与实践

《防止Linuxrm命令误操作的多场景防护方案与实践》在Linux系统中,rm命令是删除文件和目录的高效工具,但一旦误操作,如执行rm-rf/或rm-rf/*,极易导致系统数据灾难,本文针对不同场景... 目录引言理解 rm 命令及误操作风险rm 命令基础常见误操作案例防护方案使用 rm编程 别名及安全删除

C++统计函数执行时间的最佳实践

《C++统计函数执行时间的最佳实践》在软件开发过程中,性能分析是优化程序的重要环节,了解函数的执行时间分布对于识别性能瓶颈至关重要,本文将分享一个C++函数执行时间统计工具,希望对大家有所帮助... 目录前言工具特性核心设计1. 数据结构设计2. 单例模式管理器3. RAII自动计时使用方法基本用法高级用法

PHP应用中处理限流和API节流的最佳实践

《PHP应用中处理限流和API节流的最佳实践》限流和API节流对于确保Web应用程序的可靠性、安全性和可扩展性至关重要,本文将详细介绍PHP应用中处理限流和API节流的最佳实践,下面就来和小编一起学习... 目录限流的重要性在 php 中实施限流的最佳实践使用集中式存储进行状态管理(如 Redis)采用滑动

ShardingProxy读写分离之原理、配置与实践过程

《ShardingProxy读写分离之原理、配置与实践过程》ShardingProxy是ApacheShardingSphere的数据库中间件,通过三层架构实现读写分离,解决高并发场景下数据库性能瓶... 目录一、ShardingProxy技术定位与读写分离核心价值1.1 技术定位1.2 读写分离核心价值二

深入浅出Spring中的@Autowired自动注入的工作原理及实践应用

《深入浅出Spring中的@Autowired自动注入的工作原理及实践应用》在Spring框架的学习旅程中,@Autowired无疑是一个高频出现却又让初学者头疼的注解,它看似简单,却蕴含着Sprin... 目录深入浅出Spring中的@Autowired:自动注入的奥秘什么是依赖注入?@Autowired

MySQL分库分表的实践示例

《MySQL分库分表的实践示例》MySQL分库分表适用于数据量大或并发压力高的场景,核心技术包括水平/垂直分片和分库,需应对分布式事务、跨库查询等挑战,通过中间件和解决方案实现,最佳实践为合理策略、备... 目录一、分库分表的触发条件1.1 数据量阈值1.2 并发压力二、分库分表的核心技术模块2.1 水平分

Python与MySQL实现数据库实时同步的详细步骤

《Python与MySQL实现数据库实时同步的详细步骤》在日常开发中,数据同步是一项常见的需求,本篇文章将使用Python和MySQL来实现数据库实时同步,我们将围绕数据变更捕获、数据处理和数据写入这... 目录前言摘要概述:数据同步方案1. 基本思路2. mysql Binlog 简介实现步骤与代码示例1

基于C#实现PDF转图片的详细教程

《基于C#实现PDF转图片的详细教程》在数字化办公场景中,PDF文件的可视化处理需求日益增长,本文将围绕Spire.PDFfor.NET这一工具,详解如何通过C#将PDF转换为JPG、PNG等主流图片... 目录引言一、组件部署二、快速入门:PDF 转图片的核心 C# 代码三、分辨率设置 - 清晰度的决定因

Java中HashMap的用法详细介绍

《Java中HashMap的用法详细介绍》JavaHashMap是一种高效的数据结构,用于存储键值对,它是基于哈希表实现的,提供快速的插入、删除和查找操作,:本文主要介绍Java中HashMap... 目录一.HashMap1.基本概念2.底层数据结构:3.HashCode和equals方法为什么重写Has