几个特殊的运算符重载
概念
运算符重载是一个非常重要的概念,在运算符重载中我们可以重新定义 运算符 的具体含义,一个运算符重载函数的定义是
T operator 运算符 (参数)
,对于运算符重载有以下重点。
以下讨论的都是双操作数的运算符
- 双操作数的运算符左边的参数对应的是函数参数列表中第一个参数,右边的操作数对应的是第二个参数,例如:
a+b;
写成运算符重载的形式就是T operator+(a,b);
- 当运算符重载函数是类的成员函数的时候,第一个参数是省略不写的——也就是操作符左边对应的参数。但是这并不代表左边的参数不传入函数,而是由this指针替代,不在运算符重载函数的参数列表中出现。例如:
class A
{
public:
int operator+(A b)
{
return a + b.a;
}
private:
int a=1;
};
int main()
{
A a,b;
a + b;
a.operator+(b); //这两种写法是等价的 a作为*this传入函数,在参数列表中不显示写出
}
前置++、后置++运算符重载
前置和后置++,在定义时形式上无法有显示的区分,所以我们做如下规定:
T& operator++() //前置++
T operator++(int) // 后置++
注意这个int是区分 前置++ 和 后置++ 的唯一标志
Self& operator++()
{
对运算符++ 的具体操作;
return *this;
}
Self operator++(int) //注意这里返回值不能是引用,
{
Self tmp = *this;
++(*this); //调用前置++
return tmp;
}
具体定义如上
前置–和后置-- 与 前置++和后置++ 原理一模一样这里就不赘述了
>>
和<<
运算符重载
上面提到了:双操作数的运算符左边的参数对应的是函数参数列表中第一个参数,右边的操作数对应的是第二个参数。但是在流输入和流提取函数上就会出现一些问题。以流输出为例:
class A
{
public:
ostream& operator<<(ostream& os)
{
os << _a;
return os;
}
private:
int _a=1;
};
int main()
{
A a;
//cout << a; 常见的流输出
a.operator<<(cout); //实际上的流输出
a << cout; //上面的等价写法
}
但是这里的输出a<<cout
与我们的常识违背,这是由于运算符重载概念的第二条规定的,如果写成类的成员函数第一个参数一定是类的对象。所以我们必须寻找一种更好的解决方法——友元
我们可以定义一个友元函数,将参数写在函数参数列表的正确位置,同时友元函数还能访问类的私有成员,一箭双雕
class A
{
friend ostream& operator<<(ostream& os, const A& a);
public:
ostream& operator<<(ostream& os)
{
os << _a;
return os;
}
private:
int _a=1;
};
ostream& operator<<(ostream& os, const A& a)
{
os << a._a;
return os;
}
int main()
{
A a;
//cout << a; 常见的流输出
a.operator<<(cout); //实际上的流输出
a << cout; //上面的等价写法
cout << a;
}
流插入与流输入同理这里就不多赘述了