【c++】类与对象实践:日期类(运算符重载应用)详细版

2024-09-01 01:44

本文主要是介绍【c++】类与对象实践:日期类(运算符重载应用)详细版,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

 文章专栏:c++学习之路

 持续更新~


目录

一、日期类介绍

二、日期类目标功能

1.日期结构设计

2.实现功能的前提函数

3.必须具备实际意义

三、日期类具体实现

🌷头文件->Date.h

🔥逐步解析

1.成员变量

2.构造函数

3.赋值运算符重载 (operator=)

5.自增/自减运算符重载:

6.关系运算符重载:

7.必备方法:

9.流运算符的重载 >>   和<<

🔥代码展示

🌷功能实现 --> Date.cpp

🔥逐步解析:

1.构造函数

 🍬全缺省构造函数

🍬拷贝构造函数

🍬析构函数

2.必备方法

3.赋值运算符重载

3.加减相关的运算符重载

🍬+=重载

🍬+重载

🍬前置++ 和 后置++

🍬 -=、-、前置--、后置--

4.关系运算符

5.计算日期相差天数

6.流重载操作符

五、完整代码

Date.h

Date.cpp

💗感谢阅读!💗


一、日期类介绍

日期函数是用于处理日期数据的函数,通常包括获取当前日期、计算两个日期差值、日期时间比较、日期时间计算等功能。

日期类就是对以上功能的各种实现!!

通过对日期类的学习,我们可以对类和对象有更进一步的认识,同时灵活掌握运算符重载,实现自定义类型的各种运算,但是这些运算必须具备现实意义

比如,计算两个自定义类型Date 之间的差值,实际意义:两个日期相差多少天

Date d1(2023,2,20); //日期类实例化对象
Date d2(2024,5,10);
d2 - d1; //计算两个自定义类型Date 之间的差值,实际意义:两个日期相差多少天

 完成日期类的实现,必须先对成员函数有一定的概念和理解!!

二、日期类目标功能

1.日期结构设计

自定义类型名称:Date
类的属性:
                int _year;
                int  _month;
                int _day;

必要的构造函数,析构函数,拷贝构造函数

2.实现功能的前提函数

运算符重载函数

  •         < 、>、 ==、 <= 、>= 、!=等关系操作符的重载
  •         前置++、后置++、后置-- 、前置--
  •         加+、加等+=、减-、减等-=  

通过以上重载,可以实现日期的加减运算,增加或减少年、月、日来实现新的日期对象,日期的大小比较等等。

工具函数:

获取每个月的天数

int Date::GetMonthDay(int year, int month) const;

3.必须具备实际意义

Date类需要实现对日期有效性的严格检查,确保月份正常,保证闰年的判断,符合各个月份的实际天数。

比如:

  •         月份要在【1,12】区间之内;
  •         天数根据年份、月份确定。

三、日期类具体实现

🌷头文件->Date.h

🔥逐步解析

1.成员变量

私有成员

//年月日int _year;int _month;int _day;
2.构造函数

全缺省构造函数,默认日期为1年1月1日。
!!注意:缺省值,不能在头文件和接口实现文件中同时存在。

拷贝构造函数,复制给定日期对象的所有信息。

Date(int year = 1, int month = 1, int day = 1);//构造函数 + 全缺省Date(const Date& d);							// 拷贝构造函数
3.赋值运算符重载 (operator=)

用于拷贝另一个Date对象的日期信息到当前对象。

	// 赋值运算符重载// d2 = d3 -> d2.operator=(&d2, d3)Date& operator=(const Date& d);

4.算术运算符重载:

        += 和 -= 运算符用于日期增加或减少指定天数。

        一般都是先实现+= 和-=,然后+和 - 运算符 复用 += 和-=。
        +和 - 运算符分别用于返回增加或减少指定天数后的日期对象,以及两个日期之间的天数差。

Date& operator+=(int day);// 日期+=天数Date operator+(int day);// 日期+天数Date operator-(int day);// 日期-天数Date& operator-=(int day);// 日期-=天数
5.自增/自减运算符重载:


前缀和后缀形式的 ++ 与 - -运算符,用于向前或向后移动一天。
可以复用+=  和 -= ,减少代码量!!

Date& operator++();// 前置++Date operator++(int);// 后置++,有特殊处理 形参  Date operator--(int);// 后置-- ,有特殊处理 形参  Date& operator--();// 前置--
6.关系运算符重载:


