【C++】类和对象—日期类的实现

news2024/11/20 18:41:21

在这里插入图片描述

目录

  • 一、日期类的功能
  • 二、获取月的天数
  • 三、Date类中的默认成员函数
    • 构造函数
    • 析构函数
    • 拷贝构造
    • 赋值运算符重载
    • 取地址操作符重载和const取地址操作符重载
  • 四、运算符重载
    • 🌒+、+=、-、-=
      • 日期+=天数
      • 日期+天数
      • 日期-=天数
      • 日期-天数
    • 🌒==、!=、>、>=、<、<=
      • 日期-日期
      • 计算星期几
    • 🌒前置++、--和后置++、--
  • 五、代码
      • Date.cpp
      • test.cpp

一、日期类的功能

实现日期类的==、!=、+=、+、-=、-、>=、>、<=、<、前置++和–、后置++和–。

二、获取月的天数

因为GetMonthDay这个函数需要在日期类中被频繁调用,所以将 monthArr存放至静态区,减少数组频繁开辟、销毁空间的开销。

先把2(代表2月)为下标的天数置为28天。判断闰年如果为闰年就把2月的天数置为29。

int Date::getMonthDay(int year, int month)
{
	assert(month < 13 && month>0);
    
    //静态数组,每次调用不用频繁在栈区创建数组
	int monthArr[13] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
	if (month == 2 && (((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0)))
	{
		return 29;
	}
	else
	{
		return monthArr[month];
	}
}

三、Date类中的默认成员函数

构造函数

我们需要判断日期输入是否合法,不排除有人在输入时不小心输了一个2023-10-422.这样的输入的就是错误的。需要判断日期输入是否合法

Date::Date(int year, int month, int day)
{
	//需要判断日期输入是否合法
	if (month > 0 && month < 13 && (day > 0 && day <= getMonthDay(year, month)))
	{
		_year = year;
		_month = year;
		_day = day;
	}
	else
	{
		cout << "日期非法" << endl;
	}
}

析构函数

默认生成的就够用

~Date()//可不写
{
    ;
}

拷贝构造

默认生成的拷贝构造就够用,默认拷贝会对内置类型进行浅拷贝。

Date(const Date& d)//可不写
{
    _year = d._year;
    _month = d._month;
    _day = d._day;
    //cout << "拷贝构造成功" << endl;
}

赋值运算符重载

Date& operator=(const Date& d)
{
    _year = d._year;
    _month = d._month;
    _day = d._day;
    //cout << "赋值成功" << endl;
    return *this;
}

也可不写,使用系统默认生成的即可。
拷贝构造和赋值运算符重载的区别在于拷贝构造用于对象构造时使用,而赋值运算符重载用于已存在对象赋值时使用
后续处理有资源的对象时,需要先把旧空间释放,再开一块同样大小的空间,进行数据拷贝。

如果忘记了可以复习一下我的上一篇复习类和对象【中】

取地址操作符重载和const取地址操作符重载

这两个函数意义不大

这两个默认成员函数一般不用重新定义 ,编译器默认会生成的就足够用了

Date* operator&()
{
    return this;
    //return nullptr;
}
const Date* operator&()const
{
    return this;
    //return nullptr;
}

这两个运算符一般不需要重载,使用编译器生成的默认取地址的重载即可,只有特殊情况,才需要重载,比如想让别人获取到指定的内容

四、运算符重载

🌒+、+=、-、-=

日期+=天数

应该怎么办呢?
2023年4月10日 +100天,但顺着我们正常的计算思维,列写几个例子,其实很简单。✅它其实就是一个不断进位的过程,天满了往月进;月满了往年进、月归1.月满年+1,月直接重置为1.
在这里插入图片描述

Date& Date::operator+=(int day)
{
	if (day < 0)
	{
		//这里是复用的-=,后面会写
		//当日期-100时,就会复用-=
		return *this -= -day;
	}

	_day += day;
	while (_day > GetMonthDay(_year, _month))
	{
		_day -= GetMonthDay(_year, _month);
		++_month;
		if (_month == 13)
		{
			_year++;
			_month = 1;
		}
	}
	return *this;//d1没销毁,可以传引用返回
}

日期+天数

+就是不改变d1的值。
我们直接复用+=,拷贝构造一个临时变量,避免对d1的改变。

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

	return tmp;
}

日期-=天数

在这里插入图片描述

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

		_day += GetMonthDay(_year, _month);
	}
	return *this;
}

