I am currently creating a utility class that will have overloaded operators in it. What are the pros and cons of either making them member or non-member (friend
) functions? Or does it matter at all? Maybe there is a best practice for this?
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).
I'd go with "C++ Coding Standards: 101 Rules, Guidelines, and Best Practices": if you can do it as non-member function, do it as non-member function (in the same namespace).
One of the reasons: it works better with implicit type conversion. An Example: You have a complex class with an overloaded operator*. If you want to write 2.0 * aComplexNumber, you need the operator* to be a non-member function.
Another reason: less coupling. Non-member-functions a less closely coupled than member functions. This is almost always a good thing.
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).
If you plan on implementing streaming operators (<< and >>) then they will be non-members methods because your object is on the left of the operator.
If you plan on implementing ->, () or [] they are naturally member methods.
For the others (comparison and mathematical) you should check out Boost.Operators, it really helps.
For example, if you want to implement the following operators:
MyClass& MyClass::operator+=(int);
MyClass operator+(const MyClass&, int);
MyClass operator+(int, const MyClass&);
You only have to write:
class MyClass: boost::operator::addable<MyClass,int> // no need for public there
{
public:
MyClass& operator+=(int);
private:
};
The 2 operator+
will be automatically generated as non-members which will let you benefit from automatic conversions. And they will be implemented efficiently in term of operator+=
so you write code only once.
If you are implementing op, then most probably you need to implement op=. i.e. if you are overloading + operator, then you should implement +=. Make sure that you are returning const to an object if you are doing post-increment or overloading + operator. So, if you overload operator + , then implement it as a non-member operator and use += operator inside it. For eg.
const A operator+(const A& lhs, const A& rhs)
{
A ret(lhs);
ret += rhs;
return ret;
}
const A
? I have seen this a few times (returning a const value) and could never found any practical reason... –
Quinn For binary operators, one limitation of member functions is that the left object must be of your class type. This can limit using the operator symmetrically.
Consider a simple string class:
class str
{
public:
str(const char *);
str(const str &other);
};
If you implement operator+ as a member function, while str("1") + "2"
will compile, "1" + str("2")
will not compile.
But if you implement operator+ as a non-member function, then both of those statements will be legal.
There is nothing like best practices but it depends on the operator you are overloading ..
For e.g .
>> and << can't be overloaded as member functions .
Suppose you want to do like this : obj1 = 2 * obj2 then go for non-member function.
For binary operator overloading member function takes only 1 parameter (invoking object is impcliitly passed ) whereas non-member function takes 2 parameters .
<<
and >>
certainly can be overloaded as member functions, just not if you want to use them as the stream extraction/insertion operators. If you want to use them as shift operators, like Dennis Ritchie intended, no problem. –
Finale © 2022 - 2024 — McMap. All rights reserved.