Classes and Objects [5] Implementation of the Date Class

introduction

Classes and objects 1 (initial knowledge)
classes and objects 2 (default member functions)
classes and objects 3 (initialization lists)
classes and objects 4 (static, const, friends)
After understanding the basics of classes and objects, we will A date class can be implemented simply (the previous knowledge introduction link is above, and some basic knowledge will not be described in this article):

Implement the date class

overview

Let's first take a look at the functions of date calculators found on the Internet:
insert image description here
it can calculate the difference between two dates, add or subtract days from a date, etc.

Before learning classes and objects, we will store the year, month, and day of the date in the structure, and then implement the operation on the date structure through the encapsulation function; but now,
we can encapsulate the date as an attribute of the class type, The operation of the date class is encapsulated as a class method for our convenience.

Of course, in order to realize the two functions mentioned above, we need to implement the method of judging whether the two dates are equal, comparing the two dates, etc. Of course, we also need the method of printing the date. Next, it will be implemented one by one:

We first define a class type:

class Date
{
    
    
private:
	int _year;
	int _month;
	int _day;
};

default member function

First, let's implement the 4 default member functions

Constructor

There are only built-in types in this date class, so the no-argument default member function generated by the compiler cannot implement its initialization. We can implement a fully default default constructor, so that we can define class objects without passing parameters, or pass parameters:

// 全缺省的构造函数
Date::Date(int year, int month, int day)
    : _year(year)
    , _month(month)
    , _day(day)
{
    
    }

Implement the initialization of member variables in the initialization list.

destructor

In fact, there are no dynamically opened resources in the date class, so the destructor automatically generated by the compiler is enough, but here is still a realization, you can set the member variable to 0 in the destructor:

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

copy construction

The copy constructor is an overload of the constructor, and the parameter is a reference to the class object:

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

Use const to modify parameters, so that const objects can also be used as parameters to assign values ​​to new class objects.

assignment overloading

Assignment operator overloading is just operatorfunction =overloading. Explicit parameters are const Date&objects that can be modified by const:

// 赋值运算符重载
// d2 = d3 -> d2.operator=(&d2, d3)
Date& Date::operator=(const Date& d)
{
    
    
    _year = d._year;
    _month = d._month;
    _day = d._day;
    return *this;
}

In the function, assign the member variable of the object (pointed by this pointer) to the member variable in d.

It should be noted that in order to achieve continuous assignment, the return value of this function is a reference to the class type, return*this :
For example, several built-in type variables are continuously assigned:

a = b = c = d;

In such code, the result of d's assignment to c is assigned to b, and the result is assigned to a.
So for assignment operator overloading, this function should return the operand before =, that is, the reference of the first parameter, that is, return *this.

Functional operator overloading

With the default member function, we continue to implement the member function:

comparison between dates

Date comparison can be overloaded as follows:==、!=、>、>=、<、<=

The parameter lists of these functions should be the same, they are all an implicit thispointer and a class reference Date&;
the return value is bool, if the expression is true, it returns true, otherwise it returns false.

However, there is no need to change the value of the object in this type of function, so the object pointed to by this pointer and the reference of the class object can be modified with const:

//==重载举例:
bool operator==(const Date& d) const;

When implementing, the size relationship between the two dates is obtained by judging the member variables in the two objects in the function:

  1. == operator overloading
// ==运算符重载
bool Date::operator==(const Date& d)const
{
    
    
    if ((_year == d._year)
        && (_month == d._month)
        && (_day == d._day))
    {
    
    
        return true;
    }
    else
    {
    
    
        return false;
    }
}
  1. != operator overloading
// !=运算符重载
bool Date::operator!=(const Date& d)const
{
    
    
    if (!(*this == d))
    {
    
    
        return true;
    }
    return false;
}
  1. > operator overloading
// >运算符重载
bool Date::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;
}
  1. >= operator overloading
// >=运算符重载
bool Date::operator>=(const Date& d)const
{
    
    
    if (*this > d || *this == d)
    {
    
    
        return true;
    }
    return false;
}
  1. < operator overloading
// <运算符重载
bool Date::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;
}
  1. <= operator overloading
// <=运算符重载
bool Date::operator<=(const Date& d)const
{
    
    
    if (*this < d || *this == d)
    {
    
    
        return true;
    }
    return false;
}

Date += and + days

  1. date += number of days

Date += number of days, that is, calculate the date after a certain number of days of the date object (implicitly pointed to by this), and return the reference of the object. The += operator obviously changes the member variables of the date object, so it cannot be modified with const :

Date& operator+=(int day);

