Количество аргументов в перегрузке оператора в С++
Я изучаю С++, и я создал два простых приложения 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++
, оба используют одни и те же библиотеки.
Ответы
Ответ 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)