[Cpp]类和对象 | 实现日期类

news2024/11/18 9:48:20

标题:[Cpp]类和对象 | 实现日期类

@水墨不写bug



正文开始:

        类和对象是Cpp面向对象编程区别于C的面向过程编程的重要的一部分,因此打好坚实的类和对象的基础对于深入学习Cpp语言是比较明智的。

        本文通过实现简单的日期类来加深对类和对象的理解,同时梳理相关知识,熟悉对象的编写过程,为项目的经验要求打下基础。

(一)头文件

本文不加解释的给出日期类的头文件:Date.h,并实现日期类的相关功能:

        相关功能的介绍分为三部分:

        1.日期的基本默认成员函数的书写;

        2.日期的比较;

        3.日期的运算。

#pragma once
#include<cassert>
#include<iostream>
using namespace std;

class Date
{
public:
	friend ostream& operator<<(ostream& out, const Date d);

	// 获取某年某月的天数
	inline int GetMonthDay(int year, int month)
	{
		assert(month >= 1 && month <= 12);
		static int _month[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };
		//如果进入if说明是闰年并且是二月
		if (month == 2 && ( (year % 4 == 0) && (year % 100 != 0) ) || (year % 400 == 0))
		{
			return 29;
		}
		else
			return _month[month];
	}
	// 全缺省的构造函数
	//声明时写缺省值
	Date(int year = 1900, int month = 1, int day = 1);

	// 拷贝构造函数
	// d2(d1)
	Date(const Date& d);

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

	// 析构函数
	~Date();


	// 日期+=天数
	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);
private:
	int _year;
	int _month;
	int _day;
};

(二)实现日期类

(1)构造函数

       构造函数的作用是完成对象的实例化和初始化,具有固定的格式:

类名()
{
    //...
}

实例化:

        对于较复杂的对象,比如vector类,它的对象实例化后会有资源的申请(动态开辟堆区的空间);但是对于Date类,由于没有资源的申请,于是只需进行初始化即可。

注意:

        缺省值的位置:日期的定义部分不需要加上缺省值,只需在日期的声明加上缺省值即可。 


// 全缺省的构造函数
Date::Date(int year, int month, int day)
{
	//assert(month>=1 && month<=12 && day>=1);
	_year = year;
	_month = month;
	_day = day;
}

(2)析构函数

        析构函数的作用是完成已经实例化的对象的资源的回收,具有固定的格式:

~类名()
{
    //...
}

        对于较复杂的vector类,需要释放动态申请的空间。

        但是对于Date类,由于没有资源的申请,于是只需将对象的成员变量置-1,表示对象已经被析构。


// 析构函数
Date::~Date()
{
	_year = -1;
	_month = -1;
	_day = -1;
}

(3)拷贝构造

        拷贝构造的作用是完成自定义类型的拷贝,具有固定的格式:

类名(const 类名& 形参)
{
    //...
}

        对于较复杂的vector类,需要手动实现深拷贝,而不能使用编译器默认生成的浅拷贝。

        但是对于Date类,由于没雨堆区的动态空间的申请,所以不需要实现深拷贝。换句话说,编译器生成的浅拷贝也是可以使用的。

        一般情况下,我们不会留给编译器自动生成的机会,因为平常我们要实现的一个类往往比Date类复杂的多,必然会涉及到在堆区申请动态空间,所以拷贝构造一般都是自己实现的,而不用编译器的自动生成的版本。为了养成良好的习惯,我们再这里就自己实现Date类的拷贝构造。


// 拷贝构造函数
// d2(d1)
Date::Date(const Date& d)
{
	_year = d._year;
	_month = d._month;
	_day = d._day;
}

(4)赋值重载

        赋值重载的作用是完成对象的整体赋值,具有固定的格式:

类名& operator=(const 类名& 形参)
{
    //...
}

        对于Date类的赋值重载需要检查是否是给自己赋值,如果是给自己赋值,直接返回*this即可。如果不是给自己赋值,再进行赋值操作。


