30

不应该在类之外显式定义友元函数吗?
如果是这样,为什么我可以像任何成员函数一样在类定义中声明友元函数?
这是什么 ?
是否只适用于某些运算符,例如<运算符,还是适用于所有运算符?
如果它适用于所有这些,这样做有什么缺点吗?
应该避免吗?如果是,为什么?

class person 
{
public:
    bool operator<(int num)
    {
        return  x < num ? true : false ;
    }
    bool operator<(person& p)
    {
        return  x < p.x ? true : false ;
    }

    friend bool operator<(int num, person &p)
    {
        return  p.x < num ? true : false ;
    }

    void setX(int num)
    {
        x = num;
    }

private:
    int x;


};

更新
我不是要求选择非成员运算符重载或成员运算符重载。
我想知道的是:
为什么允许我们在类定义中移动友元方法的定义?.
不违反什么吗?如果不是,为什么我们首先会有朋友?
我们可以简单地将重载定义为成员函数(我知道成员函数的局限性)但我是说知道这一点,为什么编译器不抱怨我没有在类定义之外定义友元函数,因为它不需要在它里面(因为它有类参数) 那么为什么我们可以在类定义中定义一个友元函数呢?

4

5 回答 5

12

不应该在类之外显式定义友元函数吗?

友函数可以在类声明中定义(给定一个函数体)。这些函数是内联函数,就像成员内联函数一样,它们的行为就像是在看到所有类成员之后但在类范围关闭之前(类声明的结尾)立即定义的。在类声明中定义的友元函数在封闭类的范围内。 引用

仅适用于某些运算符(例如 < 运算符)还是适用于所有运算符?

最好尽量避免使用友元函数,因为它们与您尝试使用私有类范围所做的相反,主要是“隐藏”变量。如果您的所有函数都是友元函数,那么拥有私有变量有什么用?

尽管如此,还是有一些常见的运算符通常被声明为友元函数,它们是operator<<operator>>

于 2013-07-07T13:44:16.387 回答
4

因为操作员需要知道所使用的表达式右侧的详细信息,所以如果它必须访问位于该侧的类型的私有数据,则它需要friend使用该类。

如果您尝试将 aint与 a进行比较person,例如在您的示例中,则选择有两个:

  • 您提供从personto的隐式转换,int以便<可以在不访问任何私有字段的情况下使用它。
  • 或者您声明运算符 as friendofperson以便它可以x在比较的右侧访问。
于 2013-07-07T13:28:42.833 回答
4

如果您正在创建一个仅包含标头的类(这使得部署变得非常容易),那么在该类中定义一个友元函数是唯一的方法,因为定义只能出现在单个翻译单元中。包含守卫的正常技术不起作用,因为它只处理诸如递归包含之类的事情。

如果您尝试编写符合标准的代码,这可能是一件大事。例如,要实现 C++ 规范标准中的RandomNumberEngine命名要求,需要提供operator<<. 这必须是friend一个std::ostream&对象作为它的第一个参数(否则它看起来像一个普通的单参数成员函数运算符重载)。通常,friend声明将放在类定义中,而函数定义则放在单独的.cpp源文件中。但是如果你想要一个只有头文件的实现,它必须在类中定义以避免多个定义错误。

于 2019-10-24T19:23:40.643 回答
2

正如杰克所说,在需要访问私人数据的地方需要朋友功能。还有另一个目的。这与继承的类型有关。只有派生类及其朋友可以将指向私有基类的指针转换为派生类型。因此,有时您可能希望使某些函数成为派生类的朋友,以允许在函数体内执行此操作。

于 2013-07-07T13:36:49.627 回答
2

Alexandru Barbarosie 的回答是正确的。这意味着我们可以在类中声明一个非成员函数的友元函数。这可以很好地组织代码。我认为一个例子可以帮助理解它,以防它不清楚。

#include <iostream>

class A {
    public:
        A(int val) : val(val) {}
        // The following isn't a member function, it is a friend 
        // function declared inside the class and it has file scope
        friend void draw (A &a) {
            std::cout << "val: " << a.val << "\n";
        }
    private:
        int val;
};

int main() {
    A a(5);
    draw(a); // outputs "val: 5"
    //A::draw(a); // Error: 'draw' is not a member of 'A'
}
于 2018-03-06T12:47:07.880 回答