When implementing, you can first _dayadd to the members of the date object day;
when _daythe value is greater than the current _monthvalue, _daysubtract the number of days in the current month, and then _monthadd 1 (going backward one month);
if _monththe value is greater than 12, then repeat Set to 1, _yearadd 1 (go backward one year);
until _daythe value is less than the number of days in the current month;
the last reference returned*this .

We can then encapsulate a function to get the number of days in a certain month (store the number of days in 12 months in an array, and return the number of days in the corresponding month):

// 获取某年某月的天数(用于日期加减天数)
 int Date::GetMonthDay(int year, int month)
{
    
    
    int monthdays[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)))
    {
    
    
        monthdays[month] = 29;
    }
    return monthdays[month];
}

Then the += operator can be overloaded:
It should be noted that the number of days passed as a parameter can be negative, which means that the date is minus -day. At this time, just use -= to call (it will be implemented soon )

// 日期+=天数
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 > 12)
        {
    
    
            _year++;
            _month = 1;
        }
    }
    return *this;
}
  1. date + number of days

Date + number of days cannot modify the date of the date class, so you can add const modification to the object pointed to by this pointer:

Date operator+(int day)const;

In the function, create a temporary date class object tempand *thisinitialize it with it (copy construction);
then temp+=day;call the overload implemented above +=;
finally return temp.
It should be noted that the temp here will be destroyed after leaving the scope, so the return value here must be a value, not a reference (although returning by value will call the copy construction)

// 日期+天数
Date Date::operator+(int day)const
{
    
    
    Date temp(*this);//拷贝构造
    temp += day;//复用+=运算符重载
    return temp;//返回临时值,不改变*this的值
}

date-=and-number of days

  1. date -= number of days

The implementation of date-=days is similar to +=: subtract it
first ; if the subtracted value is less than 0, then add the number of days in the previous month ( ) of the current month ; if the value is less than 0, set it to 12 . The value is decremented by 1; until the value of is greater than 0; the reference returned at the end ._dayday
day_day_day_month-1
_month_month_year
_day
*this

// 日期-=天数
Date& Date::operator-=(int day)
{
    
    
    if (day < 0)
    {
    
    
        return *this += -day;
    }
    _day -= day;
    while (_day < 1)
    {
    
    
        _month--;
        _day += GetMonthDay(_year, _month);//如果--后的_month为0,函数返回0,不影响结果

        if (_month <= 0)
        {
    
    
            _year--;
            _month = 13;
        }
    }
    return *this;
}

It should be noted in the implementation that:
when _monththe value of the value is 1, _dayit is necessary to add ( _month-1) the number of days in the month, and the value passed at this time GetMonthDayis 0, but since we are implementing GetMonthDayit, the data subscripted as 0 in the month array is 0 , has no effect _day-0on _dayit, so it does not affect the final result;
when _dayit is less than 0, just call += -daythe method to solve it.

  1. date - number of days

date-days is implemented similarly to +, requires the creation of temporary objectstemp , and must return a value rather than a reference :

// 日期-天数
Date Date::operator-(int day)const
{
    
    
    Date temp;
    temp -= day;
    return temp;
}

Date Prefix++ and Postfix++

++That is +=1, it is easy to understand, so in this function, you only need to call the above overload +=1.

It should be noted that the difference between pre-++ and post-++ : after the pre-++ is +=1, the value of the expression is the value after +1; and after the post-++ is +=1, the expression The value of is the value before +1.

In ++, the operand is the class object, and the return value of the pre-loaded ++ version should be the reference after +1; the return value of the post-version should be the value of the object before incrementing .

We only need to find a way to distinguish the parameter list of the operator to achieve overloading:
for the operator operator overloading of two operands, the first parameter of the function corresponds to the left operand, and the second parameter corresponds to the right operand . For example, the overload of ==: bool operator==(const Date& d);the first parameter is implicit this, and the second parameter is const Date& d. You can call this overloaded function: d1 == d2;this call is equivalent to d1.operator==(d2);.

  1. prefix ++

The prefix ++ can only implicitly pass the this pointer as the first parameter , which corresponds to the operand of the prefix ++;
since the incremented date object is returned, it is enough to return the reference of the object :

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

When we use pre-++, it is equivalent to calling this overloaded function:d.operator++();

  1. rear ++

In order to distinguish the post ++ implementation from the pre ++, in addition to the implicit this pointer, there can also be an unused int in the parameter list . *this corresponds to the first operand of the post ++, and int corresponds to the second operand (but the int here is only for distinguishing meaning and is not used); since the date
object before incrementing is returned, it is necessary to create a temporary The object temp is initialized with *this, and the original object is incremented and returned to temp. Here value return is required instead of reference return (for the same reason as before):

// 后置++
Date Date::operator++(int)
{
    
    
    Date temp(*this);
    *this += 1;
    return temp;
}

When using postfix ++, it is equivalent to calling this overloaded function:d.operator++(0);

