【问题标题】:Alternative to friendship?友谊的替代品?
【发布时间】:2011-12-17 12:48:55
【问题描述】:

在下面的场景中,除了友谊还有其他选择吗?

我有一个代表 UI 窗口的 Window 类。此外,作为单例实现的WindowManager 类管理我的应用程序中的所有窗口对象(呈现 UI、调度事件等)

WindowManager 将有一个公共接口,仅由其单例实例化方法和函数组成,用于呈现 UI 和调度 UI 事件。

我还希望Window 对象在构造期间向WindowManager 注册,并在销毁期间取消注册。 WindowManager::registerWindowManager::deregister 方法将是私有的或受保护的,因为我不希望客户端(Window 对象除外)能够使用此接口。

在这种情况下,有没有办法避免WindowWindowManager 之间的友谊?也许用完全不同的方式来获得类似的结果?

【问题讨论】:

  • 有什么理由不希望 Window 和 WindowManager 成为朋友吗?是不是他们都曾经和同一个女孩约会,所以现在太尴尬了?
  • :)) 不,但作为一个初级 C++ 程序员,我可能正在努力避免耦合,即使我不应该这样做。
  • 最好停下来问自己一些问题,例如“将这两件事结合在一起真的有好处吗?”或者“我可以在不牺牲清晰度或性能的情况下以一种它们之间的依赖较少的方式构建这两个部分吗?”但如果要存在依赖关系,最好以最清晰、最干净和最直接的方式完成该依赖关系。查看一个类并立即知道它与哪些其他类相关,这比查看它并且必须通过查看一些细微的东西来尝试找出复杂的连接要好得多。

标签: c++ encapsulation friend access-control


【解决方案1】:

是的,但友谊是最好的解决方案,因为它是为这种情况设计的。

另一种方法是使Window 成为WindowManager 的成员(注意,这需要新的C++11 可访问性规则)。或者让它派生自WindowManager 的成员。或者让它派生自WindowManager 本身。

您还可以在Window 中放置一个私有类型,在Window 中创建一个只能从该私有类型构造的密钥类型,并需要将该密钥类型的一个实例传递给WindowManager。这应该适用于 C++11 之前的编译器。

当然,使用足够的强制转换可以绕过任何方法。

【讨论】:

  • 我对源自WindowManagerWindow 感到不舒服,因为它们没有“is-a”关系。
  • @dandrestor:我告诉过你友谊更好。这些其他方法将起作用,尽管它们并不理想。
  • @dandrestor:这是为友谊定制的场景。这是最好的设计,任何其他设计都会导致设计混乱。
  • 谢谢大家。看来我会坚持友谊。
  • @Als 这真的取决于问题。如果这是一个家庭作业/教程项目,那么友谊是一种最短、最简单的方法。如果 dandrestor 想要模拟一些“真实”的 GUI 工具包功能——友谊可能会因一个限制而窒息——它不是继承的主题。 IHMO GUI 工具包是高度使用多态性的项目。
【解决方案2】:

在这里使用Friendship 似乎很合适。您想在两个类之间表示有意的强耦合,这可以通过朋友恰当地表示。

更具体地说,一个类需要访问另一个类的内部,而您不想通过使用公共访问说明符授予每个人访问权限。

经验法则:如果公共太弱而私人太强,您需要某种形式的选择访问权限:受保护或好友。

使用Friendship 是这里的最佳解决方案。

【讨论】:

    【解决方案3】:

    使用嵌套类。

    WindowManager {
      private:
        static void construct();
        static void destruct();
      public:
        class InternalWindow { // can access WindowManager's private members (no scoping needed)
          InternalWindow() { construct(); }
          ~InternalWindow() { desstruct(); }
        };
    };
    
    typedef WindowManager::InternalWindow Window; // to make scoping easier
    

    【讨论】:

      【解决方案4】:

      另一个解决方案(没有必要更好:])是将窗口注册放到a separate component - 比如说WindowRegister。 WindowRegister 可以有一个公共的注册接口,也可以是一个 WindowManager 的私有成员。

      problem with friendship is that it is not inherited(我爷爷的朋友不一定是我的朋友)——Window 或 WindowManger 很有可能是多态的。

      问候

      【讨论】:

      • 确实,我打算让Window 多态。我会调查你的WindowRegister 想法,谢谢!
      • “我朋友的侄子也是我的朋友”怎么样?如果我让Window 成为WindowManager 的朋友,那么所有继承自Window 的类都可以注册自己吗?
      • 取决于你如何组织事物。他们将无法从他们自己的方法中调用 register,但他们仍然可以使用他们超类的方法。因此,例如,如果有一个受保护的 registerMyself 方法 Window,那么他们仍然可以调用它。
      • 啊,这很有道理。谢谢,基思。
      【解决方案5】:

      还有其他几个选项。例如:

      • 您可以使用指针数学、汇编代码和有关内存中类布局的知识在运行时调用私有方法。但是,这不是很便携。
      • 您可以公开该方法,但要求它采用由 Window 类中的私钥加密签名的参数,从而防止其他类能够实际调用该方法并让它执行任何操作。李>
      • 您可以使方法受到保护,并让一个方法从另一个继承。
      • 您可以创建一个公共超类,它们都继承自该超类并使用其中的受保护方法在它们之间进行通信。
      • 您可以使用很少使用的“enemy”关键字来允许他们运行彼此的私有方法,但前提是他们有勒索材料导致其他班级有罪。 (好吧,这不是真正的语言功能,但应该是。)

      或者你可以让他们成为朋友。这比任何其他选项以及为什么存在朋友都更容易和更理智。

      【讨论】:

      • (注意:以上评论是针对有人告诉我C++中没有敌人关键字而做出的。该人将保持匿名,此后已删除他/她的评论。)跨度>
      猜你喜欢
      • 2015-07-01
      • 2023-03-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-10-28
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多