注:

  1. 天数 <= 0都不合法,要借位
  2. 注意我们借到的天数是上一个月的天数(这与“加”不同,“加”获取的是本月天数)
  3. 到达边界时,我们是先把月置12,再对天数处理

日期-天数

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

有的同学再写这两句代码时会报错return *this -= -day; return *this += -day;如果把这四个全都是实现就不会报错。那这是什么意思呢?
在这里插入图片描述
我们就需要判断一下
+=、+负数就去复用-=,+ (-100)就是 -= 100;
-=、 -负数就去复用 +=,- (-100)就是 +=100;

🌒==、!=、>、>=、<、<=

任何一个类,只需要写一个 > == 重载 或者 < == 即可,剩下比较运算符复用即可

//d1>d2
bool Date::operator>(const Date& d)
{
	if ((_year > d._year)
		|| (_year == d._year && _month > d._month)
		|| (_year == d._year && _month == d._month && _day > d._day))
	{
		return true;
	}
	else
	{
		return false;
	}
}
// ==
bool Date::operator==(const Date& d)
{
	return _year == d._year
		&& _month == d._month
		&& _day == d._day;
}

下面我们就开始复用

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

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

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

日期-日期

//日期-日期
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 day = 0;
	while (min != max)
	{
		++min;
		++day;
	}
	return  day* flag;
}

计算星期几

void Date::PrintWeekday()
{
	Date start(1900, 1, 1); //查询得星期一
	int count = *this - start;
	cout << "星期" << ((count % 7) + 1) << endl;
}

🌒前置++、–和后置++、–

前置++和后置++都是一元运算符,为了让前置++与后置++形成能正确重载
C++规定:后置++重载时多增加一个int类型的参数,但调用函数时该参数不用传递,编译器自动传递
前置++ 返回 ++ 之后的值
后置++ 返回 ++ 之前的值

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

Date Date::operator--(int) //后置--
{
	Date ret = *this;
	*this -= 1;
	return ret;
}

五、代码

Date.cpp

#include "Date.h"
int Date::GetMonthDay(int year, int month)
{
	//静态数组,每次调用不用频繁在栈区创建数组
	static int monthArr[12] = { 31,28,31,30,31,30,31,31,30,31,30,31 };
	//判断是否闰年
	int day = monthArr[month - 1];
	if (month == 2 && ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0))
	{
		day = 29;
	}
	return day;
}

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


//任何一个类,只需要写一个 > == 重载 或者 < == 即可,剩下比较运算符复用即可
bool Date::operator==(const Date& d)
{
	return _year == d._year
		&& _month == d._month
		&& _day == d._day;
}

// d1 != d2
bool Date::operator!=(const Date& d)
{
	return !(*this == d);
}
//d1 > d2
bool Date::operator>(const Date& d)
{
	if ((_year > d._year)
		|| (_year == d._year && _month > d._month)
		|| (_year == d._year && _month == d._month && _day > d._day))
	{
		return true;
	}
	else
	{
		return false;
	}
}
//尽可能的去复用
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);
}

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

	return tmp;
}

//d2 += d1 += 100   连续加等,有返回值
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没销毁,可以传引用返回
}


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


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

		_day += GetMonthDay(_year, _month);
	}
	return *this;
}


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

Date Date::operator--(int) //后置
{
	Date ret = *this;
	*this -= 1;
	return ret;
}

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

//日期-日期
// offerDay - today =>offerDay.operator(&offerday,today);
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 day = 0;
	while (min < max)
	{
		++min;
		++day;
	}
	return  day * flag;
}

void Date::PrintWeekday()
{
	Date start(1900, 1, 1); //查询得星期一
	int count = *this - start;
	cout << "星期" << ((count % 7) + 1) << endl;
}

test.cpp

#include "Date.h"

void test1()
{
	Date d1(2002, 3, 7);
	d1.Print();

	Date d2(2022, 2, 29);
}

//测试+、+=、++
void test2()
{
	Date d1(2022, 1, 16);
	Date ret = d1 + -100;
	ret.Print();

	//Date d2(2022, 1, 16);
	//d2 += 100;
	//d2.Print();

	//++d1;
	/*d1++;*/
}

//测试这一堆运算符重载函数
void test3()
{

	Date d1(2002, 3, 7);
	Date d2(2002, 2, 19); //missing lmyy
	Date d3(2002, 3, 7);

	cout << (d1 == d3) << endl;
	cout << (d1 >= d2) << endl;
	cout << (d1 < d3) << endl;
	cout << (d1 <= d2) << endl;
	cout << (d1 != d3) << endl;

}

