【C++语言】Date类的代码实现(操作符重载运用)

news2025/2/25 2:35:14

在这里插入图片描述


文章目录

  • 前言
  • Date类的构思
  • Date类的相关实现
    • 基本框架(默认成员函数)
    • 计算n天前\后的日期
    • 补充:前置++、后置++说明
    • 判断两个日期的关系(大于,小于等);
    • 可以计算两个日期之间相差多少天
    • 补充:流输入以及流提取操作符实现:
  • 总结
  • C++语言系列学习目录


前言

在上一章节中,我们学习了类和对象的一些内容,包括:类的相关特征、类的默认成员函数、以及操作符重载(重点)。本节就综合前面的相关内容,实现一个Date类。


Date类的构思

我们设想的Date类包括以下操作:

  1. 可以计算n天前\后的日期(+、-、+=、-=等);
  2. 判断两个日期的关系(大于,小于等);
  3. 可以计算两个日期之间相差多少天;

Date类的相关实现

基本框架(默认成员函数)

因为Date类型比较简单,属性只有内置类型,所以大部分默认成员函数就可以满足需求。

class Date
{
public:
	//构造函数:全缺省的默认构造函数,但需要判断合法性,所以需要自己定义
	Date::Date(int year, int month, int day)
	{
		if (month > 0 && month < 13
			&& day > 0 && day <= GetMonthDay(year, month))
		{
			_year = year;
			_month = month;
			_day = day;
		}
		else
		{
			cout << "非法日期" << endl;
			assert(false);
		}
	}
	//拷贝构造函数:Date类属性全是内置类型,可以不写拷贝构造
	
	//赋值运算符重载:Date类属性全是内置类型,赋值运算符重载也可以不用写
	
	//析构函数:Date类属性全是内置类型,赋值运算符重载也不用写
private:
	int _year;
	int _month;
	int _day;
};

计算n天前\后的日期

计算n天后基本思路:
日期加上天数,天数相加,判断是否超出当月的日期天数(循环判断),若超出,则月数进1,同时判断月数是否等于13,若等于则再向年进1,月变回1月;

设计流程:

  1. GetMonthDay()获得当月的天数;
  2. Date Date::operator # (int day) const (#代表多种运算符重载);

1.GetMonthDay()
功能:传入年和月,得出该月的天数。
参数:(int year, int month)
返回:int (天数)

注意:方法一般设置在头文件之外,头文件(Date.h)声明函数方法,(Date.cpp)实现方法,因此方法前需要加入Date::类域

int Date::GetMonthDay(int year, int month)
{
	//静态设置每月天数,二月需要判断是否为闰年得出
	//之所以静态,是减少频繁创造过程的损失
	static int daysArr[13] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; 
	//if (((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)) && month == 2) 
	//不太好,应当容易简单判断的条件放在&&前,优化
	if (month == 2 && ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)))
	{
		return 29;
	}
	else
	{
		return daysArr[month];
	}
}
  1. Date Date::operator+=(int day) (+=运算符重载);
    功能:实现Date类和int整形相加,并且直接修改该对象;
    参数: (int day)
    返回: Date&
Date& Date::operator+=(int day)
{
	if (day < 0) //考虑我们输入的day是负数
	{
		return *this -= -day;
	}

	_day += day;
	while (_day > GetMonthDay(_year, _month))
	{
		_day -= GetMonthDay(_year, _month);
		++_month;
		if (_month == 13)
		{
			++_year;
			_month = 1;
		}
	}

	return *this;
}
  1. Date Date::operator+(int day) const (+运算符重载);
    功能:实现Date类和int整形相加,返回最终日期。
    参数: (int day)
    返回: Date (最终日期)
Date Date::operator+(int day)  const
{
	//直接复用+=号
	Date tmp(*this);
	tmp += day;
	return tmp;
}

计算n天前基本思路:
日期减去天数,天数相减,判断天数是否为负数或者零(循环判断),若为负数,则月数减1,同时判断月数是否等于0,若等于则再向年借1,月变回12月;

  1. Date& Date::operator-=(int day) (-=运算符重载)
    功能:实现Date类和int整形相减,且直接修改该对象。
    参数: (int day)
    返回: Date&
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;
}
  1. Date Date::operator-(int day) const (-运算符重载)
    功能:实现Date类和int整形相减,返回最终日期。
    参数: (int day)
    返回: Date
Date Date::operator-(int day) const
{
	Date tmp = *this;
	tmp -= day;
	return tmp;
}

补充:前置++、后置++说明

前置++,返回++后的值,实现时返回原本对象即可,所以可以引用返回
后置++,返回++前的值,需要创建临时变量储存,临时变量出函数自动销毁,所以只能传值返回

