[C + +] operator overloading, friend - class and object practice - Implementation of date class

Posted by GreyBoy on Fri, 14 Jan 2022 20:31:40 +0100

1. Preface

Preliminary knowledge for reading this article:

  • Constructor, copy construct, copy construct
  • Class access qualifier
  • Class instantiation
  • this pointer
  • Reference return

catalog:

  • Operator overloading
  • Friend function, friend class, inner class
  • Date class

After we quickly get started with C + +, the first thing to bear the brunt is to learn the object-oriented features of C + +.

We abstract things into a class, instantiate specific objects through the drawing of "class", and manage object data and methods under the characteristics of encapsulation

2. Operator overloading

Our arithmetic operators such as addition, subtraction, multiplication and division, relational operators such as > < = = and = assignment operators can naturally operate built-in type data such as int and float; However, for user-defined types of data, such as our classes, the operation and comparison between classes will change according to the properties of a specific class, so the default usage of operators can not meet our needs

Therefore, we need to customize the usage of operators at the class level, so we have operator overloading

We overload an operator as follows:

Return value operator operator(parameter){
	// realization
}

be careful:

  • The usage of overloaded operators and the position of parameters around operators should be consistent with common usage
  • The first parameter is the this pointer, which is not written by default
  • Operator overloading can be declared and defined in the class, but if so, the first parameter must be the this pointer; We need to pay attention when inserting < < and extracting > > overloaded streams
  • Operators can also be overloaded outside the class, but if you want to access private member variables, you need to define friend functions or define a public function to get private member variables; We need to pay attention when inserting < < and extracting > > overloaded streams
  • Declare the separation of definitions. When defining, use the add field operator:
Date& Date::operator+=(int day) {
	// realization
}
  • Five operators cannot be overloaded
    • .*
    • ?:
    • ::
    • sizeof
    • .

3. Friends

3.1 friend function

The global function is not inside the class and cannot access the private member function. What should I do?

I have a friend

I want to visit you and declare within you that I am your friend

A friend function can directly access the private members of a class. It is an ordinary function defined outside the class. It does not belong to any class, but needs to be declared inside the class. When declaring, it needs to add the friend keyword.

In this way, the global function becomes a friend of a class, and the function can access the private member variables of the class recklessly

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

explain:

  • Friend functions can access private and protected members of a class, but not member functions of a class
  • Friend functions cannot be modified with const
  • Friend functions can be declared anywhere in the class definition and are not limited by the class access qualifier. I like to write them at the beginning of the class
  • A function can be a friend function of multiple classes
  • The calling principle of friend function is the same as that of ordinary function

3.2 friend category

So a friend class is a class that can access private member variables of other classes recklessly
be careful:

  • Friend relationship is one-way, not exchangeable: you treat me as a friend, I don't necessarily treat you as a friend

For example, if the above Time class and Date class declare the Date class as its friend class in the Time class, you can directly access Time in the Date class
Class, but not if you want to access the private member variables in the Date class in the Time class.

  • Friend relationship cannot be passed

If B is A friend of A and C is A friend of B, the friend of A at C cannot be explained.

friend class Date;

3.3 internal class

As for the internal class, i.e. another class is defined in the class; At this time, the internal class is an independent class. It does not belong to the external class, nor can it be passed
The object of the external class calls the internal class

An inner class is a friend class of an outer class. Note the definition of the friend class. The inner class can access the data in the outer class through the object parameters of the outer class
All members of. But the outer class is not a friend of the inner class.
be careful:

  1. Internal classes can be defined in public, protected and private of external classes.
  2. Note that the internal class can directly access the static and enumeration members in the external class without the object / class name of the external class.
  3. Sizeof (external class) = external class, which has nothing to do with internal class.
class A {
private:
	static int k;
	int h;
public:
	class B {
	public:
		void foo(const A& a) {
			cout << k << endl;//OK
			cout << a.h << endl;//OK
		}
	};
};
int A::k = 1;
int main() {
	A::B b;
	b.foo(A());
	return 0;
}

4. Date category

Date.h

#pragma once
#include <iostream>
using namespace std;

class Date {
	friend void Print(const Date& d);
	friend ostream& operator<<(ostream& out, const Date& d);
	friend istream& operator>>(istream& in, Date& d);
	

public:
	// Get the days of a specific month, using an array to reflect the days 
	int GetDay(int year, int month) {
		static int dayOfmonth[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;
		}
		else {
			return dayOfmonth[month];
		}
		
	}
	// constructor
	Date(int year = 0, int month = 1, int day = 1) {
		_year = year;
		_month = month;
		_day = day;
	}
	// destructor
	~Date() {
		_year = 0;
		_month = 1;
		_day = 1;
	}
	// copy constructor
	Date(const Date& tmp) {
		_year = tmp._year;
		_month = tmp._month;
		_day = tmp._day;
	}
	// Print the date
	void Print() {
		if (_year < 0 || _month <= 0 || _month > 12 || _day <= 0 || _day > GetDay(_year, _month)) {
			cout << _year << '/' << _month << '/' << _day << "------illegal date!" << endl;;
		}
		else {
			cout << _year << '/' << _month << '/' << _day << endl;
		}
	}

