3. 运算符重载的方式

C++ 中有三种运算符重载的方式:

  1. 成员函数方式重载。
  2. 友元全局函数方式重载。
  3. 全局函数方式重载。

以之前定义的 Complex 类为例,现在我们已经创建了一个对象 Complex c1(1, 2),现在需要实现 c1 + 15 + c1 这样的操作,下面来用三种方法重载加号运算符。

需要注意的是一个虚数和整数相加时是实部相加,虚部不变。

1. 成员函数方式重载

// filename: op_methed1.cpp
#include <iostream>

using namespace std;

class Complex {
    public:
        Complex(double r=0, double i=0): real(r), image(i){}
        void info(){
            cout << "(" << real << "+" << image << "i)\n";
        }
        Complex operator +(int right) const {
            return Complex ( this->real + right, this->image);
        }
    private:
        double real;
        double image;
};
int main(int argc, char * argv[]) {
    Complex c1(1, 2);
    Complex c3;
    c3 = c1 + 1;
    c3.info();
    // c3 = 5 + c1; // 报错
    // c3.info(); 

    return 0;
}

编译和运行结果如下:

weimz@mzstudio:~$ g++ -o op_methed1 op_methed1.cpp
weimz@mzstudio:~$ ./op_methed1 
(2+2i)

上述示例成功的重载了 + 运算符能够是一个 Complex 类型的对象和一个整数相加。但是如果是一个整数和一个 Complex 类型的对象相加(如:5 + c1)则会报错,因为 左操作数是 int 类,int 类中没有重载能和 Complex 相加的成员函数。要解决这个问题则需要使用友元全局函数的方式重载 加号(+)运算符。

2. 友元全局函数方式重载

去掉原来的成员函数 Complex::operator+(int),改用两个全局函数如下:

// filename: op_methed2.cpp
#include <iostream>

using namespace std;

class Complex {
    public:
        Complex(double r=0, double i=0): real(r), image(i){}
        void info(){
            cout << "(" << real << "+" << image << "i)\n";
        }
    private:
        double real;
        double image;
    friend Complex operator +(const Complex & left, int right);
    friend Complex operator +(int left, const Complex & right);
};
// 重载加号运算符(Complex + 整数)
Complex operator +(const Complex & left, int right) {
    return Complex ( left.real + right, left.image);
}
// 重载加号运算符(整数 + Complex)
Complex operator +(int left, const Complex & right) {
    return Complex (left + right.real, right.image);
}
int main(int argc, char * argv[]) {
    Complex c1(1, 2);
    Complex c3;
    c3 = c1 + 1;
    c3.info();
    c3 = 5 + c1; // 报错
    c3.info(); 

    return 0;
}

编译和运行结果如下:

weimz@mzstudio:~$ g++ -o op_methed2 op_methed2.cpp
weimz@mzstudio:~$ ./op_methed2 
(2+2i)
(6+2i)

可见使用 友元方式重载运算符和同样可以实现相同的目的,并且可以不用修改 int类(int 类本来就无法修改)。

3. 全局函数方式重载

上述以友元函数的方式重载的示例中使用友元来重载加号运算符是因为 Complex 类中的两个成员变量 realimage 是私有成员,其他函数则无法方法,如果将其改为公有成员,则不需要使用友元,这时候则可以使用全局函数方式重载加号运算符。示例代码如下:

// filename: op_method3.cpp
#include <iostream>

using namespace std;

class Complex {
    public:
        Complex(double r=0, double i=0): real(r), image(i){}
        void info(){
            cout << "(" << real << "+" << image << "i)\n";
        }
    public:
    // private:
        double real;
        double image;
};
// 重载加号运算符(Complex + 整数)
Complex operator +(const Complex & left, int right) {
    return Complex ( left.real + right, left.image);
}
// 重载加号运算符(整数 + Complex)
Complex operator +(int left, const Complex & right) {
    return Complex (left + right.real, right.image);
}
int main(int argc, char * argv[]) {
    Complex c1(1, 2);
    Complex c3;
    c3 = c1 + 1;
    c3.info();
    c3 = 5 + c1; // 报错
    c3.info(); 

    return 0;
}

编译和运行结果如下:

weimz@mzstudio:~$ g++ -o op_method3 op_method3.cpp
weimz@mzstudio:~$ ./op_method3 
(2+2i)
(6+2i)

特殊情况:

以下运算符只能使用成员函数的方式进行重载。

=  ()  []  ->

练习

使用上述三种方法重载 减号运算符。