【C++】:拷贝构造函数与赋值运算符重载的实例应用之日期类的实现

news2024/11/16 9:31:06

在这里插入图片描述

C++实现日期类
├─属性:
│  ├─年份
│  ├─月份
│  └─日期
├─方法:
│  ├─构造函数
│  ├─拷贝构造函数
│  ├─析构函数
│  ├─设置年份
│  ├─设置月份
│  ├─设置日期
│  ├─获取年份
│  ├─获取月份
│  ├─获取日期
│  ├─判断是否为闰年
│  ├─计算该日期是该年的第几天
│  ├─计算该日期是星期几
│  └─重载运算符(+-==!=<><=>=

一、📚头文件的声明(Date.h)

🔑日期类的实现,将按以下声明依次进行,其中因为Print函数比较短,直接放到类里面让其变成内联函数

#pragma once

#include<iostream>
#include<assert.h>
using namespace std;

class Date
{
public:
	Date(int year = 1, int month = 1, int day = 1);

	void Print();
	int GetMonthDay(int year, int month);

	bool operator==(const Date& y);
	bool operator!=(const Date& y);
	bool operator>(const Date& y);
	bool operator<(const Date& y);
	bool operator>=(const Date& y);
	bool operator<=(const Date& y);

	int 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--();
	Date operator--(int);
private:
	int _year;
	int _month;
	int _day;
};
class Date
{
public:
 // 获取某年某月的天数
 int GetMonthDay(int year, int month)
 {
 static int days[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 
31};
 int day = days[month];
 if (month == 2
 &&((year % 4 == 0 && year % 100 != 0) || (year%400 == 0)))
 {
 day += 1;
 }
 return day;
 }
 
    // 全缺省的构造函数
 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;
};

二、📚获取天数的函数

🔑而我们实现日期类经常要用到某月有多少天,在这里先把获得某月有多少天的函数实现出来。实现时先检查传参有没有问题,在注意把数组设置成静态的,出了作用域还能访问,就不需要考虑每次调用函数建立栈帧后重新给数组分配空间的事情了,因为数组一直被存放在静态区 其次我们先判断这个月是不是二月份,避免判断某年是平年还是闰年一大堆操作后,发现月份不是二月份

int Date::GetMonthDay(int year, int month)
{
	assert(year >= 1 && month >= 1 && month <= 12);

	static int monthArray[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 monthArray[month];
}

三、📚Date的默认成员函数

🔑1.编译器默认生成的构造函数不会处理内置类型,所以我们需要自己去写构造函数,推荐全缺省的构造函数,编译器对自定义类型会自动调用该类型的默认构造
🔑2.由于Date类的成员变量都是内置类型,所以析构函数不需要我们自己写,因为没有资源的申请。并且拷贝构造和赋值重载也不需要写,因为Date类不涉及深拷贝的问题,仅仅使用浅拷贝就够了

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

四、📚日期类的大小比较

🔑由于日期类的大小比较,均不涉及对自身的改变,对此,我们统一用const来修饰this指针,让其变成const成员函数,减少代码的出错性

五、📚>运算符重载

🔑在这里我们找出所有日期a大于日期b的情况 第一种:年比年大 第二种:年相同 月比月大 第三种:年和月都相同 日比日大 再依次向下写就完成了>的比较

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

	return false;
}

六、📚==运算符重载

bool Date::operator==(const Date& y)
{
	return _year == y._year
		&& _month == y._month
		&& _day == y._day;
}

七、📚>= < <= !=对> ==的复用

// d1 != d2
bool Date::operator!=(const Date& y)
{
	return !(*this == y);
}

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

	return false;
}

bool Date::operator>=(const Date& y)
{
	return *this > y || *this == y;
}

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

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

八、📚日期类的计算

🔑日期类的连续赋值
在内置类型的适合我们经常有连续赋值的习惯,类似a1=a2=a3这种,而日期类也支持连续赋值的操作对此我们返回值不能写void 而应该返回引用,我们可以减少拷贝,从而提高效率 这是一名C/C++程序员的基本素养

Date& Date::operator=(const Date& d)
{
	this->_year = d._year;
	this->_month = d._month;
	this->_day = d._day;
	return *this;
}