// 赋值运算符重载
// d2 = d3 -> d2.operator=(&d2, d3)
Date& Date::operator=(const Date& d)
{
    //检查是否是给自己赋值,防止性能损失
    if(&d != this)
    {
	    _year = d._year;
	    _month = d._month;
	    _day = d._day;
    }
    
	return *this;
}

(5)日期的运算

        进行日期运算,首先要考虑的就是闰年的问题。因此我们先实现一个函数,用于知道年和月,获得每一个月的天数:

        (由于这个函数频繁调用,所以把他直接在类内部定义,也就设置为内联函数)


	// 获取某年某月的天数
	inline int GetMonthDay(int year, int month)
	{
		assert(month >= 1 && month <= 12);
		static int _month[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };
		//如果进入if说明是闰年并且是二月
		if (month == 2 && ( (year % 4 == 0) && (year % 100 != 0) ) || (year % 400 == 0))
		{
			return 29;
		}
		else
			return _month[month];
	}

 对于日期的运算,我们首先实现:

        +=和-=,这样通过复用,我们就可以实现几乎所用的功能。

        包括前置后置自增自减。


// 日期+=天数
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)
{
	if (day >= 0)
	{
		_day -= day;
		//day<=0无意义
		while (_day <= 0)
		{
			_month--;
			if (_month == 0)
			{
				_month = 12;
				--_year;
			}
			_day += GetMonthDay(_year, _month);
		}
	}
	else
		(*this) += (-day);
	return *this;
}

// 日期+天数
Date Date::operator+(int day)
{
	//不改变*this
	Date tem = *this;
	tem += day;
	return tem;
}

// 日期-天数
Date Date::operator-(int day)
{
	Date tem = *this;
	tem -= day;
	return tem;
}

//先++再使用
// 前置++
Date& Date::operator++()
{
	*this += 1;
	return *this;
}

//先使用再++
// 后置++
Date Date::operator++(int)
{
	Date tem = *this;
	*this += 1;
	return tem;
}

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

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

// 日期-日期 返回天数
int Date::operator-(const Date& d)
{
	//假设法
	Date max = *this;
	Date min = d;
	int c = 0, f = 1;

	if (min > max)
	{
		max = d;
		min = *this;
		f = -1;
	}
	//找出较大值和较小值
	while (min != max)
	{
		++min;
		++c;
	}
	return c*f;
}

 

(6)日期的比较

        对于日期类的对象的比较,我们首先实现:

等于:

        年月日分别相等,就表明两个日期对象相等。

        

大于:

        一下三个条件满足之一即可:

                年1  >  年2;

                年相等,月1 > 月2;

                年和月分别相等,日1 > 日2;

在实现了大于和等于操作符重载后,就会发现,我们可以通过复用,实现所有的功能。

        大于等于 即 大于 或者 等于满足一个即可;

        小于 即 对大于等于取反即可;

        小于等于 即 等于 或 小于 满足一个即可;

        不等于 即对 等于取反即可。


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

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

// >=运算符重载
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) || (*this < d);
}

// !=运算符重载
bool Date::operator != (const Date& d)
{
	return !(*this == d);
}


完~

未经作者同意禁止转载

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

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

相关文章

【算法】-- 二分查找详注

引入 二分查找&#xff0c;也称为折半查找&#xff1b;首先&#xff0c;二分查找是一种基于有序数组中查找特定元素的算法&#xff0c;所以它会因为数组的一些特性而受限。它的工作原理是不断将要查找的区间分成两部分&#xff0c;然后确定目标值可能存在的区间&#xff0c;直…

VUE 或 Js封装通用闭包循环滚动函数

