【C++】类和对象(十二):实现日期类

大家好,我是苏貝,本篇博客带大家了解C++的实现日期类,如果你觉得我写的还不错的话,可以给我一个赞👍吗,感谢❤️
在这里插入图片描述


目录

  • 1 ==/!=/>/</>=/<=运算符重载
  • 2 +/-/+=/-=运算符重载
    • (A) 先写+,再通过+写+=
    • (B) 先写+=,再通过+=写+
    • (C) 先写-,再通过-写-=
    • (D) 先写-=,再通过-=写-
  • 3 前置/后置++/--
  • 4 日期-日期
  • 5 >>/<<运算符重载
    • (A) <<
    • (B) >>
  • 6 优化
    • (A) const
    • (B) 判断日期是否有效
  • 7.模块化代码实现
    • 1. Date.h
    • 2. Date.cpp
    • 3. test.cpp

日期类需要自主实现构造函数,运算符重载(>,<,>=,<=,==,!=,+,-,+=,-=,++),不需要自主实现析构函数(没有动态开辟空间)、拷贝构造函数(成员变量中没有自定义类型的)。经过前面的学习,我们可以比较快的写出Date类的大部分

现在我们来新建3个文件Date.h、Date.cpp、test.cpp
将Date类放在Date.h文件中
在这里插入图片描述

上述函数的声明写在类中,但实现写在Date.cpp中

构造函数用全缺省的,注意:缺省参数如果声明和定义分离,那么缺省参数写在函数声明,函数定义中不写。因为声明和定义分离,所以函数定义时函数名前需要加Date::
在这里插入图片描述

1 ==/!=/>/</>=/<=运算符重载

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2 +/-/+=/-=运算符重载

我们有2种写法,一是先写+,再通过+写+=。二是先写+=,再通过+=写+
这里的+/-是+/-天数,如2022年3月4日加10天=2022年3月14日

(A) 先写+,再通过+写+=

在实现+运算符重载前,我们要得到每个月的天数。可以定义一个函数,用if/else条件判断语句来返回天数,当然,这比较麻烦。最简单的方法是定义一个数组
在这里插入图片描述

上面的函数可以优化一下,将数组用static修饰,这样数组就不在栈区。以后就不用每调用一次GetMonthDay函数,就要定义一个数组,等到函数运行完成,还要销毁数组了。

问:下面的Date tmp=this;是拷贝构造还是赋值运算符重载?拷贝构造,因为是用已存在的类类型对象this创建新对象tmp
在这里插入图片描述
在这里插入图片描述

为什么+运算符重载返回值类型是Date,+=运算符重载返回值类型是Date&?
如果可以,我们都希望返回的是Date&类型的,因为这返回的是引用。如果返回的是Date类型的,那么返回的是返回值的拷贝。
Tmp是临时变量,临时变量出了作用域就销毁了,所以临时变量不能用引用返回,所以返回值类型是Date。下面的返回值类型同理

(B) 先写+=,再通过+=写+

在这里插入图片描述

问:上面的2种方法写+和+=,哪一种更好?

在这里插入图片描述

右边的更好,因为左边的+=里复用+需要创建对象,右边的+里复用+=不需要创建对象

© 先写-,再通过-写-=

在这里插入图片描述

(D) 先写-=,再通过-=写-

在这里插入图片描述

同理,-/-=中先写-=再通过-=写-更好

3 前置/后置++/–

在这里插入图片描述

在这里插入图片描述

4 日期-日期

这和-天数是函数重载

思路:
先知道哪个的日期较大/较小,让较小的日期进入循环,每循环一次,较小的日期+1,等到两日期相等,看循环的次数就知道两日期相差几天

在这里插入图片描述

5 >>/<<运算符重载

(A) <<

我们知道,<<(流插入运算符)支持内置类型的打印,但不支持自定义类型的打印
在这里插入图片描述

那我们想实现<<打印自定义类型怎么办?自己写一个<<的运算符重载

将<<运算符重载的声明写在类中,<<运算符重载需要有参数:cout(类型是ostream),为什么?因为<<是双操作符,因此需要2个形参,形参this隐含,所以还需要cout当实参