<、>、>=、<= 和 == 分别用于比较两个日期的大小关系。
!= 判断两个日期是否不相等。

bool operator>(const Date& d);// >运算符重载bool operator==(const Date& d);// ==运算符重载bool operator >= (const Date& d);// >=运算符重载bool operator < (const Date& d);// <运算符重载bool operator <= (const Date& d);// <=运算符重载bool operator != (const Date& d);// !=运算符重载
7.必备方法:

 Print() 用于输出日期

GetMonthDay() 根据年份和月份获取该月的天数,考虑了闰年的特殊情况。

8.析构函数:

日期类不存在手动开辟空间的行为,无需再手动析构。

9.流运算符的重载 >>   和<<

两个函数都是全局函数。便于打印自定义类型Date。

为了访问类Date中的私有成员,必须把两个函数设为友元。

ostream& operator<<(ostream& out, const Date& d);
istream& operator>>(istream& in, Date& d);

🔥代码展示

#pragma once
#include<iostream>
using namespace std;//日期类(完结版 + 六个成员函数)//缺省参数,不能声明和定义同时定义class Date
{
public:Date(int year = 1, int month = 1, int day = 1);//构造函数 + 全缺省~Date();										//析构Date(const Date& d);							// 拷贝构造函数void Print();// 获取某年某月的天数int GetMonthDay(int year, int month);// 赋值运算符重载// d2 = d3 -> d2.operator=(&d2, d3)Date& operator=(const Date& d);Date& operator+=(int day);// 日期+=天数Date operator+(int day);// 日期+天数//实现 + 运算符重载,直接复用+=,// 为什么不选择 += 复用 + ?	 因为在 + 的重载中,发生拷贝的次数 > +=					Date operator-(int day);// 日期-天数Date& operator-=(int day);// 日期-=天数Date& operator++();// 前置++Date operator++(int);// 后置++,有特殊处理 形参  Date operator--(int);// 后置-- ,有特殊处理 形参  Date& operator--();// 前置--bool operator>(const Date& d);// >运算符重载bool operator==(const Date& d);// ==运算符重载bool operator >= (const Date& d);// >=运算符重载bool operator < (const Date& d);// <运算符重载bool operator <= (const Date& d);// <=运算符重载bool operator != (const Date& d);// !=运算符重载// 日期-日期 返回天数int operator-(const Date& d);friend ostream& operator<<(ostream& out, const Date& d);friend istream& operator>>(istream& in, Date& d);private://年月日int _year;int _month;int _day;
};ostream& operator<<(ostream& out, const Date& d);
istream& operator>>(istream& in, Date& d);

🌷功能实现 --> Date.cpp

🔥逐步解析:

1.构造函数

 🍬全缺省构造函数


首先我们需要提供一个全缺省的构造函数,方便对象的实例化。
这里我们提供默认的(1,1,1)作为缺省值.

需要注意的是,此时我们已经在头文件Date.h中,构造函数的声明中确定了缺省值!!
因此,在Date.cpp函数定义中,我们就不能再写缺省值!!

第二个注意事项:

日期的定义必须符合现实意义。

Date类需要实现对日期有效性的严格检查,确保月份正常,保证闰年的判断,符合各个月份的实际天数。

比如:

  •         月份要在【1,12】区间之内;
  •         天数根据年份、月份确定。

因此需要对传入的日期进行条件检查!

	//构造函数 + 全缺省