1、vue3 闭包滚动函数的使用 js 调用也基本雷同 // 滚动Tab组件const scoreTabRef ref()// 滚动的选项const scrollOption ref({// 滚动的Dom元素scrollDom: null,// 滚动的时间间隔scrollInterval: 1500,// 滚动的距离scrollSep: 100,// 滚动历时时间scrollDuration: 10…

视频汇聚边缘网关EasyCVR硬件设备无法访问域名,解析失败该如何处理?

安防视频监控/视频集中存储/云存储/磁盘阵列EasyCVR平台部署轻快&#xff0c;可支持的主流标准协议有国标GB28181、RTSP/Onvif、RTMP等&#xff0c;以及支持厂家私有协议与SDK接入&#xff0c;包括海康Ehome、海大宇等设备的SDK等。视频汇聚融合管理平台EasyCVR既具备传统安防视…

240多道!Go开发岗位面试题合集(含答案)

随着今年互联网寒潮环境的影响&#xff0c;找工作的人也将达到顶峰&#xff0c;今天给大家分享一份《Go开发工程师超高频面试真题》&#xff0c;一共有240多道面试真题&#xff0c;希望能够帮助大家在面试中&#xff0c;少走一些弯路、更快拿到offer&#xff01; 内容展示 GO 基…

uniapp0基础编写安卓原生插件之编写安卓页面在uniapp上显示(摄像头调用)