在这里插入图片描述
在这里插入图片描述

为什么cout<<d1;会报错?因为双操作数的操作符,左右的操作数必须和运算符重载函数的形参顺序相同,函数的第一个形参是隐藏的this,第二个才是out。因此可以d1<<cout,而不能cout<<d1。

为解决这个问题,我们就要是out是第一个形参,this是第二个形参,可是这在类中的成员函数中是不可能的。因此<<运算符重载不能写在类里,要写在全局域中。
注意:全局函数(如函数a)的定义不能写在.h文件中。如果全局函数的定义写在.h文件中,因为.h文件被2个.cpp文件包含,所以预处理时2个.cpp文件都会展开.h文件,这样就会有2个a,链接时会报错。

因此<<运算符重载也要声明和定义分离
在这里插入图片描述

Date类的成员变量是private修饰的,即不能在类外被访问。所以上图会报错,如何解决?
方法1:在Date类里写GetYear/GetMonth/GetDay函数
方法2:友元声明

友元声明即在类中也写一下函数的声明,且在声明前+friend(全局域里也需要有函数的声明,因此这个函数的声明有2个)
在这里插入图片描述

完成上面的要求,就能让<<打印自定义类型

在这里插入图片描述

在这里插入图片描述

在C++中,<<是可以连续使用的,但我们实现的不可以,为什么?
在这里插入图片描述

因为我们相等<<运算符重载没有返回cout,如果返回了cout,那么第一次cout<<d1后的返回值是cout,那接下来的表达式为cout<<d2<<endl。因此修改<<运算符重载的返回值,就能连续使用<<

在这里插入图片描述

在这里插入图片描述

(B) >>

Cin的类型是istream。>>和<<运算符重载一样,都需要在类中有友元声明

在这里插入图片描述

在这里插入图片描述

6 优化

(A) const

在Date类的成员函数中,有许多是不修改*this的,所以这些函数的this指针可以被const修饰

(B) 判断日期是否有效

像下图,2月30日是不可能的情况,所以我们需要对输入的日期进行检查
在这里插入图片描述
在这里插入图片描述

在哪里需要检查日期的有效性呢?需要输入日期的地方:构造函数和>>运算符重载

构造函数:
在这里插入图片描述

运算符>>重载:

在这里插入图片描述

7.模块化代码实现

1. Date.h

#pragma once#include<iostream>using std::endl;
using std::cout;
using std::cin;
using std::istream;
using std::ostream;class Date
{
public:bool CheckValid();Date(int year = 2020, int month = 1, int day = 1);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) const;Date& operator+=(int day);Date operator-(int day) const;Date& operator-=(int day);Date& operator++();Date operator++(int);Date& operator--();Date operator--(int);int operator-(const Date& d);friend ostream& operator<<(ostream& out, const Date& d);friend istream& operator>>(istream& in, Date& d);int GetMonthDay(int year, int month){static int monthday[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;}return monthday[month];}void Print(){cout << _year << "-" << _month << "-" << _day << endl;}private:int _year;int _month;int _day;
};ostream& operator<<(ostream& out, const Date& d);
istream& operator>>(istream& in, Date& d);

2. Date.cpp

