friend my_int operator+(const my_int& num1, const my_int& num2);
means 'declare a free function which takes 2 parameters. Make it a friend so it can see my private members'
my_int my_int::operator+(const my_int& num1, const my_int& num2) {
means 'define the (illegal) member function operator+ which takes total 3 arguments.
EDIT: by request, adding some more info.
There are a number of "correct" ways to implement operators on your classes. The 'best practice' way is to implement all binary operators as free functions (operator+ as a free function is declared with 2 parameters). Operator+ should be implemented where possible in terms of operator+= (a unary operator, therefore define it in the class). It's best practice because it allows you to write overloads of operator+ that take different objects as arguments. For example:
struct X {
explicit X(int val) : _val (val) {}
// getter
int value() const { return _val; }
// this helper += operator eases our journey later on
X& operator+=(int delta) {
_val += delta;
return *this;
}
X& operator+=(const X& r) {
_value += r.value();
return *this;
}
private:
int _val;
}
// implements X + X
X operator+(X l, const X& r)
{
return l += r;
}
// implements X + int
X operator+(X l, int r)
{
return l += r;
}
// implement int + X (returns an X)
X operator+(int l, X r) {
return r += l;
return r;
}
// later, someone else defines a Y and wants it to be addable with X, returning a Z
struct Y {
vector<int> get_numbers() const;
}
struct Z {
Z(vector<int> v);
}
// implement Z = X + Y;
Z operator+(const X& l, const Y& r) {
auto v = r.get_numbers(); // vector<int> instead of auto for c++03
v.push_back(l.value());
return Z { std::move(v) }; // c++11
// return Z(v); // c++03
}
// also implement Z = Y + X
Z operator+(const Y&l , const X&r) {
auto v = l.get_numbers();
v.push_back(r.value());
return Z { std::move(v) };
}
Note that it's possible to declare the free-function forms of binary operators as friends:
struct X {
// this is a free function - not a class memeber, but it can see X::_value
friend X operator+(X, const X&);
private:
int _value;
};
// implementation
X operator+(X l, const X& r) {
l._value += r._value;
return l;
}
but I would argue that this style is less preferable to writing truly unbound free binary operators that are implemented in terms of unary operators (above).
It's also possible to implement binary operators as member functions - in which case they are declared and defined with one parameter (the other being implied as this
):
struct X {
X operator+(X r);
private:
int _value;
};
X X::operator+(const X& r) {
// l is implied as *this
return X { _value + r._value };
}
but this is a mistake because while it allows the overload of (X + int), it does not allow overloading (int + X), for which you'd need a free function anyway.