前言 如果你对安卓插件开发部分不熟悉你可以先看uniapp0基础编写安卓原生插件和调用第三方jar包和编写语音播报插件之零基础编写安卓插件 效果 开始 dcloud_uniplugins.json {"nativePlugins": [{"hooksClass": "","plugins": [{&…

信奥一本通:1103:陶陶摘苹果

#include <iostream> using namespace std; int a[101]; int main(){int n 10;//题目要求输十个数 for(int i 1;i < 10; i){cin >> a[i];//赋值到数组 }int c;cin >> c;//要求的值 int cnt 0;//计数 for(int i 1; i < n; i){//循环比较是否小于&am…

试用NXP官方的UDS bootloader

文章目录 1.前言2.资料获取2.1 MCU例程 2.2 开发环境2.3 上位机2.4 硬件 3.工程修改3.1 boot工程修改 3.2 app工程修改4.测试情况5.例程分享 1.前言 最近很多客户在开发S32K系列MCU时咨询是否可以提供基于UDS协议的bootloader。本文以S32K144为例&#xff0c;介绍如何使用NXP官…

Parallels Desktop 19 for Mac v19.3.0.54924中文破解版

Parallels Desktop 19 for Mac v19.3.0.54924中文破解版是一款强大的虚拟机软件&#xff0c;支持多操作系统&#xff0c;提供卓越的虚拟化技术&#xff0c;确保流畅稳定的运行。新增特色功能如共享打印、TouchID集成等&#xff0c;提供便捷高效的虚拟机体验。界面美观现代&…

window golang 升级版本

执行go tidy&#xff0c;发现执行不了&#xff0c;得升级一下版本了 进入官网&#xff0c;并选择合适的系统以及版本。https://go.dev/dl/ 这台电脑是windows&#xff0c;我本人比较喜欢下载zip自己解压。 解压&#xff0c;这里我选择直接覆盖原文件&#xff0c;需要保留原版…

即将开幕,邀您共赴创新之旅“2024上海国际消费者科技及创新展览会”

备受期待的2024上海国际消费者科技及创新展览会&#xff08;以下简称“CTIS”&#xff09;即将于6月13日至15日亮相上海新国际博览中心N1-N3馆。 2024上海国际消费者科技及创新展览会总面积达40,000平方米&#xff0c;涵盖600余家展商&#xff0c;预计吸引40,000多位观众莅临现…

autodl 上 使用 LLaMA-Factory 微调 中文版 llama3

autodl 上 使用 LLaMA-Factory 微调 中文版 llama3 环境准备创建虚拟环境下载微调工具 LLaMA-Factory下载 llama3-8B开始微调测试微调结果模型合并后导出vllm 加速推理 环境准备 autodl 服务器&#xff1a; https://www.autodl.com/console/homepage/personal 基本上充 5 块钱…

毕业论文应该怎么写?推荐几款ai写论文工具

时间过的好快&#xff0c;马上又到了一年一度的毕业季了&#xff0c;对于即将毕业的学生来说毕业论文是一道难过的坎&#xff0c;想到自己为了毕业论文熬的夜&#xff0c;掉的头发&#xff0c;真的深有感触。 不过虽然翟博士给大家的毕业论文设了高门槛&#xff0c;但是随着时…

springboot项目中引入Xxl-Job并部署和使用

目录 模块划分 配置调度中心 配置执行器 添加执行器 写一个简单的定时任务 XxlJobHelper xxl-job是分布式任务调度平台&#xff0c;部署为独立的调度服务平台 github地址&#xff1a;xuxueli/xxl-job: A distributed task scheduling framework.&#xff08;分布式任务调度…

ctfshow之_萌新web9至web10

一、访问在线靶场ctfshow 1、web9 如下图所示&#xff0c;进入_萌新赛的web9问题&#xff0c;题目提醒flag在config.php中&#xff1a; 如上图所示&#xff0c;可以get传参&#xff0c;且传入的参数需要正则匹配system、exec、highlight&#xff0c;且不区分大小写&#xff0…

Flink checkpoint 源码分析- Checkpoint snapshot 处理流程

背景 在上一篇博客中我们分析了代码中barrier的是如何流动传递的。Flink checkpoint 源码分析- Checkpoint barrier 传递源码分析-CSDN博客 最后跟踪到了代码org.apache.flink.streaming.runtime.io.checkpointing.CheckpointedInputGate#handleEvent 现在我们接着跟踪相应…

element ui的确认提示框按钮样式修改

修改确认提示框的默认按钮样式&#xff0c;使用css强制修改 例&#xff1a; js代码&#xff1a; deleteUser(params){this.$confirm("您确定要删除吗&#xff1f;此操作无法撤销并且将永久删除所有数据。", "提示", { type: "warning", cancel…

西奥CHT-01软胶囊硬度计:开启硬度测试新纪元,引领制药行业品质升级

西奥CHT-01软胶囊硬度计&#xff1a;开启硬度测试新纪元&#xff0c;引领制药行业品质升级 在追求品质卓越的制药行业中&#xff0c;软胶囊硬度测试是确保药品质量与安全的关键环节。为了满足行业对高精度、高效率硬度测试的需求&#xff0c;西奥科技推出了CHT-01软胶囊硬度计…

【XR806开发板试用】使用FDCM操作Flash记录开机次数

一、寻找系统分配的自定义用户数据地址 &#xff08;1&#xff09;XR806的Flash布局 如图1所示&#xff0c;FLASH的布局有两种&#xff1a; 1、没有开启OTA模式&#xff1b;Image1PaddingSysinfo 2、开启OTA模式&#xff1b;Image1PaddingSysinfoOTA area Image2 Padding 如图…

一维数组 和 关键字 sizeof

数组的概念 “ 数组 ”我们可以理解成一组相同类型元素的集合 &#xff08;1&#xff09;其中可以是单个或是多个元素&#xff0c;可以是0&#xff0c;但元素个数不能为0 &#xff08;2&#xff09;一个数组中存放的元素必须是同类型的&#xff0c;比如一组整型&#xff0c;…

ruoyi-nbcio 基于flowable规则的多重并发网关的任意跳转

更多ruoyi-nbcio功能请看演示系统 gitee源代码地址 前后端代码&#xff1a; https://gitee.com/nbacheng/ruoyi-nbcio 演示地址&#xff1a;RuoYi-Nbcio后台管理系统 http://218.75.87.38:9666/ 更多nbcio-boot功能请看演示系统 gitee源代码地址 后端代码&#xff1a; h…