一:概念
在以前的C语言的学习中,如果我们需要比较两个整数并返回它的结果可以直接用与之相关的符号。例如我们可以直接写成A>B或者A<B一类的,但是它的局限性很大,只能比较内置类型,因为计算可以直接转换成对应的汇编代码进行比较,但如果现在我们写了一个日期类,并且构建出两个对象要比较两个日期的大小的话,直接写A>B之类的会给我们提示
可以看到给出的报错是没有与这些操作数对应的>运算符。那么在C++中,我们的祖师爷当时显然也是被这个问题困惑到了,就想出了一个名为operator的神奇,至于它有什么用我们从根部来刨析它。在之前我们先简单了解一下operator的用法和特性
用法
1:operaor后面需要接操作符(例如大于小于等)
2:函数原型 返回类型 operator(操作符)(参数列表)
特征
不能通过链接其他符号来创建新的操作符号 例如:operator@
重载操作符必须有一个类类型参数
用于内置类型不能改变其含义,例如:整形的+
作为类成员函数重载时,其形参看起来比操作数少一个,因为成员函数有一个时隐藏的this指针
.* :: sizeof ?: . 5个运算符不能重载
二:实现
我们接下来说说它的用法,当想去比较两个日期类的谁大的时候,我们只需要在构建的类中去添加一个operator>的运算符,然后就可以直接像内置类型一样直接去比较日期类的大小。例如说我现在构建出了两个日期对象,并且我要比较第一个日期大还是第二个日期大的时候,我就可以直接写成date1>date2。可能会有异或,我写的是operator>这样的运算符,按理来说如果要去调用这个重载符应该写成date1.operator(date2)不是更合理吗。其实不然,你实际写成这样,或者是写成date1.operator(date2)这样编译器实际都会把它处理成operator>(date1,date2),我们从反汇编的角度也确实看到编译器在调用这个重载函数的时候把它转换成了和我们说的一样
那既然都会转换成这样我们不如写一个读起来相对较为容易的d1>d2呢。
如果说要判断两个日期是否相等,同样也只需要去类里面写一个operator==的重载,在判断一下年月日是否相等,相等的话就返回true。
接下里就是operator真正精粹的地方。当我们写了大于和等于之后,直接可以复用前面写过的,例如我们现在要判断哪个日期比较小,只需要把上面写了的大于日期和等于逻辑取反一下,就可以完美实现小于,
我们在写成(*this)> d的时候它又会去调用刚刚我们写过的大于重载符,当比较完成之后会返回true或者false,我们只需要把拿到的结果取反一下,就实现了小于的比较。有了这个办法之后,我们同样可以对不等于,大于等于,小于等于进行复用。
三:重载cout
最后,当我们创建了一个日期对象,想去输出打印它的日期还得写一个print的函数来输出它的年月日,按照以前C语言的习惯,要输出的话还需要写一个printf打印每个数据对应的数据类型,但是在c++中有一个cout(流插入),可以直接识别我们当前的数据类型,但是它真的有这么神奇是完全靠自己去识别的吗,实则不然,我们可以去cplusplus网站看一下cout的原型。
它实际上是istream这个类里面的一个全局对象,cin实际是ostrean里面的全局对象,那么它是怎么识别的呢。我们看下面
通过这张图我们可以看到,原来cout可以识别内置类型原来是库里面实现的,operator去重载了<<所以cout在输出的时候不用打印数据类型。而可以打印自定义类型是因为函数的重载。那有了这个办法之后我们就可以不用写print这个函数了,直接去把cout重载一下就行了,但是有一点值得注意的是,如果你要使用operator去重载cout,那么就不能在类里面写这个函数,因为按照习惯我们去使用输出日期类的时候都是 cout<<date1<<endl;这样来写,但是在类中,第一个参数是隐藏的this指针,在去调用的时候就会把cout传给this指针,所以要按照习惯来写的话就只写在全局,并且参数位置由自己来控制。
四:简易天数计算器
//头
#define _CRT_SECURE_NO_WARNINGS 1
#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);
Date(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+=(int day);
Date operator+(int day);
Date& operator-=(int day);
Date operator-(int day);
Date& operator++();
Date operator++(int);
int operator-(const Date& d);
static int GetMonthDay(int year, int month);
void print()
{
cout << _year << "年" << _month << "月" << _day << "日" << endl;
}
private:
int _year;
int _month;
int _day;
};
ostream& operator<<(ostream& out,const Date& d);
istream& operator>>(istream& in, Date& d);
//实现
#include"Date.h"
Date::Date(int year, int month, int day)
{
if(month<=12&&month>0
&& day > 0 && day <= GetMonthDay(year, month))
{
_year = year;
_month = month;
_day = day;
}
else
{
cout << "非法日期" << endl;
assert(false);
}
}
Date::Date(const Date& d)
{
_year = d._year;
_month = d._month;
_day = d._day;
}
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
{
if (_year == d._year
&& _month == d._month
&& _day == d._day)
{
return true;
}
else
return false;
}
bool Date::operator<(const Date& d) const
{
return (!(*this > d) && !(*this == d));
}
bool Date::operator!=(const Date& d) const
{
return !(*this == d);
}
bool Date::operator>=(const Date& d) const
{
return (*this > d) || (*this == d);
}
bool Date::operator<=(const Date& d) const
{
return (*this < d) || (*this == d);
}
int Date::GetMonthDay(int year, int month)
{
static int days[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };
if ((month == 2) && (year % 4 == 0) && (year % 400 != 0) || (year % 100 == 0))
return 29;
else
return days[month];
}
Date& Date::operator+=(int day) //计算某个天数之后是什么时间
{
if (day < 0)
{
return *this -= abs(day);
}
_day += day;
while (_day > (GetMonthDay(_year, _month)))
{
_day -= (GetMonthDay(_year, _month));
++_month;
if (_month == 13)
{
_month = 1;
++_year;
}
}
return *this;
}
Date Date::operator+(int day)
{
Date tmp = *this;
tmp += day;
return tmp;
}
Date& Date::operator-=(int day)
{
if (day < 0)
{
return *this += abs(day);
}
_day -= day;
while (_day <= 0)
{
_day += GetMonthDay(_year, _month);
--_month;
if (_month == 0)
{
_year;
_month = 12;
}
}
return *this;
}
Date Date::operator-(int day)
{
Date tmp = *this;
tmp -= day;
return tmp;
}
Date& Date:: operator++()
{
*this += 1;
return *this;
}
Date Date:: operator++(int)
{
Date tmp = *this;
*this += 1;
return tmp;
}
int Date::operator-(const Date& d) //计算两个日期之间相差时间
{
Date max = d;
Date min = *this;
int flag = 1;
if (*this>d)
{
max = *this;
min = d;
flag = -1;
}
int day=0;
while (min != max)
{
++min;
++day;
}
return day;
}
//重载<<支持输出自定义类型的流插入
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 <= 12 && month > 0
&& day > 0 && day < (Date::GetMonthDay(year, month)))
{
d._year = year;
d._month = month;
d._day = day;
}
else
{
cout << "非法日期" << endl;
assert(false);
}
return in;
}
//测试
#include"Date.h"
void TestDate1()
{
Date d1(2023, 5, 6);
d1.print();
Date d2 = d1;
d2.print();
}
void TestDate2()
{
Date d1(2023, 5, 6);
Date d2(2024, 5, 6);
cout << (d1 > d2)<< endl;
cout << (d1 < d2) << endl;
cout << (d1 >= d2) << endl;
cout << (d1 <= d2) << endl;
cout << (d1 == d2) << endl;
cout << (d1 != d2) << endl;
}
void TestDate3()
{
Date d1(2000, 9, 9);
Date d2(2024, 5, 6);
d1 += 33000;
d1.print();
//d2 + 100;
//d2.print();
}
void TestDate4()
{
Date d1(2000, 9, 69);
Date d2(2024, 5, 6);
d1 += 3000;
d1.print();
//d2 += -100;
//d2.print();
//Date d3=(d2 - 100);
//d3.print();
//d2.print();
}
void TestDate5()
{
Date d1(2023, 5, 6);
Date d2(2024, 5, 6);
++d1;
Date d3 = d2++;
d1.print();
d3.print();
d2.print();
}
void TestDate6()
{
Date d1(2001, 1, 9);
Date d2(2023, 5, 6);
cout << d1 - d2 << endl;
}
void TestDate7()
{
Date d1(2001, 4, 9);
Date d2(2023, 5, 6);
//cout << d1 << endl;
cin >> d1 >> d2;
cout << d1 - d2 << endl;
}
int main()
{
//TestDate1();
//TestDate2();
TestDate3();
//TestDate4();
//TestDate5();
//TestDate6();
//TestDate7();
return 0;
}