[C++] Year, month, day calculator - application of operator overloading (including complete code, concise)

 Preface: Hello everyone, this is YY ; this blog is mainly about the application of operator overloading ; including [stream insertion, stream extraction] [>, <, >=, <=,] [+, -, +=, -=] [Pre ++, Post ++, Pre--, Post--]

PS: The final module has a complete code demonstration; if it is helpful to you, I hope to pay attention, like, and bookmark, thank you! 

Table of contents

1. Stream insertion, stream extraction 

1. Why stream insert << cannot be written as a member function 

2. Flow insertion is written outside the class to access the method of members in the class - friend

3. Code display:  

2. Basic operator overloading [>, >=, <, <=, etc.] 

1. Code display:  

3. Basic operator overloading [+, +=, -, -=] (calculation of dates and days)

1. Code display:  

Four. Basic operator overloading [pre ++, post ++, etc.]

1. Mechanism description:

1. How to set the return type?

2. How to distinguish front and back in definition and declaration?

2. Code display: 

Five. Overloading of subtraction (date-date)

6. Complete code implementation 


1. Stream insertion, stream extraction 

 [The library for stream insertion is in iostream, and the library for stream extraction is in ostream]

  • Built-in types can be supported because they are implemented in the library
  • Can support custom types because of artificial function overloading

Graphic:

At this point: cout<<d is equivalent to count.operator(d)


1. Why stream insert << cannot be written as a member function 

// 流插入不能写成成员函数?
	 //因为Date对象默认占用第一个参数,就是做了左操作数

     如果按照正常使用场景实现出来:
    count<<d1;  如果写在成员函数里会表现出 count.operator<<(d)
    访问不了成员

    只有写成
	d1 << cout;   才会在成员函数里表现出 d1.operator<<(count)
    才能进行传参,访问成员

 Therefore, in order to use operations in a customary manner and allow stream insertion to access members, the overload of stream insertion can only be written outside the class (although this will not happen with stream extraction, for the sake of uniformity, write them outside the class together)


2. Flow insertion is written outside the class to access the method of members in the class - friend

But the members in the class are private (private), we can use friends (declare operator overloading function can enter the access permission in the class )


3. Code display:  

Header section: 

#pragma once
#include<iostream>
#include<assert.h>
using namespace std;
class Date
{
	// 友元函数声明
	friend ostream& operator<<(ostream& out, const Date& d);
	friend istream& operator>>(istream& in, Date& d);
public:
	Date(int year = 1, int month = 1, int day = 1);

	void Print() const
	{
		cout << _year << "-" << _month << "-" << _day << endl;
	}

	Date(const Date& d)   // 错误写法:(不加引用)编译报错,会引发无穷递归
	{                     // 拷贝构造
		_year = d._year;
		_month = d._month;
		_day = d._day;
	}

	int GetMonthDay(int year, int month);
private:
	int _year;
	int _month;
	int _day;
};
//虽然友元已经声明,但那与函数声明不同,仅是表示权限
//这里还是要再次进行函数声明
ostream& operator<<(ostream& out, const Date& d);
istream& operator>>(istream& in, Date& d);

.c file part: 

ostream& operator<<(ostream& out, const Date& d)
{
	out << d._year << "年" << d._month << "月" << d._day << "日" << endl;
	return out;
}
istream& operator>>(istream& in, Date& d)
{
	int year, month, day;
	in >> year >> month >> day;

	if (month > 0 && month < 13
		&& day > 0 && day <= d.GetMonthDay(year, month))
	{
		d._year = year;
		d._month = month;
		d._day = day;
	}
	else
	{
		cout << "非法日期" << endl;
		assert(false);
	}
	return in;
}

2. Basic operator overloading [>, >=, <, <=, etc.] 

1. Code display:  

In-class declaration:

