友元函数

3
友元函数示例中,为什么以下说法是正确的?“请注意,在duplicate()的声明以及其在main()中的后续使用中,我们都没有将duplicate视为CRectangle类的成员。它并不是!它只是可以访问其私有和保护成员而不是成员。” Duplicate在CRectangle的公共部分中声明。为什么它不是成员函数而set_values是成员函数?这是一个好的例子吗?如果不是,有更好的例子吗?
4个回答

15
Pavel的回答是对你问题的直接回答,但我觉得你可能不清楚友元函数的用途,所以我想给出一个常见的例子。
友元函数的常见用法是在重载流操作符时,特定的操作符需要访问(或通过访问)对象的私有成员。例如:
class Rectangle
{
...
    friend ostream &operator<<(ostream &stream, Rectangle r);
private:
    int width;
    int height;
};

ostream &operator<<(ostream &stream, Rectangle r)
{
    return (stream << "{" << r.width << ", " << r.height << "}");
}

在这种情况下,友元函数允许我们访问私有数据并进行打印,而无需编写“获取”数据的方法。也许这有助于澄清为什么要使用友元函数。

4
好的答案,值得指出的是,friend operator<< 甚至可以完全在 Rectangle 内部定义,包括函数体,语义保持不变。 - Pavel Minaev
考虑使用Rectangle &r,如果它是一个大类会更有效率。或者使用const Rectangle &r会更好,这样你就可以打印一个“const Rectangle”(也许是你类中的一些用户定义常量)。 - VimNing

11
任何在类中声明或定义为friend的函数都不是该类的成员函数,它只是一个友元函数。
尽管如此,如果一个友元函数也在类内定义,那么它会被涉及到该类的ADL查找所发现(这通常用于重载运算符)。

1

答案在类中函数声明之前的friend关键字。

例如:friend CRectangle duplicate (CRectangle);

友元函数是一种允许访问类的私有成员变量的函数。它不是属于该类的成员函数。

set_values是该类的成员,因为它没有friend关键字,并且其作用域在类定义内部。方法体在类定义外部定义。即类似于前向定义,实现在后面。

通过在方法名前加上CRectangle::,我们告诉编译器这是在CRectangle类范围内声明的set_values函数的实现。

DeusAduro关于friend在哪里有用的回答是friend类的常见用法之一。


1

好的,我也来试试。

正如大家指出的那样,成员函数和友元函数之间的语法区别是friend关键字。

这里有一种思考方式。成员函数有一个隐式参数:指向对象本身的指针。例如,在set_values中,您可以使用成员widthheight,它们将是调用set_values的对象的成员。

另一方面,在duplicate()内部不能单独使用标识符widthheight,因为它不是成员函数,因此它没有隐式参数,即它与任何特定对象都没有关联。友谊的含义是,duplicate()可以访问传递给它的任何CRectangle对象的私有成员,或者是其范围内的局部变量。

另一个要点是:友元声明甚至不是函数的真正声明。它只是向编译器发出的一条注释,如果这个特定的函数被定义,它将被赋予访问该类的私有成员的权限。

1
静态成员函数仍然是成员函数,即使它们没有任何隐式参数。此外,虽然友元声明不会声明函数,但友元内联定义既声明又定义了一个函数(并且还将其设置为“友元”)。 - Pavel Minaev
啊,现在真的变得有趣了。 :) 成员函数:具有隐式参数并可以访问私有静态和非静态成员。静态成员函数:没有隐式参数,只能访问静态数据成员。友元函数:没有隐式参数,可以访问私有静态和非静态成员。顺便说一下,内联友元函数的优点很大。 - Dima

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接