为了更好的了解并使用类相关的知识,我们需要多加练习。在本次博客当中我们将会创建一个Date类,进行一系列相关类的操作,并且实现有关于日期之间可能需要进行的操作。
▶构造函数
对于构造函数我们需要实现三个或者以上的构造。其中包括用于初始化对象的构造函数,用于程序结束之后的构造函数,以及用于使用已存在对象生成新的对象的拷贝构造函数。
■初始化构造函数
对于上述三个构造函数当我们不进行手动编写的时候,系统当中也会自动生成一个默认的构造函数。
但是系统自动生成的构造函数有很大的局限性。它对于内置类型不做任何处理,对于自定义类型会调用我们已经生成好的构造函数,所以我们如果想要有更多的初始化对象的方法,还是最好自定义一个初始化构造函数为好。
■析构函数
对于析构函数同样会在不手动定义的时候会自动进行生成。所进行的操作为:对于内置类型的数据不做任何处理,对于自定义类型的数据会自动调用已经生成好的析构函数。但是需要注意的是:如果存在手动开辟的空间需要谨慎的斟酌是否需要手动编写析构函数,防止内存泄漏问题的产生。
■拷贝构造
自动生成的拷贝构造函数会默认进行浅拷贝操作。所谓的浅拷贝就是不进行思考和判断直接全部进行复制操作。对于内置类型直接复制的可以的,但是对于手动开辟空间的自定义类型来说,我们使用默认的拷贝构造就可能会产生错误。因为产生的对象和旧对象指向的是同一块空间,在析构的时候同一块空间会释放两次,因此会产生系统报错。
对于上面的三种构造函数,如果我们自定义的成员变量都是内置类型的数据,或者说当中的自定义类型的数据已经存在对应的构造函数的时候,我们就可以使用系统生成的默认的构造函数。如果不是尽量自己生成。
▶运算符重载
在实例化对象之后,我们会发现我们产生的对象不可以和内置类型一样直接进行++或者--等一系列操作,这是因为自定义类型没有与之相匹配的函数重载。如果想要使用就需要进行手动的函数重载操作,其主要需要实现的函数重载的功能如下:
■ >,<,<=,>=,==,!=比较运算符的重载
■ +,+=,-,-=操作运算符的重载
■ 前置++,后置++,前置--,后置--运算符的重载
■ 输入流,输出流 >>,<< 运算符的重载
其中对于我们可以根据实际的函数进行操作运算符函数的重载,比如日期减日期,计算两个日期之间相隔的天数。日期加天数,计算某个日期多少天之后的日期数等等。
●注意事项:
Number1:在重载前置++和后置++,前置--和后置--运算符的时候。我们需要注意区分两者的区别,由于都是++运算符,为了让编译器可以进行区分,我们通常情况下会将后置++或--操作的参数当中传入一个占位符。占位符不需要手动进行传参。
Number2:对于流插入和流提取运算符的重载。因为在成员函数当中会默认传入一个this指针作为第一个操作数,所以如果我们将重载的流插入流提取运算符写成成员函数的时候只能是data<<out 。这很不符合我们的使用习惯,所以我们在重载流插入流提取函数的时候就需要将函数重载成为全局的函数,并将该函数设置为类的友元函数便于我们在函数当中访问类当中的私有变量。
Number3:在我们编写成员函数的时候需要注意,如果不需要进行修改的变量尽量加上const进行修饰。因为加上const的函数既可以接收不适用const修饰的对象作为参数,也可以接收使用const进行修饰的对象作为参数,这样就不需要我们重新编写一份专门用于const对象的代码了。
Date类代码如下:
DateClass.h(头文件)
#pragma once
//在头文件当中进行类的声明以及头文件的包含等操作
#include<iostream>
using namespace std;
class Date
{
friend istream& operator>>(istream& in, Date& d);
friend ostream& operator<<(ostream& out, const Date& d);
public:
//实现一个构造函数,用于初始化date对象
Date(int year = 2024, int month = 4, int day = 13);
//重新创建一个拷贝构造函数,用于使用另外一个对象初始化目标对象
Date(const Date& d); //自动传入一个this指针
//之后使用运算符重载函数进行重载赋值运算符
Date& operator=(const Date& d);
//使用函数重载进行重载判断函数
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++();
Date operator++(int);
//使用运算符重载进行重载+操作,将日期和天数相加计算出几天后的日期
Date operator+(int day) const;
Date& operator+=(int day);
//计算两个日期之间相隔多少天
int operator-(const Date d) const;
//重载-运算符,判断某个特定日期前面某一天的日期
Date operator-(int day) const;
Date& operator-=(int day);
//使用运算符重载前置--和后置--运算符
Date& operator--();
Date operator--(int);
void print();
private:
int _year;
int _month;
int _day;
};
//使用运算符重载流插入流提取函数,流插入流提取不能作为类当中的函数,否则就会产生参数相反的情况
ostream& operator<<(ostream& out, const Date& d);
istream& operator>>(istream& in, Date& d);
DateClass.cpp(主函数)
#define _CRT_SECURE_NO_WARNINGS
#include"Date.h"
Date::Date(int year, int month, int day) //缺省值只能在函数的声明当中才可以给
{
_year = year;
_month = month;
_day = day;
}
Date::Date(const Date& d) //自动传入一个this指针
{
_year = d._year;
_month = d._month;
_day = d._day;
}
Date& Date::operator=(const Date& d)
{
_year = d._year;
_month = d._month;
_day = d._day;
return *this;
}
bool Date::operator>(const Date& d) const
{
//之后进行判断数据是否大于
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) const
{
return _year == d._year && _month == d._month && _day == d._day;
}
bool Date::operator<(const Date& d) const
{
if (!(*this == d) && !(*this > d))
{
return true;
}
return false;
}
bool Date::operator!=(const Date& d) const
{
return !(*this == d);
}
void Date::print()
{
cout << _year << "年" << _month << "月" << _day << "日" << endl;
}
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) && (*this == d))
{
return true;
}
return false;
}
int Date::operator-(const Date d) const
{
Date max(*this);
Date min(d);
if (*this < d)
{
max = d;
min = *this;
}
int count = 0;
while (min < max)
{
++min;
count++;
}
return count;
}
Date& Date::operator++()
{
//直接调用+=函数将数值相加1
*this += 1;
return *this;
}
Date Date::operator++(int)
{
Date d(*this);
*this += 1;
return d;
}
Date Date::operator+(int day) const
{
//首先创建一个日期类型
Date d(*this);
//生成数据之后调用+=修改d对象
d += day;
return d;
}
int getMonthDay(int year, int month)
{
int arr[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)))
{
return 29;
}
return arr[month];
}
Date& Date::operator+=(int day)
{
//将天数全部加到_day当中
_day += day;
while (1)
{
int ret=getMonthDay(_year, _month);
if (_day > ret)
{
_day -= ret;
//之后产生对月份进行进位操作
_month++;
if (_month == 13)
{
_year++;
_month = 1;
}
}
else
{
break;
}
}
return *this;
}
Date Date::operator-(int day) const
{
//将所有的天数都减到_day当中
Date ret(*this);
ret -= 1;
return ret;
}
Date& Date::operator-=(int day)
{
_day -= day;
while (1)
{
if (_day <= 0)
{
//需要求解上一个月的日期并进行操作
_month--;
if (_month == 0)
{
_month = 12;
_year--;
}
int tmp = getMonthDay(_year, _month);
_day += tmp;
}
else
{
break;
}
}
return *this;
}
Date& Date::operator--()
{
*this -= 1;
return *this;
}
Date Date::operator--(int)
{
Date d(*this);
*this -= 1;
return d;
}
ostream& operator<<(ostream& out, const Date& d)
{
out << d._year << "年" << d._month << "月" << d._day << "日" << endl;
return out;
}
istream& operator>>(istream& in, Date& d)
{
in >> d._year >> d._month >> d._day;
return in;
}
test.cpp(测试主函数)
#define _CRT_SECURE_NO_WARNINGS
#include"Date.h"
//void testDate()
//{
// Date d1(2023, 12, 12);
// Date d2(2022, 11, 10);
//
// //之后尝试使用拷贝构造进行检查对象的创建操作
// Date d3(d2);
//
// //之后尝试使用赋值运算符重载操作将d3修改成为d1
// d3 = d1;
//
// //之后检查比较运算符重载操作是否可以正常运行
// if (d3 > d2)
// {
// cout << "YES" << endl;
// } //该功能一切正常
//
// if (d3 == d1)
// {
// cout << "YES" << endl;
// }
//
// if (d2 < d3)
// {
// cout << "YES" << endl;
// }
//
// if (d2 != d3)
// {
// cout << "YES" << endl;
// }
//
// d1.print();
// d2.print();
// d3.print();
//} //比较两个类的函数程序一切正常
//void testDateAdd()
//{
// //Date d1(2022, 12, 12);
// //d1 += 1000;
// //d1.print(); //函数的功能一切正常
// //Date d2(d1 + 100);
// //d2.print();
// //++d2;
// //d2.print();
// //Date d3(d2++);
// //d3.print();
// //d2.print();
// Date d1(2023, 12, 12);
// Date d2(2022, 12, 12);
// Date d3(d1 - 365);
// d3.print();
//}
void testforsub()
{
Date d(2023, 12, 12);
/*d--;
d.print();
--d;
d.print();*/
//测试使用自定义的输入输出操作符输出自定义类型
cout << d;
cin >> d;
cout << d;
}
int main()
{
testforsub();
//testDate();
return 0;
}