[C++] Classes and objects (middle) fully describe examples of operator overloading -- Date class (Date) -- const members

Table of contents

1 Introduction

2. Full default constructor

3. Print interface

4. Copy construction

5. Assignment operator overloading (operator=)

5.1 Assignment overloading is the default member function, overload format:

5.2 Assignment overloading cannot be a global function

5.3 The compiler generates by default

6. Destructor

7、operator>

8、operator==

9、operator>=

10、operator<

11、operator<=

12、operator!=

13. operator+= (date += days)

14. operator+ (date + days)

15. operator-= (date-=days)

16. operator- (date-days)

17. Pre ++, post ++, pre--, post--

18. Date - date (number of days returned)

19. const members


1 Introduction

In this article, we will mainly implement the following interfaces:

#include <iostream>
using namespace std;

class Date
{
public:

	// 获取某年某月的天数
	int GetMonthDay(int year, int month) const;
	// 全缺省的构造函数
	Date(int year = 1900, int month = 1, int day = 1);
	//打印接口
	void Print() const;


	// 拷贝构造函数
	// d2(d1)
	Date(const Date& d);
	// 赋值运算符重载
	// d2 = d3 -> d2.operator=(&d2, d3)
	Date& operator=(const Date& d);
	// 析构函数
	~Date();


	//总结一下:只读函数可以加const,内部不涉及修改成员的都是只读函数
	// >运算符重载
	bool operator>(const Date& d) const;
	// ==运算符重载
	bool operator==(const Date& d) const;
	// >=运算符重载
	bool operator>=(const Date& d) const;
	// <运算符重载
	bool operator<(const Date& d) const;
	// <=运算符重载
	bool operator<=(const Date& d) const;
	// !=运算符重载
	bool operator!=(const Date& d) const;

	// 日期+=天数
	Date& operator+=(int day);
	// 日期+天数
	Date operator+(int day) const;
	// 日期-天数
	Date operator-(int day) const;
	// 日期-=天数
	Date& operator-=(int day);


	// 函数重载
	// 运算符重载
	// 前置++
	Date& operator++(); //++d1 -> d1.operator()
	// 加一个int参数,进行占位,跟前置++构成函数重载进行区分
	// 后置++
	Date operator++(int); //d1++ -> d1.operator(0)
	// 后置--
	Date operator--(int);
	// 前置--
	Date& operator--();


	// 日期-日期 返回天数
	int operator-(const Date& d) const;

private:

	int _year;
	int _month;
	int _day;

};

This project we write in multiple files, including the following three files:

Next, we will implement the above interfaces one by one:

2. Full default constructor

There is a shortcoming when writing the full default constructor normally. In case the month and day passed as parameters do not exist, although the instantiated object is initialized, it is illegal, so we need to make a judgment, here We need to write a function for the number of days in the month, and compare it when constructing it.

Here we first implement the GetMonthDay interface:

// 获取某年某月的天数
int Date::GetMonthDay(int year, int month) const
{
	static int monthDay[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };

	if(2 == month
		&& ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)))
	{
		return 29;
	}

	return monthDay[month];
}
// 全缺省的构造函数
Date::Date(int year, int month, int day)
{
	if (month < 1 || month > 12
		|| day < 1 || day > GetMonthDay(year, month))// 判断日期是否合法
	{
		cout << "非法日期" << endl;
		exit(-1);
	}
	else
	{
		_year = year;
		_month = month;
		_day = day;
	}
}

For the GetMonthDay interface, we wrote an array to store the number of days in each month. The default February is 28 days. Below we will judge if it is to find the number of days in February, and judge the year to see if it is a leap year. In leap year, it returns 29 directly, and in other cases, it directly returns the number of days corresponding to the month. We use static modification for the array, because this function will be called continuously later, so we put it in the static area, only open it once, which saves time, and the time for one time is not much, but if it is a large number of calls, it will be greatly improved efficiency.

Here we will be asked, why add a const after the GetMonthDay interface, here we will explain:

3. Print interface

There is nothing to talk about the printing interface, let's stud it directly:

//打印接口
void Date::Print() const
{
	cout << _year << "年" << _month << "月" << _day << "日" << endl;
}

The printing interface uses const modification for this because it is possible that the object we pass is modified by const. If the Print interface does not add const, it will involve the problem of enlarging permissions, resulting in errors. After changing to const, there is no permission problem.

4. Copy construction

If you are still unclear about the copy, you can click the link below, which contains a detailed explanation of the copy structure: click here

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