Date prefix- - and postfix- -

The implementation and distinction of pre- - - and post- - are similar to ++, use -= in the function, and distinguish with an additional int parameter :

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

The reference returns the decremented object, which is equivalent to:d.operator--();

  1. rear - -
// 后置--
Date Date::operator--(int)
{
    
    
    Date temp(*this);
    *this -= 1;
    return *this;
}

Value returns the object before decrementing, which is equivalent to:d.operator--(0);

date - date

Date - Date is an overload -that returns the number of days between two dates.

There are two parameter lists, the implicit this pointer and the reference to the class object. Since the date object will not be changed when calculating the number of days between two dates, the references to *this and the object are all modified with const (same as when the comparison operator is overloaded before, so I won’t repeat it here);
the return value is int , indicating the difference of days:

int operator-(const Date& d)const;

When implementing this function, we can directly increment by the small date, and record the number of increments, know that the two dates are equal, and return the value of the counter variable.
It should be noted that the value of the original object cannot be changed, so a temporary object temp is created to increment the count :

// 日期-日期 返回天数
int Date::operator-(const Date& d)const
{
    
    
    int day = 0;
    Date temp(*this);
    if (temp > d)
    {
    
    
        while (temp != d)
        {
    
    
            --temp;
            day++;
        }
    }
    else
    {
    
    
        while (temp != d)
        {
    
    
            ++temp;
            day--;
        }
    }
    return day;
}

Input and output overloading (friends)

After implementing the above member functions, the addition, subtraction, multiplication, division, comparison, etc. of class objects can be used like built-in types, which greatly improves the convenience and readability. So can the input and output operators >>, <<What about overloading too? Of course it is possible:

cinand coutare standard input and standard output objects, use cin >>can read data from standard input stream; cout <<can print data in standard output stream. Their class types are istreamand ostream.

With such knowledge, we can realize overloading of >> as long as the operand on the left of the >> operator corresponds to cin, and the operand on the right corresponds to the class object to be input; similarly, the operation on the left of << The number corresponds to cout, and the operand on the right corresponds to the class object to be printed, so that << can be overloaded.
So, >>the first parameter type of the overload should be istream&, the second parameter type should be Date&; <<the overloaded first parameter type should be ostream&, and the second parameter type should be const Date&.

However, for member functions of a class, the first parameter must be a fixed this pointer for implicit parameter passing , which makes it impossible to implement the above parameter passing method for member functions.

To implement the above method of passing parameters, it must be a non-member function, and must be able to access member variables in the function. Under such requirements, we can use friendto declare an external function as a friend function of this class, so that there is no implicit this and member variables can be accessed; in
order to achieve continuous input and output, the value of the expression Should be a stream, so when overloaded, the return value of the function istream&is or ostream&:

//>>重载
istream& operator>>(istream& in,  Date& d)
{
    
    
    int year = 0;
    int month = 0;
    int day = 0;
    in >> year >> month >> day;
    if (month < 1 || month>12 || day<1 || day>Date::GetMonthDay(year, month))
    {
    
    
        cout << "输入错误" << endl;
        assert(0);
    }
    else
    {
    
    
        d._year = year;
        d._month = month;
        d._day = day;
    } 
    return in;
}
//<<重载
ostream& operator<<(ostream& out, const Date& d)
{
    
    
    if (d._month < 1 || d._month>12 || d._day<1 || d._day>Date::GetMonthDay(d._year, d._month))
    {
    
    
        cout << "输入错误" << endl;
    }
    out << d._year << "年" << d._month << "月" << d._day << "日" << endl;
    return out;
}

Of course, you also need to add a statement inside the class friend.

At this point, all member functions of the date class have been implemented, and the general code is in the back. We can also write a program to test this date class.

code overview

head File

//头文件

#include<iostream>
#include<cassert>
using namespace std;

class Date
{
    
    
	//友元输入输出
	friend istream& operator>>(istream& in, Date& d);
	friend ostream& operator<<(ostream& out, const Date& d);
public:
	// 全缺省的构造函数
	Date(int year = 1900, int month = 1, int day = 1);

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

	// 析构函数
	~Date();	
	
	// 获取某年某月的天数
	static int GetMonthDay(int year, int month);

	// 日期+=天数
	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);
	// >运算符重载
	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;
	// 日期-日期 返回天数
	int operator-(const Date& d)const;

	//打印
	void printDate()const;
private:
	int _year;
	int _month;
	int _day;
};
istream& operator>>(istream& in, Date& d);
ostream& operator<<(ostream& out, const Date& d);

Source File

//源文件
#include"data.h"

// 全缺省的构造函数
Date::Date(int year, int month, int day)
    : _year(year)
    , _month(month)
    , _day(day)
{
    
    }

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

