Cpp学习——通过日期类来了解Cpp中的运算符重载

2023-11-01

 

目录

一,日期类

二,运算符重载

 运算符重载1(比较)

1.< 

2. ==

复用

3.>

4.!=

5.<=

6.>=

运算符重载2(日期加减)

0.准备条件------计算每月的日期函数

1.+=

2.+

 3.-=

4.-

5.前置++

6.后置++

7前置--

6.后置--

7.计算两个日期的相差天数

  三,改进优化

四,源代码


一,日期类

写日期类的第一步是啥?当然是构建一个日期类啦。那这个类里面有啥啊?

1.成员变量:_year,_month,_day。

2.构造函数。

3.#include<iostream>。

4.using namespace std;

现在基本上就写这些。代码如下:

#include<iostream>
using namespace std;
class Date
{
public:
	Date(int year, int month, int day)
	{
		_year = year;
		_month = month;
		_day = day;
	}

private:

	int _year;
	int _month;
	int _day;
};

 此时,我们的类对象就创建好了。我们便可以定义一个日期类对象了。在另一个cpp源文件里。

#include"Date.h"
int main()
{
	Date d1(2023, 8, 29);
	Date d2(2023, 8, 31);

}

 运行发现没有问题。

二,运算符重载

接下来我们来探索新功能吧。如果现在我们想要比较这两个日期的大小我们该如何比较呢?

答案是写个函数,但是纠结的点就来了:

1.不会英文,那就写个拼音来作函数名吧!但是如果你的同事是个老外怎么办?

2.会英文,那就起个英文名吧compare1,compare2,compare3,compare4。哈哈,这就难为死看的人了。

那到底要怎么办啊?直接用大于,小于号?但是这明显是不行的,因为类比较不了啊!此时一个叫做运算符重载的靓仔走过。

 运算符重载1(比较)

运算符重载是啥呢?运算符重载其实就是Cpp增加的一个新语法。通过一个叫做operator的关键字将一些符号重载,从而扩展该符号的功能。比如<号想要扩展功能的话便可以写成operator<函数。比如要比较上面的日期类,便可以写成如下代码:

1.< 
//思想:先比较年,再比较月,再比较天
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;
	}
	else
	{
		return false;
	}
}

 这样便实现了<的函数重载。当我们定义:Date d1(3023, 8, 29);       Date d2(2023, 8, 31);

时调用<比较时,编译器会把d1<d2解释为:d1.operator<(d2) 因为有this指针的原因再进一步剖析的话其实就是:operator<(&d1,d2)。

2. ==

在理解了上面的<运算符重载以后,便可以再趁热打铁写一个==运算符重载。代码如下:

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

等于便写出来了。

复用

其实在写完上面的两个运算符以后,其它的运算符便很好写了。比如大于,不就是!<嘛!

比如!=不就是!==嘛!比如大于等于不就是>或者==中的一个条件成立即可,小于等于不就是<和==中的一个条件成立即可。知道了这些以后,便可以着手写代码了:

3.>
bool Date:: operator>(const Date& d)
{
	return !(*this < d);
}
4.!=
bool Date:: operator!=(const Date& d)
{
	return !(*this == d);
}
5.<=
bool Date:: operator<=(const Date& d)
{
	return (*this == d) || (*this < d);
}
6.>=
bool Date::operator>=(const Date& d)
{
	return (*this == d) || (*this > d);
}

运算符重载2(日期加减)

在搞定了比较的运算符以后便可以来搞+,+=,-,-=,++,--;以及计算日期之间的差值的运算符重载了。

0.准备条件------计算每月的日期函数

其实在加减日期时最关键的便是计算出每个月的天数。日期天数计算代码如下:

int GetMonthDay(int year, int month)
{
	int MonthDay[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };//按平年写数组数据
	if (month == 2 && ((year % 400 == 0) || (year % 4 == 0 && year % 100 != 0)))//如果是闰年便可以将二月的天数++
	{
		MonthDay[2]++;
	}
	return MonthDay[month];
}
1.+=
Date& Date:: operator+=(int day)
{
	_day += day;
	while (_day > GetMonthDay(_year, _month))
	{
		_day -= GetMonthDay(_year, _month);
		_month++;
		if (_month == 13)
		{
			_year++;
			_month = 1;
		}
	}
	return *this;
}
2.+

+与+=的区别就是,+不改变自身,+=改变自身。所以复用+=实现+的运算符重载代码如下:

Date Date::operator+(int day)//此时的返回值就不能是Date&了,
                             //因为tmp是这个运算符重载函数里的临时变量。
{
	Date tmp(*this);
	tmp += day;
	return tmp;
}

 补充说明:

为什么不先实现+而先实现+=呢?因为先实现+会比+=多几次拷贝。这样虽然不会对计算机的运行效率有太多的影响,但是为了发扬中国人民勤俭节约的美好品德还是先实现+=为好!

 3.-=
Date& Date:: operator-=(int day)
{
	_day -= day;
	while (_day <= 0)
	{
		_month--;
		if (_month == 0)
		{
			_year--;
			_month = 12;
		}
		_day += GetMonthDay(_year, _month);
	}

	return *this;
}
4.-

和前面的+一样,复用就完事了。

Date Date::operator-(int day)
{
	Date tmp(*this);
	tmp -= day;
	return tmp;
}
5.前置++

再实现前置++与后置++时可能大家会很好奇,这两个长得一摸一样的东西到底需要怎么区分呢?在这里可以这样区分:前置++是:operator ++(),后置++是:operator ++(int)。这个好像是祖师爷自己定义的,我们知道就可以了。所以代码如下:

Date& Date:: operator++()//因为前置++是先++后使用的所以直接改变*this
{
	*this += 1;
	return *this;
}
6.后置++
Date Date:: operator++(int)
{
	Date tmp(*this);
	++*this;
	return tmp;
}
7前置--

前置--和后置--的声明也和前置++与后置++的声明类似,所以--的代码如下:

Date&Date:: operator--()
{
	*this -= 1;
	return *this;
}
6.后置--
Date Date:: operator--(int)
{
	Date tmp(*this);
	--*this;
	return tmp;
}
7.计算两个日期的相差天数

这个函数算是比较有意思的函数了,一开始我还不会写。但是在实现了前面的运算符重载以后这个函数代码的书写也就水到渠成了。具体代码如下:

int Date::operator-(Date& d)
{
	Date max = *this;
	Date min = d;
	if (max < min)
	{
		max = d;
		min = *this;
	}

	int count = 0;
	while (min != max)
	{
		min+=1;
		count++;
	}
	return count;

}

  三,改进优化

大家能看出这里还有什么需要优化的地方吗?

1.判断日期是否合法,这该在那里判断呢?这是不是应该就要在传入日期的时候就判断啊?

所以判断日期是否合法就应该在构造函数里判断。

Date(int year, int month, int day)
	{
		if (day > GetMonthDay(year, month) || month >= 13)
		{
			cout << "日期非法" << endl;
		}
		_year = year;
		_month = month;
		_day = day;
	}

2.我们有没有可能想要计算一个日期+=负数的情况呢?以此来计算前面几天是什么日子呢?

答案是当然有,那我们该如何实现呢?还是复用。加等一个负数其实就是减等一个负的负数。减等一个负数其实就是+=一个负的负数。所以改进代码如下:

+=:

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

-=:

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

	return *this;
}

3.打印日期,我们都知道自定义类型的变量都可以用cout打印出来。那我们是否可以将日期也用cout打印出来呢?答案是不能,那我们有没有办法打印出来呢?答案是有的,那就是运算符重载。代码如下:

​
ostream& operator<<(ostream& out, Date& d)
{
	out << d.Getyear() << "/" << d.Getmonth() << "/" << d.Getday() << endl;
	return out;
}

​

记得要将声明与定义分离!!!

四,源代码

1,Date.h

