【C++】实现一个日期计算器

2023-11-06


需要云服务器等云产品来学习Linux的同学可以移步/-->腾讯云<--/-->阿里云<--/-->华为云<--/官网,轻量型云服务器低至112元/年,新用户首次下单享超低折扣。


 目录

 一、日期计算器的功能

二、获取每个月的天数

三、Date类中的默认成员函数

1、构造函数

2、析构函数

3、拷贝构造

4、赋值运算符重载

5、取地址操作符重载和const取地址操作符重载

四、运算符重载

1、+=、+、-=、-

2、==、!=、>、>=、<、<=

3、前置++和--、后置++和--

4、<<流插入、>>流提取运算符

五、日期类代码


 一、日期计算器的功能

实现日期类的==、!=、+=、+、-=、-、>=、>、<=、<、前置++和--、后置++和--。

二、获取每个月的天数

int GetMonthDay(int year, int month)
{
    //静态数组,每次调用不用频繁在栈区创建数组
    static int monthArr[12] = { 31,28,31,30,31,30,31,31,30,31,30,31 };
    //判断是否闰年
    int day = monthArr[month - 1];
    if (month == 2 && ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0))
    {
        day = 29;
    }
    return day;
}

1、因为GetMonthDay这个函数需要在日期类中被频繁调用,所以将 monthArr存放至静态区,减少数组频繁开辟、销毁空间的开销。

三、Date类中的默认成员函数

1、构造函数

Date(int year = 1, int month = 1, int day = 1)
{
    if (year >= 1 && month >= 1 && day >= 1 && day <= GetMonthDay(year, month))
    {
        _year = year;
        _month = month;
        _day = day;
        //cout << "构造成功" << endl;
    }
    else
    {
        cout << "日期不合法" << endl;
    }
}

日期类的构造函数需要对日期的的合法性进行判断。

2、析构函数

~Date()//可不写
{
    ;
}

日期类因为没有申请资源(动态开辟空间、文件的打开等),所以无需写析构函数,系统默认生成的就可以。

3、拷贝构造

Date(const Date& d)//可不写
{
    _year = d._year;
    _month = d._month;
    _day = d._day;
    //cout << "拷贝构造成功" << endl;
}

系统默认生成的拷贝构造函数会对内置类型完成浅拷贝,所以内置类型也可以不用写,用系统默认生成的就可以。

后续处理有资源的对象时,需要深拷贝。

4、赋值运算符重载

Date& operator=(const Date& d)
{
    _year = d._year;
    _month = d._month;
    _day = d._day;
    //cout << "赋值成功" << endl;
    return *this;
}

也可不写,使用系统默认生成的即可。

拷贝构造和赋值运算符重载的区别在于拷贝构造用于对象构造时使用,而赋值运算符重载用于已存在对象赋值时使用。

后续处理有资源的对象时,需要先把旧空间释放,再开一块同样大小的空间,进行数据拷贝。

5、取地址操作符重载和const取地址操作符重载

Date* operator&()
{
    return this;
    //return nullptr;
}
const Date* operator&()const
{
    return this;
    //return nullptr;
}

不用自己写,除非想让别人通过取地址操作符获取到特定值(自己在重载函数内部写)或屏蔽类地址。 

四、运算符重载

1、+=、+、-=、-

Date& operator+=(int day)
	{
		if (day < 0)
			*this -= -day;
		else
		{
			_day += day;
			while (_day > GetMonthDay(_year, _month))
			{
				_day -= GetMonthDay(_year, _month);
				++_month;
				if (_month > 12)
				{
					_month = 1;
					++_year;
				}
			}
		}
		return *this;
	}
	Date operator+(int day)const
	{
		Date tmp(*this);
		return tmp += day;
	}
	Date& operator-=(int day)
	{
		if (day < 0)
			*this += -day;
		else
		{
			_day -= day;
			while (_day <= 0)
			{
				--_month;
				if (_month <= 0)
				{
					_month = 12;
					--_year;
				}
				_day += GetMonthDay(_year, _month);
			}
		}
		return *this;
	}
	Date operator-(int day)const
	{
		Date tmp(*this);
		return tmp -= day;
	}
	int operator-(const Date& d)const
	{
		Date max = *this, min = d;
		int flag = 1;//用于表示符号位
		if (*this < d)
		{
			max = d;
			min = *this;
			flag = -1;
		}
		int count = 0;//用于计数
		while (max > min)
		{
			++min;
			++count;
		}
		return count * flag;
	}

