Количество аргументов в перегрузке оператора в С++ - программирование
Подтвердить что ты не робот

Количество аргументов в перегрузке оператора в С++

Я изучаю С++, и я создал два простых приложения 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];
}

Но в моем втором приложении (простой калькулятор сложных чисел) - этот метод не работал. После googling и выяснения причин, я в конечном итоге с этим кодом:

Заголовок:

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++, оба используют одни и те же библиотеки.

4b9b3361

Ответ 1

Предположим, что у вас есть такой класс:

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

Существует четыре способа определения двоичного оператора, такого как +.

  • Как бесплатная функция с доступом только к членам 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)

  • Как функция-член, с доступом ко всем членам класса:

    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)

  • Как функция 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)

  • Как функция 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)

Ответ 2

Так как + - двоичный оператор, если вы перегружаете его внутри struct/class, вы можете предоставить только один операнд, причина в том, что первый операнд неявно является вызывающим объектом. Вот почему в первом случае у вас есть два параметра, так как он выходит за рамки вашего класса/структуры, а во втором случае он был перегружен как функция-член.

Ответ 3

Если вы предпочитаете, чтобы operator+ принимал оба операнда как явные аргументы, он должен быть определен как свободная (то есть нечлена) функция:

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

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

Вы должны использовать эту форму, если левый операнд имеет примитивный тип или класс, который вы не контролируете (и, следовательно, не можете добавить функцию-член).

Ответ 4

Если перегруженная функция является функцией-членом класса, мы передаем только один аргумент, и есть один скрытый параметр (этот указатель), который указывает на другой объект, необходимый для выполнения двоичной операции, такой как "+". этот указатель указывает на один из операндов и вызывает перегруженную функцию; в то время как другой операнд передается в качестве аргумента. Пример:

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

Когда перегруженная функция не является функцией-членом (либо свободной функцией, либо функцией друга), мы не предоставляем этот указатель для перегруженной функции. В этом случае компилятор ожидает два аргумента функции, которые используются в качестве операндов.

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

Ответ 5

e1 + e2 == e1.operator + (e2) это означает, что e1 - объект, а оператор + - член, а e2 - как переменная. basicaly oops позволяет нам просто написать e1 + e2 компилятор, автоматически понимающий как e1. оператор + (е1)