Why should we use a friend function to define the comparison operator?
Asked Answered
T

4

10

From http://www.learncpp.com/cpp-tutorial/142-function-template-instances/

class Cents
{
private:
    int m_nCents;
public:
    Cents(int nCents)
        : m_nCents(nCents)
    {
    }

    friend bool operator>(Cents &c1, Cents&c2)  // <--- why friend?
    {
        return (c1.m_nCents > c2.m_nCents) ? true: false;
    }
};

We could have also implemented it like this:

class Cents
{
private:
    int m_nCents;
public:
    Cents(int nCents)
        : m_nCents(nCents)
    {
    }

    bool operator> (Cents& c2)  // <---
    {
        return (this->m_nCents > c2.m_nCents) ? true: false;
    }
};

Is there any downside of using the second implementation?

Tertius answered 28/2, 2012 at 5:42 Comment(4)
Don't forget const correctness.Centigrade
Explained well in the C++-faqCentigrade
If you must use ? true : false on boolean expressions, then remember that the result is also a boolean expression, so you should write ((c1.m_nCents > c2.m_nCents) ? true : false) ? true : false).Methuselah
@MikeSeymour I believe you mean (((c1.m_nCents > c2.m_nCents) ? true : false) ? true : false) ? false == false : true != true. Don't want those boolean expressions getting away from you.Atlante
O
14

Assuming you are using const references as the parameters, the first implementation can be used in conditions like this: bool b = 42 > c; which will provide a compiler error in the second implementation. This will automatically creates a Cent object using the integer 42 (since constructor is not defined as explicit) and then use the friend function for comparison. See point 7 in this FAQ

Oberhausen answered 28/2, 2012 at 5:49 Comment(0)
E
0

The first is defined as Class Member overload operator , the second is a Nonmember overload operator .When Nonmember function accesses the private member private: int m_nCents;, friend should be added.Even I change to public:int m_nCents;,it does not work.friend seems to be a rule, not because of member access limitation. But you can move the Nonmember operator out of class body and access public member variable. Any better idea?I feel confused. I think that ALL Nonmember operator(have same parameter number with operand and can not be called as a member function ) must be declared as friend in class body.

> is a binary operator which have two parameter for each operand. You have found that the Class Member overload operator > only have one explicit parameter and an implicit this parameter. Nonmember operator must have two.

class Cents{
  private:
     int m_nCents;
  public:
  Cents(int nCents)
     : m_nCents(nCents)
   {
   }

   friend bool operator>(Cents &c1, Cents&c2); //Nomember 

   bool operator<(Cents &c1); //class member
};

bool operator>(Cents &c1, Cents&c2)  // <--- why friend?
{
   //cout << "in >"  << endl;
   return (c1.m_nCents > c2.m_nCents) ? true: false;
}

bool Cents::operator<(Cents &c1)
{
    //cout << "in <"  << endl;
    return (this->m_nCents < c1.m_nCents) ? true: false;
}

int main(){
 //nomember
 //if(poor.operator>(rich))  //compiler error 
 if(poor > rich){
     cout << "oh yeal!" << endl;
 }
 else
 {
     cout << "oh no!" << endl;
 }

 //member
 //if(poor.operator<(rich)) //can call this way
 if(poor.operator<(rich)){
     cout << "oh yeal!" << endl;
 }
 else
 {
     cout << "oh no!" << endl;
 }

}

I move implementations out of class body. Now you can see class member operator has a Cents:: qualifier just like member function.

Evelyne answered 28/2, 2012 at 6:15 Comment(0)
G
-1

I don't see much difference in most of the practical examples in general.

I prefer the 2nd option, which gets associated with the class directly. Moreover, following syntax is more appropriate:

bool operator> (const Cents& c2) const
{         //    ^^^^^            ^^^^^
  return (this->m_nCents > c2.m_nCents); // simple
}
Gink answered 28/2, 2012 at 5:51 Comment(1)
The difference is that a non-member allows type conversions on both arguments, while a member only allows them on the second.Methuselah
M
-2

There's no reason to tag a public method with friend. Friend functions are useful for unrelated classes accessing private or protected members.

That said, you could just drop friend from the first implementation and it'll work fine.

Miyokomizar answered 28/2, 2012 at 5:55 Comment(2)
Its tagged friend because it is a free function not a public method.Centigrade
If you drop friend, you have a compiler error, cause you cannot change an operator arity (the number of arguments it takes) when you overload it.Remarkable

© 2022 - 2024 — McMap. All rights reserved.