运算符重载:
内置类型是直接支持比较和运算的,那我们的自定义类型可以随意的去运算比较嘛?是不是不能阿,所以就有了运算符重载(这样还可以提高可读性):
函数名:关键字operator后面接需要重载的运算符
参数:它是跟操作数一起变化的
返回值:运算符运算后的结果
注意:不能通过链接其他不是运算符的符号来创建一个新的操作符
有这五个运算符是不能重载的:( :: sizeof ?: . .* )
class stu { public: stu(const stu& d) { _year = d._year; _month = d._month; _day = d._day; } stu(int year = 2022,int month = 1,int day = 1) { _year = year; _month = month; _day = day; } void print() { cout << _year << "-" << _month << "-" << _day << endl; } bool operator==(stu& d1,stu& d2); private: int _year; int _month; int _day; }; bool stu::operator==(stu& d1,stu& d2) { return d1._year==d2._year && d1._month==d2._month && d1._day==d2._day; } int main() { stu s1(2000,6,9); stu s2(2011,5,19); if(s1==s2)//这里也是可以这样写的,operator(s1,s2),但这样太别扭了,跟调用函数一样 { cout<<"YES"<<endl; } }
但是我们上面这段代码是有问题的:
这是因为我们在类里面定义,是会有一个this指针的,正确的定义是这样的:
class stu { public: stu(const stu& d) { _year = d._year; _month = d._month; _day = d._day; } stu(int year = 2022, int month = 1, int day = 1) { _year = year; _month = month; _day = day; } void print() { cout << _year << "-" << _month << "-" << _day << endl; } bool operator==(stu& d1); private: int _year; int _month; int _day; }; bool stu::operator==(stu& d1) { return d1._year == _year && d1._month == _month && d1._day == _day; } int main() { stu s1(2000, 6, 9); stu s2(2011, 5, 19); if (s1 == s2)//这里也是可以这样写的,s1.operator(s2) { cout << "YES" << endl; } }
我们的重载也是可以定义为全局的,只不过这样你必须保证你能拿到对象里的成员,可以定义为共有 或者 写个函数去获取(这个是java里面喜欢用的)、写成友元函数:
class stu { public: stu(const stu& d) { _year = d._year; _month = d._month; _day = d._day; } stu(int year = 2022, int month = 1, int day = 1) { _year = year; _month = month; _day = day; } void print() { cout << _year << "-" << _month << "-" << _day << endl; } //private: int _year; int _month; int _day; }; bool operator==(stu& d1,stu& d2) { return d1._year == d2._year && d1._month == d2._month && d1._day == d2._day; } int main() { stu s1(2000, 6, 9); stu s2(2011, 5, 19); if (s1 == s2)//这里也是可以这样写的,operator(s1,s2),但这样太别扭了,跟调用函数一样 { cout << "YES" << endl; } }
假如我们又有全局也有类里面的,如果全都又它会调用谁呢?
注意这里如果要验证记得拿一个函数的参数加上const,不然编译会报错 :
:调用我们的全局的,我们的编译器会先去类里面找,如果没有再去全局里面找,像上面那种s1.operator(s2)这个是指定了去调用类里面的
现在再来实现一下比较大小吧,大家觉得实现一个 大于 的重载应该怎么写呢
bool operator>(const stu& d) const { if ((_year > d._year) || (_year == d._year && _month > d._month) || (_year == d._year && _month == d._month && _day > d._day)) { return true; } return false; }
这里函数的后面那个const 是为了给this修饰的(不会给其他形参修饰),因为我们的this是不能显示写在形参的位置的,所以有了这样的方法。这里也是因为不涉及值得改变所以才用const来修饰,十分严谨
还有一个小细节:我们在平常写的时候一个运算符可能会涉及一些和它相关的运算符,这些运算符如果写了,就可以直接用这些写好的,更加方便比如 >= 就是 > 和 = 。
接着来看一下赋值重载:
stu& operator=(const stu& d) { if (this != &d)//防止自己给自己赋值 { _year = d._year; _month = d._month; _day = d._day; return *this; } }
注意这里是有返回值的,我们在赋值完后,可能还会赋值一次,也就是连续赋值,我们这里也是返回的引用,避免了传值返回调用拷贝构造带来的消耗
赋值重载和拷贝构造是不一样的,拷贝构造是去创建一个为定义的对象,赋值重载是两个操作数都存在的赋值
六大成员函数里面是有我们的赋值重载的,那我们自己不写,让编译器自动生成,实现的操作又是什么样的呢?
其实赋值重载参考的是拷贝构造,对于内置类型会完成他的值拷贝 ,自定义类型会去调用它的赋值重载。
重载前置++后置++?
对于重载运算符还有几个要说的点:大家觉得我们的前置++ 和 后置++ 应该怎么写呢?
1. stu operator++() 2. stu operator++()
他们函数名相同 返回值也相同,是不是应该用重载来实现阿
1. stu operator++() 2. stu operator++(int i)
编译器规定带参数的是后置++ 不带的是前置 并且规定传参是一个整型,传参这个操作我们不用管这个是编译器来帮我们做的
stu& operator++() { *this += 1; return *this; } stu operator++(int) { date tmp(*this); *this += 1; return tmp; }
后置 ++ 返回的是一个临时拷贝,所以不能够返回引用!!!
注意:我们这里的参数 int 是为了让编译器传参,区分是 前置 还是 后置,所以这里是不能是加缺省值的,加了两个函数都可以不传参调用,这样就报错了,这里没有给形参,也是因为我这里只是要告诉编译器这里要传参,不在乎传的值,方便编译器判断。我不写形参的意思就是:这个值不重要,我可以选择不接收或者接收了但我不需要
重载流插入流提取?
流插入:cout << 流提取: cin >>
我们的 cin 和 cout都是存在头文件<iostream>,他们分别是两个流的对象,istream->cin,ostream->cout。像我们的内置类型都是已经重载好了的
void operator<<(ostream& out)//延续上面的代码,成员变量依旧是这几个日期 { out << _year << '-' << _month << '-' << _day << endl; }
如果我这个重载写在类里面大家觉得写得对嘛?
当然肯定是不对的:我们写在类里面他是不是会有一个隐含的this指针,那但我们想正常调用的时候是不是就成这样了:
s1(2022,6,7); cout<<s1<<endl;//cout.operator<<(s1)
我的s1是不是就传到out的位置上了这样是不是不对阿,况且我们总不可能因为这样写成:s1<<cout是吧
想要解决这个问题很显然我们是不想要这个this指针的,那我们吧函数写在类外面不就可以了嘛至于访问它的成员变量有多种方法,这里我就选择友元函数来解决(意思是告诉我们这个类这个函数是我们的朋友,可以访问私有成员)
friend ostream& operator<<(ostream& out, const stu& d); void operator<<(ostream& out, const stu& d) { out << d._year << '-' << d._month << '-' << d._day << endl; }
现在这个重载虽可以运行但还有一个问题:我们的返回值是不是应该重新考虑一下呢
我们平常写的时候是有可能会这样写的 cout<<d1<<d2<<d3<<endl; 所以我们输出完一个对象后还得紧接着输出下一个对象:
friend ostream& operator<<(ostream& out, const stu& d); friend istream& operator>>(istream& in, stu& d); ostream& operator<<(ostream& out, const stu& d) { out << d._year << '-' << d._month << '-' << d._day << endl; return out; } istream& operator>>(istream& in, stu& d) { in >> d._year >> d._month >> d._day; return in; }
感谢大家能够看到这里,预祝大家都能收到自己心仪大厂的offer!!!