【C++程序员的自我修炼】日期类Date的实现

山河日月镌刻璀璨初心

八载春秋写就举世华章


目录

 日期类Date的实现

构造函数 

拷贝构造函数

获取月份天数的函数

 日期类的检查

 日期类的打印

运算符重载日期类的比较 

运算符重载>

运算符重载==

运算符的复用

日期加天数

日期减天数

​编辑 运算符重载+

 运算符重载-

 日期类的前置++

 日期类的后置++

日期类的前置--

日期类的后置--

日期减日期

整体代码的实现


契子✨ 

我们学了那么久的 C++ 类与对象,是时候写个小项目练练手了~

先提前总结一下今天要用到的知识点(日期类Date 最基本的东西):

私有成员,构造函数,拷贝构造函数,析构函数(编译器默认生成),赋值运算符重载


 日期类Date的实现

首先登场的就是我们日期类的成员变量

//私有成员变量:
private:
	int _year;
	int _month;
	int _day;

构造函数 

//构造函数
Date::Date(int year, int month, int day)
{
	this->_year = year;
	this->_month = month;
	this->_day = day;
}

拷贝构造函数

//拷贝构造函数
Date::Date(const Date& d)
{
	this->_year = d._year;
	this->_month = d._month;
	this->_day = d._day;
}

获取月份天数的函数

<1>因为这个函数后面要反复调用,所以为了节省空间我们最好写成内联的形式

在C++中放在 public 内的就是内联

<2>如果 MonthDayArray 数组没有转化成静态,也就是每调用一次都要进行空间开辟和释放

效率不高,所以我们加 static 进行修饰转换成静态变量