但我们运算符重载的时候发现,他们都以Date& operator++()为声明,这会导致编译器无法区分,从而报错。从而为了区别,C++这样规定:
前置++声明:Date& operator++();
后置++声明:Date operator++(int);
为区分他们,在后置++的传参部分加入(int)int占位,以示区分,并没有其他作用。

代码实现很简单,但必须认识到这点(减减一并实现):

// 前置++
Date& Date::operator++()
{
	*this += 1;
	return *this;
}
// 后置++
// 增加这个int参数不是为了接收具体的值,仅仅是占位,跟前置++构成重载
Date Date::operator++(int)
{
	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;
}

判断两个日期的关系(大于,小于等);

我们需要先判断两个日期的大小关系,才可以实现两个日期的相减;
大小关系操作数我们通常只需要实现两个最基本的,其他复用就可以了:大于或者小于,以及等于。

bool operator<(const Date& x) const
功能:判断两个日期的大小,该对象是否小于x对象;
参数:(const Date& x)
返回值: bool 布尔类型

bool Date::operator<(const Date& x) 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;
}

bool Date::operator==(const Date& x) const
{
	return _year == x._year
		&& _month == x._month
		&& _day == x._day;
}

// 复用
// d1 <= d2
bool Date::operator<=(const Date& x) const
{
	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);
}

可以计算两个日期之间相差多少天

基本思路:用最简单的思路,一天一天计算。判断并找出谁大谁小,用小的日期不断++,++过程中用临时变量计数,直到小的日期等于大的日期结束。

int Date::operator-(const Date& d) const
功能:计算两个日期之间相差多少天
参数:(const Date& d)
返回值: int (相差天数)

int Date::operator-(const Date& d) const
{
//假设法:任意假设大小;
	Date max = *this;
	Date min = d;
	int flag = 1;//巧妙运用1和-1

	if (*this < d)
	{
		max = d;
		min = *this;
		flag = -1;
	}

	int n = 0;
	while (min != max)
	{
		++min;
		++n;
	}

	return n * flag;
}

补充:流输入以及流提取操作符实现:

这里我们只是简单认识其中的一些问题即可,内容实现需要i/o相关库的基础,不容易懂。

  1. <<(>>) 流输入(流提取)他们无法在类域中实现,因为我们在使用cout和cin的过程中,第一参数并不是我们的Date(或其他类对象)而是cout和cin,所以我们需要定义为类外的函数方法;
  2. 我们要实现连续输入或输出,所以返回参数应当是ostream&或istream&;
  3. 外部定义实现的函数无法访问类中private的属性,因此需要类有相关方法或者设置该外部定义为友元函数;
class Date
{
	// 友元函数声明
	friend ostream& operator<<(ostream& out, const Date& d);
	friend istream& operator>>(istream& in, Date& d);
	...其他代码
}

代码实现:

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

	return out;
}

istream& operator>>(istream& in, Date& d)
{
	int year, month, day;
	in >> year >> month >> day;

	if (month > 0 && month < 13
		&& day > 0 && day <= d.GetMonthDay(year, month))
	{
		d._year = year;
		d._month = month;
		d._day = day;
	}
	else
	{
		cout << "非法日期" << endl;
		assert(false);
	}

	return in;
}

完整代码如下:

Date.h

#pragma once
#include<iostream>
#include<assert.h>
using namespace std;

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);

	void Print() const
	{
		cout << _year << "-" << _month << "-" << _day << endl;
	}


	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);

	// d1 + 100
	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.cpp

#include "Date.h"

Date::Date(int year, int month, int day)
{
	if (month > 0 && month < 13
		&& day > 0 && day <= GetMonthDay(year, month))
	{
		_year = year;
		_month = month;
		_day = day;
	}
	else
	{
		cout << "非法日期" << endl;
		assert(false);
	}
}

bool Date::operator<(const Date& x) 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;
}

bool Date::operator==(const Date& x) const
{
	return _year == x._year
		&& _month == x._month
		&& _day == x._day;
}

// 复用
// d1 <= d2
bool Date::operator<=(const Date& x) const
{
	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);
}

int Date::GetMonthDay(int year, int month)
{
	static int daysArr[13] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
	//if (((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)) && month == 2)
	if (month == 2 && ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)))
	{
		return 29;
	}
	else
	{
		return daysArr[month];
	}
}

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 == 13)
		{
			++_year;
			_month = 1;
		}
	}

	return *this;
}