1、注意这几个运算符要防止外部传入的day是负数。例如+=传入的参数如果是负数,则去调用-=函数。

2、注意传值返回和传引用返回,当return对象出了作用域还存在时,可以用传引用返回,减少一次拷贝构造。

3、实现完+=、-=后,+、-运算符可复用逻辑。

4、对于*this不变的成员函数,函数后记得加上const。

2、==、!=、>、>=、<、<=

bool operator==(const Date& d)const
	{
		if (_year == d._year && _month == d._month && _day == d._day)
		{
			return true;
		}
		return false;
	}
	bool operator>(const Date& d)const
	{
		if (_year > d._year)
			return true;
		if (_year == d._year && _month > d._month)
			return true;
		if (_year == d._year && _month == d._month && _day > d._day)
			return true;
		return false;
	}
	bool operator>=(const Date& d)const
	{
		return *this > d || *this == d;
	}
	bool operator!=(const Date& d)const
	{
		return !(*this == d);
	}
	bool operator<(const Date& d)const
	{
		return !(*this >= d);
	}
	bool operator<=(const Date& d)const
	{
		return !(*this > d);
	}

1、注意右操组数一定要加上&,减少一次传参时的拷贝构造;再加上const,防止被引用的对象被改变。

2、写完==和>函数,其他运算符都可以复用逻辑。

3、前置++和--、后置++和--

Date& operator++()
	{
		++_day;
		if (_day > GetMonthDay(_year, _month))
		{
			_day = 1;
			++_month;
			if (_month > 12)
			{
				_month = 1;
				++_year;
			}
		}
		return *this;
	}
	Date operator++(int)
	{
		Date tmp(*this);
		++* this;
		return tmp;
	}
	Date& operator--()
	{
		--_day;
		if (_day <= 0)
		{
			--_month;
			if (_month == 0)
			{
				_month = 12;
				--_year;
			}
			_day += GetMonthDay(_year, _month);
		}
		return *this;
	}
	Date operator--(int)
	{
		Date tmp(*this);
		--* this;
		return tmp;
	}

1、因为++和--是单操作数的运算符,在重载时,无法区分是前置的重载还是后置的重载,所以C++规定:前置重载与普通运算符重载一致,后置重载需要在参数列表中加入一个无用的参数。这个参数必须是int类型(用别的类型编译器报错)。

2、前置++--可以使用传引用返回,但后置++--因为返回值暂时不改变,所以只能传值返回。这也是使用前置++--性能优于后置++--的原因。

4、<<流插入、>>流提取运算符

//类内声明为友元函数
friend ostream& operator<<(ostream& out, const Date& d);
friend istream& operator>>(istream& in, Date& d);
//需要在类外定义
inline ostream& operator<<(ostream& out, const Date& d)
{
	out << d._year << " " << d._month << " " << d._day << endl;
	return out;
}
inline istream& operator>>(istream& in, Date& d)
{
	in >> d._year >>d._month >> d._day;
	return in;
}

需要在类外定义,在类内声明为友元函数。

五、日期类代码