int GetMonthDay(int year, int month)
{
	static int MonthDayArray[13] = {-1, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
	if (this->_month == 2 && (this->_year % 4 == 0 && this->_year % 100 != 0) || (this->_year % 400 == 0))
	{
		return 29;
	}
	else
	{
		return MonthDayArray[this->_month];
	}
}

 日期类的检查

bool Date::CheckDate()
{
	if (this->_month < 1 || this->_month>12 || this->_day<0 || this->_day>GetMonthDay(this->_year, this->_month))
	{
		return false;
	}
	else
	{
		return true;
	}
}

 日期类的打印

void Date::Print()
{
	cout << this->_year << " 年 " << this->_month << " 月 " << this->_day << " 日 " << endl;
	if (!CheckDate())
	{
		cout << "非法日期!" << endl;
	}
}

运算符重载日期类的比较 

运算符重载>

bool Date::operator>(const Date& d)
{
	if (this->_year > d._year)
	{
		return true;
	}
	else
	{
		if (this->_year == d._year)
		{
			if (this->_month > d._month)
			{
				return true;
			}
			else
			{
				if (this->_month == d._month)
				{
					return this->_day > d._day;
				}
			}
		}
	}
	return false;
}

写好了我们就来测试一下,最好写一点就测一点(不要写代码两分钟,改错两小时)

void Test()
{
	Date d1(2024, 4, 15);
	Date d2(2024, 5, 1);
	if (d1 > d2)
	{
		cout << "d1>d2" << endl;
	}
	else
	{
		cout << "d1<d2" << endl;
	}
	system("pause");
}

事实证明我们的程序是没有任何问题的

运算符重载==

bool Date::operator==(const Date& d)
{
	return this->_year == d._year && this->_month == d._month && this->_day == d._day;
}
void Test()
{
	Date d1(2024, 4, 15);
	Date d2(2024, 5, 1);
	Date d3(2024, 5, 1);
	if (d1 == d2)
	{
		cout << "d1 == d2" << endl;
	}
	else
	{
		cout << "d1 != d2" << endl;
	}
	if (d2 == d3)
	{
		cout << "d2 == d3" << endl;
	}
	else
	{
		cout << "d2 != d3" << endl;
	}
	system("pause");
}

写完 > 和 == 的运算符我们写其他的运算符重载就可以直接复用啦

运算符的复用

bool Date::operator>=(const Date& d)
{
	return (*this > d) || (*this == d);
}

bool Date::operator<(const Date& d)
{
	return !(*this > d);
}

bool Date::operator<=(const Date& d)
{
	return !(*this > d) || (*this == d);
}

bool Date::operator!=(const Date& d)
{
	return !(*this == d);
}

我在这里就不一一进行测试了

日期加天数

<1>首先用当前的天数加上跨越的天数
<2>如果大于当月的最大天数则进入循环进行 消日增月
<3>如果月份超过了 12 则 消月增年
<4>当天数合法则退出循环并返回 *this 
Date& Date::operator+=(int day)
{
	if (day < 0)
	{
		return *this -= -day;
	}
	this->_day += day;
	while (this->_day > GetMonthDay(this->_year, this->_month))
	{
		this->_day -= GetMonthDay(this->_year, this->_month);
		++this->_month;
		if (this->_month == 13)
		{
			++this->_year;
			this->_month = 1;
		}
	}
	return *this;
}

代码测试 -- 网上做好的日期计算器(来看看我们写的是否相符)

void Test()
{
	Date d1(2024, 4, 16);
	d1.Print();
	d1 += 100;
	d1.Print();
	system("pause");
}

事实证明我们的程序是没有任何问题的

我们再来测试一个:

日期减天数

<1>首先用当前的天数减去跨越的天数
<2>如果大于或等于 0 则进入循环进行 消月增日
<3>如果月份不够减,就 消年增月
<4>当天数合法则退出循环并返回 *this 
Date& Date::operator-=(int day)
{
	if (day < 0)
	{
		return *this += -day;
	}
	this->_day -= day;
	while (_day <= 0)
	{
		--this->_month;
		if (this->_month == 0)
		{
			this->_month = 12;
			--this->_year;
		}
		this->_day += GetMonthDay(this->_year, this->_month);
	}
	return *this;
}

这个和加天数类似,就不进行讲解了

注意:因为总有一些人会在加天数中写负值,在减天数中写正值,所以我们要一开始要判断

 运算符重载+

Date Date::operator+(int day)
{
	Date tmp = *this;
	tmp += day;
	return tmp;
}

我们这里需要使用拷贝构造,我们要返回的是加后的值,但是并不希望当前日期变化

所以我们使用拷贝函数将当前日期拷贝一份进行加的操作

注意:Date tmp = *thisDate tmp(*this) 是等价的,都是拷贝构造

注意:

运算符重载+,内部创建tmp拷贝构造,值返回拷贝构造(传值调用),2 次调用拷贝构造

日期减天数+=,内部没有拷贝构造

所以综上还是写+=调用拷贝构造的次数少,效率更高

 运算符重载-

Date Date::operator-(int day)
{
	Date tmp = *this;
	tmp -= day;
	return tmp;
}

 日期类的前置++

this 指向的对象函数结束后不会销毁,故以引用方式返回提高效率

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

 日期类的后置++

注意:后置++是先使用后+1,因此需要返回+1之前的旧值,故需在实现时需要先将 this 保存一份

而 tmp 是临时对象,因此只能以值的方式返回,不能返回引用

Date Date::operator++(int)
{
	Date tmp = *this;
	*this += 1;
	return tmp;
}

因为前置和后置的命名会冲突,所以 C++ 将 后置++ 的参数设为 int 进行区分

但调用函数时该参数不用传递(参数变量可以不写),编译器自动传递

日期类的前置--

Date& Date::operator--()
{
	*this -= 1;
	return *this;
}

日期类的后置--

Date Date::operator--(int)
{
	Date tmp = *this;
	*this -= 1;
	return tmp;
}

日期减日期

日期减日期返回的是天数,所以我们采用的方法很简单就是用计数器去记录两者相差的天数

int Date::operator-(const Date& d) 
{
	int flag = 1;
	Date max = *this;
	Date min = d;
	if (*this < d)
	{
		max = d;
		min = *this;
		flag = -1;
	}
	int count = 0;
	while (min != max)
	{
		++min;
		++count;
	}
	return count * flag;
}

代码测试:

写一个大家最关心的问题~

void Test()
{
	Date d1(2024, 4, 16);
	Date d2(2024, 5, 1);
	cout << "距离五一放假还有 " << d2 - d1 << " 天" << endl;
	system("pause");
}

再来测试一个:

整体代码的实现

Date.h⭐ 

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

class Date
{
public:
	Date(int year = 2024, int month = 5, int day = 1);
	Date(const Date& d);
	int GetMonthDay(int year, int month)
	{
		static int MonthDayArray[13] = {-1, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
		if (this->_month == 2 && (this->_year % 4 == 0 && this->_year % 100 != 0) || (this->_year % 400 == 0))
		{
			return 29;
		}
		else
		{
			return MonthDayArray[this->_month];
		}
	}
	//判断日期是否正确
	bool CheckDate();
	//打印日期
	void Print();
	//运算符重载
	bool operator>(const Date& d)const;
	bool operator==(const Date& d)const;
	bool operator >= (const Date& d)const;
	bool operator < (const Date& d)const;
	bool operator <= (const Date& d)const;
	bool operator != (const Date& d)const;
	Date& operator+=(int day);
	Date operator+(int day)const;
	Date operator-(int day)const;
	Date& operator-=(int day);
	// 前置++
	Date& operator++();
	// 后置++
	Date operator++(int);
	// 后置--
	Date operator--(int);
	// 前置--
	Date& operator--();
	//计算两个日期之差
	int operator-(const Date& d)const;
private:
	int _year;
	int _month;
	int _day;
};

Date.cpp⭐ 

#include"Date.h"

//构造函数
Date::Date(int year, int month, int day)
{
	this->_year = year;
	this->_month = month;
	this->_day = day;
}

//拷贝构造函数
Date::Date(const Date& d)
{
	this->_year = d._year;
	this->_month = d._month;
	this->_day = d._day;
}

//判断日期是否正确
bool Date::CheckDate()
{
	if (this->_month < 1 || this->_month>12 || this->_day<0 || this->_day>GetMonthDay(this->_year, this->_month))
	{
		return false;
	}
	else
	{
		return true;
	}
}

//打印日期
void Date::Print() 
{
	cout << this->_year << " 年 " << this->_month << " 月 " << this->_day << " 日 " << endl;
	if (!CheckDate())
	{
		cout << "非法日期!" << endl;
	}
}

bool Date::operator>(const Date& d)const
{
	if (this->_year > d._year)
	{
		return true;
	}
	else
	{
		if (this->_year == d._year)
		{
			if (this->_month > d._month)
			{
				return true;
			}
			else
			{
				if (this->_month == d._month)
				{
					return this->_day > d._day;
				}
			}
		}
	}
	return false;
}

bool Date::operator==(const Date& d)const
{
	return this->_year == d._year && this->_month == d._month && this->_day == d._day;
}

bool Date::operator>=(const Date& d)const
{
	return (*this > d) || (*this == d);
}

bool Date::operator<(const Date& d)const
{
	return !(*this > d);
}

bool Date::operator<=(const Date& d)const
{
	return !(*this > d) || (*this == d);
}

bool Date::operator!=(const Date& d)const
{
	return !(*this == d);
}

Date& Date::operator+=(int day)
{
	if (day < 0)
	{
		return *this -= -day;
	}
	this->_day += day;
	while (this->_day > GetMonthDay(this->_year, this->_month))
	{
		this->_day -= GetMonthDay(this->_year, this->_month);
		++this->_month;
		if (this->_month == 13)
		{
			++this->_year;
			this->_month = 1;
		}
	}
	return *this;
}

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

Date& Date::operator-=(int day)
{
	if (day < 0)
	{
		return *this += -day;
	}
	this->_day -= day;
	while (_day <= 0)
	{
		--this->_month;
		if (this->_month == 0)
		{
			this->_month = 12;
			--this->_year;
		}
		this->_day += GetMonthDay(this->_year, this->_month);
	}
	return *this;
}

Date Date::operator-(int day)const
{
	Date tmp = *this;
	tmp -= day;
	return tmp;
}

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

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

int Date::operator-(const Date& d) const
{
	int flag = 1;
	Date max = *this;
	Date min = d;
	if (*this < d)
	{
		max = d;
		min = *this;
		flag = -1;
	}
	int count = 0;
	while (min != max)
	{
		++min;
		++count;
	}
	return count * flag;
}

Test.cpp⭐ 

#include"Date.h"

void Test()
{
	Date d1(2024, 4, 16);
	Date d2(2024, 5, 1);
	cout << "距离五一放假还有 " << d2 - d1 << " 天" << endl;
	system("pause");
}

int main()
{
	Test();
	return 0;
}

 

 🌤️注意:我上面有些函数加了const修饰,限制了隐含的this指针,表明在该成员函数中不能对类的任何成员进行修改


举个栗子~

我们知道类的成员函数都有一个 隐藏的 this 指针

bool Date::operator>(const Date& d) const

按语法可以写成这个

bool Date::operator>(Date *this,const Date& d) const

等价于下面这个式子

bool Date::operator>(const Date *this,const Date& d) 

我们发现加了 const 限制了成员函数的 this 指针:

表明在该成员函数中不能对类的任何成员进行修改,起到一定的代码安全维护性

 


先介绍到这里啦~

有不对的地方请指出💞

 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

11.盛最多水的容器(Java,双指针)

目录 题目描述&#xff1a;输入&#xff1a;输出&#xff1a;代码实现&#xff1a; 题目描述&#xff1a; 给定一个长度为 n 的整数数组 height 。有 n 条垂线&#xff0c;第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。 找出其中的两条线&#xff0c;使得它们与 x 轴共同…

PHP01——php快速入门 之 在Mac上使用phpstudy快速搭建PHP环境

PHP01——php快速入门 之 在Mac上使用phpstudy快速搭建PHP环境 0. 前言1. 下载小皮面板1.1 下载phpstudy&#xff08;小皮面板&#xff09;1.2 启动、简单访问1.2.1 启动Apache1.2.2 访问1.2.3 访问自定义文件或页面 2. 创建网站2.1 创建网站2.2 可能遇到的问题2.2.1 hosts权限…

企业指标开发流程新主张

作为数据开发人员&#xff0c;你是否在指标开发过程中有过如下苦恼&#xff1a; Q1、 &#xff08;甲方&#xff09;业务人员&#xff1a;你这个指标计算逻辑不对&#xff0c;我们前期不是这么对的。 &#xff08;乙方&#xff09;卑微的你&#xff1a;Fu*k……我有录音。 …

创建和使用pipenv

创建pipenv 1.环境区别2.安装pipenv3.使用1.创建项目名称2.创建pipenv环境3.安装包1.安装包卡顿或卡住 4.查看包之间联系5.进入虚拟环境6.只安装dev环境的包7.常见的pipenv指令 1.环境区别 真实环境 真实环境可能被系统的其他软件依赖&#xff0c;下载包可能导致其他软件环境变…

Spark Standalone模式部署

准备至少2台虚拟机&#xff0c;装好linux系统&#xff0c;我装的是Ubuntu20.04。 1.修改主机名&#xff08;每台&#xff09; 1&#xff09;修改/etc/hostsname内容&#xff0c;主节点改为master&#xff0c;子节点改为slaver1 sudo vim /etc/hostname 2&#xff09;在/etc/…

【面试经典 150 | 数学】阶乘后的零

文章目录 写在前面Tag题目来源题目解读解题思路方法一&#xff1a;数学优化计算 写在最后 写在前面 本专栏专注于分析与讲解【面试经典150】算法&#xff0c;两到三天更新一篇文章&#xff0c;欢迎催更…… 专栏内容以分析题目为主&#xff0c;并附带一些对于本题涉及到的数据结…

防御性编程失败,我开始优化我写的多重 if-else 代码

最近防御性编程比较火&#xff0c;码农出身&#xff08;前后端内推&#xff09;的我不得试试 不出意外我被逮捕了&#xff0c;组内另外一位同事对我的代码进行了 CodeReview&#xff0c;我的防御性编程编程没有幸运逃脱&#xff0c;被标记上了“多重 if-else ”需要进行优化。 …

数据结构速成--链表

由于是速成专题&#xff0c;因此内容不会十分全面&#xff0c;只会涵盖考试重点&#xff0c;各学校课程要求不同 &#xff0c;大家可以按照考纲复习&#xff0c;不全面的内容&#xff0c;可以看一下小编主页数据结构初阶的内容&#xff0c;找到对应专题详细学习一下。 目录 一…

中仕公考:2024山东高校毕业生“三支一扶”开始报名

2024年度山东省高校毕业生‘三支一扶’计划开始报名&#xff0c;此次全省共计招募1350名。 招募范围&#xff1a; 30周岁及其以下的山东省内普通高校全日制毕业生(1993年4月以后出生) 报名时间&#xff1a;2024年4月16日9:00—4月20日16:00 查询时间&#xff1a;2024年4月1…

在Docker里面修改mysql的密码(8.0以上版本)

介绍 我们在阿里或者华为的服务器上安装了mysql而且还公开了端口3306恰好你创建的容器的端口也是3306;那么我建议你修改mysql的密码,而且越复杂越好,因为我就被黑客给攻击过 修改密码 首先我们要启动好mysql容器 进入容器内部 **docker exec -it mysql bash ** 登入初始…

Qt for Android 开发环境

在搭建环境时开始感觉还挺顺利的&#xff0c;从 Qt 配置的环境里面看并没有什么问题&#xff0c;可真正编译程序的时候发现全是错误。 最开始的时候安装了 JDK21 最新版本&#xff0c;然后根据 JDK21 安装 ndk, build-tools, Platform-Tools 和 Gradle&#xff0c;但是不管这么…

基于SpringBoot+Vue的城镇住房管理系统(源码+文档+包运行)

一.系统概述 随着信息技术在管理上越来越深入而广泛的应用&#xff0c;管理信息系统的实施在技术上已逐步成熟。本文介绍了城镇保障性住房管理系统的开发全过程。通过分析城镇保障性住房管理系统管理的不足&#xff0c;创建了一个计算机管理城镇保障性住房管理系统的方案。文章…

【k8s】:深入理解 Kubernetes 中的污点(Taints)与容忍度(Tolerations)

【k8s】&#xff1a;深入理解 Kubernetes 中的污点&#xff08;Taints&#xff09;与容忍度&#xff08;Tolerations&#xff09; 1、污点&#xff08;Taints&#xff09;2、容忍度&#xff08;Tolerations&#xff09;3、示例演示-测试污点的具体应用场景3.1 给节点打污点&…

ThinkPHP V5.1框架源码

源码下载地址&#xff1a;ThinkPHP V5.1.zip www WEB部署目录&#xff08;或者子目录&#xff09; ├─application 应用目录 │ ├─common 公共模块目录&#xff08;可以更改&#xff09; │ ├─module_name 模块目录 │ │ ├─common.php 模块函数文件 │ │ ├─controll…

Springboot+Vue项目-基于Java+MySQL的免税商品优选购物商城系统(附源码+演示视频+LW)

大家好&#xff01;我是程序猿老A&#xff0c;感谢您阅读本文&#xff0c;欢迎一键三连哦。 &#x1f49e;当前专栏&#xff1a;Java毕业设计 精彩专栏推荐&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; &#x1f380; Python毕业设计 &…

DBA面试总结(Mysql篇)

一、delete与trancate的区别 相同点 1.两者都是删除表中的数据&#xff0c;不删除表结构 不同点 1.delete支持按条件删除&#xff0c;TRUNCATE不支持。 2.delete 删除后自增列不会重置&#xff0c;而TRUNCATE会被重置。 3.delete是逐条删除&#xff08;速度较慢&#xff09…

LeetCode 面试经典150题 219.存在重复元素II

题目&#xff1a;给你一个整数数组 nums 和一个整数 k &#xff0c;判断数组中是否存在两个 不同的索引 i 和 j &#xff0c;满足 nums[i] nums[j] 且 abs(i - j) < k 。如果存在&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。 思路&#xff1a; 代码…

超像素分割在AI去衣技术中的应用与探讨

随着人工智能技术的飞速发展&#xff0c;图像处理领域不断涌现出新的方法和应用。其中&#xff0c;超像素分割作为一种重要的图像预处理技术&#xff0c;在AI去衣这一特定应用中发挥着至关重要的作用。本文将深入探讨超像素分割在AI去衣技术中的应用&#xff0c;并尝试从专业的…

SpringBoot3 集成Springdoc 实现Swagger3功能

说明&#xff1a; 只通过引用org.springdoc 的两个包就可以使用Swagger3 功能&#xff08;步骤1&#xff09;&#xff1b;如想更美观及实现动态认证的开启与关闭&#xff0c;及Swagger3登录认证等功能&#xff0c;需实现&#xff08;步骤1、2、3&#xff09;的配置; 1、 引包…

基于springboot实现车辆管理系统设计项目【项目源码+论文说明】计算机毕业设计

基于springboot实现车辆管理系统演示 摘要 随着信息技术在管理上越来越深入而广泛的应用&#xff0c;管理信息系统的实施在技术上已逐步成熟。本文介绍了车辆管理系统的开发全过程。通过分析车辆管理系统管理的不足&#xff0c;创建了一个计算机管理车辆管理系统的方案。文章介…