为什么可以将友元函数定义放在类定义中?

时间:2013-07-07 13:25:46

标签: c++ operator-overloading friend

是否应该在类之外明确定义朋友函数? 如果是这样,为什么我可以像任何成员函数一样在类定义中声明友元函数?
这是什么?
只有<运算符等运算符可以使用它还是适用于所有运算符? 如果它适用于所有这些,这样做是否有任何不利之处?
应该避免吗?如果是这样的话?

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;


};

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

5 个答案:

答案 0 :(得分:11)

是否应该在类之外明确定义友元函数?

  

可以在类声明中定义友元函数。这些函数是内联函数,就像成员内联函数一样,它们的行为就好像它们是在看到所有类成员之后但在类作用域关闭之前(类声明结束)之后立即定义的。   在类声明中定义的友元函数不在封闭类的范围内考虑;他们在文件范围内。   quote

仅适用于某些运营商,例如&lt;运营商还是适用于所有运营商?

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

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

答案 1 :(得分:4)

因为操作员需要知道使用的表达式右侧的详细信息,如果它必须访问驻留在该侧的类型的私有数据,则需要friend那个班。

如果您尝试将int与Person进行比较,就像在您的示例中一样,选择是两个:

  • 或者您提供从Person到int的隐式转换,以便<可以在不访问任何私有字段的情况下使用它
  • 或者您将运算符声明为friend的{​​{1}},以便它可以在比较的rhs中访问x

答案 2 :(得分:2)

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

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

答案 3 :(得分:1)

正如杰克所说,在需要访问私人数据的地方需要朋友功能。还有另一个目的。这与继承类型有关。只有派生类及其朋友才能将指向私有库的指针转换为派生类型。所以你有时可能想让某些函数成为派生类的朋友,以允许这个内部函数体。

答案 4 :(得分:0)

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