🔑日期类的加法
+=运算符重载和+对+=的复用
🔑+=实现的思路就是,实现一个循环,直到天数回到该月的正常天数为止,在循环内部要做的就是进月和进年,让天数不断减去本月天数,直到恢复本月正常天数时,循环结束,返回对象本身即可

// d1 += 100
Date& Date::operator+=(int day)
{
	if (day < 0)
	{
		return *this -= (-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);
	tmp += day;
	return tmp;
}

🔑-=实现的思路就是,实现一个循环,直到天数变为正数为止,在循环内部要做的就是借月和借年,让天数不断加上上一个月份的天数,直到恢复正数为止,循环结束,返回对象本身

Date& Date::operator-=(int day)
{
	if (day < 0)
	{
		return *this += (-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;

	return tmp;
}

🔑前置++和后置++重载
后置++比前置++多一个参数int 同时后置返回的临时变量 不能添加引用 同时两个this都被改变了 不加const修饰

++d1;
d1.operator++();
d1.Print();

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

// d1++
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;
}

九、📚日期−日期重载

🔑日期类相减不需要日期本身,因此用const修饰。由于采用运算法求日期减去日期比较麻烦 还好考虑差有几年 几月 甚至几月中是否包括二月 所以在这样我们采用小日期自增的方式实现 用一个变量n记录

// d1 - d2
int Date::operator-(const Date& d)
{
	// 假设左大右小
	int flag = 1;
	Date max = *this;
	Date min = d;

	// 假设错了,左小右大
	if (*this < d)
	{
		max = d;
		min = *this;
		flag = -1;
	}

	int n = 0;
	while (min != max)
	{
		++min;
		++n;
	}
	return n * flag;
}

十、📚日期类实现总代码

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

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

bool Date::operator==(const Date& y)
{
	return _year == y._year
		&& _month == y._month
		&& _day == y._day;
}

// d1 != d2
bool Date::operator!=(const Date& y)
{
	return !(*this == y);
}

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

	return false;
}

bool Date::operator>=(const Date& y)
{
	return *this > y || *this == y;
}

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

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

int Date::GetMonthDay(int year, int month)
{
	assert(year >= 1 && month >= 1 && month <= 12);

	int monthArray[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 monthArray[month];
}

// d1 += 100
Date& Date::operator+=(int day)
{
	if (day < 0)
	{
		return *this -= (-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);
	tmp += day;

	return tmp;
}
// 
// d1 += 100
//Date& Date::operator+=(int day)
//{
//	//Date d = *this + day;
//	//*this = d;
//
//	*this = *this + day;
//	return *this;
//}
//
//Date Date::operator+(int day)
//{
//	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)
{
	if (day < 0)
	{
		return *this += (-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;

	return tmp;
}

// 21:13继续
// ++d1
Date& Date::operator++()
{
	*this += 1;
	return *this;
}

// d1++
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;
}

// d1 - d2
int Date::operator-(const Date& d)
{
	// 假设左大右小
	int flag = 1;
	Date max = *this;
	Date min = d;

	// 假设错了,左小右大
	if (*this < d)
	{
		max = d;
		min = *this;
		flag = -1;
	}

	int n = 0;
	while (min != max)
	{
		++min;
		++n;
	}

	return n * flag;
}
#pragma once

#include<iostream>
#include<assert.h>
using namespace std;

class Date
{
public:
	Date(int year = 1, int month = 1, int day = 1);

	void Print();
	int GetMonthDay(int year, int month);

	bool operator==(const Date& y);
	bool operator!=(const Date& y);
	bool operator>(const Date& y);
	bool operator<(const Date& y);
	bool operator>=(const Date& y);
	bool operator<=(const Date& y);

	int 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--();
	Date operator--(int);
private:
	int _year;
	int _month;
	int _day;
};
#include "Date.h"

void TestDate1()
{
	Date d1(2023, 10, 24);
	d1.Print();

	Date ret1 = d1 - 100;
	ret1.Print();

	Date ret2 = d1 - 10000;
	ret2.Print();

	Date ret3 = d1 + 100;
	ret3.Print();

	Date ret4 = d1 + 10000;
	ret4.Print();
}

void TestDate2()
{
	Date d1(2023, 10, 24);
	d1.Print();

	// 语法设计,无法逻辑闭环,那么这时就只能特殊处理
	// 特殊处理
	++d1;
	d1.operator++();
	d1.Print();

	d1++;
	d1.operator++(10);
	d1.operator++(1);
	d1.Print();
}

void TestDate3()
{
	Date d1(2023, 10, 24);
	d1.Print();
	Date d2(2024, 5, 5);
	d2.Print();
	Date d3(2024, 8, 1); 
	d3.Print();

	cout << d2 - d1 << endl;
	cout << d1 - d3 << endl;

}

void TestDate4()
{
	Date d1(2023, 10, 24);
	d1 += -100;

	d1.Print();
}

int main()
{
	TestDate4();

	return 0;
}

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

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

相关文章

mysql-linux归档版安装

什么是归档版安装&#xff1f;简单来说就是编译好的软件压缩打包版。 说明&#xff1a;我这里服务器之前已经装过一个不同版本的mysql&#xff0c;已经占用了3306端口&#xff0c;所以这里我用3307端口来演示&#xff0c;命令和官方的稍有不同&#xff0c;不过步骤都是差不多的…

next项目部署到云服务器上(手动)

准备环境: 云服务器 ECS,服务器安装好了docker 自己的next项目 开始: 1.在next项目根目录下创建Dockerfile文件 FROM node:18-alpine AS base# Install dependencies only when needed FROM base AS deps # Check https://github.com/nodejs/docker-node/tree/b4117f9333d…

SpringMVC Day 05 : Spring 中的 Model

前言 欢迎来到 SpringMVC 系列教程的第五天&#xff01;在之前的教程中&#xff0c;我们已经学习了如何使用控制器处理请求和返回视图。今天&#xff0c;我们将深入探讨 Spring 中的 Model。 在 Web 应用程序开发中&#xff0c;数据的传递和展示是非常重要的。SpringMVC 提供…

flutter版本选择

使用命令dart --version查看dart版本 使用命令flutter doctor查看flutter版本 Flutter 有 3 个发布渠道&#xff0c;分别是 stable、beta 和 master。我们推荐使用 stable 渠道除非你需要体验最新更新的 Flutter 特性。 要查看你当前使用的哪个渠道&#xff0c;使用下面的命令&…

山西电力市场日前价格预测【2023-10-28】

日前价格预测 预测说明&#xff1a; 如上图所示&#xff0c;预测明日&#xff08;2023-10-28&#xff09;山西电力市场全天平均日前电价为324.42元/MWh。其中&#xff0c;最高日前电价为601.09元/MWh&#xff0c;预计出现在18:15。最低日前电价为0.00元/MWh&#xff0c;预计出…

微信native支付对接

简介 Native支付是指商户系统按微信支付协议生成支付二维码,用户再用微信“扫一扫”完成支付的模式。 应用场景 Native支付适用于PC网站、实体店单品或订单、媒体广告支付等场景,用户扫描商户展示在各种场景的二维码进行支付。聚体步骤如下: 1.商户根据微信支付的规则,…

【EI会议投稿】第三届电气、控制与信息技术国际学术会议(ECITech 2024)

第三届电气、控制与信息技术国际学术会议&#xff08;ECITech 2024&#xff09; 2024 3rd International Conference on Electrical, Control and Information Technology 继往届ECITech年度系列会议的成功举办&#xff0c;第三届电气、控制与信息技术国际学术会议&#xff08…

JTAG 详解

10.1 JTAG简介 JTAG接口的基本工作原理是&#xff1a;在芯片内部定义一个TAP&#xff08;Test Access Port&#xff0c;测试访问端口&#xff09;&#xff0c;开发人员使用连接到芯片的JTAG外部接口上的JTAG调试器&#xff0c;通过访问芯片内部的TAP端口来扫描芯片内部各个扫…

数据驱动决策:大数据分析如何塑造业务成功

文章目录 大数据分析的定义大数据分析如何影响业务1. 洞察业务趋势2. 提高决策质量3. 优化运营效率4. 个性化客户体验5. 发现新商机 如何利用大数据分析实现业务成功1. 收集和整合数据2. 选择适当的工具和技术3. 制定数据策略4. 建立数据分析团队5. 进行实验和反馈 大数据分析的…

激活函数作用以及 sigmoid和softmax

激活函数 激活函数在神经网络中起着非常重要的作用&#xff0c;它的主要功能是引入非线性性质&#xff0c;使得神经网络可以学习和表示更加复杂的模式和关系。下面是激活函数的几个主要作用&#xff1a; 引入非线性&#xff1a;激活函数通过引入非线性变换&#xff0c;打破了…

java.sql.SQLException: ORA-28000: the account is locked

1.遇到的问题 Oracle执行报下面的错误 java.sql.SQLException: ORA-28000: the account is locked 2.解决办法 登录sysdba管理账号&#xff0c;执行下面命令。 alter user demo account unlock&#xff1b;

NPDP产品经理证书值得考吗?

NPDP&#xff08;New Product Development Professional&#xff09;证书是由新产品开发专业协会&#xff08;PDMA&#xff09;提供的一项专业认证。对于那些在产品开发领域寻求进一步发展的人来说&#xff0c;考取这个证书可能是一个值得考虑的选择。 首先&#xff0c;NPDP证…

以“降本增效”为目标,智能视频监控能为企业带来哪些经济价值?

随着经济的发展和科技的进步&#xff0c;企业需要不断提升自身的品质和效率&#xff0c;以保持竞争优势。而智能视频监控技术正是一项值得考虑的工具&#xff0c;其对企业带来的降本增效效益可以通过以下几个方面来体现。 1、降低运行成本 EasyCVR智能视频监控平台可以实现远程…

Mysql数据库 5.SQL语言聚合函数 语言日期-字符串函数

一、聚合函数 SQL中提供了一些可以对查询的记录的列进行计算的函数——聚合函数 1.count&#xff08;&#xff09; 统计函数&#xff0c;统计满足条件的指定字符的值的个数 统计表中rebirth_mood个数 select count(列名) from 表名; #统计表中rebirth_namelcl的个数 select …

亚马逊发布Q3财报,营收利润强劲,云业务增长缓慢

KlipC报道&#xff1a;10月26日&#xff0c;亚马逊发布财报显示&#xff0c;该公司2023年第三季度每股收益0.94美元&#xff0c;营收同比增13%至1431亿美元&#xff0c;营业利润率7.8%远超预期的5.46%&#xff0c;均高于预期。 KlipC的合伙人Andi D表示&#xff1a;“三季度盈利…

S-3A5001 DPDK性能优化

一、已知问题 1. 7A1000桥片总带宽约20G&#xff0c; 7A2000桥片总带宽约40G 2. 7A1000桥片单槽无法跑满2个10G口&#xff0c;需要用双槽来跑&#xff0c;每个槽用1个port 二、 板卡当前状态 用双槽单port模式测试丢包 调试方案1&#xff1a;配置HT拆包寄存器 busybox devm…

如何开通 Medium会员

1 开通 WildCard 卡 首先你需要一张可以支付的外国卡 选择开通 WildCard 卡&#xff0c;优点&#xff1a; 1 无需上传身份证件&#xff0c;支付宝认证即可 2 可以使用国内手机号注册 3 可以使用支付宝、微信充值 开通地址&#xff1a; https://bewildcard.com/card 一步一步…

【AI视野·今日Sound 声学论文速览 第三十期】Fri, 20 Oct 2023

AI视野今日CS.Sound 声学论文速览 Fri, 20 Oct 2023 Totally 7 papers &#x1f449;上期速览✈更多精彩请移步主页 Interesting: &#x1f4da;Loop Copilot,基于对话模型的作曲助理 (from 伦敦大学玛丽女王学院) website:https://sites.google.com/view/loop-copilot Daily…

c语言中啥时候用double啥时候用float?

c语言中啥时候用double啥时候用float&#xff1f; 一般来说&#xff0c;可以使用double来表示具有更高精度要求的浮点数&#xff0c;因为它可以存储更大范围的数值并且具有更高的精度。 最近很多小伙伴找我&#xff0c;说想要一些c语言资料&#xff0c;然后我根据自己从业十年…