Reputation: 2665
I'm learning C++ and I created two simple hello-world applications. In both of them I use operator overload, but here is the problem. On the first one, I can provide two arguments to overload operator, and it's fine.
Header:
enum Element {a,b,c,d,e};
Element operator + (Element x, Element y);
//more overloads for -, *, / here
Source:
Element operator + (Element x, Element y) {
return ArrayOfElements[x][y];
}
But in my second app (simple complex number calculator) - this method didn't work. After googling and figuring out why, I end up with this code:
Header:
struct Complex {
double Re;
double Im;
Complex (double R, double I) : Re(R), Im(I) { }
Complex operator + (Complex &Number);
//more overloads
};
Source:
Complex Complex::operator + (Complex &Number)
{
Complex tmp = Complex(0, 0);
tmp.Re = Re + Number.Re;
tmp.Im = Im + Number.Im;
return tmp;
}
It's working now, but I want to know, why in the first piece of code I was allowed to put two arguments in operator
overloading, but with the second one I was given the following error?
complex.cpp:5:51: error: 'Complex Complex::operator+(Complex, Complex)' must take either zero or one argument
It's the same whenever I use classes or not. I've been seeking through many docs and the second way seem to be more correct. Maybe it's because of different argument types?
Both sources compiled with -Wall -pedantic
parameters using g++
, both are using the same libraries.
Upvotes: 25
Views: 49667
Reputation: 91
e1 + e2 == e1.operator+(e2) this means e1 is a object and operator+ is a member and e2 is as a variable .basicaly oops permits us to do just write e1 + e2 compiler automatically understand as a e1.operator+(e1)
Upvotes: 1
Reputation: 779
If overloaded function is a member function to the class, the we pass only one argument, and there is one hidden parameter (this pointer) that points to other object required to perform binary operation like '+'. this pointer points to one of the operands and calls the overloaded function; while other operand is passed as an argument. Example:
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
When the overloaded function is not a member function (either a free function or a friend function), then we don't have the this pointer provided to the overloaded function. In this case, the compiler expects two arguments to the function which are used as operands.
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
Upvotes: 1
Reputation: 55009
Suppose you have a class like this:
class Element {
public:
Element(int value) : value(value) {}
int getValue() const { return value; }
private:
int value;
};
There are four ways to define a binary operator such as +
.
As a free function with access to only the public
members of the class:
// 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)
As a member function, with access to all members of the class:
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)
As a friend
function, with access to all members of the class:
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)
As a friend
function defined outside the class body—identical in behaviour to #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)
Upvotes: 46
Reputation: 23644
Since + is a binary operator, if you overload it inside a struct/class, you can only provide one more operand, the reason is that the first operand is implicitly the calling object. That is why in the first case, you have two parameters since it is outside scope of your class/struct, while in the second case, it was overloaded as member function.
Upvotes: 7
Reputation: 500585
If you prefer that operator+
takes both operands as explicit arguments, it must be defined as a free (i.e. non-member) function:
class Complex {
friend Complex operator+(const Complex& lhs, const Complex& rhs);
}
Complex operator+(const Complex& lhs, const Complex& rhs) {
...
}
You have to use this form if the left operand is of a primitive type, or of a class that you don't control (and thus can't add a member function to).
Upvotes: 8