Overload Operators as Member Function or Non-Member (Friend) Function

Overload operators as member function or non-member (friend) function?

Each operator has its own considerations. For example, the << operator (when used for stream output, not bit shifting) gets an ostream as its first parameter, so it can't be a member of your class. If you're implementing the addition operator, you'll probably want to benefit from automatic type conversions on both sides, therefore you'll go with a non-member as well, etc...

As for allowing specialization through inheritance, a common pattern is to implement a non-member operator in terms of a virtual member function (e.g. operator<< calls a virtual function print() on the object being passed).

How to use both member function and friend function operator overloading in same class

Most operators can be overloaded either as member or nonmember function. Some operators (= [] () ->) can be overloaded only as members. But you cannot have any oeprator both as a member and nonmember, specifically because it is unclear how to pick either one of them.

What the assignment wants is probably:

  • you overload prefix ++ as a member and the postfix ++ as a nonmember (in your case, also friend)
  • create two separate programs: in one, those operators are overloaded as members, in another - as nonmembers

operator overloading and non-member functions c++

Here is the addition operator outside of the class:

Complex operator+(const Complex& lhs, const Complex& rhs) {
//implement the math to add the two
return Complex(lhs.aGetValue() + rhs.aGetValue(),
lhs.bGetValue() + rhs.bGetValue());
}

Of course you will need to declare aGetValue() and bGetValue() as const:

double aGetValue() const {return a;}
double bGetValue() const {return b;}

Operator overloading : member function vs. non-member function?

If you define your operator overloaded function as member function, then the compiler translates expressions like s1 + s2 into s1.operator+(s2). That means, the operator overloaded member function gets invoked on the first operand. That is how member functions work!

But what if the first operand is not a class? There's a major problem if we want to overload an operator where the first operand is not a class type, rather say double. So you cannot write like this 10.0 + s2. However, you can write operator overloaded member function for expressions like s1 + 10.0.

To solve this ordering problem, we define operator overloaded function as friend IF it needs to access private members. Make it friend ONLY when it needs to access private members. Otherwise simply make it non-friend non-member function to improve encapsulation!

class Sample
{
public:
Sample operator + (const Sample& op2); //works with s1 + s2
Sample operator + (double op2); //works with s1 + 10.0

//Make it `friend` only when it needs to access private members.
//Otherwise simply make it **non-friend non-member** function.
friend Sample operator + (double op1, const Sample& op2); //works with 10.0 + s2
}

Read these :

A slight problem of ordering in operands

How Non-Member Functions Improve Encapsulation

friend vs member functions in Operator Overloading C++

The choice isn't "member or friend" but "member or non-member".

(Friendship is frequently overused, and usually taught much too early in schools.)

This is because you can always add a public member function that a free function can call.

For instance:

class A
{
public:
explicit A(int y) : x(y) {}
A plus(const A& y) const { return A{x + y.x}; }
private:
int x;
};

A operator+(const A& lhs, const A& rhs) { return lhs.plus(rhs); }

As for how to choose: if the operator doesn't take an instance of the class as its left-hand operand, it must be a free function, otherwise it's pretty much a matter of personal taste (or coding standards if you're not alone).

Example:

// Can't be a member because the int is on the left.
A operator+ (int x, const A& a) { return A{x} + a; }

For operators that have a corresponding mutating operator (like + and +=), it's common to do the mutating operator as a member and the other as a non-member:

class B
{
public:
explicit B(int y) : x(y) {}
B& operator+= (const B& y) { x += y.x; return *this; }
private:
int x;
};

B operator+(B lhs, const B& rhs) { return lhs += rhs; }

but you can spell this out too, of course:

class C
{
public:
explicit C(int y) : x(y) {}
C& add(const C& y) { x += y.x; return *this; }
private:
int x;
};

C& operator+=(C& lhs, const C& rhs) { return lhs.add(rhs); }
C operator+(C lhs, const C& rhs) { return lhs += rhs; }

Operator overload: Member vs. non-member when only same type objects can be involved

Because operator== has symmetric semantics for its LHS and RHS argument, the recommended approach is to always implement it as a non-member in terms of the public interface of its operands (or if private data is required, to declare it as a friend inside the class).

So

class Bla
{
public:
// complete interface to data required for comparison
auto first();
auto second();
// ... more
private:
// data goes here
};

bool operator==(Bla const& L, Bla const& R)
{
return
std::forward_as_tuple(L.first(), L.second() /*, ... */) ==
std::forward_as_tuple(R.first(), R.second() /*, ... */)
;
}

This way, implicit conversion to Bla are considered for both the L and R arguments (I'm not saying implicit conversions are a good idea, but if you have those, it's better to avoid surprises where they are only considered for the RHS argument).



Related Topics



Leave a reply



Submit