class Date
{
public:
	int GetMonthDay(int year, int month)
	{
		//静态数组,每次调用不用频繁在栈区创建数组
		static int monthArr[12] = { 31,28,31,30,31,30,31,31,30,31,30,31 };
		//判断是否闰年
		int day = monthArr[month - 1];
		if (month == 2 && ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0))
		{
			day = 29;
		}
		return day;
	}
	//构造函数
	Date(int year=1 , int month = 1, int day = 1)
	{
		if (year >= 1 && month >= 1 && day >= 1 && day <= GetMonthDay(year, month))
		{
			_year = year;
			_month = month;
			_day = day;
			//cout << "构造成功" << endl;
		}
		else
		{
			cout << "日期不合法" << endl;
		}
	}
	//析构函数
	~Date()
	{
		cout << "析构成功" << endl;;
	}
	//拷贝构造
	Date(const Date& d)
	{
		_year = d._year;
		_month = d._month;
		_day = d._day;
		cout << "拷贝构造成功" << endl;
	}
	//赋值运算符重载
	Date& operator=(const Date& d)
	{
		_year = d._year;
		_month = d._month;
		_day = d._day;
		cout << "赋值成功" << endl;
		return *this;
	}
	//运算符重载
	Date& operator+=(int day)
	{
		if (day < 0)
			*this -= -day;
		else
		{
			_day += day;
			while (_day > GetMonthDay(_year, _month))
			{
				_day -= GetMonthDay(_year, _month);
				++_month;
				if (_month > 12)
				{
					_month = 1;
					++_year;
				}
			}
		}
		return *this;
	}
	Date operator+(int day)const
	{
		Date tmp(*this);
		return tmp += day;
	}
	Date& operator-=(int day)
	{
		if (day < 0)
			*this += -day;
		else
		{
			_day -= day;
			while (_day <= 0)
			{
				--_month;
				if (_month <= 0)
				{
					_month = 12;
					--_year;
				}
				_day += GetMonthDay(_year, _month);
			}
		}
		return *this;
	}
	Date operator-(int day)const
	{
		Date tmp(*this);
		return tmp -= day;
	}
	int operator-(const Date& d)const
	{
		Date max = *this, min = d;
		int flag = 1;//用于表示符号位
		if (*this < d)
		{
			max = d;
			min = *this;
			flag = -1;
		}
		int count = 0;//用于计数
		while (max > min)
		{
			++min;
			++count;
		}
		return count * flag;
	}
	bool operator==(const Date& d)const
	{
		if (_year == d._year && _month == d._month && _day == d._day)
		{
			return true;
		}
		return false;
	}
	bool operator>(const Date& d)const
	{
		if (_year > d._year)
			return true;
		if (_year == d._year && _month > d._month)
			return true;
		if (_year == d._year && _month == d._month && _day > d._day)
			return true;
		return false;
	}
	bool operator>=(const Date& d)const
	{
		return *this > d || *this == d;
	}
	bool operator!=(const Date& d)const
	{
		return !(*this == d);
	}
	bool operator<(const Date& d)const
	{
		return !(*this >= d);
	}
	bool operator<=(const Date& d)const
	{
		return !(*this > d);
	}
	Date& operator++()
	{
		++_day;
		if (_day > GetMonthDay(_year, _month))
		{
			_day = 1;
			++_month;
			if (_month > 12)
			{
				_month = 1;
				++_year;
			}
		}
		return *this;
	}
	Date operator++(int)
	{
		Date tmp(*this);
		++* this;
		return tmp;
	}
	Date& operator--()
	{
		--_day;
		if (_day <= 0)
		{
			--_month;
			if (_month == 0)
			{
				_month = 12;
				--_year;
			}
			_day += GetMonthDay(_year, _month);
		}
		return *this;
	}
	Date operator--(int)
	{
		Date tmp(*this);
		--* this;
		return tmp;
	}
	friend ostream& operator<<(ostream& out, const Date& d);
	friend istream& operator>>(istream& in, Date& d);
	//取地址重载和const取地址重载
	Date* operator&()
	{
		return this;
	}
	const Date* operator&()const
	{
		return this;
	}
private:
	int _year;
	int _month;
	int _day;
};
inline ostream& operator<<(ostream& out, const Date& d)
{
	out << d._year << " " << d._month << " " << d._day << endl;
	return out;
}
inline istream& operator>>(istream& in, Date& d)
{
	in >> d._year >>d._month >> d._day;
	return in;
}

因为函数的声明和定义全部放在类中,会被编译器当成内联函数处理。所以可以根据自身需要,将部分调用不频繁、稍长的函数的声明写在类中,而定义写在类外。

