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

【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本身变化了,因此最后返回a


	if (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本身变化了,因此最后返回a


	if (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;
}

💗感谢阅读!💗



http://www.kler.cn/news/285337.html

相关文章:

  • linux 9系统分区扩容
  • 【Mybatis】Web中的数据库操作
  • laravel-admin的select联动首次加载
  • 【云原生kubernetes系列之SkyWalking篇】
  • 数组,集合流式互转
  • Android架构组件:MVVM模式的实战应用与数据绑定技巧|Android架构|MVVM模式|数据绑定
  • Python的VSCode配置
  • Mybatis的XML文件中<if>标签内的判断语句equals的坑
  • k8s在mac和linux下的安装步骤
  • 怎么才能快速提升网站在谷歌的收录?
  • SpringBoot下调用kettle脚本
  • Code Practice Journal | Day59-60_Graph09 最短路径(待更)
  • 麦穗检测计数-目标检测数据集(包括VOC格式、YOLO格式)
  • 【Qt】Spacer
  • 二叉树的前序遍历(LeetCode)
  • 深度学习_数据读取到model模型存储
  • 华为云征文|初识Flexus云服务X实例和参数配置,finalShell远程连接,安装MySQL并配置和远程访问
  • 2024-如何在低版本Mac OS安装合适的xcode-详细的技术篇
  • Spring Cloud全解析:网关之GateWay过滤器
  • QT:详解信号和槽
  • 相机坐标系转换世界坐标系,zedimudepth
  • 【C++ 第十八章】C++11 新增语法(4)
  • BMC lighttpd kvm数据分析(websocket)
  • 【Qt笔记】QCommandLinkButton控件详解
  • Unity编辑器扩展之Scene视图扩展
  • Windows Edge浏览器对Web Authentication API的支持分析与实践应用
  • 音频处理新纪元:深入探索PyTorch的torchaudio
  • vue新建按钮弹出选框
  • 【第0004页 · 递归】生成括号对
  • 缓存Mybatis一级缓存与二级缓存