【问题标题】:Why should we use a friend function to define the comparison operator?为什么要使用友元函数来定义比较运算符?
【发布时间】:2012-02-28 05:42:21
【问题描述】:

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

使用第二种实现有什么缺点吗?

【问题讨论】:

  • 不要忘记 const 的正确性。
  • C++-faq中解释得很好
  • 如果你必须在布尔表达式上使用? true : false,那么记住结果也是一个布尔表达式,所以你应该写((c1.m_nCents &gt; c2.m_nCents) ? true : false) ? true : false)
  • @MikeSeymour 我相信你的意思是(((c1.m_nCents &gt; c2.m_nCents) ? true : false) ? true : false) ? false == false : true != true。不要让那些布尔表达式远离你。

标签: c++ friend-function


【解决方案1】:

假设您使用 const 引用作为参数,第一个实现可以在这样的条件下使用:bool b = 42 &gt; c; 这将在第二个实现中提供编译器错误。这将使用整数42 自动创建Cent 对象(因为构造函数未定义为explicit),然后使用friend 函数进行比较。请参阅FAQ中的第 7 点

【讨论】:

    【解决方案2】:

    第一个定义为Class Member重载运算符,第二个是Nonmember重载运算符。当Nonmember函数访问私有成员时 private: int m_nCents;friend应该加。即使我改成public:int m_nCents;,它也不起作用。friend似乎是一个规则,不是因为会员访问限制。但是您可以将非成员运算符移出类主体并访问公共成员变量。有更好的主意吗?我感到困惑。我认为 ALL 非成员运算符(具有与操作数相同的参数号,不能作为成员函数调用)必须在类体中声明为friend

    &gt; 是一个二元运算符,每个操作数有两个参数。您发现类成员重载运算符&gt; 只有一个 显式参数和一个隐式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:: 限定符,就像成员函数一样。

    【讨论】:

      【解决方案3】:

      我认为大多数实际示例一般没有太大区别。

      我更喜欢第二个选项,它直接与class 关联。此外,以下语法更合适:

      bool operator> (const Cents& c2) const
      {         //    ^^^^^            ^^^^^
        return (this->m_nCents > c2.m_nCents); // simple
      }
      

      【讨论】:

      • 不同之处在于非成员允许在两个参数上进行类型转换,而成员只允许在第二个参数上进行类型转换。
      【解决方案4】:

      没有理由用朋友标记公共方法。 Friend 函数对于访问私有或受保护成员的无关类很有用。

      也就是说,您可以从第一个实现中删除朋友,它会正常工作。

      【讨论】:

      • 它的 tagged 朋友,因为它是免费函数而不是公共方法。
      • 如果你放弃朋友,你有一个编译器错误,因为当你重载它时你不能改变一个运算符的数量(它需要的参数的数量)。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-07-20
      • 1970-01-01
      • 1970-01-01
      • 2017-07-26
      • 2018-09-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多