Should operator be implemented as a friend or as a member function?
The problem here is in your interpretation of the article you link.
Equality
This article is about somebody that is having problems correctly defining the bool relationship operators.
The operator:
- Equality == and !=
- Relationship < > <= >=
These operators should return a bool as they are comparing two objects of the same type. It is usually easiest to define these operators as part of the class. This is because a class is automatically a friend of itself so objects of type Paragraph can examine each other (even each others private members).
There is an argument for making these free standing functions as this lets auto conversion convert both sides if they are not the same type, while member functions only allow the rhs to be auto converted. I find this a paper man argument as you don't really want auto conversion happening in the first place (usually). But if this is something you want (I don't recommend it) then making the comparators free standing can be advantageous.
Streaming
The stream operators:
- operator << output
- operator >> input
When you use these as stream operators (rather than binary shift) the first parameter is a stream. Since you do not have access to the stream object (its not yours to modify) these can not be member operators they have to be external to the class. Thus they must either be friends of the class or have access to a public method that will do the streaming for you.
It is also traditional for these objects to return a reference to a stream object so you can chain stream operations together.
#include <iostream>
class Paragraph
{
public:
explicit Paragraph(std::string const& init)
:m_para(init)
{}
std::string const& to_str() const
{
return m_para;
}
bool operator==(Paragraph const& rhs) const
{
return m_para == rhs.m_para;
}
bool operator!=(Paragraph const& rhs) const
{
// Define != operator in terms of the == operator
return !(this->operator==(rhs));
}
bool operator<(Paragraph const& rhs) const
{
return m_para < rhs.m_para;
}
private:
friend std::ostream & operator<<(std::ostream &os, const Paragraph& p);
std::string m_para;
};
std::ostream & operator<<(std::ostream &os, const Paragraph& p)
{
return os << p.to_str();
}
int main()
{
Paragraph p("Plop");
Paragraph q(p);
std::cout << p << std::endl << (p == q) << std::endl;
}
Why is it recommended to declare functions as friends in operator overloading
There are a few reasons people use friend
:
sometimes granting friendship is actually reasonable, as the public API shouldn't expose some members than need to be compared
it's convenient for a lazy programmer to grant access to all the
private
andprotected
data members, ensuring you can write the operator implementation without needing to go back to grant access later or use a less obvious/direct public function (that's NOT a good reason, just a lazy one)you can define the operator function inside the class, where any template parameters, typedefs, constants etc. don't need to be explicitly qualified as they would in the surrounding [namespace] scope. That's considerably simpler for those new to C++.
e.g.:
template <typename T>
struct X
{
friend bool operator==(const X& lhs, const X& rhs) { ... }
};
...vs...
...struct X as above without ==...
template <typename T>
bool operator==(const X<T>& lhs, const X<T>& rhs) { ... }
- in a two-birds-with-one-stone scoop, it makes the function nominally inline, avoiding One Definition Rule complications
Only the first reason above is a compelling functional reason for making the operator a friend, rather than making it a non-member function, given the lesser encapsulation and correspondingly higher maintenance burden involved.
There are excellent reasons though to prefer either a friend or non-friend non-member function to a member function, as an implicit constructor can then kick in to allow the operator to work with one instance of the class and another value from which a second instance can be constructed:
struct X { X(int); };
bool operator==(const X& lhs, const X& rhs);
x == 3; // ok for member or non-member operator==
3 == x; // only works for non-member operator== after implicit X(3) for lhs
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; }
What operators should be declared as friends?
This really depends on whether a class is going to be on the left- or right-hand side of the call to operator==
(or other operator). If a class is going to be on the right-hand side of the expression—and does not provide an implicit conversion to a type that can be compared with the left-hand side—you need to implement operator==
as a separate function or as a friend
of the class. If the operator needs to access private class data, it must be declared as a friend
.
For example,
class Message {
std::string content;
public:
Message(const std::string& str);
bool operator==(const std::string& rhs) const;
};
allows you to compare a message to a string
Message message("Test");
std::string msg("Test");
if (message == msg) {
// do stuff...
}
but not the other way around
if (msg == message) { // this won't compile
You need to declare a friend operator==
inside the class
class Message {
std::string content;
public:
Message(const std::string& str);
bool operator==(const std::string& rhs) const;
friend bool operator==(const std::string& lhs, const Message& rhs);
};
or declare an implicit conversion operator to the appropriate type
class Message {
std::string content;
public:
Message(const std::string& str);
bool operator==(const std::string& rhs) const;
operator std::string() const;
};
or declare a separate function, which doesn't need to be a friend if it doesn't access private class data
bool operator==(const std::string& lhs, const Message& rhs);
friend in operator == or when should i use it?
In the first case, your function operator==
is a nonstatic class member. It has therefore access to private and protected member variables.
In the second case, the operator is externally declared, therefore it should be defined as a friend of the class to access those member variables.
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).
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 keyword for operator overloading
You want to stream objects whose internals are not accessible through their class' public interface, so the operator can't get at them. Then you have two choices: Either put a public member into the class which does the streaming
class T {
public:
void stream_to(std::ostream& os) const {os << obj.data_;}
private:
int data_;
};
and call that from the operator:
inline std::ostream& operator<<(std::ostream& os, const T& obj)
{
obj.stream_to(os);
return os;
}
or make the operator a friend
class T {
public:
friend std::ostream& operator<<(std::ostream&, const T&);
private:
int data_;
};
so that it can access the class' private parts:
inline std::ostream& operator<<(std::ostream& os, const T& obj)
{
os << obj.data_;
return os;
}
Related Topics
What Is the Meaning of Prepended Double Colon "::"
Is There a Max Array Length Limit in C++
Where Is C Not a Subset of C++
Undefined Reference to Static Constexpr Char[]
Does Initialization Entail Lvalue-To-Rvalue Conversion? Is 'Int X = X;' Ub
Cout ≪≪ Order of Call to Functions It Prints
How to Find the Location of the Executable in C
How to Use Queryperformancecounter
Why Can't the Template Argument Be Deduced When It Is Used as Template Parameter to Another Template
What Are the Errors, Misconceptions or Bad Pieces of Advice Given by Cplusplus.Com
Template Specialization VS Function Overloading
Sequence-Zip Function For C++11
Does C++ Support Variable Length Arrays
Can't Make Value Propagate Through Carry