#include<iostream>
using namespace std;
class Date
{
public:
	Date(int year, int month, int day)
	{
		if (day > GetMonthDay(year, month) || month >= 13)
		{
			cout << "日期非法" << endl;
		}
		_year = year;
		_month = month;
		_day = day;
	}
	int GetMonthDay(int year, int month)
	{
		int MonthDay[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };//按平年写数组数据
		if (month == 2 && ((year % 400 == 0) || (year % 4 == 0 && year % 100 != 0)))//如果是闰年便可以将二月的天数++
		{
			MonthDay[2]++;
		}
		return MonthDay[month];
	}

	int Getyear()
	{
		return _year;
	}

	int Getmonth()
	{
		return _month;
	}

	int Getday()
	{
		return _day;
	}

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

	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);
	int operator-(Date& d1);
private:

	int _year;
	int _month;
	int _day;
};


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

2,Date.c:

#include"Date.h"
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;
	}
	else
	{
		return false;
	}
}


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

bool Date:: operator>(const Date& d)
{
	return !(*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) || (*this > d);
}


Date& Date:: operator+=(int day)
{
	if (day < 0)
	{
		*this -= (-day);
		return *this;
	}
	_day += day;
	while (_day > GetMonthDay(_year, _month))
	{
		_month++;
		_day -= GetMonthDay(_year, _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)
	{
		*this += (-day);
		return *this;
	}
	_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;
}

Date& Date:: operator++()
{
	*this += 1;
	return *this;
}

Date Date:: operator++(int)
{
	Date tmp(*this);
	++*this;
	return tmp;
}

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

Date Date:: operator--(int)
{
	Date tmp(*this);
	--*this;
	return tmp;
}

int Date::operator-(Date& d)
{
	Date max = *this;
	Date min = d;
	if (max < min)
	{
		max = d;
		min = *this;
	}

	int count = 0;
	while (min != max)
	{
		min+=1;
		count++;
	}
	return count;

}

ostream& operator<<(ostream& out, Date& d)
{
	out << d.Getyear() << "/" << d.Getmonth() << "/" << d.Getday() << endl;
	return out;
}

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

Cpp学习——通过日期类来了解Cpp中的运算符重载 的相关文章

  • 如何在C++中生成非常大的随机数

    我想使用 C 生成 0 2 64 范围内的非常大的随机数 我已经使用了 rand 函数 但它没有生成非常大的数字 有人可以帮忙吗 使用c 11 使用标准c 11的随机库 http en cppreference com w cpp nume
  • 如何将这段 javascript 代码重写为 C++11?

    这是我在 Javascript Definitive Guide 中看到的 javascript 闭包代码 我想把它写成C 11 var uniqueID1 function var id 0 return function return
  • Visual Studios 2015 中的“恢复 NuGet 包”没有执行任何操作

    我将解决方案从 SVN 拉入 Visual Studios 2015 代码中的一些 使用 引用出现错误 因此我尝试在右键单击 解决方案 中的解决方案时运行 恢复 NuGet 包 选项探索者 这没有任何作用 我必须手动进入 nuget 管理器
  • 无法使用c#更改视频捕获分辨率

    我正在尝试使用 C 中的 DirectShowNet 更改默认网络摄像头分辨率 据我所知 我需要通过调用 windows win32 api dll 中内置的 VideoInfoHeader 类来更改它以进行 avi 捕获 我有来自 Dir
  • 如何使用 Entity Framework 和 Identity 解决对象处置异常 ASP.NET Core

    我正在尝试编写一个控制器 该控制器接收来自 AJAX 调用的请求并通过 DBContext 对数据库执行一些调用 但是 当我发出命令时var user await GetCurrentUserAsynch 在对 DBContext 的任何调
  • 更新 Azure Blob 上的 LastModified

    我正在移植代码以使用 C 中的 Azure 存储 SDK 传统上 我称其为更新修改文件的上次写入 修改时间 File SetLastWriteTimeUtc fileName lastWriteTimeUtc 要更新 blob 的上次修改时
  • 如何通过覆盖 MSBuild 目标来防止外语资源生成?

    我正在致力于减少大型 C ASP NET 解决方案的编译时间 我们的解决方案使用通常的 resx 文件方法翻译成大约十几种外语 这些资源文件的解析和编译极大地减慢了我们的编译时间 并且是日常的挫败感 我知道可以创建自定义资源提供程序并摆脱
  • 对 ExecuteNonQuery() 的单次调用是原子的

    对 ExecuteNonQuery 的单次调用是否是原子的 或者如果单个 DbCommand 中有多个 sql 语句 那么使用事务是否有意义 请参阅我的示例以进行说明 using var ts new TransactionScope us
  • 预编译头和 Visual Studio

    有没有办法设置 Visual Studio 解决方案参数 以便它只创建预编译头而不构建整个解决方案 具体来说 它是一个巨大的 C 解决方案 本身有许多项目 谢谢 仅选择 pch 创建者源文件 通常是 stdafx cpp 然后编译该文件 C
  • 为什么像 BindingList 或 ObservableCollection 这样的类不是线程安全的?

    我一次又一次发现自己必须编写 BindingList 和 ObservableCollection 的线程安全版本 因为当绑定到 UI 时 这些控件无法从多个线程更改 我想理解的是why情况就是这样 这是设计错误还是故意的 问题是设计一个线
  • 如何调试.NET Windows Service OnStart方法?

    我用 NET 编写的代码仅在作为 Windows 服务安装时才会失败 该故障甚至不允许服务启动 我不知道如何进入 OnStart 方法 如何 调试 Windows 服务应用程序 http msdn microsoft com en us l
  • 模板与非模板类,跨编译器的不同行为

    我在一些应用程序中使用编译时计数器 它确实很有用 昨天我想用 gcc 编译一个程序 我之前使用的是 msvc 并且计数器的行为在模板类中发生了变化 它在模板类中不再工作 过于简化的代码 Maximum value the counter c
  • 列表到优先队列

    我有一个 C 大学编程项目 分为两个部分 在开始第二部分时应该使用priority queues hash tables and BST s 我 至少 在优先级队列方面遇到了麻烦 因为它迫使我自己重做第一部分中已经实现的许多代码 该项目是关
  • ASP.net WebForms - 在标记中使用 GetRouteUrl

    我一直在尝试弄清楚如何将路由功能与 ASP net 4 0 WebForms 一起使用 我将一条路线添加到我的路线集合中 void Application Start RegisterRoutes RouteTable Routes voi
  • 使用 OleDbCommand / OleDbDataAdapter 读取 CSV 文件

    我不明白为什么 但是当我使用 OleDbDataAdapter 或 OleDbCommand 读取 CSV 文件时 在这两种情况下 生成的数据结构良好 它识别文件头中的列 但行数据都是空字符串 我之前已经成功进行过多次 CSV 处理 因此我
  • 如何禁用基于 ValidationRule 类的按钮?

    如何禁用基于 ValidationRule 类的 WPF 按钮 下面的代码可以很好地突出显示 TextBox
  • 'iter' 的名称查找已更改为新的 ISO 'for' 范围

    我正在尝试编译下面的两个文件 但从编译器收到错误消息 gcc 4 3 3 Linux 错误位于带有以下符号的行 LINE WITH ERROR 我做错了什么 我该怎么改变 路易斯 g c b h b cpp b cpp In functio
  • 展开 std::reference_wrapper 的成本

    Given include
  • 为什么 C++ 标准没有将 sizeof(bool) 定义为 1?

    Size of char signed char and unsigned char由 C 标准本身定义为 1 个字节 我想知道为什么它没有定义sizeof bool also C 03 标准 5 3 3 1 说 sizeof char s
  • 检查一个数是否是完全平方数?

    我认为以下代码存在精度问题 bool isPerfectSquare long long n long long squareRootN long long sqrt n 0 5 return squareRootN squareRootN

随机推荐