5. Assignment operator overloading (operator=)

5.1 Assignment overloading is the default member function, overload format:

Parameter type : const T&, passing reference can improve the efficiency of parameter passing
Return value type : T&, returning reference can improve the efficiency of returning, the purpose of returning value is to support continuous assignment to detect
whether to assign to itself
return *this : to compound continuous assignment the meaning of

Let's write it in overloaded format:

// 赋值运算符重载
// d2 = d3 -> d2.operator=(&d2, d3)
Date& Date::operator=(const Date& d)
{
	if (this != &d)// 存在this就是d的情况
	{
		_year = d._year;
		_month = d._month;
		_day = d._day;
	}

	return *this;
}

5.2 Assignment overloading cannot be a global function

Reason: If the assignment operator is not explicitly implemented, the compiler will generate a default one. At this time, if the user implements a global assignment operator overload outside the class, it will conflict with the default assignment operator overload generated by the compiler in the class, so the assignment operator overload can only be a member function of the class.

Let's try to write it ourselves:

The vs2019 compiler I use here, the compiler will prompt that an error is reported directly during compilation, so assignment operator overloading cannot be a global function.

5.3 The compiler generates by default

When we don't write it, the compiler will automatically generate a copy overload function, but the function generated by default is directly assigned to the built-in type, and the member variable of the custom type needs to call the corresponding class assignment overload function to complete the assignment.

Therefore, if there is a custom type (class type) in the member variable, the assignment overload function of the custom type must be correct, which is correct.

If two stacks implement a queue, the assignment overload function of the queue can be generated by default, but the stack must be written by itself, because the stack has application resources. If it is copied directly, the two stacks use the same resource. In this case, one is The stack that is popped out, and the stack that is pushed into the stack, no matter whether it is in or out, it is actually operating on the same stack, which is wrong.

Note: If resource management is not involved in the class, whether the assignment operator can be implemented or not; once resource management is involved, it must be implemented.

The difference between assignment and copy: copy is an existing object to initialize another object to be created;

Assignment is the copying of two existing objects.

6. Destructor

If you are still unclear about the destructor, you can click the following link, which contains a detailed explanation of the destructor: click here

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

7、operator>

Judging on date > date

1. If it is less than that year, there is no need to compare, and return false directly

2. Compare the same month in the same year, if the month is less than, return false directly

3. The year and month are the same, if the day is less than, return false

4. When the above judgments are not correct, it means that the previous date is greater than the latter date, and return true

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

8、operator==

The judgment of date == date is very simple. It is correct that the year, month and day are equal. Let's look at the code implementation:

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

The code above can be simplified even further:

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

9、operator>=

For >=, we can actually reuse the above > and == without having to write a set of logic to judge. The logic of >= is greater than or equal to.

Let's take a look at the implementation code:

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

10、operator<

< and >= are the opposite logic, so we can achieve it by negating >=.

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

11、operator<=

<= and > are the opposite logic, so we can realize it by negating >.

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

12、operator!=

!= and == are the opposite logic, so we can achieve it by negating ==.

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

13. operator+= (date += days)

+= is modified on the original basis, so the implicit this cannot be modified with const, because it is modified on the original basis, so the += function body is displayed, the object is still there, and we return it by reference, which can reduce copying.

We plot the analysis against += days:

Code:

// 日期+=天数
Date& Date::operator+=(int day)
{
	if (day < 0)
	{
		return *this -= (-day);
	}

	_day += day;
	while (_day > GetMonthDay(_year, _month))
	{
		_day -= GetMonthDay(_year, _month);
		//月进位
		_month++;

		//月满了
		if (13 == _month)
		{
			_year++;
			_month = 1;
		}
	}

	return *this;
}

Let's test it out:

Check to see if the += we wrote is correct

14. operator+ (date + days)

The difference between + and += is that += is + to the object itself, and + is not a change to the object itself. So we need to instantiate a new object, copy the passed object to the new object, store the result of + days and return.

// 日期+天数
Date Date::operator+(int day) const
{
	Date tmp(*this);

	tmp += day;

	return tmp;
}

Here we can reuse the code of += after copying one copy.

Let's take a look at the results of the passed object and the object after +:

Here we can see that + does not affect the result of d1.

15. operator-= (date-=days)

-= is modified on the original basis, so the implicit this cannot be modified with const, because it is modified on the original basis, so the -= function body is displayed, and the object is still there. We return it by reference, which can reduce copying.