// 测试-,-=,--
void test4()
{
	Date d1(2022, 1, 10);
	Date d2(2022, 2, 19);

	Date ret2 = d2 - 60;
	ret2.Print();

	d1 -= 10;
	d1.Print();

	/*--d2;
	d2--;*/
}

//测试日期 - 日期,星期几
void test5()
{
	Date today(2023, 4, 10);
	Date offerDay(2023, 5, 1);
	cout << (offerDay - today) << endl;
	today.PrintWeekday();
}

int main()
{
	//test1();
	//test2();
	//test3();
	//test4();
	//test5();
	return 0;
}

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

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

相关文章

C++ :websocket 通讯下的五种 I/O 模型

目录 I/O 多路复用&#xff08;一种同步 I/O 模型&#xff09; 非阻塞与阻塞 select、poll、epoll 起因 改善 select 与 poll 的差别 I/O 模型 阻塞 I/O 模型 非阻塞 I/O 模型 I/O 多路复用模型 信号驱动 I/O 模型&#xff08;SIGIO&#xff09; 异步 I/O 模型&…

VirtualBox下Ubuntu系统磁盘扩容

1. 正确扩容虚拟硬盘&#xff1a;修改虚拟硬盘和快照的虚拟硬盘大小 打开VirtualBox所在目录&#xff0c;打开cmd&#xff0c;输入命令VBoxManage list hdds&#xff0c;这样能够列出所有的虚拟磁盘。找到你需要扩容的磁盘输入命令VBoxManage" modifyhd "D:\Pat\to\…

米尔STM32MP135核心板 又一款入门级嵌入式开发平台

自2007年意法半导体&#xff08;ST&#xff09;推出STM32首款Cortex-M内核 MCU,十几年来&#xff0c;ST在MCU领域的发展是飞速向前的。而2019年ST发布了全新的STM32MPU系列产品线&#xff0c;STM32MP1作为新一代 MPU 的典范&#xff0c;有着极富开创意义的异构系统架构兼容并蓄…

WMS智能仓储

子产品介绍篇--智能仓储 智能仓储 我们通常也称 WMS 系统。是一个实时的计算机软件系统&#xff0c;它能够按照运作的业务规则和运算法则&#xff0c;对信息、资源、行为、存货和分销运作进行更完美地管理&#xff0c;提高效率。 一. 仓储管理系统&#xff08;wms&#xff09;…

javaweb过滤器与监听器

一、过滤器程序的基本结构、web.xml文件的配置过程和过滤器的执行过程 <?xml version"1.0" encoding"UTF-8"?> <web-app xmlns"https://jakarta.ee/xml/ns/jakartaee"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance&quo…

MobPush创建推送

功能说明 MobPush提供遵循REST规范的HTTP接口&#xff0c;适用各开发语言环境调用。 IP绑定 工作台可以绑定服务器IP地址&#xff0c;未绑定之前所有IP均可进行REST API的调用&#xff0c;绑定后进仅绑定的IP才有调用权限。 调用地址 POSThttp://api.push.mob.com/v3/push/c…

03.vue3的计算属性

文章目录1.计算属性1.get()和set()2.computed的简写3.computed和methods对比2.相关demo1.全选和反选2.todos列表1.计算属性 模板内的表达式非常便利&#xff0c;但是设计它们的初衷是用于简单运算的。在模板中放入太多的逻辑会让模板过重且难以维护。所以&#xff0c;对于任何…

CRM系统是什么?它有什么作用?

CRM系统是什么&#xff1f; CRM是Customer Relationship Management&#xff08;客户关系管理&#xff09;的缩写&#xff0c;是一种通过对客户进行跟踪、分析和管理的方法&#xff0c;以增加企业与客户之间的互动和联系&#xff0c;提高企业与客户之间的互信&#xff0c;从而…

GoNote第一章 环境搭建

GoNote第一章 环境搭建 golang介绍 1. 语言介绍 Go 是一个开源的编程语言&#xff0c;它能让构造简单、可靠且高效的软件变得容易。 Go是从2007年末由Robert Griesemer, Rob Pike, Ken Thompson主持开发&#xff0c;后来还加入了Ian Lance Taylor, Russ Cox等人&#xff0c…

oracle远程克隆pdb

使用远程克隆的先决条件是: oracle版本是12.2以上,开启归档模式以及本地undo. 这里是想从172.16.12.250将PRODPDB1克隆到172.16.12.251下&#xff0c;命名为PRODPDB1COPY。 1 确保源端数据库开启归档模式 备注&#xff1a;进cdb里开启归档。 2 在源数据库中&#xff0c;确保…

