实现日期类

news2024/12/26 9:20:07

前言:

        本篇我们要实现一个日期类,其实非常困难,因为要对日期实现加加减减,也就是要对前面的知识做出一个巩固。

头文件:

        因为要判断闰年,所以我们要去创建一个数组。也就是创建一个返回每月日期的函数。因为闰年要单独判断,所以

        这里有一个知识点,就是直接声明在类中的函数,都是内联函数。

//直接定义在类里面,默认是inline(内联)
//频繁调用
int getMonthDay(int year, int month)
{
	assert(month > 0 && month < 13);

	//默认平年
	static int monthDayArray[13] = { -1, 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;
	}
	else 
	{
		return monthDayArray[month];
	}

	return monthDayArray[month];
}

日期相加:

        日期类相加是有意义的,我们相当于对未来几天的计算。

        我们完成日期类,先写+=,之后完善+可以复用+=。

        复用+=比较好,因为复用+的话会先调用拷贝构造,之后返回的时候再调用一次拷贝构造。

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

	_day += day;
	//这里是while循环
	while (_day > getMonthDay(_year, _month))
	{
		_day -= getMonthDay(_year, _month);
		_month++;
		if (_month == 13)
		{
			_year++;
			_month = 1;
		}
	}

	return *this;
}

Date Date::operator+(int day) const
{
	Date tmp = *this;//拷贝构造
	//再写一遍就会很冗余,所以直接调用+=
	tmp += day;

	return tmp;
	//此时不能使用引用返回,因为会销毁tmp
}

日期相减: 

        这也是有意义的。

        日期类相减我们需要注意的事项: 函数重载和运算符重载没有关系。

        多个同一运算符可以构成函数重载。

日期++:

        此时如果我们要实现前置++和后置++的运算符重载,为了区分,后置++需要强制加上int形参。

//++d1
Date& operator++();

//d1++
//为了区分,构成重载
//强行给后置++ 增加了一个int形参
Date& operator++(int);

打印日期: 

        自动识别类型本质是因为流插入重载构成函数重载。

        因为可以直接打印内置类型,但是此时我们想直接打印引用类型,我们就需要自己去写。

        operator<< 想重载为成员函数,可以,但是用起来不符合正常逻辑,不建议这样使用,建议重载为全局函数。所以我们使其成为全局函数。

void operator<<(ostream& out, Date d)
{
	//out就是cout
	out << d._year << "年" << d._month << "月" << d._day << "日" << endl;
}

        但是此时私有的问题又出现了,我们可以利用友元……看图:

        本质就是实参顺序,但是此时:

cout << d1 << d2;

        会报错,所以该怎么办呢?因为流插入结合性是从左往右,所以要返回ostream&才行。

ostream& operator<<(ostream& out, Date d);

        这样就支持链式输出。 

传入const常量: 

        如果我们定义一个常量的日期类,如果直接调用里面的函数,会报错。

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

        因为权限可以缩小,所以对于比较的函数最好都加上const(也就是没有改变*this的函数)。

        +=不能加const,但是+可以,因为+=相当于修改了*this,但是+不会。

总结:

        没啥总结,就是有空再写一遍,这里给出全部代码:

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 = 1900, int month = 1, int day = 1);
	void Print() const;

	//直接定义在类里面,默认是inline(内联)
	//频繁调用
	int getMonthDay(int year, int month)
	{
		assert(month > 0 && month < 13);

		//默认平年
		static int monthDayArray[13] = { -1, 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;
		}
		else 
		{
			return monthDayArray[month];
		}

		return monthDayArray[month];
	}

	//检查日期合法性
	bool CheckDate();

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

	// d1 - 100
	Date operator-(int day) const;

	// d1 - d2
	int operator-(const Date& d) const;

	//++d1 -> d1.operator++()
	Date& operator++();

	//d1++ -> d1.operator++(1)
	//为了区分,构成重载
	//强行给后置++ 增加了一个int形参
	Date operator++(int);

	Date& operator--();
	Date operator--(int);

	//流插入
	//不建议,因为Date* this 占据了第一个参数位置,使用 d << cout 不符合习惯
	//void operator<<(ostream& out);//必须传入引用

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"