	// reload functions
	// =
	Date& operator=(const Date& date);
	// 8 assignment
	// +=
	Date& operator+=(int day);
	// +
	Date operator+(int day);
	// -=
	Date& operator-=(int day);
	// -
	Date operator-(int day);
	// Front++
	Date& operator++();
	// Post++
	Date operator++(int);
	// Front--
	Date& operator--();
	// Post--
	Date operator--(int);

	// 6 comparable operators
	// ==
	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 minus date -> days intervals
	int operator-(const Date& d);

private:
	int _year;
	int _month;
	int _day;
};

Date.cpp

	#define _CRT_SECURE_NO_WARNINGS 1
	#include "Date.h"

	Date& Date::operator=(const Date& date) {
		if (this != &date) {
			_year = date._year;
			_month = date._month;
			_day = date._day;
		}
		return *this;
	}
	Date& Date::operator+=(int day) {
		_day += day;
		while (_day > GetDay(_year, _month)) {
			_day -= GetDay(_year, _month);
			_month++;
			if (_month == 13) {
				_year++;
				_month = 1;
			}
		}
		return *this;
	}
	Date Date::operator+(int day) {
		Date tmp(*this);
		tmp += day;
		return tmp;
	}
	// -=
	// method 1
	//Date& Date::operator-=(int day) {
	//	while (_day < day) {
	//		day -= _day;
	//		_month--;
	//		if (_month == 0) {
	//			_year--;
	//			_month = 12;
	//		}
	//		_day = GetDay(_year, _month);
	//	}
	//	_day -= day;
	//	return *this;
	//}

	// method 2
	//Date& Date::operator-=(int day) {
	//	if (day > _day) {
	//		day -= _day;
	//		_month--;
	//		if (_month == 0) {
	//			_month = 12;
	//			_year--;
	//		}
	//	}
	//	while (day > GetDay(_year, _month)) {
	//		day -= GetDay(_year, _month);
	//		_month--;
	//		if (_month == 0) {
	//			_month = 12;
	//			_year--;
	//		}
	//	}
	//	_day = GetDay(_year, _month) - day;
	//	return *this;
	//}

	// best method
	Date& Date::operator-=(int day) {
		_day -= day;

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

	// Front++
	Date& Date::operator++() {
		*this += 1;
		return *this;
	}
	// Post++
	Date Date::operator++(int) {
		Date tmp = *this;
		*this += 1;
		return tmp;
	}
	// Front--
	Date& Date::operator--() {
		*this -= 1;
		return *this;
	}
	// Post--
	Date Date::operator--(int) {
		Date tmp = *this;
		*this -= 1;
		return tmp;
	}

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

	// date minus date -> days intervals
	int Date::operator-(const Date& d) {
		int i = 0;
		int flag = 1;
		Date max = *this;
		Date min = d;
		if (max < min) {
			max = d;
			min = *this;
			flag = -1;
		}
		while (max > min) {
			min++;
			i++;
		}
		return i * flag;
	}

	// Stream insertion
	ostream& operator<<(ostream& out, const Date& d) {
		out << d._year << "/" << d._month << "/" << d._day;
		return out;
	}
	 //Stream extraction
	istream& operator>>(istream& in, Date& d) {
		in >> d._year;
		in >> d._month;
		in >> d._day;
		return in;
	}

test.cpp

#define _CRT_SECURE_NO_WARNINGS 1
#include "Date.h"

void Print(const Date& d) {
	cout << d._year << "/" << d._month << "/" << d._day << endl;
}
void Test1() {
	Date d1(2000, 1, 1);
	d1.Print();
	d1 += 100;
	d1.Print();
	d1 += 500;
	d1.Print();
	d1 -= 500;
	d1.Print();
	d1 -= 100;
	d1.Print();
}

void Test2() {
	Date d1(2000, 1, 1);
	Print(d1);
	Print(d1++);
	Print(d1);
	Print(++d1);
	Print(d1);
	Print(d1--);
	Print(d1);
	Print(--d1);
	Print(d1);
}

void Test3() {
	Date d1(2000, 1, 2);
	Date d2(2000, 1, 1);
	cout << "d1==d2: " << (d1 == d2) << endl;
	cout << "d1>d2: " << (d1 > d2) << endl;
	cout << "d1<d2: " << (d1 < d2) << endl;
	cout << "d1>=d2: " << (d1 >= d2) << endl;
	cout << "d1<=d2: " << (d1 <= d2) << endl;
	cout << "d1!=d2: " << (d1 != d2) << endl;
}

void Test4() {
	Date d1(2022, 1, 14);
	Date d2(2022, 2, 20);
	cout << "2022/1/14 - 2022/2/20 = " << d1 - d2 << endl;
	cout << "2022/2/20 - 2022/1/14 = " << d2 - d1 << endl;
}

void Test5() {
	Date d1;
	cout << d1 << endl;
	cout << "Please enter:>";
	cin >> d1;
	cout << d1 << endl;
}

int main() {

	Test5();
	return 0;
}

Topics: C++ Back-end Class OOP