#define _CRT_SECURE_NO_WARNINGS 1#include"Date.h"Date::Date(int year, int month, int day)
{_year = year;_month = month;_day = day;if (!CheckValid()){cout << "构造日期错误" << _year << "-" << _month << "-" << _day << endl;}
}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);
}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){if (_day > d._day)return true;}}return false;
}bool Date::operator<(const Date& d) const
{return !(*this == d) && !(*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) const
{Date tmp(*this);tmp += day;return tmp;
}Date& Date::operator+=(int day)
{_day += day;while (_day > GetMonthDay(_year, _month)){_day -= GetMonthDay(_year, _month);_month++;if (_month == 13){_year++;_month = 1;}}return *this;
}//Date Date::operator+(int day)
//{
//	Date tmp(*this);//拷贝构造
//	//Date tmp = *this;//拷贝构造
//	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)
//{
//	*this = *this + day;
//	return *this;
//}Date Date::operator-(int day) const
{Date tmp(*this);tmp -= day;return tmp;
}Date& Date::operator-=(int day)
{_day -= day;while (_day <= 0){_month--;if (_month == 0){_year--;_month = 12;}_day += GetMonthDay(_year, _month);}return *this;
}//Date Date::operator-(int day)
//{
//	Date tmp(*this);
//	tmp._day -= day;
//	while (tmp._day <= 0)
//	{
//		tmp._month--;
//		if (tmp._month == 0)
//		{
//			tmp._year--;
//			tmp._month = 12;
//		}
//		tmp._day += GetMonthDay(tmp._year, tmp._month);
//	}
//	return tmp;
//}
//
//Date& Date::operator-=(int day)
//{
//	*this = *this - day;
//	return *this;
//}//++d
Date& Date::operator++()
{*this += 1;return *this;
}//d++
Date Date::operator++(int)
{Date tmp(*this);*this += 1;return tmp;
}//--d
Date& Date::operator--()
{*this -= 1;return *this;
}//d--
Date Date::operator--(int)
{Date tmp(*this);*this -= 1;return tmp;
}//d1-d2
int Date::operator-(const Date& d)
{Date max(*this);Date min(d);int flag = 1;if (min > max){flag = -1;max = d;min = *this;}int tmp=0;while (min != max)//比min<max要简单{++min;tmp++;}return tmp * flag;
}ostream& operator<<(ostream& out, const Date& d)
{out << d._year << "/" << d._month << "/" << d._day << endl;return out;
}istream& operator>>(istream& in, Date& d)
{cout << "请依次输入年月日:";while (1){in >> d._year >> d._month >> d._day;if (!d.CheckValid()){cout << "输入的日期错误,请重新输入:";}elsebreak;}return in;
}bool Date::CheckValid()
{if (_year <= 0|| _month > 12 || _month <= 0|| _day > GetMonthDay(_year, _month)){return false;}elsereturn true;
}

3. test.cpp

#define _CRT_SECURE_NO_WARNINGS 1#include"Date.h"int main()
{Date d1(2022, 2, 30);cout << d1 << endl;/*d1.operator<<(cout);cout << d1;d1 << cout;*//*cin >> d1;cout << d1 << endl;*//*d3 = d1--;cout << d3;d3 = --d2;cout << d3;*///cin >> d3;/*cin >> d1 >> d2 >> d3;cout << d1 << d2 << d3;*///cout << d1;/*d1.operator<<(cout);d1 << cout;*//*cout << (d1 - d2) << endl;cout << (d2 - d1) << endl;*//*d3 = ++d1;d3.Print();d3 = d2++;d3.Print();*//*d3 = d1 + 49;d3.Print();d3= d1 - 342;d3.Print();d2 += 67;d2.Print();d2 -= 98;d2.Print();*//*d2 = d1;cout << (d1 == d2) << endl;cout << (d1 != d2) << endl;cout << (d1 > d2) << endl;cout << (d1 >= d2) << endl;cout << (d1 < d2) << endl;cout << (d1 <= d2) << endl;*/return 0;
}

好了,那么本篇博客就到此结束了,如果你觉得本篇博客对你有些帮助,可以给个大大的赞👍吗,感谢看到这里,我们下篇博客见❤️

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

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

相关文章

KTHREAD--InitialStack和KernelStack和TSS的esp0

InitialStack和TSS.esp0的关系,在这里可以看到 mov ecx, [esi_KTHREAD.InitialStack] ; esi: newthread lea eax, [ecx-210h] ; 越过FPXSAVE指令存储地址 test byte ptr [eax-1Ah], 2 ; 判断efalgs寄存器的VIF位是否为1 jnz short loc_458743 sub eax, 10h…

xlrd.biffh.XLRDError: Excel xlsx file; not supported

文章目录 一、问题报错二、报错原因三、解决思路四、解决方法 一、问题报错 在处理Excel文件时&#xff0c;特别是当我们使用Python的xlrd库来读取.xlsx格式的文件&#xff0c;偶尔会遇到这样一个错误&#xff1a;“xlrd.biffh.XLRDError: Excel xlsx file; not supported”。…

二叉树进阶-二叉搜索树

目录 1.二叉树的概念 2.二叉搜索树的操作 2.1二叉搜索树的结构 2.2实现节点的查找&#xff08;find&#xff09; 2.3实现增加节点&#xff08;insert&#xff09; 2.4实现删除节点&#xff08;erase&#xff09; 2.5析构函数 2.6二叉搜索树的完整实现 3.二叉搜索树的应…

「Mac畅玩鸿蒙与硬件24」UI互动应用篇1 - 灯光控制小项目

本篇将带领你实现一个互动性十足的灯光控制小项目&#xff0c;用户可以通过点击按钮来控制灯光的开关。该项目将涉及状态管理、动态图片加载以及按钮交互&#xff0c;是学习鸿蒙应用开发的重要基础。 关键词 UI互动应用状态管理动态图片加载用户交互 一、功能说明 在这个灯光…

自制inscode项目推荐:色块小游戏

小编的inscode部署项目&#xff1a;割绳子游戏。 更多精彩内容见InsCode - 让你的灵感立刻落地~ 介绍一下项目及玩法。 游戏概述 颜色匹配小游戏是一款基于HTML、CSS和JavaScript开发的简单而有趣的网页游戏。游戏的目标是通过点击颜色块&#xff0c;将整个游戏板上的所有方块…

DevOps赋能:优化业务价值流的实战策略与路径(下)

下篇&#xff1a;加速工作项流动与持续改进优化 —— 跨越差距&#xff0c;迈向卓越交付 在上篇中&#xff0c;我们已经深入探讨了看板方法的四大核心实践&#xff0c;它们共同致力于实现“顺畅且高质量地交付价值”的终极目标。然而&#xff0c;理想与现实之间往往存在一定的…

使用带有令牌认证的 Jupyter Notebook 服务器

当你不想在默认浏览器打开Jupyter Notebook,但是在其他浏览器打开http://localhost:8890/lab或者http://localhost:8889/tree&#xff0c;却显示 Token authentication is enabled&#xff0c;如下图 可以按以下步骤操作&#xff1a; 获取令牌&#xff1a;在启动 Jupyter Note…

FRIENDLYARM Tiny6410 superboot烧写进sd卡教程

友善之臂真的垃圾&#xff0c;pdf乱不说&#xff0c;资料在哪也不说&#xff0c;没有视频教程&#xff0c;就染你自己去一堆资料里找&#xff0c;** superboot在资料B盘tooles-image里 注意有些朋友scan不到sd卡是因为没有给这个软件开启管理员模式&#xff0c;他没权限去扫描…

宝藏虚拟化学习资料大全

最近发现了关于虚拟化的宝藏资料&#xff0c;瑞斯拜&#xff01;原文链接如下&#xff1a; 500篇关于虚拟化的经典资料&#xff0c;含CPU虚拟化&#xff0c;磁盘虚拟化&#xff0c;内存虚拟化&#xff0c;IO虚拟化。 目录 &#x1fa90; 虚拟化基础 &#x1f343; 虚拟化分类&…

C++模拟真人动态生成鼠标滑动路径

一.简介 鼠标轨迹算法是一种模拟人类鼠标操作的程序&#xff0c;它能够模拟出自然而真实的鼠标移动路径。 鼠标轨迹算法的底层实现采用C/C语言&#xff0c;原因在于C/C提供了高性能的执行能力和直接访问操作系统底层资源的能力。 鼠标轨迹算法具有以下优势&#xff1a; 模拟…

【Redis实践】使用zset实现实时排行榜以及一些优化思考

文章目录 1.概述2.zset的基本概念说明2.1.数据结构说明2.2.zset做排行榜的指令 3. 项目中的实践3.1.RedisTemplate实现排行榜3.2.可能存在的问题及解决方案3.2.1. 限制成员的数量3.2.2.保留当前分数与最高分数3.2.3.批量操作成员分数&#xff0c;减少并发 4.总结 1.概述 我们在…

C++_STL_xx_番外01_关于STL的总结(常见容器的总结;关联式容器分类及特点;二叉树、二叉搜索树、AVL树(平衡二叉搜索树)、B树、红黑树)

文章目录 1. 常用容器总结2. 关联式容器分类3. 二叉树、二叉搜索树、AVL树、B树、红黑树 1. 常用容器总结 针对常用容器的一些总结&#xff1a; 2. 关联式容器分类 关联式容器分为两大类&#xff1a; 基于红黑树的set和map&#xff1b;基于hash表的unorder_set和unorder_ma…

【LwIP源码学习4】主线程tcpip_thread

前言 本文对lwip的主要线程tcpip_thread进行分析。 正文 tcpip_thread是lwip最主要的线程&#xff0c;其创建在tcpip_init函数中 sys_thread_new(TCPIP_THREAD_NAME, tcpip_thread, NULL, TCPIP_THREAD_STACKSIZE, TCPIP_THREAD_PRIO);tcpip_init函数被TCPIP_Init函数调用。…

光圈,感光度,感光器件

光圈&#xff08;通光孔&#xff09;&#xff0c;是一个用来控制光线透过镜头进入机身内感光面光量的装置&#xff0c;通常设置在镜头内。通常&#xff0c;我们用f值来表达光圈大小。通俗来说&#xff0c;摄像机镜头拍照时&#xff0c;不可能随意改变镜头直径&#xff0c;但可以…

Llama 3.2 Vision Molmo:多模态开源生态系统基础

编者按&#xff1a; 视觉功能的融入对模型能力和推理方式的影响如何&#xff1f;当我们需要一个既能看懂图像、又能生成文本的 AI 助手时&#xff0c;是否只能依赖于 GPT-4V 这样的闭源解决方案&#xff1f; 我们今天为大家分享的这篇文章&#xff0c;作者的核心观点是&#xf…

高效视频制作大提速,视频剪辑软件的高级自定义命令功能批量调整视频的色调、饱和度和亮度,轻松驾驭视频编辑技巧

在浩瀚的数字海洋中&#xff0c;视频如同璀璨的星辰&#xff0c;而每一颗星辰都渴望被精心雕琢&#xff0c;闪耀出最独特的光芒。想象一下&#xff0c;你手握一把神奇的钥匙&#xff0c;能够轻松解锁批量视频剪辑的奥秘&#xff0c;让每一帧画面都跃动着你的创意与激情。这把钥…

[RootersCTF2019]ImgXweb

审题 看到robots.txt,看到里面的文件&#xff0c;打开看到 you-will-never-guess这个字符串 进行注册登录 可以看到典型的jwt加密的Cookie 想到之前的字符串可能是密匙&#xff0c;更改为admin&#xff0c;进行登录。 成功后可以看到flag.png。 发现图形打不开 使用curl进…

32单片机HAL库的引脚初始化

在使用HAL库时&#xff0c;GPIO初始化函数定义在stm32f4xx_hal_gpio.c文件中&#xff0c;如下&#xff1a; void HAL_GPIO_Init(GPIO_TypeDef *GPIOx, GPIO_InitTypeDef *GPIO_Init); 由这个函数可以看出&#xff0c;在初始化GPIO时&#xff0c;需要向函数传入2个结构体&…

ubuntu【桌面】 配置NAT模式固定IP

DHCP分配导致虚拟机IP老变&#xff0c;SSH老要重新配置&#xff0c;设成静态方便些 一、设NAT模式 1、设为NAT模式 2、看模式对应的虚拟网卡 - VMnet8 3、共享主机网卡网络到虚拟网卡 - VMnet8 二、为虚拟网卡设置静态IP 记住这个IP 三、设置ubuntu固定IP 1、关闭DHCP并…

确保企业架构与业务的一致性与合规性:数字化转型中的关键要素与战略实施

在现代企业的数字化转型过程中&#xff0c;确保企业架构&#xff08;Enterprise Architecture, EA&#xff09;与企业业务的紧密一致性与合规性至关重要。无论是在战略层面还是运营层面&#xff0c;EA都为企业的未来发展提供了清晰的蓝图&#xff0c;确保企业在应对复杂的业务环…