//检查日期合法性
bool Date::CheckDate()
{
	if (_month < 1 || _month > 12
		|| _day < 1 || _day > getMonthDay(_year, _month))
	{
		return false;
	}

	return true;
}

Date::Date(int year, int month, int day)
{
	_year = year;
	_month = month;
	_day = day;

	if (!CheckDate())
	{
		cout << "日期非法" << endl;
	}
}

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

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

	return false;
}

bool Date::operator==(const Date& d) const
{
	return _year == d._year
		&& _month == d._month
		&& _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);
}

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

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

	_day += day;
	//这里是while循环
	while (_day > getMonthDay(_year, _month))
	{
		_day -= getMonthDay(_year, _month);
		_month++;
		if (_month == 13)
		{
			_year++;
			_month = 1;
		}
	}

	return *this;
}

Date Date::operator+(int day) const
{
	Date tmp = *this;//拷贝构造
	//再写一遍就会很冗余,所以直接调用+=
	tmp += day;

	return tmp;
	//此时不能使用引用返回,因为会销毁tmp
}

//Date Date::operator+(int day)
//{
//
//	Date tmp = *this;//拷贝构造
//	tmp._day += day;
//	//这里是while循环
//	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;
//	//此时不能使用引用返回,因为会销毁tmp
//}
//
//Date& Date::operator+=(int day)
//{
//	 *this = *this + day;
//	return *this;
//}


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

	_day -= day;
	while (_day <= 0)
	{
		//小于等于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;
}

//++d1 -> d1.operator++()
Date& Date::operator++()
{
	*this += 1;
	return *this;
}

//d1++ -> d1.operator++(1)
//为了区分,构成重载
//强行给后置++ 增加了一个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;
}

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

流插入
//void Date::operator<<(ostream& out)
//{
//	//out就是cout
//	out << _year << "年" << _month << "月" << _day << "日" << endl;
//}

ostream& operator<<(ostream& out, const Date d)
{
	//out就是cout
	out << d._year << "年" << d._month << "月" << d._day << "日" << endl;
	return out;
}

//流提取
istream& operator>>(istream& in, Date& d) {
	cout << "请一次输入年月日:" << endl;
	in >> d._year >> d._month >> d._day;

	if (!d.CheckDate())
	{
		cout << "日期非法" << endl;
	}

	return in;
}

test.cpp源文件:

using namespace std;

#include"Date.h"

void TestDate1()
{
	Date d1(2024, 4, 14);
	Date d2 = d1 + 5000;
	d1.Print();
	d2.Print();
	d1 += 5000;
	d1.Print();
	cout << endl;

	Date d3(2024, 4, 14);
	Date d4 = d3 - 5000;
	d3.Print();
	d4.Print();
	d3 -= 5000;
	d3.Print();

	Date d5(2024, 4, 14);
	d5 += -5000;
	d5.Print();
}

void TestDate2()
{
	Date d1(2024, 4, 14);
	Date d2 = ++d1;
	d1.Print();
	d2.Print();

	Date d3 = d1++;
	d3.Print();
	d1.Print();
}

void TestDate3()
{
	Date d1(2024, 4, 25);
	Date d2(2034, 4, 25);
	int n = d1 - d2;
	cout << n << endl;
}

void TestDate4()
{
	Date d1(2024, 4, 25);
	Date d2(2034, 4, 25);
	//d1.operator<<(cout);
	//cout << d1;
	//d1 << cout;//要这样写
}

void TestDate5()
{
	Date d1(2024, 4, 25);
	Date d2(2034, 4, 25);
	cout << d1;
	cout << d1 << d2;
	cin >> d2;
	d2.Print();
}

void TestDate6()
{
	const Date d1(1024, 4, 27);
	//这里相当于权限放大
	d1.Print();
}

int main()
{
	//TestDate2();
	//TestDate3();
	//TestDate4();
	//TestDate5();
	TestDate6();
	return 0;
}

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

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

相关文章

Isaac Sim 4 键盘控制小车前进方向(学习笔记5.8.2)

