不能重载的运算符有:. 和 :: 和 ?:和.*和sizeof
注意点1:
使用运算符重载的本质上是一次函数调用,所以这些关于运算对象的求值顺序无法应用到重载的运算符上。
友元函数和成员函数的使用场合:
一般情况下,建议一元运算符使用成员函数,二元运算符使用友元函数
1、运算符的操作需要修改类对象的状态,则使用成员函数。如需要做左值操作数的运算符(如 =,+=,++)
2、运算时,有数和对象的混合运算时,必须使用友元
3、二元运算符中,第一个操作数为非对象时,必须使用友元函数。如输入输出运算符 << 和 >>
4、当一个重载运算符是成员函数时,this 绑定到左侧运算对象。成员运算符函数的显式形参比运算对象的数量少一个
5、可以直接调用一个重载的运算符函数,如 operator+(data1, data2), data1.operator(data2)
6、当运算符作用于内置类型对象时,我们无法改变运算符的含义
如下运算符 | 建议使用 |
---|---|
所有一元运算符 | 成员函数 |
= ( ) [ ] -> | 必须是成员函数 |
+= -= /= *= ^= &= != %= >>= <<= , 似乎带等号的都在这里了. | 成员函数 |
所有其它二元运算符, 例如: –,+,*,/ | 友元函数 |
<< >> | 必须是友元函数 |
注意点2当参数不会被改变,一般按 const 引用来传递(若是使用成员函数重载,函数也为 const).对于返回数值的决定:
1) 如果返回值可能出现在 = 号左边, 则只能作为左值, 返回非 const 引用。
2) 如果返回值只能出现在 = 号右边, 则只需作为右值, 返回 const 型引用或者 const 型值。
3) 如果返回值既可能出现在 = 号左边或者右边, 则其返回值须作为左值, 返回非 const 引用。
也就是左值为非const,右值const
重载 -> 运算符:
#include<bits/stdc++.h>
using namespace std;
struct Node{
//friend string *operator->();
public :
string *operator->(){
return ptr;
}
Node(string *s):ptr(s){}
Node()=default;
private :
string* ptr;
};
//string* operator->(const Node&x){
// return x.ptr;
//}
int main(){
string s="asdf";
Node x(&s);
cout<<x->size();//当 ptr 的类型是内置指针类型时,等价于 (*ptr).mem;
//当 ptr 的类型是类时,等价于ptr.operator->()->mem;//从这里也可以看出 -> 重载必须是成员函数
return 0;
}
-> 操作符只能通过成员函数来重载,不能通过友元函数来重载。如果通过友元函数来重载,会报错
->操作符的返回根据类型不同,(返回值 function)的解释也不同。
如果返回类型值内置指针,那么就相当于 解引用一下((*返回值).function );
如果返回类型是类的时候,那么就相当于ptr.operator->()->function。
重载–和++运算符:
#include<bits/stdc++.h>//成员函数
using namespace std;
class Node{
friend void print(ostream&,const Node&);
private:
int x;
public :
Node()=default;
Node(int a):x(a){}
~Node(){}
Node& operator--(){//前缀
x--;
return *this;
}
const Node& operator--(int){
const Node& cmp = *this;
--x;
return cmp;
}
};
void print(ostream& os,const Node&it){
os<<it.x<<endl;
}
int main(){
Node a(10);
print(cout,a);
print(cout,a--);
print(cout,a);
print(cout,--a);
print(cout,a);
}
#include<bits/stdc++.h>//友元
using namespace std;
class Node{
friend void print(ostream&,const Node&);
friend Node& operator--(Node&);
friend const Node operator--(Node&,int);
public :
Node()=default;
int x;
};
Node& operator--(Node&it){//先减去
it.x--;
return it;
}
const Node operator--(Node&it,int) {//有一个占位符号
const Node tmp=it;
it.x--;
return tmp;
}
void print(ostream & os,const Node&x){os<<x.x<<endl;}
int main(){
Node a;
a.x=0;
print(cout,a--);
print(cout,a);
print(cout,--a);
}
注意
需要用一个占位符(虚参数)区分前后缀运算
后置时不要返回引用,不然会返回一个局部对象引用
重载[]运算符:
#include<bits/stdc++.h>
using namespace std;
class Node{
public :
~Node(){}
Node()=default;
Node(int *a){
for(int i=0;i<100;i++)x[i]=a[i];
}
int operator[](int in){
if(0<=in&&in<100)return x[in];
else {
cout<<"out of range;";
}
}
private:
int x[100];
};
int main(){
int tmp[100];
for(int i=0;i<100;i++)tmp[i]=i;
Node a(tmp);
cout<<a[2];
}
//【】的重载必须是非静态成员重载
我们可以发现 [] 只能作为成员函数重载,如果重载为友元函数的话会报错:
重载()运算符
我们可以发现 () 只能作为非静态成员函数重载,如果重载为友元函数的话会报错:
#include<bits/stdc++.h>
using namespace std;
class Node{
private :
int x;
public:
~Node(){}
Node(int a):x(a){}
const int operator()(const Node &it)const {
return x+it.x;
}
};
int main(){
Node a(10);
cout<<a(a);
return 0;
}
重载运算符 () 的目的:对象 () 类似于函数名 (x),更加符合习惯
语法:
重载方式:只能使用成员函数重载
重载后还可以继续重载
函数名:operator( )(参数表)
参数表:参数随意,具体根据实际情况而定。
函数调用:显式调用:Obj(x)
隐式调用:obj.operator( )(x)
返回类型:
1、返回成员的实际类型随意,具体由程序员根据函数体定义
2、因为返回值只能做右值,只读,应该使用返回值为const类型
重载>><<运算符
#include <iostream>
using namespace std;
class gel{
// friend ostream& operator<<(const gel&, ostream&);
friend ostream& operator<<(ostream&, const gel&);
private:
int x, y;
public:
gel(int a, int b) : x(a), y(b){}
gel(int a) : gel(a, 0){}
gel(void) : gel(0, 0){}
~gel(){}
};
// ostream& operator<<(const gel &it, ostream &os){
// os << it.x << " " << it.y;
// return os;
// }
ostream& operator<<(ostream &os, const gel &it){
os << it.x << " " << it.y;
return os;
}
int main(void){
gel a(1, 2);
cout << a << endl;
return 0;
}
#include <iostream>
using namespace std;
class gel{
private:
int x, y;
public:
gel(int a, int b) : x(a), y(b){}
gel(int a) : gel(a, 0){}
gel(void) : gel(0, 0){}
~gel(){}
ostream& operator<<(ostream &os){
os << this->x << " " << this->y;
return os;
}
};
int main(void){
gel a(1, 2);
// cout << a << endl;
//我们可以发现不加这个语句的话这个代码是正确的,再结合前面的东西,我们可以得出这个语句错误的原因:
//将<<重载成gel类的成员函数,其第一个参数必须是gel类的对象,即要求<<是右结合的(a在<<右边嘛),而<<本身是要求左结合的.此处矛盾所以是错误的
//那么我们可以尝试着将cout << a << endl;改成既满足<<是左结合的,又满足<<的第一个参数是a
a.operator << (cout) << endl;//此处cout必须加括号,将opetator<<当成一个a类的成员函数,后面接着的当然是参数列表啦,cout是实参.又因为其返回的是一个cout流,所以后面可以接其它输出内容
return 0;
}
重载 = 运算符:
= 只能作为成员函数重载,如果重载为友元函数的话会报错:
自己打过ACM,感觉这个东西没什么总结的,
详细总结在这里:https://www.cnblogs.com/geloutingyu/p/8283810.html