Почему мы должны использовать функцию друга для определения оператора сравнения? - PullRequest
5 голосов
/ 28 февраля 2012

С 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;
    }
};

Мы могли бы также реализовать это так:

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;
    }
};

Есть ли минус в использовании второй реализации?

Ответы [ 4 ]

12 голосов
/ 28 февраля 2012

Предполагая, что вы используете константные ссылки в качестве параметров, первая реализация может использоваться в таких условиях: bool b = 42 > c;, что приведет к ошибке компиляции во второй реализации. Это автоматически создаст объект Cent, используя целое число 42 (поскольку конструктор не определен как explicit), а затем использует функцию friend для сравнения. Смотрите пункт 7 в этом FAQ

0 голосов
/ 28 февраля 2012

Первый определяется как оператор перегрузки члена класса, второй - оператор перегрузки без члена. Когда функция без члена получает доступ к закрытому члену, private: int m_nCents;, friend следует добавить. Даже если я перехожу на public:int m_nCents;, он неработа. friend кажется правилом, а не из-за ограничения доступа членов.Но вы можете переместить оператор Nonmember из тела класса и получить доступ к общедоступной переменной-члену.Есть идея получше? Я чувствую растерянность.Я думаю, что ALL Оператор, не являющийся членом (имеет тот же номер параметра с операндом и не может быть вызван как функция-член), должен быть объявлен как friend в теле класса.

> isбинарный оператор, который имеет два параметра для каждого операнда.Вы обнаружили, что оператор перегрузки члена класса > имеет только один явный параметр и неявный this параметр.Оператор без членов должен иметь два.

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;
 }

}

Я перемещаю реализации из тела класса.Теперь вы можете видеть, что оператор члена класса имеет квалификатор Cents::, как и функция-член.

0 голосов
/ 28 февраля 2012

Нет причин отмечать общедоступный метод с другом.Функции друзей полезны для несвязанных классов, получающих доступ к закрытым или защищенным членам.

Тем не менее, вы можете просто удалить друга из первой реализации, и все будет работать нормально.

0 голосов
/ 28 февраля 2012

Я не вижу большой разницы в большинстве практических примеров в целом .

Я предпочитаю второй вариант, который напрямую связан с class. Более того, следующий синтаксис более уместен:

bool operator> (const Cents& c2) const
{         //    ^^^^^            ^^^^^
  return (this->m_nCents > c2.m_nCents); // simple
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...