2023年环境工程与生物技术国际会议(CoEEB 2023)

会议简介 Brief Introduction 2023年环境工程与生物技术国际会议(CoEEB 2023) 会议时间&#xff1a;2023年5月19日-21日 召开地点&#xff1a;瑞典马尔默 大会官网&#xff1a;www.coeeb.org 2023年环境工程与生物技术国际会议(CoEEB 2023)将围绕“环境工程与生物技术”的最新研…

【教程】Unity 与 Simence PLC 联动通讯

开发平台&#xff1a;Unity 2021 依赖DLL&#xff1a;S7.NET 编程语言&#xff1a;CSharp 6.0 以上   一、前言 Unity 涉及应用行业广泛。在工业方向有着一定方向的涉足与深入。除构建数据看板等内容&#xff0c;也会有模拟物理设备进行虚拟孪生的需求需要解决。而 SIMATIC&a…

测评:腾讯云轻量4核8G12M服务器CPU内存带宽流量

腾讯云轻量4核8G12M应用服务器带宽&#xff0c;12M公网带宽下载速度峰值可达1536KB/秒&#xff0c;折合1.5M/s&#xff0c;每月2000GB月流量&#xff0c;折合每天66GB&#xff0c;系统盘为180GB SSD盘&#xff0c;地域节点可选上海、广州或北京&#xff0c;4核8G服务器网来详细…

02-参数传递+统一响应结果

1. 参数传递&#xff1a; -- 简单参数 如果方法形参数名称与请求方法名称不匹配&#xff0c;采用RequestParam注解 -- 实体参数 -- 数组集合参数 -- 日期参数 -- JSON参数 -- 路径参数 2. 统一响应结果 -- 1. 创建Result类&#xff08;放到pojo包中&#xff09; package dem…

centos8 源码安装 apache(内附图片超详细)

♥️作者&#xff1a;小刘在C站 ♥️个人主页&#xff1a;小刘主页 ♥️每天分享云计算网络运维课堂笔记&#xff0c;努力不一定有收获&#xff0c;但一定会有收获加油&#xff01;一起努力&#xff0c;共赴美好人生&#xff01; ♥️夕阳下&#xff0c;是最美的绽放&#xff0…

Redis 如何实现库存扣减操作和防止被超卖?

本文已经收录到Github仓库&#xff0c;该仓库包含计算机基础、Java基础、多线程、JVM、数据库、Redis、Spring、Mybatis、SpringMVC、SpringBoot、分布式、微服务、设计模式、架构、校招社招分享等核心知识点&#xff0c;欢迎star~ Github地址&#xff1a;https://github.com/…

《Rank-LIME: Local Model-Agnostic Feature Attribution for Learning to Rank》论文精读

文章目录一、论文信息摘要二、要解决的问题现有工作存在的问题论文给出的方法&#xff08;Rank-LIME&#xff09;介绍贡献三、前置知识LIMEFeature AttributionModel-AgnosticLocalLearning to Rank&#xff08;LTR&#xff09;单文档方法&#xff08;PointWise Approach&#…

工业相机标定(张正友标定法)

目录 相机标定的概念 a. 相机标定的定义 b. 相机标定的目的 相机标定的过程 a. 标定板选择 b. 标定板摆放及拍摄 c. 标定板角点提取 张正友标定法 a. 反解相机矩阵 b.反解畸变系数 使用Python进行相机标定 a. 安装OpenCV b. 准备标定板图片 c. 利用OpenCV进行角点…

HashMap、HashTable、ConcurrentHashMap 之间的区别

哈喽&#xff0c;大家好~我是保护小周ღ&#xff0c;本期为大家带来的是 HashMap、HashTable、ConcurrentHashMap 之间的区别&#xff0c;从数据结构到多线程安全~确定不来看看嘛~更多精彩敬请期待&#xff1a;保护小周ღ *★,*:.☆(&#xffe3;▽&#xffe3;)/$:*.★* ‘一、…

内存、CPU与指针的知识

在计算机中&#xff0c;内存、CPU和指针是非常重要的概念。在本篇博客中&#xff0c;我们将探讨内存、CPU和指针的知识。 内存的概念 内存是计算机中的一种存储设备&#xff0c;用于存储程序和数据。内存可以被CPU读取和写入&#xff0c;因此是计算机中非常重要的组成部分。在…