写的乱糟糟&#xff0c;主要是这两周忘了记录了...吭哧吭哧往下搞&#xff0c;突然想起来要留档&#xff0c;先大致写一个&#xff0c;后面再往里添加和修改吧&#xff0c;再不写就全忘了 有一个一直没解决的问题&#xff1a; 在保存文件时出现问题&#xff1a;isaac sim mism…

蜜蜂收卡系统 加油卡充值卡礼品卡自定义回收系统源码 前后端开源uniapp可打包app

本文来自&#xff1a;蜜蜂收卡系统 加油卡充值卡礼品卡自定义回收系统源码 前后端开源uniapp可打包app - 源码1688 卡券绿色循环计划—— 一项旨在构建卡券价值再利用生态的社会责任感项目。在当前数字化消费日益普及的背景下&#xff0c;大量礼品卡、优惠券因各种原因未能有效…

2024年软件测试最全渗透测试工具_下载地址1下载地址2下载地址3(1),我了解到的面试的一些小内幕

网上学习资料一大堆&#xff0c;但如果学到的知识不成体系&#xff0c;遇到问题时只是浅尝辄止&#xff0c;不再深入研究&#xff0c;那么很难做到真正的技术提升。 需要这份系统化的资料的朋友&#xff0c;可以戳这里获取 一个人可以走的很快&#xff0c;但一群人才能走的更…

java项目之智慧图书管理系统设计与实现(springboot+vue+mysql)

风定落花生&#xff0c;歌声逐流水&#xff0c;大家好我是风歌&#xff0c;混迹在java圈的辛苦码农。今天要和大家聊的是一款基于springboot的智慧图书管理系统设计与实现。项目源码以及部署相关请联系风歌&#xff0c;文末附上联系信息 。 项目简介&#xff1a; 智慧图书管理…

华为OD机试【城市聚集度】(java)(200分)

1、题目描述 一张地图上有N个城市&#xff0c;城市和城市之间有且只有一条道路相连&#xff0c;要么直接相连&#xff0c;要么通过其他城市中转相连(可中转一次或多次)。城市与城市之间的道路都不会成环。 当切断通往某城市i的所有道路后&#xff0c;地图上将分成多个连通的城…

【Linux】Linux——Centos7安装RabbitMQ

目录 安装包准备socaterlang 安装rabbitmq安装命令启动rabbitmq&#xff0c;两种方式查看rabbitmq 启动后的情况配置并开启网页插件关闭防火墙或开放端口测试登录问题配置web端访问账号密码和权限添加用户&#xff0c;后面两个参数分别是用户名和密码.添加权限修改用户角色再次…

通过 Java 操作 redis -- hash 哈希表基本命令

目录 使用命令 hset&#xff0c;hget 使用命令 hexists 使用命令 hdel 使用命令 hkeys&#xff0c;hvals 使用命令 hmget&#xff0c;hmset 关于 redis hash 哈希表类型的相关命令推荐看Redis - hash 哈希表 要想通过 Java 操作 redis&#xff0c;首先要连接上 redis 服务…

【C语言】static关键字用法

目录 一、static修饰局部变量 二、static修饰全局变量 三、static修饰函数 一、static修饰局部变量 首先我们来看两段代码: 代码1&#xff08;不加static&#xff09; #include <stdio.h> void test() {int i 0;i;printf("%d ", i); } int main() {int i…

【管理篇】如何向上沟通?

目录标题 向上沟通中下列问题最普遍和上级能不聊就不聊拿捏不好该不该和上级聊的分寸和尺度很难领会到上级的意图如何影响上级的一些观点和决策? 如何应对上述问题呢&#xff1f;&#x1f60e;如何管理上级&#xff1f;&#x1f44c; 向上沟通中下列问题最普遍 和上级能不聊就…

Ubuntu 24.04 LTS 安装 touchegg 开启触控板多指手势

文章目录 〇、概述一、安装 touchegg二、安装 gnome-shell 扩展 X11 Gestures三、安装可视化配置工具 touche 〇、概述 之前为了让笔记本支持多指手势&#xff0c;我安装的是 fusuma&#xff0c;安装教程详见 这篇文章 &#xff0c;考虑到 fusuma 安装过程繁琐且不支持可视化配…