// 赋值运算符重载
// d2 = d3 -> d2.operator=(&d2, d3)
Date& Date::operator=(const Date& d)
{
    
    
    _year = d._year;
    _month = d._month;
    _day = d._day;
    return *this;
}

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

// 获取某年某月的天数(用于日期加减天数)
 int Date::GetMonthDay(int year, int month)
{
    
    
    int monthdays[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)))
    {
    
    
        monthdays[month] = 29;
    }
    return monthdays[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 > 12)
        {
    
    
            _year++;
            _month = 1;
        }
    }
    return *this;
}
// 日期+天数
Date Date::operator+(int day)const
{
    
    
    Date temp(*this);//拷贝构造
    temp += day;//复用+=运算符重载
    return temp;//返回临时值,不改变*this的值
}
// 日期-=天数
Date& Date::operator-=(int day)
{
    
    
    if (day < 0)
    {
    
    
        return *this += -day;
    }
    _day -= day;
    while (_day < 1)
    {
    
    
        _month--;
        _day += GetMonthDay(_year, _month);//如果--后的_month为0,函数返回0,不影响结果

        if (_month <= 0)
        {
    
    
            _year--;
            _month = 13;
        }
    }
    return *this;
}
// 日期-天数
Date Date::operator-(int day)const
{
    
    
    Date temp;
    temp -= day;
    return temp;
}
// 前置++
Date& Date::operator++()
{
    
    
    *this += 1;
    return *this;
}
// 后置++
Date Date::operator++(int)
{
    
    
    Date temp(*this);
    *this += 1;
    return temp;
}
// 前置--
Date& Date::operator--()
{
    
    
    *this -= 1;
    return *this;
}
// 后置--
Date Date::operator--(int)
{
    
    
    Date temp(*this);
    *this -= 1;
    return *this;
}
// ==运算符重载
bool Date::operator==(const Date& d)const
{
    
    
    if ((_year == d._year)
        && (_month == d._month)
        && (_day == d._day))
    {
    
    
        return true;
    }
    else
    {
    
    
        return false;
    }
}
// >运算符重载
bool Date::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 Date::operator>=(const Date& d)const
{
    
    
    if (*this > d || *this == d)
    {
    
    
        return true;
    }
    return false;
}
// <运算符重载
bool Date::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 Date::operator<=(const Date& d)const
{
    
    
    if (*this < d || *this == d)
    {
    
    
        return true;
    }
    return false;
}
// !=运算符重载
bool Date::operator!=(const Date& d)const
{
    
    
    if (!(*this == d))
    {
    
    
        return true;
    }
    return false;
}
// 日期-日期 返回天数
int Date::operator-(const Date& d)const
{
    
    
    int day = 0;
    Date temp(*this);
    if (temp > d)
    {
    
    
        while (temp != d)
        {
    
    
            --temp;
            day++;
        }
    }
    else
    {
    
    
        while (temp != d)
        {
    
    
            ++temp;
            day--;
        }
    }
    return day;
}
//打印
void Date::printDate()const
{
    
    
    cout << _year << " " << _month << " " << _day << endl;
}

istream& operator>>(istream& in,  Date& d)
{
    
    
    int year = 0;
    int month = 0;
    int day = 0;
    in >> year >> month >> day;
    if (month < 1 || month>12 || day<1 || day>Date::GetMonthDay(year, month))
    {
    
    
        cout << "输入错误" << endl;
        assert(0);
    }
    else
    {
    
    
        d._year = year;
        d._month = month;
        d._day = day;
    } 
    return in;
}
ostream& operator<<(ostream& out, const Date& d)
{
    
    
    if (d._month < 1 || d._month>12 || d._day<1 || d._day>Date::GetMonthDay(d._year, d._month))
    {
    
    
        cout << "输入错误" << endl;
    }
    out << d._year << "年" << d._month << "月" << d._day << "日" << endl;
    return out;
}

main function

//main函数
int main()
{
    
    
    Date d1;
    cin >> d1;
    cout << d1;

    Date d2(2023, 5, 20);
    cout << d2;
    cout << d2 - d1 << "天" << endl;
    return 0;
}

insert image description here

Summarize

At this point, the implementation of the date class is introduced. By implementing the date class, I believe that everyone has a deeper understanding of classes and objects.
At the same time, the basic knowledge of classes and objects has also been introduced.
The C++ journey is still going on. Welcome everyone to continue to pay attention! ! !

If you think that I did not introduce a certain part clearly or that there is a problem with a certain part, you are welcome to raise it in the comment area

If this article is helpful to you, I hope it will be connected with one click

Hope to make progress together with you

Guess you like

Origin blog.csdn.net/weixin_73450183/article/details/130773853