Date::Date(int year, int month, int day)
{_year = year;_month = month;_day = day;if (_year < 1 ||_month < 1 || _month > 12 ||_day < 1 || _day > GetMonthDay(_year, _month)){//assert(false);Print();cout << "日期非法" << endl;}
}

🍬拷贝构造函数

拷贝构造函数,让我们更加灵活的创建对象,以及可以传引用返回!提高效率!

Date::Date(const Date& d) {_year = d._year;_month = d._month;_day = d._day;
}

🍬析构函数

因为我们没有开辟空间,不需要考虑复杂问题。

//析构
Date::~Date()
{}
2.必备方法

便于实现后面的+=、-=

 Print() 用于输出日期

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

GetMonthDay() 根据年份和月份获取该月的天数,考虑了闰年的特殊情况。

// 获取某年某月的天数
int Date::GetMonthDay(int year, int month)
{int dayArr[13] = { 0, 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;}return dayArr[month];
}
3.赋值运算符重载

返回值:传引用返回,注意this指针需要解引用。

参数类型:const 防止不小心修改参数内容

                   使用引用,提高效率,减少拷贝

函数体: 不要对自己本身进行赋值,直接利用地址相同规避。

// 赋值运算符重载// this = d  
Date& Date::operator=(const Date& d)
{//不对自己赋值//引用返回,直接对左操作数进行修改,减少拷贝if (this != &d){_year = d._year;_month = d._month;_day = d._day;}return *this;
}
3.加减相关的运算符重载

+、 -、 +=、 -=、 前置++、 后置++ 、前置--、 后置–

我们只需要实现+=、-=,然后其他运算符就可以复用 += 、-=来实现,极大节省我们的时间。


🍬+=重载

 日期+=天数

因为是+=,对日期本身进行了修改,所以传引用返回。

// 日期+=天数
// d+= 1000 ---->  d = d+1000,d 的实际内容发生改变
Date& Date::operator+=(int day) 
{// a+=b,a本身变化了,因此最后返回aif (day < 0){return *this -= day;}_day += day;while(_day > GetMonthDay(_year, _month))//天数已经超过当前月份{_day -= GetMonthDay(_year, _month);_month++;if (_month > 12){_year++;_month = 1;}}return *this;
}

🍬+重载

复用+=,可以实现+重载。

d + 1000 ---->  a  = d+1000,d 的实际内容不改变,而是,其他临时变量接收结果。
所以不能传回引用 , 这里是临时变量,函数结束后会自动释放,传引用会导致错误。

// 日期+天数
// d + 1000 ---->  a  = d+1000,d 的实际内容不改变,而是,其他变量接收结果
Date Date::operator+(int day)
{Date temp(*this);temp += day;return temp;
}

🍬前置++ 和 后置++

直接复用+=

为了便于区分前置和后置++,

对于前置++,无参数

对于后置++,设个int形参

// 前置++Date& Date::operator++()
{return *this += 1;
}// 后置++
//先用一个临时变量存储this原先的数值,然后this++,返回临时变量
Date Date::operator++(int)
{Date temp(*this);*this+=1;return temp;
}

🍬 -=、-、前置--、后置--

思路和加法类似!!

// 日期-=天数
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) {Date temp(*this);temp -= day;		//复用-=return temp;
}// 前置--Date& Date::operator--()
{return *this -= 1;
}// 后置--Date Date::operator--(int)
{Date temp(*this);*this -= 1;return temp;
}
4.关系运算符

只需要实现== 、> ,就可以通过复用实现其他操作!


==重载


// ==运算符重载bool Date::operator==(const Date& d)
{if (_year == d._year && _month == d._month && _day == d._day){return true;}return false;
}

>重载


// >运算符重载bool Date::operator>(const Date& d)
{if (_year > d._year){return true;}else if (_year == d._year && _month > d._month){return true;}else if (_year == d._year && _month == d._month && _day > d._day){return true;}return false;
}

其他操作符



// >=运算符重载bool Date::operator >= (const Date& d)
{if (*this > d || *this == d){return true;}return false;
}// <运算符重载bool Date::operator < (const Date& d) {if (*this >= d)return false;return true;
}// <=运算符重载bool Date::operator <= (const Date& d) {if (*this > d)return false;return true;
}// !=运算符重载bool Date::operator != (const Date& d) {if (*this == d)return false;return true;
}
5.计算日期相差天数

思想:

找出较小的日期,采用++,利用计数器计算出天数,直到两个日期相等。

那么计数器,就是相差天数!

// 日期-日期 返回天数int Date::operator-(const Date& d) {Date min = *this;Date max = d;if (min > max){swap(min, max);}int day = 0;while (min != max){min++;day++;}return day;
}
6.流重载操作符

需要在类Date的声明中设置为友元!才可以访问私有变量。

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

五、完整代码

Date.h

