26

I feel I have a bit of a hole in my understanding of the friend keyword.

I have a class, presentation. I use it in my code for two variables, present1 and present2, which I compare with ==:

if(present1==present2)

Here's how I defined the operator == (in class presentation):

bool operator==(const presentation& p) const;

However, I was told that using friend and defining it outside of the class is better:

friend bool operator==(presentation&, presentation&);

Why? What's the difference between the two?

Nic
  • 6,211
  • 10
  • 46
  • 69
Nadav
  • 555
  • 3
  • 10
  • 19

5 Answers5

24

Your solution works, but it's less powerful than the friend approach.

When a class declares a function or another class as friend it means that friend function or class have access to the declaring class' privates and protected members. It's as if the declared entity was a member of the declaring class.

If you define operator==() as a member function then just like with the friend case the member function has full access to the class' members. But because it is a member function it specifies a single parameter, as the first parameter is implied to be this: an object of type presentation (or a descendent thereof). If, however, you define the function as a non-member then you can specify both parameters, and this will give you the flexibility of comparing any two types that can cast into a presentation using that same function.

For example:

class presentation {
    friend bool operator==(const presentation&, const presentation&);
    // ...
};

class Foo : public presentation { /* ... */ };
class Bar : public presentation { /* ... */ };

bool operator==(const presentation& p1, const presentation& p2)
{
    // ...
}

bool func(const Foo& f, const Bar& b, const presentation& p)
{
    return f == b || f == p );
}

Lastly, this raises the question "why the friend declaration?". If the operator==() function does not need access to private members of presentation then indeed the best solution is to make it a non-member, non-friend function. In other words, don't give a function access privileges which is doesn't need.

Owen
  • 7,494
  • 10
  • 42
  • 52
wilhelmtell
  • 57,473
  • 20
  • 96
  • 131
  • I think it effectively boils down to a matter of style. If one always makes operator overloads external friend functions (even when it's not necessary), then all the operator overloads will be "together" outside the class. – Emile Cormier Oct 03 '10 at 14:24
  • @Emile: I think it boils down to functionality, as wilhelmtell says. If you implement member `operator==` (and other operators), then when you use it, you get implicit conversion on the rhs, but not the lhs. If you implement it as a non-member function, you get implicit conversion on both. Style is all very well, but there are some operators that cannot be overloaded using non-member functions, so it only takes you so far. – Steve Jessop Oct 03 '10 at 15:33
  • @Steve: Good point. I hadn't considered implicit conversion of the LHS. – Emile Cormier Oct 07 '10 at 15:12
4

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.

Benoit
  • 76,634
  • 23
  • 210
  • 236
  • 2
    Ok, but why would i want it externally declared? does it still externally even though the declaration is listed inside the class as public? and is the first one ok too? – Nadav Oct 03 '10 at 14:14
  • Both work. But in the second case, the function is not part of the class, even if it might be in the same header file. – Benoit Oct 03 '10 at 14:17
2

An operator implemented as a method, can only be called, if the left hand side expression is a variable (or a reference to the object) of the class, the operator is defined for.

In case of an operator== usually you are interested in comparing two objects of the same class. Implementation, as a method solves your problem here.

Imagine however, that you write a string class and you want an operator, to work in this scenario:

const char *s1 = ...
MyString s2 = ...
if(s1 == s2){...

To make the expression s1 == s2 legal, you have to define an opetator== as a function external to MyString class.

bool operator==(const char *, const MyString&);

If the operator needs an access to the private members if your class, it has to be a friend of your class.

In case of operators << and >>, that work on streams, you define an operator, whose left operand is a stream instance and the right one is your class, so they can't be methods of your class. Like in the example above, they have to be functions external to your class and friends, if the access to private members is required.

Maciej Hehl
  • 7,895
  • 1
  • 22
  • 23
1

I like Benoit's answer (but I can't vote it up), but I figure an example wouldn't hurt to clarify it. Here's some Money code I have (assume everything else is placed right):

// header file
friend bool operator ==(const Money, const Money); // are the two equal?

// source file
bool operator ==(const Money a1, const Money a2)
{
    return a1.all_cents == a2.all_cents;
}

Hope that helps.

Wolfman2000
  • 169
  • 1
  • 9
0

Take a look at this sorta duplicate here: should-operator-be-implemented-as-a-friend-or-as-a-member-function

What is important to point out, this linked question is about << and >> which should be implemented as friends since the two operand are different types.

In your case it makes sense to implement it as part of the class. The friend technique is used (and useful) for cases where more than one type is used and often does not apply to == and !=.

Community
  • 1
  • 1
Hogan
  • 69,564
  • 10
  • 76
  • 117