什么情况下应该将一个成员函数声明为友元函数?

5

在什么样的情况下我们会将成员函数声明为“友元函数”?“友元函数”这个违反了面向对象编程中“封装”核心概念的东西到底有什么作用呢?

6个回答

2
你可以使用友元函数和友元类的方式来实现相同的功能,但是它们适用于不同的情况。友元函数适用于成员函数(而不是整个类),而友元类则适用于整个类。在这个线程中有一些很好的解释。
虽然友元函数和类确实会破坏封装性,但在某些情况下它们很有用。例如,您可能希望允许测试工具访问类内部以进行白盒测试。与其将整个类开放给测试工具,不如只开放特定的函数以便测试工具访问所需的内部内容。虽然这仍然会破坏封装性,但比完全打开整个类更加安全。
您还可以参考这篇文章了解有关友元类和函数的更多信息。

2
友元函数和类不会破坏封装,当您试图构建一个必须在多个C++类或函数之间物理跨越的抽象或接口时!这就是为什么友元被发明的原因。
这种类型的情况并不经常出现,但有时您不得不使用不同的类和函数来实现抽象或接口。经典示例是实现某种复数类。非成员运算符函数被赋予主要复数类的友元关系。
我还记得在C++中使用CORBA编程时也这样做过。CORBA强制我使用单独的类来实现CORBA服务。但是对于我们软件的特定部分,我需要将它们作为一个接口结合在一起。友元关系允许这两个类共同工作,为我们软件的某个部分提供无缝服务。
将另一个类的特定成员函数标记为您类的友元可能看起来更奇怪,但这只是一种紧密控制友谊的方法。与其允许整个其他类“进入”您的朋友圈,不如只允许其中一个成员函数访问。同样,这并不常见,但在需要时非常有用。

1
+1 对于“不违反”是有用的。然而,在大多数数字类别(如复数、有理数等)的情况下,它是无用的。 - Luc Hermitte

1

请参阅C++ FAQ Lite:

有时候,友元函数在语法上更好(例如,在类Fred中,友元函数允许将Fred参数放在第二个位置,而成员函数要求它必须是第一个)。另一个很好的使用友元函数的例子是二元中缀算术运算符。例如,如果您想允许aFloat + aComplex,那么aComplex + aComplex应该定义为友元而不是成员(因为成员函数不允许左侧参数提升,因为这会改变作为成员函数调用接收者的对象的类)。


0
一个我觉得相关的要点是:成员类可以访问包含类的私有部分。这有时可能是比“友元”更好的选择。
class A
{
private:
  int b;
public:
  class MemberNotFriend {
  public:
    static void test() {
      A a;
      a.b = 0;
    }
  };


};


void test()
{
  A::MemberNotFriend::test();
}

0

这里有一个简单的具体例子,说明我如何使用友元函数:

我有一个游戏,每个精灵对象都将其信息存储为私有成员,例如X、Y位置。 然而,我希望将游戏对象与渲染分离:游戏对象不需要知道它是如何被渲染的。游戏对象仅存储游戏状态,而这个游戏状态可以以多种不同的方式进行渲染。

因此,游戏对象类有一个友元函数:render()。render()函数在游戏对象类外部实现,但它可以根据需要访问X、Y位置成员来渲染游戏对象。


0
有时候,公共/私有/受保护的保护级别并不足以应对现实世界中的情况。因此,我们提供了一个小的逃脱条款,可以在不必使方法公开可访问的情况下帮助解决问题。
我个人使用这种方式与Java使用“包”保护级别的方式相同。 如果我有一个在同一包中需要访问的类,我会考虑使用friend。如果它是另一个包中的类,那么我会想知道为什么这个其他类需要访问,并检查我的设计。

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