#pragma once
#include<iostream>
using namespace std;//日期类(完结版 + 六个成员函数)//缺省参数,不能声明和定义同时定义class Date
{
public:Date(int year = 1, int month = 1, int day = 1);//构造函数 + 全缺省~Date();										//析构Date(const Date& d);							// 拷贝构造函数void Print();// 获取某年某月的天数int GetMonthDay(int year, int month);// 赋值运算符重载// d2 = d3 -> d2.operator=(&d2, d3)Date& operator=(const Date& d);Date& operator+=(int day);// 日期+=天数Date operator+(int day);// 日期+天数//实现 + 运算符重载,直接复用+=,// 为什么不选择 += 复用 + ?	 因为在 + 的重载中,发生拷贝的次数 > +=					Date operator-(int day);// 日期-天数Date& operator-=(int day);// 日期-=天数Date& operator++();// 前置++Date operator++(int);// 后置++,有特殊处理 形参  Date operator--(int);// 后置-- ,有特殊处理 形参  Date& operator--();// 前置--bool operator>(const Date& d);// >运算符重载bool operator==(const Date& d);// ==运算符重载bool operator >= (const Date& d);// >=运算符重载bool operator < (const Date& d);// <运算符重载bool operator <= (const Date& d);// <=运算符重载bool operator != (const Date& d);// !=运算符重载// 日期-日期 返回天数int operator-(const Date& d);friend ostream& operator<<(ostream& out, const Date& d);friend istream& operator>>(istream& in, Date& d);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)
{_year = year;_month = month;_day = day;if (_year < 1 ||_month < 1 || _month > 12 ||_day < 1 || _day > GetMonthDay(_year, _month)){//assert(false);Print();cout << "日期非法" << endl;}
}//析构
Date::~Date()
{}
// 拷贝构造函数
Date::Date(const Date& d)
{_year = d._year;_month = d._month;_day = d._day;
} void Date::Print()
{cout << _year << "/" << _month << "/" << _day << endl;
}// 获取某年某月的天数
int Date::GetMonthDay(int year, int month)
{int dayArr[13] = { 0, 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;}return dayArr[month];
}// 赋值运算符重载// this = d  
Date& Date::operator=(const Date& d)
{//不对自己赋值//引用返回,直接对左操作数进行修改,减少拷贝if (this != &d){_year = d._year;_month = d._month;_day = d._day;}return *this;
}// 日期+=天数
// d+= 1000 ---->  d = d+1000,d 的实际内容发生改变
Date& Date::operator+=(int day) 
{// a+=b,a本身变化了,因此最后返回aif (day < 0){return *this -= day;}_day += day;while(_day > GetMonthDay(_year, _month))//天数已经超过当前月份{_day -= GetMonthDay(_year, _month);_month++;if (_month > 12){_year++;_month = 1;}}return *this;
}// 日期+天数
// d + 1000 ---->  a  = d+1000,d 的实际内容不改变,而是,其他变量接收结果
Date Date::operator+(int day)
{Date temp(*this);temp += day;return temp;
}// 日期-=天数
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) {Date temp(*this);temp -= day;		//复用-=return temp;
}// 前置++Date& Date::operator++()
{return *this += 1;
}// 后置++
//先用一个临时变量存储this原先的数值,然后this++,返回临时变量
Date Date::operator++(int)
{Date temp(*this);*this+=1;return temp;
}// 前置--Date& Date::operator--()
{return *this -= 1;
}// 后置--Date Date::operator--(int)
{Date temp(*this);*this -= 1;return temp;
}// >运算符重载bool Date::operator>(const Date& d)
{if (_year > d._year){return true;}else if (_year == d._year && _month > d._month){return true;}else if (_year == d._year && _month == d._month && _day > d._day){return true;}return false;
}// ==运算符重载bool Date::operator==(const Date& d)
{if (_year == d._year && _month == d._month && _day == d._day){return true;}return false;
}// >=运算符重载bool Date::operator >= (const Date& d)
{if (*this > d || *this == d){return true;}return false;
}// <运算符重载bool Date::operator < (const Date& d) {if (*this >= d)return false;return true;
}// <=运算符重载bool Date::operator <= (const Date& d) {if (*this > d)return false;return true;
}// !=运算符重载bool Date::operator != (const Date& d) {if (*this == d)return false;return true;
}// 日期-日期 返回天数int Date::operator-(const Date& d) {Date min = *this;Date max = d;if (min > max){swap(min, max);}int day = 0;while (min != max){min++;day++;}return day;
}ostream& operator<<(ostream& out, const Date& d)
{out << d._year << "年" << d._month << "月" << d._day << "日" << endl;return out;
}istream& operator>>(istream& in, Date& d)
{in >> d._year >> d._month >> d._day;return in;
}

💗感谢阅读!💗


这篇关于【c++】类与对象实践:日期类(运算符重载应用)详细版的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1125596

相关文章

基于MySQL Binlog的Elasticsearch数据同步实践

一、为什么要做 随着马蜂窝的逐渐发展,我们的业务数据越来越多,单纯使用 MySQL 已经不能满足我们的数据查询需求,例如对于商品、订单等数据的多维度检索。 使用 Elasticsearch 存储业务数据可以很好的解决我们业务中的搜索需求。而数据进行异构存储后,随之而来的就是数据同步的问题。 二、现有方法及问题 对于数据同步,我们目前的解决方案是建立数据中间表。把需要检索的业务数据,统一放到一张M

