C++——类和对象练习(日期类)

日期类

  • 1. 构造函数和析构函数
  • 2. 拷贝构造和赋值运算符重载
  • 3. 运算符重载
    • 3.1 日期的比较
    • 3.2 日期加减天数
    • 3.3 日期减日期
    • 3.4 流插入和流提取
  • 4. 取地址和const取地址重载
  • 5. 完整代码
    • Date.h
    • Date.c

对日期类进行一个完善,可以帮助我们理解六个默认成员函数,这里选择全部显式实现,包括构造函数,运算符重载,赋值重载等。对有之前的知识点的提示,以及注意事项,这里采用声明和定义分离的形式,下面代码放的全部是定义,除非必要说明。在最后会有完整的代码。包括头文件和源文件内的。

1. 构造函数和析构函数

//构造函数,初始化列表
Date::Date(int year = 2024, int month = 1, int day = 1):_year(year),_month(month),_day(day)
{}//析构函数
Date::~Date() {}

2. 拷贝构造和赋值运算符重载

//拷贝构造函数
Date::Date(const Date& d)
{_year = d._year;_month = d._month;_day = d._day;
}//赋值运算符重载
Date& Date::operator=(const Date& d)
{//可能出现d=d的情况,即自己给自己赋值,可以不用执行代码if (this != &d){_year = d._year;_month = d._month;_day = d._day;}return *this;
}

3. 运算符重载

3.1 日期的比较

比较包括大于,等于,小于,大于或等于,小于或等于,不等于六种。

不需要全部都实现,复用代码即可。我们先写一个大于,日期的比较按照年月日依次比较,年大日期就大,年等的情况,月大日期就大,年等月等的情况,天大日期就大。剩下的所有情况就是不大于。

//运算符重载  大于
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 _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
{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);
}

3.2 日期加减天数

加包括 + 和 +=,减包括 - 和 -=。前者不会修改左操作数,后者会修改左操作数,比如

a=10;
a+5 //不会修改a
a+=5 //会修改a

减同理。

这里先实现 += ,我们需要判断闰年,因为闰年2月有29天,因此,这里封装一个函数,用来获得某年某月的最大天数。

//内联函数声明定义不能分离,在调用处直接展开,不用建立栈帧
inline int GetMonthDay(int year, int month) //获得某年某月的天数
{int MonthDay[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };if (year % 4 == 0 && year % 100 != 0 || year % 400 == 0){++MonthDay[2];}return MonthDay[month];
}

由于这个函数会频繁调用,因此将这个函数声明为内联函数,由于声明定义不能分离,所有这段代码是在头文件内。

有了这个函数后,在实现+=就比较容易了,我们不需要判断是不是闰年,是不是二月了,全部交给这个函数就可以了。

思路:把天全部加上,判断是否超过该月最大天数。有则进行修改,在判断是否超过最大月份,有则进行修改。循环,直到天数小于该月的最大天数。

那么+=代码如下

//日期加等天数(会改变*this)
Date& Date::operator+=(int day)
{//+=一个负数,相当于-=一个正数if (day < 0){*this -= -day;}else{_day += day;while (_day > GetMonthDay(_year, _month)){_day -= GetMonthDay(_year, _month);_month++;if (_month == 13){_year++;_month = 1;}}}return *this;
}

+的实现,可以复用+=的代码

如下

//日期加天数(不会改变*this)
Date Date::operator+(int day) const
{//加不改变*this,需要创建局部变量Date retDate = *this;//拷贝构造retDate += day;//出作用域局部变量销毁,不能传引用返回return retDate;
}

因为+不能改变*this,所以先拷贝一个对象,修改这个对象的内容,在返回。

-= 和 - 的重载很类似,就不赘述了,直接放码

