In some books and often around the internet I see recommendations like "operator== should be declared as friend".
How should I understand when an operator must be declared as friend and when it should be declared as member? What are the operators that will most often need to be declared as friends besides == and <<?
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);
When you have your operators outside the class, both parameters can participate in implicit type conversions (whereas with operators being defined in the class body, only the right-hand operands can). Generally, that's a benefit for all the classic binary operators (i.e. ==,!=, +, -, <<, ... ).
Of course you should only declare operators friends of your class if you need to and not if they compute their result solely based on public members of the class.
Generally, only operators which are implemented as free functions that genuinely need to access to private or protected data of the class that they operate on should be declared as friends, otherwise they should just be non-friend non-member functions.
Generally, the only operators that I implement as member functions are those that are fundamentally asymmetric and where the operands don't have equivalent roles. The ones that I tend to implement as members are those required to be members: simple assignment, (), [] and -> together with compound assignment operators, unary operators and perhaps some overloads of << and >> for classes that are themselves stream or stream-like classes. I never overload &&, || or ,.
All other operators I tend to implement as free functions, preferably using the public interface of the classes which they operate on, falling back to being friends only where necessary.
Keeping operators such as !=, ==, <, +, /, etc as non-member functions enables identical treatment of the left and right operands with respect to implicit conversion sequences which helps to reduce the number of surprising asymmetries.
No one has mentioned hidden friends idiom which I suspect is what the books mean.
Long version: https://www.justsoftwaresolutions.co.uk/cplusplus/hidden-friends.html
Short version:
Operators are found via ADL (argument dependent lookup) most of the time. This is how an operator== defined for std::string in std is found when you are not in namespace std.
One of the problems, common for operators is a gigantic overload set. You can often see this in error messages if you try to use operator<< for something that is not printable.
So - if you declare operator== in the namespace containing the class directly, it will work but it will also participate in all of the overload resolutions in that namespace which is going to slow down your compilation and give you more noise in the errors.
Introducing hidden friends:
struct X {
friend bool operator==(const X& x, const X& y) {...}
};
This operator== will only be considered for overload resolution if one of the operands has type X. In all other cases it will not be seen, so your compilation will be faster and your error messages better.
Same goes for all two operand operators, like operator<< and also other functions intended for ADL, like swap.
I always define my operators like this and it's considered a good practise by quite a few people nowadays.
The only downside is - there is no very good way to define it out of line. You might want to consider dispatching to some private function.
Or you can do this: https://godbolt.org/z/hMarb4 - but it means that at least in one cpp file the operator== will participate in normal lookup.
Related
I want to use my class as key in a map, so I overload operator+. It works well if I overload it as a friend function. When I overload it as a member function inside the class, it causes a compile error.
error C2678: binary '<': no operator found which takes a left-hand operand of type 'const Syl' (or there is no acceptable conversion)'.
In details, this doesn't compile, and generate the compile error:
Syl.h
bool operator< (const Syl& rhs);
Syl.cpp
bool Syl::operator< (const Syl& rhs) { return false; }
While this compiles.
Syl.h
friend bool operator< (const Syl& lhs, const Syl& rhs);
Syl.cpp
bool operator< (const Syl& lhs, const Syl& rhs) { return false; }
I don't know why. I know that operator< is binary, but is there anyway to overload it as function member?
Typically, member operators such as operator< do not modify the object they operate on. If that is the case you need to specify that the method is constant by putting the keyword const at the end of the declaration, i.e.
class Syl {
...
public:
bool operator<(const Syl& rhs) const;
}
An operator like that can be used with STL containers such as std::map.
Your current version of the member operator, when translated into a stand-alone operator would look as:
friend bool operator<(Syl& lhs, const Syl& rhs);
Notice the lack of const for lhs. It is still correct per se, but atypical. You need to provide an l-value as lhs. If you provide something else you get the ``no operator found...'' error. STL std::map does not expect that either, hence your error, probably originating from standard headers, somewhere deep in the template implementation.
Assuming a and b are both of type Syl, your first (member form) is not valid in an expression a < b if a is const, and will result in a compilation error.
To fix that, you need to specify the member operator<() as
bool operator< (const Syl& rhs) const; // note the trailing const
Without that trailing const, in an expression a < b, a cannot be const (i.e. the operator<() is permitted to change it).
Your second form is correct, since it specifies that both operands are const references.
Comparison operators like < don't generally change EITHER of their operands. The const qualifiers communicate that fact.
Bear in mind that you can provide the member form OR the non-member form. Providing both will cause an error due to ambiguity (the compiler has no basis to prefer one over the other, when it sees an expression like a < b).
Why it is not allowed to overload "=" using friend function?
I have written a small program but it is giving error.
class comp
{
int real;
int imaginary;
public:
comp(){real=0; imaginary=0;}
void show(){cout << "Real="<<real<<" Imaginary="<<imaginary<<endl;}
void set(int i,int j){real=i;imaginary=j;}
friend comp operator=(comp &op1,const comp &op2);
};
comp operator=(comp &op1,const comp &op2)
{
op1.imaginary=op2.imaginary;
op1.real=op2.real;
return op1;
}
int main()
{
comp a,b;
a.set(10,20);
b=a;
b.show();
return 0;
}
The compilation gives the following error :-
[root#dogmatix stackoverflow]# g++ prog4.cpp
prog4.cpp:11: error: ‘comp operator=(comp&, const comp&)’ must be a nonstatic member function
prog4.cpp:14: error: ‘comp operator=(comp&, const comp&)’ must be a nonstatic member function
prog4.cpp: In function ‘int main()’:
prog4.cpp:25: error: ambiguous overload for ‘operator=’ in ‘b = a’
prog4.cpp:4: note: candidates are: comp& comp::operator=(const comp&)
prog4.cpp:14: note: comp operator=(comp&, const comp&)
Because if you do not declare it as a class member compiler will make one up for you and it will introduce ambiguity.
The assignment operator is explicitly required to be a class member operator. That is a sufficient reason for the compiler to fail to compile your code. Assignment is one of the special member functions defined in the standard (like the copy constructor) that will be generated by the compiler if you do not provide your own.
Unlike other operations that can be understood as external to the left hand side operator, the assignment is an operation that is semantically bound to the left hand side: modify this instance to be equal to the right hand side instance (by some definition of equal), so it makes sense to have it as an operation of the class and not an external operation. On the other hand, other operators as addition are not bound to a particular instance: is a+b an operation of a or b or none of them? -- a and b are used in the operation, but the operation acts on the result value that is returned.
That approach is actually recommended and used: define operator+= (that applies to the instance) as a member function, and then implement operator+ as a free function that operates on the result:
struct example {
example& operator+=( const example& rhs );
};
example operator+( const example& lhs, const example& rhs ) {
example ret( lhs );
ret += rhs;
return ret;
}
// usually implemented as:
// example operator+( example lhs, const example& rhs ) {
// return lhs += rhs; // note that lhs is actually a copy, not the real lhs
//}
Assignment(=) operator is a special operator that will be provided by the constructor to the class when programmer has not provided(overloaded) as member of the class.(like copy constructor).
When programmer is overloading = operator using friend function, two = operations will exists:
1) compiler is providing = operator
2) programmer is providing(overloading) = operator by friend function.
Then simply ambiguity will be created and compiler will gives error. Its compilation error.
There is no good reason for that, I think Stepanov proposed that there should be a free operator= and many good stuff can be done with that (even more than what can be done with the move assignment). I can't find the citation but Stepanov went as a far as to suggest that the constructors could be free functions http://www.stlport.org/resources/StepanovUSA.html.
There is a way around it, which is to systematically declare a template<class Other> A& operator=(Other const& t); in inside all your classes, in this way you leave the option to anyone to define a custom assignment operator.
Of course you can't do this with a class you don't have control over.
Having said that it is nowadays not that bad since we have move assignment. And in some sense conversion operators B::operator A() const{...} are almost like a custom copy assignment. Conversion operators are now usable because of explicit. However you have to have control over the second type (B), the right-hand type in assignment.
Next question is why conversion operator need to be members them selves? Again, I don't think there is a good reason.
Hi I have a code like this, I think both the friend overloaded operator and conversion operator have the similar function. However, why does the friend overloaded operator is called in this case? What's the rules?
Thanks so much!
class A{
double i;
public:
A(int i):i(i) {}
operator double () const { cout<<"conversion operator"<<endl;return i;} // a conversion operator
friend bool operator>(int i, A a); // a friend funcion of operator >
};
bool operator>(int i, A a ){
cout<<"Friend"<<endl;
return i>a.i;
}
int main()
{
A aa(1);
if (0 > aa){
return 1;
}
}
No conversion is necessary for the overloaded operator> to be called. In order for the built-in operator> to be called, one conversion is necessary (the user-defined conversion operator. Overload resolution prefers options with fewer required conversions, so the overloaded operator> is used.
Note that if you were to change the definition of your overloaded operator> to be, for example:
friend bool operator>(double i, A a);
you would get a compilation error because both the overloaded operator> and the built-in operator> would require one conversion, and the compiler would not be able to resolve the ambiguity.
I am not claiming that my answer is supported by the standards, but lets think about it logically.
When you hit this line:
0 > aa
You have two options. Either you call the provided operator:
friend bool operator>(int i, A a);
Which is 100% compatible, or you can do two conversions to reach your destination! Which one would you choose?
If you add a conversion operator then an object of type A may be converted to double when you least expect it.
A good program does not provide a way for his classes to be accidently used and the conversion operator opens up the opertunity for the class to be used in a whole host of unintended situations (normally situations where you would expect a compile time error are not because of the auto type conversion).
As a result conversion operators (and single argument constructors) should be treateed with some care because of situations were the compiler may do conversion when you least expect it.
It is called because it is an exact match in the context of the expression 0 > aa. In fact, it is hard to figure out how you came up with the "why" question. By logic, one'd expect a "why" question if the friend weren't called in this case.
If you change the expression to 0.0 > aa, the call will beciome ambiguous, because neuther path will be better than the other.
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?
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.
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.
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;
}
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 .
I wrote an abstraction class for a math object, and defined all of the operators. While using it, I came across:
Fixed f1 = 5.0f - f3;
I have only two subtraction operators defined:
inline const Fixed operator - () const;
inline const Fixed operator - (float f) const;
I get what is wrong here - addition is swappable (1 + 2 == 2 + 1) while subtraction is not (same goes for multiplication and division).
I immediately wrote a function outside my class like this:
static inline const Fixed operator - (float f, const Fixed &fp);
But then I realized this cannot be done, because to do that I would have to touch the class's privates, which results to using the keyword friend which I loath, as well as polluting the namespace with a 'static' unnecessary function.
Moving the function inside the class definition yields this error in gcc-4.3:
error: ‘static const Fixed Fixed::operator-(float, const Fixed&)’ must be either a non-static member function or a non-member function
Doing as GCC suggested, and making it a non-static function results the following error:
error: ‘const Fixed Fixed::operator-(float, const Fixed&)’ must take either zero or one argument
Why can't I define the same operator inside the class definition? if there's no way to do it, is there anyway else not using the friend keyword?
Same question goes for division, as it suffers from the same problem.
If you need reassuring that friend functions can be OK:
http://www.gotw.ca/gotw/084.htm
Which operations need access to
internal data we would otherwise have
to grant via friendship? These should
normally be members. (There are some
rare exceptions such as operations
needing conversions on their left-hand
arguments and some like operator<<()
whose signatures don't allow the *this
reference to be their first
parameters; even these can normally be
nonfriends implemented in terms of
(possibly virtual) members, but
sometimes doing that is merely an
exercise in contortionism and they're
best and naturally expressed as
friends.)
You are in the "operations needing conversions on the left-hand arguments" camp. If you don't want a friend, and assuming you have a non-explicit float constructor for Fixed, you can implement it as:
static inline Fixed operator-(const Fixed &lhs, const Fixed &rhs) {
return lhs.minus(rhs);
}
then implement minus as a public member function, that most users won't bother with because they prefer the operator.
I assume if you have operator-(float) then you have operator+(float), so if you don't have the conversion operator, you could go with:
static inline Fixed operator-(float lhs, const Fixed &rhs) {
return (-rhs) + lhs;
// return (-rhs) -(-lhs); if no operator+...
}
Or just Fixed(lhs) - rhs if you have an explicit float constructor. Those may or may not be as efficient as your friend implementation.
Unfortunately the language is not going to bend over backwards to accommodate those who happen to loathe one of its keywords, so operators can't be static member functions and get the effects of friendship that way ;-p
"That's what friends are for..."
You could add an implicit conversion between float and your type (e.g. with a constructor accepting float)... but I do think using a friend is better.
When you define something like this,
inline const Fixed operator - (float f) const;
you are saying that I want this operator(you are inside the class) to operate on a specific type, float here for example.
Whereas a friend binary operator, means an operation between two types.
class Fixed
{
inline friend const Fixed operator-(const Fixed& first, const float& second);
};
inline const Fixed operator-(const Fixed& first, const float& second)
{
// Your definition here.
}
with friend operators you can have your class on either side of the operator it self.
In general, free function operators for arithmetic operations are better than implementing member functions. The main reason is the problem you are facing now. The compiler will treat the left and right sides differently. Note that while strict OO followers will consider only those methods inside the class curly braces part of its interface, but it has been argued by experts that not to be the case in C++.
If the free function operator requires access to private members, make the operator friend. After all if it is provided in the same header file (following Sutter's rationale above) then it is part of the class.
If you really want to avoid it and don't mind making your code less idiomatic (and thus less maintainable) you can provide a public method that does the real work and dispatch to that method from the operator.
class Fixed {
private:
Fixed();
Fixed( double d ); // implicit conversion to Fixed from double
Fixed substract( Fixed const & rhs ) const;
// ...
};
Fixed operator-( Fixed const & lhs, Fixed const & rhs )
{
return lhs.substract( rhs );
}
In the code above, you can substract Fixed - Fixed, Fixed - double, double - Fixed. The compiler will find the free function and implicitly convert (in the example through the double constructor) the doubles into Fixed objects.
While this is unidiomatic for arithmetic operators, it is close to the idiomatic way of proving a polymorphic dump operator. So while not being the most natural solution it won't be the most surprising code around either
// idiomatic polymorphic dump operator
class Base {
public:
virtual std::ostream& dump( std::ostream & ) const;
};
std::ostream& operator<<( std::ostream& o, Base const & d )
{
return d.dump( o );
}