// d1 + 100
Date Date::operator+(int day)  const
{
	Date tmp(*this);
	tmp += day;
	return tmp;

	/*tmp._day += day;
	while (tmp._day > GetMonthDay(tmp._year, tmp._month))
	{
		tmp._day -= GetMonthDay(tmp._year, tmp._month);
		++tmp._month;
		if (tmp._month == 13)
		{
			++tmp._year;
			tmp._month = 1;
		}
	}
	return tmp;
	*/
}

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) const
{
	Date tmp = *this;
	tmp -= day;
	return tmp;
}

// 前置++
Date& Date::operator++()
{
	*this += 1;
	return *this;
}

// 后置++
// 增加这个int参数不是为了接收具体的值,仅仅是占位,跟前置++构成重载
Date Date::operator++(int)
{
	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;
}

// d1 - d2;
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 (min != max)
	{
		++min;
		++n;
	}

	return n * flag;
}

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

	return out;
}

istream& operator>>(istream& in, Date& d)
{
	int year, month, day;
	in >> year >> month >> day;

	if (month > 0 && month < 13
		&& day > 0 && day <= d.GetMonthDay(year, month))
	{
		d._year = year;
		d._month = month;
		d._day = day;
	}
	else
	{
		cout << "非法日期" << endl;
		assert(false);
	}

	return in;
}

总结

本节重点是实践各种操作符的重载,以简单Date类做案例。


C++语言系列学习目录

提示:这里可以添加系列文章的所有文章的目录,目录需要自己手动添加,添加超链接

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1661204.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

rbac权限和多级请假设计的流程演示和前端页面实现

登录账号&#xff1a;t6普通用户 t7部门经理 m8总经理 密码都为&#xff1a;test 多级请假&#xff1a;7级及以下申请请假需要部门经理审核&#xff0c;若是请假时长超过72小时&#xff0c;则需要总经理审核&#xff0c;7级申请请将需要总经理审核&#xff0c;总经理请假自动审…

VBA_NZ系列工具NZ06:VBA创建PDF文件说明

我的教程一共九套及VBA汉英手册一部&#xff0c;分为初级、中级、高级三大部分。是对VBA的系统讲解&#xff0c;从简单的入门&#xff0c;到数据库&#xff0c;到字典&#xff0c;到高级的网抓及类的应用。大家在学习的过程中可能会存在困惑&#xff0c;这么多知识点该如何组织…

这3种深拷贝实现,你都知道吗?

目录&#xff1a; 1、JSON.parse 2、structuredClone 3、cloneDeep

Secure Transformer Inference Made Non-interactive

目录 1.概述2.Attention2.1 Matrix multiplication (ciphertext-plaintext).2.2 Matrix multiplication (ciphertext-ciphertext)2.3 Placement of bootstrapping3.SIMD密文压缩和解压缩4.SIMD槽折叠5.实验结果 1.概述 我们提出了NEXUS&#xff0c;这是第一个用于安全变压器推…

AI 产品经理和 AIGC 产品经理有什么区别,怎么选择

AI 产品经理和 AIGC 产品经理有什么区别&#xff0c;怎么选择&#xff1f; AI 和 AIGC 行业两个行业带动了产品经理的的能力提升&#xff0c;那AI产品经理与AIGC产品经理两者中间有什么区别的呢&#xff1f;下面一起来看一下&#xff0c;之间的不同之处吧&#xff01; 目前很火…

构建智能化组织架构权限管理系统:架构设计与实践

随着企业规模的扩大和信息化程度的提升&#xff0c;对权限管理的需求与重要性也日益凸显。本文将深入探讨智能化权限管理系统的架构设计&#xff0c;介绍其关键特点和最佳实践&#xff0c;助力企业提升组织架构的有效性、安全性和管理效率。 1. **需求分析与功能设计&#xff…

基于OpenCV对胸部CT图像的预处理

1 . 传作灵感 胸部CT中所包含的噪声比较多&#xff0c;基于OpenCV简单的做一些处理&#xff0c;降低后续模型训练的难度。 2. 图像的合成 在语义分割任务中有的时候需要将原图&#xff08;imput&#xff09;和标注数据&#xff08;groudtruth&#xff09;合成一幅图像&#x…

iframe的替代方案有吗?做页面嵌套界面套娃

UIOTOS可以了解下&#xff0c;uiotos.net&#xff0c;通过连线来代替脚本逻辑开发&#xff0c;复杂的交互界面&#xff0c;通过页面嵌套轻松解决&#xff0c;是个很新颖的思路&#xff0c;前端零代码&#xff01; 蓝图连线尤其是独创的页面嵌套和属性继承技术&#xff0c;好家…

