25

我正在学习 C++,并创建了两个简单的 hello-world 应用程序。在他们两个中,我都使用运算符重载,但这是问题所在。在第一个上,我可以为重载运算符提供两个参数,这很好。

标题:

enum Element {a,b,c,d,e};
Element operator + (Element x, Element y);
//more overloads for -, *, / here

来源:

Element operator + (Element x, Element y) {
    return ArrayOfElements[x][y];
}

但是在我的第二个应用程序(简单的复数计算器)中 - 这种方法不起作用。在谷歌搜索并找出原因之后,我最终得到了以下代码:

标题:

struct Complex {
        double Re;
        double Im;

        Complex (double R, double I) : Re(R), Im(I) { }

        Complex operator + (Complex &Number);
        //more overloads
    };

来源:

Complex Complex::operator + (Complex &Number)
    {
        Complex tmp = Complex(0, 0);
        tmp.Re = Re + Number.Re;
        tmp.Im = Im + Number.Im;
        return tmp;
    }

它现在可以工作了,但我想知道,为什么在第一段代码中我被允许在operator重载中放置两个参数,但在第二个代码中我得到了以下错误?

complex.cpp:5:51: error: 'Complex Complex::operator+(Complex, Complex)' must take either zero or one argument

无论我是否使用类,它都是一样的。我一直在寻找许多文档,第二种方式似乎更正确。也许是因为不同的参数类型?

-Wall -pedantic使用参数编译的两个源g++都使用相同的库。

4

5 回答 5

42

假设你有一个这样的类:

class Element {
public:
    Element(int value) : value(value) {}
    int getValue() const { return value; }
private:
    int value;
};

有四种方法可以定义二元运算符,例如+.

  1. 作为一个只能访问public类成员的自由函数:

    // Left operand is 'a'; right is 'b'.
    Element operator+(const Element& a, const Element& b) {
        return Element(a.getValue() + b.getValue());
    }
    

    e1 + e2 == operator+(e1, e2)

  2. 作为成员函数,可以访问类的所有成员:

    class Element {
    public:
        // Left operand is 'this'; right is 'other'.
        Element operator+(const Element& other) const {
            return Element(value + other.value);
        }
        // ...
    };
    

    e1 + e2 == e1.operator+(e2)

  3. 作为一个friend函数,可以访问类的所有成员:

    class Element {
    public:
        // Left operand is 'a'; right is 'b'.
        friend Element operator+(const Element& a, const Element& b) {
            return a.value + b.value;
        }
        // ...
    };
    

    e1 + e2 == operator+(e1, e2)

  4. 作为friend在类体之外定义的函数——与#3 的行为相同:

    class Element {
    public:
        friend Element operator+(const Element&, const Element&);
        // ...
    };
    
    Element operator+(const Element& a, const Element& b) {
        return a.value + b.value;
    }
    

    e1 + e2 == operator+(e1, e2)

于 2013-03-15T20:48:35.173 回答
7

如果您更喜欢operator+将两个操作数都作为显式参数,则必须将其定义为自由(即非成员)函数:

class Complex {
    friend Complex operator+(const Complex& lhs, const Complex& rhs);
}

Complex operator+(const Complex& lhs, const Complex& rhs) {
    ...
}

如果左操作数是原始类型或您无法控制的类(因此无法添加成员函数),您必须使用这种形式。

于 2013-03-15T20:36:39.703 回答
6

由于 + 是二元运算符,如果在结构/类中重载它,则只能再提供一个操作数,原因是第一个操作数隐式为调用对象。这就是为什么在第一种情况下,您有两个参数,因为它超出了类/结构的范围,而在第二种情况下,它被重载为成员函数。

于 2013-03-15T20:40:17.420 回答
1

如果重载函数是类的成员函数,我们只传递一个参数,并且有一个隐藏参数(this指针)指向执行二进制操作所需的其他对象,如“+”。this指针指向操作数之一并调用重载函数;而其他操作数作为参数传递。例子:

class ExampleClass
{
public:
   int x;
   //a this pointer will be passed to this function
   ExampleClass& operator+(const ExampleClass& o){ return x+o.x; }
};



ExampleClass obj1, obj2, obj;
obj = obj1 + obj2; //the overloaded function is called as obj1.operator+(obj2) internally
                  //this pointer is passed to the function

当重载函数不是成员函数(自由函数或友元函数)时,我们没有提供给重载函数的this指针。在这种情况下,编译器需要函数的两个参数用作操作数。

class ExampleClass
{
    public:
       int x;
       //this pointer will not be passed to this function
       friend ExampleClass& operator+(const ExampleClass& o1, const ExampleClass& o2){ return o1.x+o2.x; }
};



obj = obj1 + obj2; //the overloaded function is called as operator+(obj1, obj2) internally
于 2016-06-09T14:55:35.020 回答
1

e1 + e2 == e1.operator+(e2) 这意味着 e1 是一个对象,operator+ 是一个成员,e2 是一个变量。基本 oops 允许我们只编写 e1 + e2 编译器自动理解为 e1.operator+(e1 )

于 2017-09-22T07:02:45.140 回答