为了在C++中依然延续我们在C中运算符的使用习惯,运算符重载是我们写代码中经常要进行的操作。
大家都知道运算符的重载可以使用成员函数来实现,也可以全局函数来实现,但是一些情况下成员函数又受到了一些限制,为什么会产生这种限制以及何种情况下会有这种限制呢?我们先以 '+' 的重载讲起。
#include<iostream>
using namespace std;
class Person{
public:
Person(int height,int weight):m_height(height),m_weight(weight){}
int getHeight()const{
return m_height;
}
int getWeight()const{
return m_weight;x
}
Person operator+ (const Person& p){
return Person(m_height+p.getHeight() , m_weight+p.getWeight());
}
private:
int m_height;
int m_weight;
};
/*Person operator+ (const Person& p1,const Person& p2){
return Person(p1.getHeight()+p2.getHeight() , p1.getWeight()+p2.getWeight());
}*/
void test01(){
Person p1(10,10);
Person p2(20,20);
Person p3 = p1+p2;
cout<<p3.getHeight()<<endl;
cout<<p3.getWeight()<<endl;
}
int main(){
test01();
system("pause");
return 0;
}
以上代码实现了两个Person类加法运算的运算符重载(成员函数实现和全局函数实现)
我们知道运算符重载也能发生函数重载,当我们有类似p+10或者10+p的运算需求时,上方的加法号重载就不够用了。
为了满足p+10类似的运算我们需要补充以下代码
//成员函数
Person operator+ (int a){
return Person(m_height + a , m_weight + a);
}
//全局函数
Person operator+ (const Person& p,int a){
return Person(p.getHeight() + a , p.getWeight() + a);
}
我们将对上面代码刨析,来说明为什么可以用成员函数来实现。
首先我们要明白p1+p2的本质上是执行了p1.operator+(p2) 或者operator+(p1,p2),因为‘+’是二元运算符,需要两个操作数。但当我们使用前者的时候只传递了一个操作数,另一个操作数是this被编译器隐藏传递了,所以我们明白了要想使用成员函数来运算符重载,符号的左操作数一定要是个对象。
p+10的本质上是执行了p.operator+(10) 或者operator+(p,10)。前者的左操作数p被编译器当作this隐藏传递。
到这你就会发现当我们要重载类似10+p的运算时,就不能使用成员函数来重载了。因为这时候加法号+的左操作数不再是个对象。编译器自然不会把它当作this隐藏传递。只能使用全局函数来重载。
还有一些情况是为了满足我们使用习惯也不推荐使用成员函数来重载运算符,比如'<<'运算符
#include<iostream>
using namespace std;
class Person {
friend ostream& operator<<(ostream& out, Person& p);
public:
Person(int a, int b):m_A(a),m_B(b){}
//成员函数 实现不了 p << cout 不是我们想要的效果
//void operator<<(Person& p){
//
//}
private:
int m_A;
int m_B;
};
//全局函数实现左移重载
//ostream对象只能有一个
ostream& operator<< (ostream& out,const Person& p) {
out << "a:" << p.m_A << " b:" << p.m_B;
return out;
}
void test() {
Person p1(10, 20);
cout << p1 << "hello world" << endl; //链式编程
}
int main() {
test();
system("pause");
return 0;
}
对上解释:前面我们说过,要想使用成员函数来运算符重载,符号的左操作数一定要是个对象。我们通常的习惯是cout << p,这里cout也确实是一个对象,然而这个对象所对相应的类ostream不是我们实现的,我们自然不可能跑到ostream这个类里边去重载运算符<<。如果我们让p当左操作数,我们可以到Person类里用成员函数重载运算符,但是这违背了我们cout的使用习惯(没有人会p << cout去输出)。因此最好的办法就是使用全局函数。