CSDN话题挑战赛第2期
参赛话题:学习笔记

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【C++】实现一个日期计算器 的相关文章

  • “构建”构建我的项目,“构建解决方案”则不构建

    我刚刚开始使用VS2010 我有一个较大的解决方案 已从 VS2008 成功迁移 我已将一个名为 Test 的控制台应用程序项目添加到解决方案中 选择构建 gt 构建解决方案不编译新项目 选择构建 gt 构建测试确实构建了项目 在失败的情况
  • 查找c中结构元素的偏移量

    struct a struct b int i float j x struct c int k float l y z 谁能解释一下如何找到偏移量int k这样我们就可以找到地址int i Use offsetof 找到从开始处的偏移量z
  • Asp.NET WebApi 中类似文件名称的路由

    是否可以在 ASP NET Web API 路由配置中添加一条路由 以允许处理看起来有点像文件名的 URL 我尝试添加以下条目WebApiConfig Register 但这不起作用 使用 URIapi foo 0de7ebfa 3a55
  • 如何从 appsettings.json 文件中的对象数组读取值

    我的 appsettings json 文件 StudentBirthdays Anne 01 11 2000 Peter 29 07 2001 Jane 15 10 2001 John Not Mentioned 我有一个单独的配置类 p
  • 将 VSIX 功能添加到 C# 类库

    我有一个现有的单文件生成器 位于 C 类库中 如何将 VSIX 项目级功能添加到此项目 最终目标是编译我的类库项目并获得 VSIX 我实际上是在回答我自己的问题 这与Visual Studio 2017 中的单文件生成器更改 https s
  • 带动态元素的 WPF 启动屏幕。如何?

    我是 WPF 新手 我需要一些帮助 我有一个加载缓慢的 WPF 应用程序 因此我显示启动屏幕作为权宜之计 但是 我希望能够在每次运行时更改屏幕 并在文本区域中显示不同的引言 这是一个生产力应用程序 所以我将使用非愚蠢但激励性的引言 当然 如
  • 创建链表而不将节点声明为指针

    我已经在谷歌和一些教科书上搜索了很长一段时间 我似乎无法理解为什么在构建链表时 节点需要是指针 例如 如果我有一个节点定义为 typedef struct Node int value struct Node next Node 为什么为了
  • 重载<<的返回值

    include
  • WCF 中 SOAP 消息的数字签名

    我在 4 0 中有一个 WCF 服务 我需要向 SOAP 响应添加数字签名 我不太确定实际上应该如何完成 我相信响应应该类似于下面的链接中显示的内容 https spaces internet2 edu display ISWG Signe
  • 垃圾收集器是否在单独的进程中运行?

    垃圾收集器是否在单独的进程中启动 例如 如果我们尝试测量某段代码所花费的进程时间 并且在此期间垃圾收集器开始收集 它会在新进程上启动还是在同一进程中启动 它的工作原理如下吗 Code Process 1 gt Garbage Collect
  • 链接器错误:已定义

    我尝试在 Microsoft Visual Studio 2012 中编译我的 Visual C 项目 使用 MFC 但出现以下错误 error LNK2005 void cdecl operator new unsigned int 2
  • 向现有 TCP 和 UDP 代码添加 SSL 支持?

    这是我的问题 现在我有一个 Linux 服务器应用程序 使用 C gcc 编写 它与 Windows C 客户端应用程序 Visual Studio 9 Qt 4 5 进行通信 是什么very在不完全破坏现有协议的情况下向双方添加 SSL
  • 通过指向其基址的指针删除 POD 对象是否安全?

    事实上 我正在考虑那些微不足道的可破坏物体 而不仅仅是POD http en wikipedia org wiki Plain old data structure 我不确定 POD 是否可以有基类 当我读到这个解释时is triviall
  • 如何将带有 IP 地址的连接字符串放入 web.config 文件中?

    我们当前在 web config 文件中使用以下连接字符串 add name DBConnectionString connectionString Data Source ourServer Initial Catalog ourDB P
  • C# 成员变量继承

    我对 C 有点陌生 但我在编程方面有相当广泛的背景 我想做的事情 为游戏定义不同的 MapTiles 我已经像这样定义了 MapTile 基类 public class MapTile public Texture2D texture pu
  • 基于 OpenCV 边缘的物体检测 C++

    我有一个应用程序 我必须检测场景中某些项目的存在 这些项目可以旋转并稍微缩放 更大或更小 我尝试过使用关键点检测器 但它们不够快且不够准确 因此 我决定首先使用 Canny 或更快的边缘检测算法 检测模板和搜索区域中的边缘 然后匹配边缘以查
  • 测试用例执行完成后,无论是否通过,如何将测试用例结果保存在变量中?

    我正在使用 NUNIT 在 Visual Studio 中使用 Selenium WebDriver 测试用例的代码是 我想在执行测试用例后立即在变量中记录测试用例通过或失败的情况 我怎样才能实现这一点 NUnit 假设您使用 NUnit
  • C++ 中类级 new 删除运算符的线程安全

    我在我的一门课程中重新实现了新 删除运算符 现在我正在使我的代码成为多线程 并想了解这些运算符是否也需要线程安全 我在某处读到 Visual Studio 中默认的 new delete 运算符是线程安全的 但这对于我的类的自定义 new
  • 使用.NET技术录制屏幕视频[关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 有没有一种方法可以使用 NET 技术来录制屏幕 无论是桌面还是窗口 我的目标是免费的 我喜欢小型 低
  • 对来自流读取器的过滤数据执行小计

    编辑问题未得到解答 我有一个基于 1 个标准的过滤输出 前 3 个数字是 110 210 或 310 给出 3 个不同的组 从流阅读器控制台 问题已编辑 因为第一个答案是我给出的具体示例的字面解决方案 我使用的实际字符串长度为 450 个

随机推荐

  • 学习Python之路之Python中常见的数据结构一——列表

    列表 List 是Python语言中最通用的序列数据结构之一 列表是一个没有固定长度的 用来表示任意类型对象的位置相关的有序集合 列表的数据项不需要具有相同的类型 常用的列表操作主要包括 索引 连接 乘法和切片等 列表中的每个元素都分配一个
  • 线性dp-----最长公共上升子序列

    首先介绍一下什么是最长公共上升子序列 对于两个数列A B 如果他们都包含一段位置不一定连续的且数值是严格递增的 那么称这一段数就是两个数列的公共上升子序列 所有公共子序列中最长的就是最长公共子序列 例 A 1 7 3 2 4 B 7 2 1
  • 阿里云dataworks离线同步

    业务场景 用公网ip 从本地mysql数据库到另一个本地mysql数据库 在dataworks上配置离线同步和调度任务 步骤 阿里云登录 1 进入dataworks 2 进入控制台 3 选择数据开发 4 配置数据源 选择mysql数据源 连
  • cmd指令杀掉某个端口或线程

    第一步 点击起始菜单 或是通过win R快捷键 在输入框中输入cmd 点击确定 即可打开dos命令窗 第二步 输入netstat ano 查询所有端口 第三步 找到你想杀掉的端口对应的 PID 比如 上面的127 0 0 1 4369对应的
  • 为什么零基础选择语言首选python

    在众多编程语言中 似乎已经没有什么能够阻挡Python的步伐 本月Python又是第一名 市场份额达到了13 42 在2023年 Python已经连续7个月蝉联榜首 遥遥领先于其他对手 每个月榜单发布后 都有小伙伴会好奇 为什么又是Pyth
  • JWT实现登陆认证及Token自动续期

    技术选型 要实现认证功能 很容易就会想到JWT或者session 但是两者有啥区别 各自的优缺点 应该Pick谁 夺命三连 区别 基于session和基于JWT的方式的主要区别就是用户的状态保存的位置 session是保存在服务端的 而JW
  • 在央企当程序员是一种怎样的体验?

    来源 zhihu com question 276681361 answer 2134441878 大家好 又到了求职季 给大家分享一段一位朋友的央企工作经历 希望对于观望工作机会的小伙伴 有些参考 我校招加入了某垄断央企 在里面从事研发工
  • 解决VS2015生成Qt5的QMainWindows界面解决方案时产生一个“表达式必须包含指针类型”的问题

    解决VS2015生成Qt5的QMainWindows界面解决方案时产生一个 表达式必须包含指针类型 的问题 问题描述 分析过程 总结 问题描述 VS2015生成了一个QMainWindow界面 我在cpp实现文件使用ui这个表达式时出现下面
  • 单链表的合并【去重】

    2个有序单链表的合并 void Mergelist L LinkList LA LinkList LB LinkList LC pa LA gt next pb LB gt next LC LA LinkList pc LC while p
  • 智能仓储管理系统(自动化仓库管理解决方案)

    企业实际的仓储管理中 往往会出现那样这样的错误 归根结底 主要是由于没使用合适的仓库管理工具 相反 人工使用合适的仓库管理工具 不仅可以在日常仓库管理方法中根据采集到的产品信息数据 大大地提高管理效率 降低库存实际管控成本 还可降低人工管理
  • 【严重】Smartbi未授权设置Token回调地址获取管理员权限

    漏洞描述 Smartbi是一款商业智能应用 提供了数据集成 分析 可视化等功能 帮助用户理解和使用他们的数据进行决策 在 Smartbi 受影响版本中存在Token回调地址漏洞 未授权的攻击者可以通过向目标系统发送POST请求 smartb
  • 个人用记录:docker启动容器之后不久就会自动关闭

    原因是 docker容器运行必须有一个前台进程 如果没有前台进程执行 容器认为空闲 就会自行退出 尝试方案1 docker run dit name jenkins p 8080 8080 jenkinsci blueocean bin b
  • JS基础-Navigator-尚硅谷-P124

    视频链接 视频 代码
  • C语言之va_list

    va list va list 是在C语言中解决变参问题的一组宏 变参问题是指参数的个数不定 可以是传入一个参数也可以是多个 可变参数中的每个参数的类型可以不同 也可以相同 可变参数的每个参数并没有实际的名称与之相对应 用起来是很灵活 va
  • IT项目管理作业4

    分析与工具 你联合同学做一个年级微信公众号加强各班相互了解 联合活动等 请编制项目章程和项目管理计划 指导该项目实施与运营 必须包含 WBS 和 甘特图 召开一个项目策划研讨会 每个人用思维导图记录会议内容 该图必须满足 话题跟踪 热点标注
  • JVM(java 虚拟机)内存设置

    一 设置JVM内存设置 1 设置JVM内存的参数有四个 Xmx Java Heap最大值 默认值为物理内存的1 4 最佳设值应该视物理内存大小及计算机内其他内存开销而定 Xms Java Heap初始值 Server端JVM最好将 Xms和
  • 半导体制程发展史

    半导体制程发展史 大杀器级别文献 摘要 半导体制造的工艺节点 涉及到多方面的问题 如制造工艺和设备 晶体管的架构 材料等 分析半导体制造的工艺节点发展历程 其实就是在回顾半导体大咖的统治史 首先 技术节点 诸如台积电16nm工艺的Nvidi
  • 函数式编程-Stream流学习第二节-中间操作

    1 Stream流概述 java8使用的是函数式编程模式 如同它的名字一样 它可以用来对集合或者数组进行链状流式操作 让我们更方便的对集合或者数组进行操作 2 案例准备工作 我们首先创建2个类一个作家类 一个图书类 package com
  • STL(标准模板库)专题

    STL 标准模板库 专题 STL主要分为分为三类 容器 STL主要分为分为三类 algorithm 算法 对数据进行处理 解决问题 步骤的有限集合 container 容器 用来管理一组数据元素 Iterator 迭代器 可遍历STL容器内
  • 【C++】实现一个日期计算器

    需要云服务器等云产品来学习Linux的同学可以移步 gt 腾讯云 lt gt 阿里云 lt gt 华为云 lt 官网 轻量型云服务器低至112元 年 新用户首次下单享超低折扣 目录 一 日期计算器的功能 二 获取每个月的天数 三 Date类