38

可能重复:
什么时候应该在 C++ 中使用“朋友”?

我在复习我的 C++(我是一名 Java 开发人员)时遇到了friend class一个我已经忘记了一段时间的关键字。这是只是厨房水槽一部分的功能之一,还是有充分的理由这样做,而不仅仅是香草吸气剂?我理解不同之处在于它限制了谁可以访问数据,但我想不出有必要这样做的场景。

注意:我见过一个类似的问题,但我特别想问的是,这只是一个高级功能,除了让人们在看你的代码之前感到困惑,直到他们意识到你在做什么之外,并没有增加任何真正的价值?

4

11 回答 11

41

我同意这样的评论,即如果使用得当,friend 关键字可以提高封装性。我只想补充一点,朋友课程最常见的(合法的!)用途可能是测试。您可能希望测试程序类比其他客户端类具有更大程度的访问权限。测试人员类可能有充分的理由查看故意对其他类隐藏的内部细节。

于 2009-02-06T19:45:15.893 回答
19

根据我的经验,与打破封装的频率相比,真正增强数据封装的朋友(或可变的,有点相似)的情况很少见。

它对我来说很少有用,但是当我使用它时,我不得不将一个以前是单个类的类拆分为两个需要访问一些常见数据/功能的单独类。

编辑以回应 Outlaw Programmer 的评论:我们完全同意这一点。除了在拆分类后加好友之外,另一种选择是制作公共访问器,这有时会破坏封装!我认为有些人认为友好的类以某种方式破坏了封装,因为他们经常看到它使用不当,而且很多人可能永远不会看到正确使用它的代码,因为它很少见。不过,我喜欢你的陈述方式——友好是一个很好的中间立场,介于不允许你分开班级和让公众可以接触到所有东西之间。

编辑以回应 David Thornley:我同意 C++ 允许您执行此类操作的灵活性是 C++ 设计决策的结果。我认为这使得理解在灵活的语言中通常是好还是坏的风格变得更加重要。Java 的观点是,您永远不应该有友元类,因此不提供这些类,但作为 C++ 程序员,我们作为社区有责任定义这些非常灵活但有时被误用的语言结构的适当使用。

编辑以回应 Tom:Mutable 并不一定会破坏封装,但我在现实生活中看到的许多 mutable 关键字的使用都会破坏封装,因为看到人们用 mutable 破坏封装比 to 更常见实际上首先要找到并理解 mutable 的正确用法。

于 2009-02-06T19:20:27.380 回答
13

当您希望一个类(工厂)负责创建另一个类(类型)的实例时。您可以将 Type 的构造函数设为私有,从而确保只有 Factory 可以创建 Type 对象。当您希望将检查委托给可以用作验证器的其他类时,它很有用。只是一种使用场景。

PS真的缺少C#中的“朋友”关键字......

于 2009-02-06T20:27:54.090 回答
9

具体实例将是一个类工厂,您希望一个类仅通过另一个工厂类创建,因此您将构造函数设为私有,并且工厂类成为生产类的朋友。

它有点像一个 2" 12 点 3/4" 驱动器插座 - 不是很常见,但当你需要它时,你会非常高兴拥有它。

于 2009-02-06T20:24:18.577 回答
4

帮助Memento 设计模式

于 2009-02-06T19:24:57.697 回答
2

关于朋友的常见问题解答部分:这里

FQA关于朋友的部分:这里

关于朋友的两种不同观点。

于 2009-02-06T20:26:57.353 回答
1

我将friend构造视为应该在极少数情况下使用的语言特性之一,但这并不意味着它毫无用处。有几种模式需要制作friend课程,其中许多已经在该站点右侧的“相关”栏中。====>

于 2009-02-06T19:23:22.303 回答
1

当您有多个类和/或函数一起工作以提供相同的抽象或接口时,使用友谊。经典的例子是实现某种数值类,并且所有非成员运算符函数(*、-、+、<< 等)都被赋予友谊,以便它们可以处理数值类的私有数据。

这样的用例有些少见,但确实存在,friend 很有用。

于 2009-02-06T20:15:39.780 回答
1

这是几个例子中的一个,我敢肯定,朋友类可以在不考虑封装原因的情况下合法使用。

MyClass 继承自 GeneralClass。MyClass 变大了,所以你创建了 HelperClass 来封装 MyClass 的一些功能。但是,HelperClass 需要访问 GeneralClass 中的一些受保护函数才能正确执行其功能,因此您将 HelperClass 设为 MyClass 的朋友。

这比公开受保护的函数要好,因为它们不需要对每个人都可用,但它有助于保持您的代码以 OOP 方式组织,以防止 MyClass 变得过于复杂。这是有道理的,因为尽管 HelperClass 与 MyClass 没有通过继承具体相关,但它确实与它有某种逻辑联系,体现在代码和设计中,作为“朋友”。

于 2010-12-15T18:15:58.090 回答
0

我总是(并且只)使用朋友对私有方法进行单元测试。我能想到的唯一另一种方法是使用大量测试方法加载公共接口,这太混乱了,所以我更喜欢将测试方法隐藏在单独的测试类中。

像这样的东西:

class cMyClassTest;

class cMyClass
{
public:
.....

private:
friend cMyClassTest;
int calc();     // tricky algorithm, test carefully

};

class cMyClassTest
{
public:
int test_calc()
{
    cMyClass test;
    ....
    int result = test.calc();

    if( result == 42 )
        return 1;
    return 0;
}
};
于 2009-02-12T16:18:50.187 回答
0

朋友类的意思是我们都知道它是从其他类访问变量的值,所以它主要用于使用这些值,所以我们不需要将其他类的值返回给主函数,然后将主函数返回到所需的类成员函数,但它具有一个班级的问题是其他班级的朋友,那么朋友班级应该在该班级的下方

于 2010-01-27T13:33:37.010 回答