//日期减天数
Date Date::operator-(int day) const
{Date retDate = *this;retDate -= day;return retDate;
}Date& Date::operator-=(int day)
{if (day < 0){*this += -day;}else{_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;
}
//后置++,先使用后++,为了构成函数重载,后置++需要多一个int类型的参数,不需要我们传参
//函数调用时,编译器自动传参。
Date Date::operator++(int)
{//返回修改前的值Date retDate(*this);*this += 1;return retDate;
}//前置--
Date& Date::operator--()
{*this -= 1;return *this;
}
//后置--
Date Date::operator--(int)
{Date retDate(*this);*this -= 1;return retDate;
}

3.3 日期减日期

日期的相加没有意义,但是相减还是比较有意义的,比如计算一下我们从出生到现在生活了多久,和对象已经在一起多久等。

有两种方法:
法一:
在这里插入图片描述
法二:
先比较日期,在对小日期进行自增,直到与大日期相等。

这里选择法二

//日期减日期
int Date::operator-(const Date& d) const
{//找出日期大的和日期小的Date maxDate = *this > d ? *this : d;Date minDate = *this < d ? *this : d;int flag = 1;int day = 0;//第一个日期较小,结果是负数。if (minDate == *this){flag = -1;}while (minDate != maxDate){++minDate;++day;}return day * flag;
}

3.4 流插入和流提取

对于内置类型,可以使用<<和>>来打印或者从键盘输入,自定义类型也可以重载一个流插入和流提取。

// >>和<<需要重载成全局函数,因为成员函数的第一个参数默认是this,重载成成员函数会打破 cout<<d 的习惯//流插入重载
ostream& operator<<(ostream& out, const Date& d)
{out << d._year << "年" << d._month << "月" << d._day << "日" << endl;return out;
}//流提取重载
istream& operator>>(istream& in,Date& d)
{cin >> d._year >> d._month >> d._day;return in;
}

istream和ostream是标准库内的一种输入输出类型,代码内的cou和in就是cout和cin,只不过是别名,在函数内部可以自己定义输出格式,甚至检查错误等。返回值是为了支持连续的输入和输出。

注意:在类外想使用类内部的私有成员,需要在类内部声明为友元函数。

4. 取地址和const取地址重载

这两个函数较为简单,就不过的讲解了。

//const取地址重载
const Date* Date::operator&()const
{return this;
}
//取地址重载
Date* Date::operator&()
{return this;
}

5. 完整代码

Date.h

#pragma once
#include<iostream>
using namespace std;class Date
{//友元函数声明,友元函数可以在类外使用类内的私有成员friend ostream& operator<<(ostream& out,const Date& d);friend istream& operator>>(istream& out,Date& d);public://内联函数声明定义不能分离,在调用处直接展开,不用建立栈帧inline int GetMonthDay(int year, int month) //获得某年某月的天数{int MonthDay[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };if (year % 4 == 0 && year % 100 != 0 || year % 400 == 0){++MonthDay[2];}return MonthDay[month];}//构造函数特征://              1、程序员不显示实现的话,编译器会自动生成默认构造函数//              2、函数名和类名相同,没有返回值(也不能写void,这是规定)//              3、在类对象实例化的过程中编译器对会自动调用对应的构造函数//              4、无参的构造函数,全缺省的构造函数,编译器自动生成的构造函数都可以称为默认构造函数,//                 并且默认构造函数只能存在一个,虽然编译时没有问题,但在调用时会有歧义//              5、构造函数支持函数重载//              6、对内置数据类型如int,char,double等,构造函数不做处理,//                 对自定义数据类型,编译器会调用对应的默认构造函数Date(int year = 2024, int month = 1, int day = 1);//析构函数特征://              1、函数名为类名但需要在类名前加 ~ 符号,没有参数,没有返回值(也不能写void,这是规定)//              2、我们不显示实现的话,编译器会自动生成对应的析构函数//              3、在类对象生命周期结束后,编译器自动调用对应的析构函数//              4、析构函数不能重载,因为析构函数没有参数//              5、一个类只允许有一个析构函数~Date() {};//拷贝构造函数特征://                  1、拷贝构造函数是构造函数的重载函数,所以函数名和类名相同//                  2、有且只有一个参数,该参数必须是类对象的引用,如果不是引用,编译器会直接报错//                  3、若没有显示实现,编译器会自动实现一个默认的拷贝构造函数,对已有的类对象进行拷贝//                     但是是按对应的字节序列完成拷贝,这种拷贝方式称为浅拷贝。//                  4、编译器生成的默认拷贝构造函数可以完成浅拷贝Date(const Date& d);//日期的比较,末尾const是限制*this的,此时this的类型为const Date* const this//不能修改this指针,也不能修改this指针指向的内容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=(const Date& d2);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) const;const Date* operator&()const;Date* operator&();private:int _year;int _month;int _day;
};

Date.c

#define _CRT_SECURE_NO_WARNINGS 1
#include"Date.h"//构造函数,初始化列表
Date::Date(int year = 2024, int month = 1, int day = 1):_year(year),_month(month),_day(day)
{}//析构函数
Date::~Date() {}//拷贝构造函数
Date::Date(const Date& d)
{_year = d._year;_month = d._month;_day = d._day;
}//运算符重载  大于
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 _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
{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) const
//{
//	Date retDate = *this;
//	retDate._day += day;
//	while (retDate._day > GetMonthDay(retDate._year, retDate._month))
//	{
//		retDate._day -= GetMonthDay(retDate._year, retDate._month);
//		retDate._month++;
//		if (retDate._month == 13)
//		{
//			retDate._year++;
//			retDate._month = 1;
//		}
//	}
//	
//	return retDate;
//}
//Date& Date::operator+=(int day)
//{
//	*this = *this + day;//赋值
//	return *this;
//}//日期加天数(不会改变*this)
Date Date::operator+(int day) const
{//加不改变*this,需要创建局部变量Date retDate = *this;//拷贝构造retDate += day;//出作用域局部变量销毁,不能传引用返回return retDate;
}//日期加等天数(会改变*this)
Date& Date::operator+=(int day)
{if (day < 0){*this -= -day;}else{_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) const
{Date retDate = *this;retDate -= day;return retDate;
}
Date& Date::operator-=(int day)
{if (day < 0){*this += -day;}else{_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;
}
//后置++,先使用后++,为了构成函数重载,后置++需要多一个int类型的参数,不需要我们传参
//函数调用时,编译器自动传参。
Date Date::operator++(int)
{Date retDate(*this);*this += 1;return retDate;
}//前置--
Date& Date::operator--()
{*this -= 1;return *this;
}
//后置--
Date Date::operator--(int)
{Date retDate(*this);*this -= 1;return retDate;
}//日期减日期
int Date::operator-(const Date& d) const
{//找出日期大的和日期小的Date maxDate = *this > d ? *this : d;Date minDate = *this < d ? *this : d;int flag = 1;int day = 0;//小日期减大日期为负数if (minDate == *this){flag = -1;}while (minDate != maxDate){++minDate;++day;}return day * flag;
}// >>和<<需要重载成全局函数,因为成员函数的第一个参数默认是this,重载成成员函数会打破 cout<<d 的习惯
//流插入重载
ostream& operator<<(ostream& out, const Date& d)
{out << d._year << "年" << d._month << "月" << d._day << "日" << endl;return out;
}//流提取重载
istream& operator>>(istream& in,Date& d)
{cin >> d._year >> d._month >> d._day;return in;
}//赋值运算符重载
Date& Date::operator=(const Date& d)
{if (this != &d){_year = d._year;_month = d._month;_day = d._day;}return *this;
}const Date* Date::operator&()const
{return this;
}Date* Date::operator&()
{return this;
}

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

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

相关文章

软件行业中的蓝海领域有哪些?

一、什么是蓝海&#xff1f; 蓝海&#xff0c;指的是未知的市场空间。这个概念相对于“红海”而言&#xff0c;红海则是指已知的市场空间。 企业要启动和保持获利性增长&#xff0c;就必须超越产业竞争&#xff0c;开创全新市场&#xff0c;这其中包括两块&#xff1a;一块是…

【软件测试】Selenium实战技巧-多页面和Windows控件处理

01 多页面处理 做UI自动化的时候常常会遇到浏览器弹出新的Tab页&#xff0c;或者需要在多个网页服务之间来回取数据的情况。 比如在首页点击文章“Jmeter使用&#xff1f;”的链接&#xff0c;浏览器会弹出一个新的页面显示“Jmeter使用&#xff1f;”这篇文章的详情。此时如…

Python多线程与多进程编程

一、引言 随着计算机技术的飞速发展&#xff0c;程序运行的速度和效率成为了人们关注的焦点。为了提高程序的执行效率&#xff0c;多线程与多进程编程技术应运而生。Python作为一种通用编程语言&#xff0c;在支持多线程与多进程编程方面有着独特的优势。本文将详细探讨Python…

书生·浦语大模型实战营之 XTuner 微调 Llama 3 个人小助手认知

书生浦语大模型实战营之 XTuner 微调 Llama 3 个人小助手认知 Llama 3 近期重磅发布,发布了 8B 和 70B 参数量的模型,XTuner 团队对 Llama 3 微调进行了光速支持!!!开源同时社区中涌现了 Llama3-XTuner-CN 手把手教大家使用 XTuner 微调 Llama 3 模型。 XTuner:http://…

牛客NC238 加起来和为目标值的组合【中等 DFS C++、Java、Go、PHP】

题目 题目链接&#xff1a; https://www.nowcoder.com/practice/172e6420abf84c11840ed6b36a48f8cd 思路 本题是组合问题&#xff0c;相同元素不同排列仍然看作一个结果。 穷经所有的可能子集&#xff0c;若和等于target&#xff0c;加入最终结果集合。 给nums排序是为了方便…

计算机网络【CN】Ch4 网络层

总结 一台主机可以有多个IP地址&#xff0c;但是必须属于多个逻辑网络【不同的网络号】。 解决IP地址耗尽&#xff1a; IP地址结构&#xff1a; 划分子网&#xff1a;&#x1d43c;&#x1d443;地址<网络号>,<子网号>,<主机号> CIDR&#xff1a;IP地址{&…

智能算法 | Matlab基于CBES融合自适应惯性权重和柯西变异的秃鹰搜索算法

智能算法 | Matlab基于CBES融合自适应惯性权重和柯西变异的秃鹰搜索算法 目录 智能算法 | Matlab基于CBES融合自适应惯性权重和柯西变异的秃鹰搜索算法效果一览基本介绍程序设计参考资料效果一览 基本介绍 Matlab基于CBES融合自适应惯性权重和柯西变异的秃鹰搜索算法 融合自适应…

pycharm爬虫模块(scrapy)基础使用

今天学了个爬虫。在此记录 目录 一.通过scrapy在命令行创建爬虫项目 二.判断数据为静态还是动态 三.pycharm中的设置 三:爬虫主体 四.pipelines配置&#xff08;保存数据的&#xff09; 五.最终结果 一.通过scrapy在命令行创建爬虫项目 1.首先需要在cmd中进入到python文…

华为od机试真题——智能成绩表

题目描述 算法结果 3 3 math chinese english z3 71 81 91 l4 81 71 93 w5 21 91 95 math l4 81 71 93 245 z3 71 81 91 243 w5 21 91 95 207 算法详情 public class SmartScoreTable {public static void main(String[] args) {// 输入Scanner scanner new Scanner(Syste…

一款pdf工具

下载链接&#xff1a;点击跳转&#xff1b; 它是一个installer&#xff0c;下好它之后&#xff0c;把网断掉&#xff0c;然后双击它&#xff0c;他会默认安装在C盘&#xff0c;安装时&#xff0c;浏览器可能会有一个弹窗&#xff0c;直接关掉并进入任务管理器杀掉所有smallerp…

小清新思维题

CF521D shop Problem Solution 首先如果确定了执行的操作&#xff0c;执行顺序一定为赋值、加、乘。赋值操作只保留最大的&#xff0c;并可以转化为加法。每个数的加法操作按从大到小顺序排序后可以转化为乘法。最后将所有乘法操作从大到小排序选前&#x1d45a;个即可。 先…

VMware 15 虚拟机网络遇到的问题

剧情提要 通过Cent os7 的镜像文件&#xff0c;创建了一个虚拟机A&#xff08;后面简称A&#xff09;&#xff0c;事后发现&#xff0c;宿主机无法ping通A 在虚拟机中通过IP a 看到的IP信息也没有只管的ip信息如图 然后执行&#xff0c;宿主机才能访问A。 sudo dhclient ens…

四信AI睿析—边缘智脑:赋能农业新时代,开启智慧种植新篇章

方案简介 本系统前端安装土壤墒情监测站&#xff0c;包括温湿度传感器、二氧化碳传感器、PH值传感器、土壤电导率传感器、土壤温湿度传感器、光照传感器等组成&#xff1b;高清枪机摄像头等、负责种植区域温湿度、土壤EC、土壤温湿度、光照等环境因子、视频数据、农作物生长图…

加速大数据分析:Apache Kylin使用心得与最佳实践详解

Apache Kylin 是一个开源的分布式分析引擎&#xff0c;提供了Hadoop之上的SQL接口和多维分析&#xff08;OLAP&#xff09;能力以支持大规模数据。它擅长处理互联网级别的超大规模数据集&#xff0c;并能够进行亚秒级的查询响应时间。Kylin 的主要使用场景包括大数据分析、交互…

全自动开箱机:从原理到应用,全面解析自动化装箱技术

随着科技的飞速发展&#xff0c;自动化技术在各行各业的应用越来越广泛。其中&#xff0c;全自动开箱机作为现代物流领域的重要设备&#xff0c;以其高效、精准的特点&#xff0c;受到了广大企业的青睐。与星派全面解析全自动开箱机的原理、应用领域以及它所带来的变革。 一、…

Vins-mono中的IMU预积分【SLAM】

世界系下连续时间的IMU积分 w w w代表世界系&#xff0c; b k b_{k} bk​代表第k帧图像。 在 [ t k , t k 1 ] [t_{k}, t_{k1}] [tk​,tk1​]时间段内&#xff0c;有通过加速度和角速度在连续时间下的积分&#xff1a; p b k 1 w p b k w v b k w Δ t k ∬ t ∈ [ t k ,…

插入排序的可视化实现(Python)

插入排序的Python代码 import tkinter as tk import random import timeclass InsertionSortVisualizer:def __init__(self, root, canvas_width800, canvas_height400, num_bars10):self.root rootself.canvas_width canvas_widthself.canvas_height canvas_heightself.nu…

登录的几种方式

一、session 1、客户端发送请求&#xff0c;服务器将登录信息存储在 Session 中&#xff0c;Session 依赖于 Cookie&#xff08;cookie指的就是在浏览器里面存储的一种数据&#xff0c;仅仅是浏览器实现的一种数据存储功能。Cookie实际上是一小段的文本信息。&#xff09;&…

【行为型模式】状态模式

一、状态模式概述 状态模式的定义&#xff1a;允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它的类。(对象行为型) 策略模式和状态模式是双胞胎&#xff0c;在出生时才分开。 策略模式是围绕可以互换的算法来创建成功业务的。状态模式走的是更崇高的路&#xff0…

全民拼购:社交电商与拼购玩法的完美结合

大家好&#xff0c;我是微三云周丽&#xff0c;今天给大家分析当下市场比较火爆的商业模式&#xff01; 小编今天跟大伙们分享什么是社交电商与拼购玩法的wan美结合&#xff1f; 随着社交电商和拼购玩法的兴起&#xff0c;全民拼购模式正逐渐成为电商行业的新宠。结合了人性化…