PS: Add const, so that both ordinary variables and const variables can call this function (for specific knowledge points, see YY's C++ knowledge collection blog, about the interpretation of const)

    bool operator<(const Date& x) const;
   //相当于bool operator<(const Date* const this,const Date& x);,下列声明同理
	bool operator==(const Date& x) const;
	bool operator<=(const Date& x) const;
	bool operator>(const Date& x) const;
	bool operator>=(const Date& x) const;
	bool operator!=(const Date& x) const;

.c file implementation: 

PS: You can use the technique "reuse" in the process of function implementation

(Multiple functions only need to reuse one definition, specific code)

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

//直接利用一个<的复用完成其他定义

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

3. Basic operator overloading [+, +=, -, -=] (calculation of dates and days)


1. Code display:  

In-class declaration:

PS: Add const, so that both ordinary variables and const variables can call this function (for specific knowledge points, see YY's C++ knowledge collection blog, about the interpretation of const)

PS: const is added at the end to indicate const Date* this ; it indicates that any member of the class cannot be modified in the member function, and +=, -= is to realize the change of members in the class, so it cannot be added;

    Date& operator+=(int day);
	Date operator+(int day) const;

	Date& operator-=(int day);
	Date operator-(int day) const;

.c file implementation: 

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

	/*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)
		{
			_month = 12;
			--_year;
		}

		_day += GetMonthDay(_year, _month);
	}
	return *this;
}
Date Date::operator-(int day) const
{
	Date tmp = *this;
	tmp -= day;
	return tmp;
}

Four. Basic operator overloading [pre ++, post ++, etc.]


1. Mechanism description:

1. How to set the return type?

  • The prefix is ​​[assignment before use]: the return is itself (Date&received) (reference improves efficiency)
  • The post-position is [use first and then assign]: the return is a temporary variable (Date reception) (no reference is needed, because the temporary variable will be destroyed when it goes out of scope, and the reference will become a wild reference)

2. How to distinguish front and back in definition and declaration?

  •  Add parameter int to form function overload

2. Code display: 

In-class declaration:

 //增加这个int参数不是为了接收具体的值,仅仅是占位,跟前置++构成重载 
	Date& operator++();
	Date operator++(int);

	Date& operator--();
	Date operator--(int);

 Implementation in .c:

// 前置++
Date& Date::operator++()
{
	*this += 1;
	return *this;
}
// 后置++
// 增加这个int参数不是为了接收具体的值,仅仅是占位,跟前置++构成重载
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;
}

Five. Overloading of subtraction (date-date)

Skill:

  • Preset size: to be able to calculate the absolute value
  • Default flag: to achieve the final result

.c file implementation: 

int Date::operator-(const Date& d) const
{
	Date max = *this;
	Date min = d;
	int flag = 1;
	if (*this < d)
	{
		max = d;
		min = *this;
		flag = -1;
	}
	int n = 0;
	while (min != max)
	{
		++min;
		++n;
	}
	return n * flag;
}

6. Complete code implementation 

head File:

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

class Date
{
	// 友元函数声明
	friend ostream& operator<<(ostream& out, const Date& d);
	friend istream& operator>>(istream& in, Date& d);
public:
	Date(int year = 1, int month = 1, int day = 1);

	void Print() const
	{
		cout << _year << "-" << _month << "-" << _day << endl;
	}

	Date(const Date& d)   // 错误写法:编译报错,会引发无穷递归
	{
		_year = d._year;
		_month = d._month;
		_day = d._day;
	}

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

	int GetMonthDay(int year, int month);

	// d1 + 100
	Date& operator+=(int day);
	Date operator+(int day) const;

	Date& operator-=(int day);
	Date operator-(int day) const;

	Date& operator++();
	Date operator++(int);

	Date& operator--();
	Date operator--(int);

	int operator-(const Date& d) const;

	// 流插入不能写成成员函数?
	// 因为Date对象默认占用第一个参数,就是做了左操作数
	// 写出来就一定是下面这样子,不符合使用习惯
	//d1 << cout; // d1.operator<<(cout); 
	//void operator<<(ostream& out);

	/*int GetYear()
	{
		return _year;
	}*/
private:
	int _year;
	int _month;
	int _day;
};

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

.c file:

#include "Date.h"

Date::Date(int year, int month, int day)
{
	if (month > 0 && month < 13
		&& day > 0 && day <= GetMonthDay(year, month))
	{
		_year = year;
		_month = month;
		_day = day;
	}
	else
	{
		cout << "非法日期" << endl;
		assert(false);
	}
}

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

	return false;
}

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

// 复用
// d1 <= d2
bool Date::operator<=(const Date& x) const
{
	return *this < x || *this == x;
}

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

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

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

int Date::GetMonthDay(int year, int month)
{
	static int daysArr[13] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
	//if (((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)) && month == 2)
	if (month == 2 && ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)))
	{
		return 29;
	}
	else
	{
		return daysArr[month];
	}
}

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

// d1 + 100
Date Date::operator+(int day)  const
{
	Date tmp(*this);
	tmp += day;
	return tmp;

	/*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)
		{
			_month = 12;
			--_year;
		}

		_day += GetMonthDay(_year, _month);
	}

	return *this;
}

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

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

// 后置++
// 增加这个int参数不是为了接收具体的值,仅仅是占位,跟前置++构成重载
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) const
{
	Date max = *this;
	Date min = d;
	int flag = 1;

	if (*this < d)
	{
		max = d;
		min = *this;
		flag = -1;
	}

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

	return n * flag;
}

//void Date::operator<<(ostream& out)
//{
//	out << _year << "年" << _month << "月" << _day << "日" << endl;
//}

// 21:20继续
ostream& operator<<(ostream& out, const Date& d)
{
	out << d._year << "年" << d._month << "月" << d._day << "日" << endl;

	return out;
}

istream& operator>>(istream& in, Date& d)
{
	int year, month, day;
	in >> year >> month >> day;

	if (month > 0 && month < 13
		&& day > 0 && day <= d.GetMonthDay(year, month))
	{
		d._year = year;
		d._month = month;
		d._day = day;
	}
	else
	{
		cout << "非法日期" << endl;
		assert(false);
	}

	return in;
}

Guess you like

Origin blog.csdn.net/YYDsis/article/details/130535116