We draw a graph to analyze the number of -= days:

Code:

// 日期-=天数
Date& Date::operator-=(int day)
{
	if (day < 0)
	{
		return *this += (-day);
	}

	_day -= day;
	while (_day <= 0)
	{
		_month--;
		if (0 == _month)
		{
			_year--;
			_month = 12;
		}

		_day += GetMonthDay(_year, _month);
	}

	return *this;
}

operation result:

Compare it to see if we have implemented it correctly:

16. operator- (date-days)

The logic of - and + is similar, and the difference between - and -= is that -= is - to the object itself, and - is not a change to the object itself. So we need to instantiate a new object, copy the passed object to the new object, store the result of - days and return.

// 日期-天数
Date Date::operator-(int day) const
{
	Date tmp(*this);

	tmp -= day;

	return tmp;
}

After copying this here, you can reuse -= on the copied tmp.

Let's test it out:

17. Pre ++, post ++, pre--, post--

For pre-++ and post-++, pre-- and post--, their function names are the same, but the functions they implement are different. How can they be clearly distinguished if they are found in the symbol table? ?

For this kind of problem, C++ has its own rules. C++ stipulates that an additional parameter of type int is added when the post-position ++ is overloaded, but this parameter does not need to be passed when calling the function, and the compiler will pass it automatically. Rear - same goes.

In this way, function overloading can be realized. Although the function names in the symbol table are the same, one has parameters and the other has no parameters.

Let's implement these function interfaces separately:

The rule of pre-++ is: first ++, then use. Therefore, the pre-++ is equivalent to +=1, and the multiplexing +=.

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

The rule of post ++ is: use first, then ++. Here we first make a copy of this, and then return the copied object to this+=1, so that we can use it first, then ++.

// 后置++
Date Date::operator++(int) //d1++ -> d1.operator(0)
{
	Date tmp(*this);

	*this += 1;

	return tmp;
}

The rule of pre--- is: first--, then use. Therefore, the preposition ++ is equivalent to -=1, and multiplexing -=.

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

	return *this;
}

The post-- rule is: use first, then --. Here we first make a copy of this, and then return the copied object to this-=1, so that we can use it first, and then --.

// 后置--
Date Date::operator--(int)
{
	Date tmp(*this);

	*this -= 1;

	return tmp;
}

18. Date - date (number of days returned)

This interface is date-date, here is a small detail, when the small date-large date, the return value is a negative number, so we should pay attention to this detail, let's sort out the idea of ​​this interface:

1. We use the hypothesis method, assuming that this is a large date, assign it to the max object, and the second parameter is a small date, assign it to the min object, and define a flag to initialize to 1;

2. Compare, if this is a small date, reassign the contents of the max and min objects, and assign the flag to -1;

3. Define a counter n, let the small chase the big, ++min once, the counter also ++, jump out of the loop after catching up, and return n*flag.

Note: We use pre-++ when we let the small chasing big, although both pre-++ and post-++ can be realized, but the interface of post-++ needs to be copied twice, copy once at the beginning, and the return value will be copied again Copying once, pre-++ can realize the dual advantages of time and space when calculating a large amount of calculations.

Let's implement the code:

// 日期-日期 返回天数
int Date::operator-(const Date& d) const
{
	int flag = 1;
	Date max = *this;
	Date min = d;
	if (max < min)
	{
		max = d;
		min = *this;
		flag = -1;
	}

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

	return n * flag;
}

test:

19. const members

The const-modified "member function" is called a const member function . The const-modified class member function actually modifies the implicit this pointer of the member function , indicating that any member of the class cannot be modified in the member function .

Here we use the Print interface:

After being modified with const, it does not conflict with the original member function, because it constitutes overloading.

Let's take a look at the two versions of the Print interface:

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

void Date::Print() const
{
	cout << _year << "年" << _month << "月" << _day << "日" << endl;
}

For the print function, there is no modification of members inside the function, and this is a read-only function.

Therefore, we use const decoration, and there is still a problem. When our object is const decoration, if the Print function does not use const decoration, there will be a problem of privilege amplification when calling.

Let's close the const-modified Print function first:

Let's take a look at the const-modified interface:

Summary: For the same function, const-modified this and undecorated functions constitute overloading;

Functions that do not involve modifying members are read-only functions. After const modification, it is safer and compatible with objects with constant properties.

Guess you like

Origin blog.csdn.net/Ljy_cx_21_4_3/article/details/132128446