2. 操作符 ==
1. 错误写法
#include<iostream> using namespace std; class date { public: date(int year = 1, int month = 1, int day = 1)//构造 { _year = year; _month = month; _day = day; } void print() { cout << _year << "-" << _month << "-" << _day << endl; } //private://需要将_year等改为public int _year; int _month; int _day; }; bool operator ==(const date& d1, const date& d2)//由几个参数,就接收几个 { //判断年月日是否都相等 return d1._year == d2._year && d1._month == d2._month && d1._day == d2._day; } int main() { date d1(2022,12,21); date d2(2022,12,22); d1 == d2; cout << (d1 == d2) << endl;// 0 代表假 return 0; }
第一个参数作为左操作数,第二个参数作为右操作数
这样写看起来是对的,但是这种方法会 把date类中私有的成员变量变成共有的,破坏类的封装,不符合我们本意
2. 正确写法
- 写入类中作为成员函数
#include<iostream> using namespace std; class date { public: date(int year = 1, int month = 1, int day = 1)//构造 { _year = year; _month = month; _day = day; } void print() { cout << _year << "-" << _month << "-" << _day << endl; } bool operator ==( const date& d2)// 由于隐藏的this指针的存在,&d1传过来由this指针接收 { return _year == d2._year && _month == d2._month && _day == d2._day; } private: int _year; int _month; int _day; }; int main() { date d1(2022,12,21); date d2(2022,12,22); d1 == d2;// d1.operator==(d2) 等价于 d1.operator==(&d1,d2) cout << (d1 == d2) << endl; return 0; }
传入类中,由于隐藏的this指针的存在,取第一个参数d1的地址传过去被this指针接收,_year等价于d1._year
但是由于this指针是隐藏的,所以&d1也不需要表现出来直接传入d2即可
3. cout << d1 == d2<< endl; 报错问题
- 运算符优先级问题,<<代表流插入,<<优先级比==高,所以会先执行cout<<d1 ,剩余的 = =d2无法执行,就会报错
3. 注意事项
1. 不能通过连接其他符号来创建新的操作符 (如 operator@)
2.重载操作符必须有一个类类型参数
3.用于内置类型的操作符,其含义不能改变(如 int 加法 不能改变)
- 所以要改成 (d1= =d2)来保证d1与d2先执行
- 这里理解很简单,因为运算符重载是针对自定义类型的,对于内置类型,编译器都已经设置好了
4.作为类成员的重载函数时,其形参看起来比操作数数目少1成员函数的操作符有一个默认的形参this,限定为第一个形参
- 这里理解很简单,因为运算符重载是针对自定义类型的,对于内置类型,编译器都已经设置好了
4.作为类成员的重载函数时,其形参看起来比操作数数目少1成员函数的操作符有一个默认的形参this,限定为第一个形参
4. 操作符 >
#include<iostream> using namespace std; class date { public: date(int year = 1, int month = 1, int day = 1)//构造 { _year = year; _month = month; _day = day; } void print() { cout << _year << "-" << _month << "-" << _day << endl; } bool operator >( const date& d2)// 由于隐藏的this指针的存在,&d1传过来由this指针接收 { if (_year > d2._year)//年大为大 { return true; } else if (_year == d2._year && _month > d2._month) //年相等,月大为大 { return true; } else if (_year == d2._year && _month == d2._month && _day > d2._day)//年 月相等,天大为大 { return true; } else { return false; } } private: int _year; int _month; int _day; }; int main() { date d1(2022,12,21); date d2(2022,12,22); d1 > d2;//等价于 operator>(&d1,d2) cout << (d1 > d2) << endl; return 0; }
判断大于时 ,同样存在一个隐藏的this指针,我们只需要判断 年大的就为大 ,年相等 ,月大的就为大,年月相等,天大的就为大,其他情况都为假
5. 操作符 !=
#include<iostream> using namespace std; class date { public: date(int year = 1, int month = 1, int day = 1)//构造 { _year = year; _month = month; _day = day; } void print() { cout << _year << "-" << _month << "-" << _day << endl; } bool operator==(const date& d2)//d1==d2 { return _year == d2._year && _month == d2._month && _day == d2._day; } bool operator!=(const date& d2) { return !(*this == d2);//借助上面的d1==d2的相反即 d1!=d2 } private: int _year; int _month; int _day; }; int main() { date d1(2022,12,21); date d2(2022,12,22); d1 != d2; cout << (d1 != d2) << endl; return 0; }
借助上面已经写好的d1==d2 ,取其相反 即为 d1!=d2
6. 操作符 <
#include<iostream> using namespace std; class date { public: date(int year = 1, int month = 1, int day = 1)//构造 { _year = year; _month = month; _day = day; } void print() { cout << _year << "-" << _month << "-" << _day << endl; } bool operator >(const date& d2)// d1>d2 { if (_year > d2._year)//年大为大 { return true; } else if (_year == d2._year && _month > d2._month) //年相,月大为大 { return true; } else if (_year == d2._year && _month == d2._month && _day > d2._day)//年 月相等,天大为大 { return true; } else { return false; } } bool operator<(const date& d2)// d1 < d2 { return !(*this > d2); } private: int _year; int _month; int _day; }; int main() { date d1(2022,12,21); date d2(2022,12,22); d1 < d2; cout << (d1 < d2) << endl; return 0; }
- 若直接写d1<d2 的条件太复杂,直接采用 d1 >d2 的相反,*this 代表 d1
2 .赋值操作符(编译器默认实现)
1. 正常使用
#include<iostream> using namespace std; class date { public: date(int year = 1, int month = 1, int day = 1)//构造 { _year = year; _month = month; _day = day; } void print() { cout << _year << "-" << _month << "-" << _day << endl; } void operator=(const date& d2) { //为了防止自己给自己赋值的事情发生,如:d1=d1 if ( this != &d2) { _year = d2._year; _month = d2._month; _day = d2._day; } } private: int _year; int _month; int _day; }; int main() { date d1(2022,12,21); date d2(2022,12,22); d1 =d2; return 0; }
- 如果是单个赋值这样就符合了,但是还是有连续赋值的情况存在
2. 连续赋值情况的考虑
#include<iostream> using namespace std; class date { public: date(int year = 1, int month = 1, int day = 1)//构造 { _year = year; _month = month; _day = day; } void print() { cout << _year << "-" << _month << "-" << _day << endl; } date operator=(const date& d)//传值返回 类型为date { //为了防止自己给自己赋值的事情发生,如:d1=d1 if (this != &d) { _year = d._year; _month = d._month; _day = d._day; } return *this; } date(const date& d) { _year = d._year; _month = d._month; _day = d._day; } private: int _year; int _month; int _day; }; int main() { date d1(2022, 12, 21); date d2(d1); date d3; d2 = d3 = d1; int i = 0; int j = 0; int z = 0; i = j = z; return 0; }
- 如果为内置类型,如int 则可以进行连续赋值
- 对于int 来说,根据结合性,j=z ,返回值为j ,i=j,生成最终结果i
- 对于 d2=d3=d1自定义类型来说,将 d1赋值给d3,将其返回值作为d2= 的右操作数存在
- 所以operator= 要有一个返回值
传值返回
由于*this为date 类型,属于传值返回,即返回一个临时变量,所以需进行拷贝构造
同时也会多开辟一块空间存储, 就会导致当return ( * this) 返回时,传入拷贝构造中创建临时变量 ,再次从中返回时,才能返回到 主函数中
传引用返回
传 * this的引用作为变量的别名,相当于 * this本身,不会消耗一块空间,自然在return*this 返回时,不会进入拷贝构造中,而是直接返回
所以传引用返回更优
5. const成员
1.对象调用const成员函数
#include<iostream> using namespace std; class date { public: void print() { cout << _a << endl; } private: int _a; }; int main() { const date a; a.print();//权限放大,会报错 return 0; }
- 将&a传过去由this指针接收, a指针类型为 const date* ,this指针类型为 date* ,将const date * 传给date * 属于权限的放大
- 把this指针类型改成 const date* 就可以了,但是由于this指针是隐藏的,要怎么解决呢?
#include<iostream> using namespace std; class date { public: void print()const //this指针类型变为const date* { cout << _a << endl; } private: int _a; }; int main() { const date a; a.print();//正确 权限保持 return 0; }
在括号外面加上const,使this指针类型改成 const date*
const 在*左右对于指针的影响
const date* p1 : 修饰的是* p1, const在 * 左面 指针所指向的内容不变
date const * p2 : 修饰的是* p2,const在* 左面 指针所指向的内容不变
date * const p3 : 修饰的是 p3,const在 * 右面,指针本身不变
注意事项
#include<iostream> using namespace std; class date { public: void print()const //this指针类型变为const date* { _a=10;//报错 cout << _a << endl; } private: int _a; }; int main() { const date a; a.print();//正确 权限保持 return 0; }
若在print函数内部修改成员变量_a的值就会报错,_a代表this->_a,但是由于 this指针当前类型为 const date *,使this指向的内容不变
2.成员函数调用const成员函数
#include<iostream> using namespace std; class date { public: void f1() { f2(); } void f2()const { } private: int _a; }; int main() { date a; a.f1(); return 0; }
在f1中时,this指针的类型为 date*
进入 f2后, this指针 转换为 const date *
属于权限缩小 ,可以实现
#include<iostream> using namespace std; class date { public: void f3() { } void f4()const { f3(); } private: int _a; }; int main() { date a; a.f4(); return 0; }
f4中 this指针类型为 const date*
f3中 this指针类型为 date*
权限放大了,不可以实现
6.取地址及const取地址操作符重载
#include<iostream> using namespace std; class date { public: date* operator&() { return this; } const date* operator&()const { return this; } }; int main() { date d; cout << &d << endl; return 0; }