Android ViewFlipper

Android ViewFlipper 在很多APP都有如下的头条/热榜效果&#xff08;上下自动翻滚&#xff09; 这种效果可以使用很多方式实现&#xff0c;有一个简便的方式可以使用ViewFlipper控件实现&#xff0c;ViewFlipper控件继承结果如下&#xff1a; 可以看出ViewFlipper 继承自ViewA…

解锁电脑潜能,提高办公效率:这个桌面助手您可千万不能错过!

文章目录 &#x1f4d6; 介绍 &#x1f4d6;&#x1f4dd; 你是否有这些烦恼&#xff1f;&#x1f4dd; 一站式效率工具平台&#x1f4dd; 插件市场&#xff1a;无限扩展的可能&#x1f4dd; 如何开始使用&#x1f3af; 结语 ⚓️ 相关链接 ⚓️ &#x1f4d6; 介绍 &#x1f4…

未授权访问:MongoDB未授权访问漏洞

目录 1、漏洞原理 2、环境搭建 3、未授权访问 防御手段 今天继续学习各种未授权访问的知识和相关的实操实验&#xff0c;一共有好多篇&#xff0c;内容主要是参考先知社区的一位大佬的关于未授权访问的好文章&#xff0c;还有其他大佬总结好的文章&#xff1a; 这里附上大佬…

OpenCV单窗口并排显示多张图片

OpenCV单窗口并排显示多张图片 效果代码 PS&#xff1a;本例的代码适合图片的宽度和高度都相同。 效果 原始三张图片&#xff1a; 合并显示&#xff1a; 代码 import cv2 import numpy as npdef opencv_multi_img():# 读取图片img1 cv2.imread(saw_1.jpeg)img2 cv2.im…

HTML学习|初识表单post和get提交、文本框和单选框、按钮、多选框和下拉框、文本域和文件域、搜索框滑块和简单验证、表单的应用、表单初级验证

初识表单post和get提交 form标签是表单&#xff0c;method控制表单提交方式&#xff0c;get方式&#xff0c;表单填写的参数能够在跳转的url地址中看到&#xff0c;post方式是看不到的&#xff0c;action是向何处跳转表单数据 input标签&#xff0c;且typetext&#xff0c;是…

Vue 3.3 编译宏 vue3.3新增了一些语法糖和宏,包括泛型组件、defineSlots、defineEmits、defineOptions

Vue 3.3新增了一些语法糖和宏&#xff0c;包括泛型组件、defineSlots、defineEmits、defineOptions defineProps 父组件传参 <template><Child name"my"></Child> </template> <script setup lang"ts"> import Child fro…

Java设计模式-工厂

Java设计模式中&#xff0c;工厂模式主要包括普通工厂模式以及抽象工厂模式&#xff0c;普通工厂模式是用于制造输出不同类型的对象&#xff0c;抽象工厂模式是用于制造输出不同类型的普通工厂&#xff0c;本文主要描述工厂模式的基本用法。 如上所示&#xff0c;使用普通工厂模…

牛客网刷题 | BC81 KiKi求质数个数

目前主要分为三个专栏&#xff0c;后续还会添加&#xff1a; 专栏如下&#xff1a; C语言刷题解析 C语言系列文章 我的成长经历 感谢阅读&#xff01; 初来乍到&#xff0c;如有错误请指出&#xff0c;感谢&#xff01; 描述 KiKi知道了什么是质…

android基础-多线程

多线程&#xff1a; 创建子线程&#xff0c;子线程不允许直接更新UI&#xff0c;试想下如果多个线程去更新UI&#xff0c;则会造成资源错乱&#xff0c;如果枷锁就会使得代码冗余复杂。 android异步处理&#xff1a; 另一种异步多线程方法 doInBackground是在子线程中。

【线性代数】俗说矩阵听课笔记

基础解系的概念 31线性相关&#xff0c;线性无关&#xff0c;拓展与证明 n个m维向量在n<m时可能线性相关也可能线性无关&#xff0c;线性无关时可以构成某个m维空间的一组基。m不小于n时&#xff0c;秩小于n则线性相关。 n个m维向量在n>m时可一定线性相关。低维向量一定…