【问题标题】:When to use friend class in C++ [duplicate]何时在 C++ 中使用朋友类 [重复]
【发布时间】:2010-10-06 00:35:53
【问题描述】:

可能重复:
When should you use 'friend' in C++?

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

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

【问题讨论】:

  • 虽然朋友类显然是有用的,否则我不会将它们包含在语言规范中,但我倾向于将它们视为一种设计气味。它们通常向我表明我应该再次查看我的类层次结构,而且我通常发现我可以更优雅地重组它并消除对朋友类的需要。

标签: c++ keyword friend


【解决方案1】:

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

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

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

【讨论】:

    【解决方案2】:

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

    【讨论】:

      【解决方案3】:

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

      类似这样的:

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

      【讨论】:

        【解决方案4】:

        当您有多个类和/或函数一起工作以提供相同的抽象或接口时,使用友谊。经典的例子是实现某种数值类,并且所有非成员运算符函数(*、-、+、

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

        【讨论】:

        • 问题是关于朋友类而不是朋友的其他用途?
        • 是同一个想法。如果函数或类一起工作以提供统一的抽象,你就可以给它们友谊。
        【解决方案5】:

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

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

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

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

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

        【讨论】:

        • +1 有时您可能不得不从现有的类中提取一个新类,例如可读性问题,但您仍然希望保持紧密耦合。您想为新类提供特殊访问权限,但又不想公开这些方法。
        • 请记住,C++ 的理念是提供锐利、强大的工具,而不必担心它们会被如何滥用。 Stroustrup 在“设计与进化”中的某处解释了这一点。这就是为什么“朋友”在 C++ 中,而不是在 Java 中(它有不同的理念)。
        • 为什么mutable 会破坏封装?
        • 我倾向于将“朋友”视为班级外成员,也可以访问私人数据。有点类似于 java 中的“包私有”保护。你有不同的部分做不同的工作,但他们可以从访问其他人的实现中受益——也许是为了提高速度。
        • friend 的状态与mutable 不同。将mutable 用于除记忆、临时工作区或丑陋丑陋的 C++ hack 之外的任何东西,有些人喜欢为了好玩而制作这些代码,这是设计缺陷的有力指标。 Friend 有很多用途,也有很多误用,但它的用途比 mutable 更多。
        【解决方案6】:

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

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

        【讨论】:

          【解决方案7】:

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

          FQA的朋友圈:here

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

          【讨论】:

            【解决方案8】:

            一个具体的实例是一个类工厂,你希望一个类只能通过另一个工厂类创建,所以你将构造函数设为私有,而工厂类是生成类的朋友。

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

            【讨论】:

            • 这是一个很好的观点。由于 C++ 没有包(这可能是您在 C# 或 Java 中实现工厂的一种方式),看来您要么必须使用朋友工厂,要么拥有受保护的构造函数,以及创建的子实现类由工厂。 Friend 让你拥有一个 C++ 代码更少的工厂。
            【解决方案9】:

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

            【讨论】:

            • 好点约翰:“我只想补充一点,朋友类最常见的(合法的!)用途可能是测试”:)。
            • 为嵌套类(函子、迭代器等)提供友谊是我使用friend 的最常见方式。授予对相关类的访问权限应谨慎进行(这意味着紧密耦合),但可能是合理的。我也进行了第二次测试。
            【解决方案10】:

            【讨论】:

              【解决方案11】:

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

              【讨论】:

              • 一个很好的评论,但几乎没有答案
              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2018-07-13
              • 2010-09-19
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多