【问题标题】:friend in operator == or << when should i use it?运算符中的朋友 == 或 << 我应该什么时候使用它?
【发布时间】:2011-04-20 11:41:44
【问题描述】:

我觉得我对 friend 关键字的理解有点坑。

我有一堂课,presentation。我在代码中将它用于两个变量 present1present2,我将它们与 == 进行比较:

if(present1==present2)

这是我如何定义运算符 ==(在 class presentation 中):

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

但是,有人告诉我,使用 friend 并在课堂之外定义它会更好:

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

为什么?两者有什么区别?

【问题讨论】:

  • -1 不完整且机器人可以理解
  • 对我来说这是完全可以理解的。 operator== 应该是类外的友元函数,还是类内定义的?
  • 机器人能理解这个问题吗? >_>
  • 我认为不完整是指他对为什么得到-1的解释。
  • @Nadav 我澄清了你的问题,我想——你能检查一下并确保我做对了吗? (此外,如果您选择的答案不能回答您的问题,您需要不接受它。)

标签: c++ operator-overloading friend


【解决方案1】:

在第一种情况下,您的函数operator== 是一个非静态类成员。因此它可以访问私有和受保护的成员变量。

在第二种情况下,操作符是外部声明的,因此它应该被定义为类的友元来访问那些成员变量。

【讨论】:

  • 好的,但我为什么要在外部声明它?即使声明在类中列为公共,它仍然在外部吗?第一个也可以吗?
  • 两者都有效。但在第二种情况下,函数不是类的一部分,即使它可能在同一个头文件中。
【解决方案2】:

我喜欢 Benoit 的回答(但我不能投票),但我认为举个例子来澄清它不会有什么坏处。这是我拥有的一些 Money 代码(假设其他所有内容都正确放置):

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

希望对您有所帮助。

【讨论】:

    【解决方案3】:

    您的解决方案有效,但不如friend 方法强大。

    当一个类将一个函数或另一个类声明为friend 时,这意味着友元函数或类可以访问声明类的私有成员和受保护成员。就好像声明的实体是声明类的成员一样。

    如果您将operator==() 定义为成员函数,那么就像friend 的情况一样,成员函数可以完全访问类的成员。但是因为它是一个成员函数,所以它指定了一个参数,因为第一个参数暗示为thispresentation 类型的对象(或其后代)。但是,如果您将函数定义为非成员,那么您可以指定两个参数,这将使您可以灵活地比较任何两种可以使用同一函数转换为 presentation 的类型。

    例如:

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

    最后,这引出了一个问题“为什么要声明friend?”。如果operator==() 函数不需要访问presentation 的私有成员,那么确实最好的解决方案是使其成为非成员、非朋友函数。换句话说,不要给不需要的函数访问权限。

    【讨论】:

    • 我认为这实际上归结为风格问题。如果总是让运算符重载外部友元函数(即使没有必要),那么所有运算符重载都将在类之外“一起”。
    • @Emile:我认为它归结为功能,正如 wilhelmtell 所说。如果您实现成员 operator==(和其他运算符),那么当您使用它时,您会在 rhs 上获得隐式转换,而不是在 lhs 上。如果将其实现为非成员函数,则两者都会进行隐式转换。样式都很好,但是有些运算符不能用非成员函数重载,所以只带你到这里。
    • @Steve:说得好。我没有考虑过 LHS 的隐式转换。
    【解决方案4】:

    在此处查看此排序副本:should-operator-be-implemented-as-a-friend-or-as-a-member-function

    需要指出的是,这个链接的问题是关于 &lt;&lt;&gt;&gt; 应该作为朋友实现,因为这两个操作数是不同的类型。

    在您的情况下,将其作为类的一部分来实现是有意义的。友元技术用于(并且很有用)使用多种类型的情况,并且通常不适用于==!=

    【讨论】:

      【解决方案5】:

      作为方法实现的运算符,只能被调用,如果左侧表达式是类的变量(或对象的引用),则定义该运算符。

      如果是operator==,通常您有兴趣比较同一类的两个对象。实施,作为一种方法可以解决您的问题。

      但是,想象一下,您编写了一个字符串类并希望有一个运算符在这种情况下工作:

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

      要使表达式s1 == s2 合法,您必须将opetator== 定义为MyString 类的外部函数。

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

      如果操作员需要访问您的班级的私有成员,则它必须是您班级的朋友。

      如果操作符&lt;&lt;&gt;&gt; 在流上工作,您定义一个操作符,其左操作数是流实例,右操作数是您的类,因此它们不能是您的类的方法.就像上面的例子一样,如果需要访问私有成员,它们必须是你的班级和朋友之外的函数。

      【讨论】:

        猜你喜欢
        • 2011-10-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-01-19
        • 2014-07-15
        • 2011-01-18
        • 2011-08-18
        • 2017-03-21
        相关资源
        最近更新 更多