在RK3588开发板使用FFMpeg 结合云服务器加SRS实现摄像头数据推流到云端拱其他设备查看

今天测试了一把在开发板把摄像头数据推流到云端服务器&#xff0c;然后给其他电脑通过val软件拉取显示摄像头画面&#xff0c;浅浅记录一下大概步骤 1.开发板端先下载ffmpeg apt install ffmpeg2.云服务器先安装SRS的库 云服务器我使用ubuntu系统&#xff0c;SRS是个什么东西&…

非模块化 Vue 开发的 bus 总线通信

个人感觉&#xff0c;JavaScript 非模块开发更适合新人上手&#xff0c;不需要安装配置一大堆软件环境&#xff0c;不需要编译&#xff0c;适合于中小项目开发&#xff0c;只需要一个代码编辑器即可开发&#xff0c;例如 vsCode。网页 html 文件通过 script 标签引入 JavaScrip…

【NLP练习】使用seq2seq实现文本翻译

使用seq2seq实现文本翻译 &#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 from __future__ import unicode_literals, print_function, division from io import open import unicodedata import string impo…

[附源码]石器时代_恐龙宝贝内购版_三网H5手游_带GM工具

石器时代之恐龙宝贝内购版_三网H5经典怀旧Q萌全网通手游_Linux服务端源码_视频架设教程_GM多功能授权后台_CDK授权后台 本教程仅限学习使用&#xff0c;禁止商用&#xff0c;一切后果与本人无关&#xff0c;此声明具有法律效应&#xff01;&#xff01;&#xff01;&#xff0…

【spring】Bean的生命周期回调函数和Bean的循环依赖

目录 1、Bean的生命周期 2、Bean的生命周期回调函数 2.1、初始化的生命周期回调 2.2、销毁的生命周期回调 3、Bean的循环依赖 1、Bean的生命周期 spring的bean的生命周期主要是创建bean的过程&#xff0c;一个bean的生命周期主要是4个步骤&#xff1a;实例化&#xff0c;…

【属性系统概述】

属性系统概述 &#x1f31f; 静态属性与动态属性&#x1f31f; 官方文档中的定义&#x1f31f;《Qt 5.9 C开发指南》中的定义&#x1f31f; Qt中属性的使用 &#x1f31f; 静态属性与动态属性 ✨ 静态属性 &#xff1a;在创建QObject类时通过宏Q_PROPERTY定义的属性&#xff0c…

让GPT们成为我们的小助手:使用ChatGPT来生成测试用数据

让GPT们成为我们的小助手 任务&#xff1a;帮忙生成测试数据 今天本来想做一个测试&#xff0c;所以需要一些测试数据。为了让测试显得更真实&#xff0c;所以希望测试数据看上去就是一份真实的数据&#xff0c;所以我就希望ChatGPT&#xff08;这里是代指&#xff0c;我有使…

vue3对象数组格式的动态表单校验

如你有一个表单&#xff0c;表单内容是对象&#xff0c;但是对象内还有可动态循环的数组进行动态表单校验。 效果如图&#xff1a;查看源码 页面内容&#xff1a; <div class"arrForm-Box"><el-form :model"state.formData" :rules"rule…

基于springboot+vue+Mysql的体质测试数据分析及可视化设计

开发语言&#xff1a;Java框架&#xff1a;springbootJDK版本&#xff1a;JDK1.8服务器&#xff1a;tomcat7数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09;数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/ideaMaven包&#xff1a;…

Oracle count的优化-避免全表扫描

Oracle count的优化-避免全表扫描 select count(*) from t1; 这句话比较简单&#xff0c;但很有玄机&#xff01;对这句话运行的理解&#xff0c;反映了你对数据库的理解深度&#xff01; 建立实验的大表他t1 SQL> conn scott/tiger 已连接。 SQL> drop table t1 purge…

OpenAI 正在开发一种可以防止版权诉讼的工具

OpenAI 正在开发一种名为 Media Manager 的工具&#xff0c;该工具将使内容创建者和所有者能够确定他们是否愿意将自己的内容用于 ML 研究和 AI 模型训练。 Media Manager 将做什么&#xff1f; 明年推出的 Media Manager 将使内容创作者和所有者能够更好地控制他们的工作是否…

Java学习第05天-编程思维与编程能力

文章目录 综合应用案例&#xff1a;找素数数组元素的复制数字加密模拟双色球 综合应用 涉及的知识点&#xff1a; 变量、数组运算符&#xff1a;基本运算符、关系运算符、逻辑运算符流程控制&#xff1a;if、switch、for、while、死循环、循环嵌套跳转关键字&#xff1a;break、…