中文分词jieba库的使用与实景应用(一)

知识星球:https://articles.zsxq.com/id_fxvgc803qmr2.html 目录 一.定义: 精确模式(默认模式): 全模式: 搜索引擎模式: paddle 模式(基于深度学习的分词模式): 二 自定义词典 三.文本解析   调整词出现的频率 四. 关键词提取 A. 基于TF-IDF算法的关键词提取 B. 基于TextRank算法的关键词提取

水位雨量在线监测系统概述及应用介绍

在当今社会,随着科技的飞速发展,各种智能监测系统已成为保障公共安全、促进资源管理和环境保护的重要工具。其中,水位雨量在线监测系统作为自然灾害预警、水资源管理及水利工程运行的关键技术,其重要性不言而喻。 一、水位雨量在线监测系统的基本原理 水位雨量在线监测系统主要由数据采集单元、数据传输网络、数据处理中心及用户终端四大部分构成,形成了一个完整的闭环系统。 数据采集单元:这是系统的“眼睛”,

【C++ Primer Plus习题】13.4

大家好,这里是国中之林! ❥前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站。有兴趣的可以点点进去看看← 问题: 解答: main.cpp #include <iostream>#include "port.h"int main() {Port p1;Port p2("Abc", "Bcc", 30);std::cout <<

csu 1446 Problem J Modified LCS (扩展欧几里得算法的简单应用)

这是一道扩展欧几里得算法的简单应用题,这题是在湖南多校训练赛中队友ac的一道题,在比赛之后请教了队友,然后自己把它a掉 这也是自己独自做扩展欧几里得算法的题目 题意:把题意转变下就变成了:求d1*x - d2*y = f2 - f1的解,很明显用exgcd来解 下面介绍一下exgcd的一些知识点:求ax + by = c的解 一、首先求ax + by = gcd(a,b)的解 这个

C++包装器

包装器 在 C++ 中,“包装器”通常指的是一种设计模式或编程技巧,用于封装其他代码或对象,使其更易于使用、管理或扩展。包装器的概念在编程中非常普遍,可以用于函数、类、库等多个方面。下面是几个常见的 “包装器” 类型: 1. 函数包装器 函数包装器用于封装一个或多个函数,使其接口更统一或更便于调用。例如,std::function 是一个通用的函数包装器,它可以存储任意可调用对象(函数、函数

hdu1394(线段树点更新的应用)

题意:求一个序列经过一定的操作得到的序列的最小逆序数 这题会用到逆序数的一个性质,在0到n-1这些数字组成的乱序排列,将第一个数字A移到最后一位,得到的逆序数为res-a+(n-a-1) 知道上面的知识点后,可以用暴力来解 代码如下: #include<iostream>#include<algorithm>#include<cstring>#include<stack>#in

C++11第三弹:lambda表达式 | 新的类功能 | 模板的可变参数

🌈个人主页: 南桥几晴秋 🌈C++专栏: 南桥谈C++ 🌈C语言专栏: C语言学习系列 🌈Linux学习专栏: 南桥谈Linux 🌈数据结构学习专栏: 数据结构杂谈 🌈数据库学习专栏: 南桥谈MySQL 🌈Qt学习专栏: 南桥谈Qt 🌈菜鸡代码练习: 练习随想记录 🌈git学习: 南桥谈Git 🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈�

【C++】_list常用方法解析及模拟实现

相信自己的力量,只要对自己始终保持信心,尽自己最大努力去完成任何事,就算事情最终结果是失败了,努力了也不留遗憾。💓💓💓 目录   ✨说在前面 🍋知识点一:什么是list? •🌰1.list的定义 •🌰2.list的基本特性 •🌰3.常用接口介绍 🍋知识点二:list常用接口 •🌰1.默认成员函数 🔥构造函数(⭐) 🔥析构函数 •🌰2.list对象

zoj3820(树的直径的应用)

题意:在一颗树上找两个点,使得所有点到选择与其更近的一个点的距离的最大值最小。 思路:如果是选择一个点的话,那么点就是直径的中点。现在考虑两个点的情况,先求树的直径,再把直径最中间的边去掉,再求剩下的两个子树中直径的中点。 代码如下: #include <stdio.h>#include <string.h>#include <algorithm>#include <map>#