【问题标题】:Copying Methods from Member从成员复制方法
【发布时间】:2011-08-22 01:30:20
【问题描述】:

我有一个简单的低级容器类,供更高级别的文件类使用。基本上,文件类在将最终版本保存到实际文件之前使用容器在本地存储修改。因此,一些方法直接从容器类传递到文件类。 (例如,Resize()。)

我刚刚定义了文件类中的方法来调用它们的容器类变体。例如:

void FileClass::Foo()
{
    ContainerMember.Foo();
}

然而,这越来越令人讨厌。有没有更好的方法来做到这一点?

这是一个简化的例子:

class MyContainer
{
    // ...

    public:

    void Foo()
    {
        // This function directly handles the object's
        // member variables.
    }
}

class MyClass
{
    MyContainer Member;

    public:

    void Foo()
    {
        Member.Foo();

        // This seems to be pointless re-implementation, and it's
        // inconvenient to keep MyContainer's methods and MyClass's
        // wrappers for those methods synchronized.
    }
}

【问题讨论】:

  • 我在这里看到的是组合,而不是继承。我错过了什么吗?
  • @Doug 我在问是否有一种方法可以从容器类继承,或者在我的示例中为MyContainer,仅用于几种方法。 (或者更好的解决方案,如果有的话。)我将编辑问题以使其更清楚。
  • 在这种情况下,听起来您应该将 MyContainer 拆分为一个类,该类具有您想要的方法(然后从该类继承)以及 MyContainer 的其余方法在不同的类中。

标签: c++ oop inheritance methods class-design


【解决方案1】:

是的,维护这样的代理类非常烦人。您的 IDE 可能有一些工具可以使它更容易一些。或者您可以下载一个 IDE 插件。

但这通常不是很困难,除非您需要支持几十个函数、覆盖和模板。

我通常这样写:

void Foo()      { return Member.Foo(); }
int  Bar(int x) { return Member.Bar(x); }

漂亮且对称。 C++ 允许您在 void 函数中返回 void 值,因为这使模板工作得更好。但是你可以用同样的东西让其他代码更漂亮。

【讨论】:

    【解决方案2】:

    那么,为什么不直接从MyContainer 私有继承,并通过using 声明公开您想要转发的那些函数呢?这就是所谓的“实现MyClass在MyContainer。

    class MyContainer
    {
    public:
        void Foo()
        {
            // This function directly handles the object's
            // member variables.
        }
    
        void Bar(){
          // ...
        }
    }
    
    class MyClass : private MyContainer
    {
    public:
        using MyContainer::Foo;
    
        // would hide MyContainer::Bar
        void Bar(){
          // ...
          MyContainer::Bar();
          // ...
        }
    }
    

    现在“外部”将能够直接调用Foo,而Bar 只能在MyClass 内部访问。如果您现在创建一个具有相同名称的函数,它会隐藏基本函数,您可以像这样包装基本函数。当然,您现在需要完全限定对基函数的调用,否则您将陷入无休止的递归。


    此外,如果您想允许MyClass 的(非多态)子类化,那么这是少数几个地方之一,受保护的继承实际上很有用:

    class MyClass : protected MyContainer{
      // all stays the same, subclasses are also allowed to call the MyContainer functions
    };
    

    如果您的 MyClass 没有虚拟析构函数,则为非多态。

    【讨论】:

      【解决方案3】:

      那是delegation inheritance,我不知道 C++ 提供了任何机制来帮助解决这个问题。

      【讨论】:

        【解决方案4】:

        考虑在您的情况下什么是有意义的 - MyClass 和 MyContainer 之间的组合(具有 a)或继承(是 a)关系。

        如果您不想再有这样的代码,那么您几乎受限于实现继承(MyContainer 作为基/抽象基类)。但是,您必须确保这在您的应用程序中确实有意义,并且您不是纯粹为了实现而继承(实现的继承是不好的)。

        如果有疑问,你所拥有的可能没问题。

        编辑:我更习惯于用 Java/C# 思考,而忽略了 C++ 具有更大的继承灵活性这一事实,Xeo 在他的回答中利用了这一点。在这种情况下,这感觉就像是一个不错的解决方案。

        【讨论】:

          【解决方案5】:

          这个你需要编写大量代码的功能实际上是必要的功能。 C++ 是一种冗长的语言,如果你尽量避免用 C++ 编写代码,你的设计永远不会很好。

          但是这个问题的真正问题是这个类没有行为。它只是一个什么都不做的包装器。每个类都需要做一些事情,而不仅仅是传递数据。

          关键是每个类都有正确的接口。这一要求使得编写转发函数成为必要。每个成员函数的主要目的是将所需的工作分配给所有数据成员。如果你只有一个数据成员,而你还没有决定这个类应该做什么,那么你所拥有的就是转发函数。一旦你添加了更多的成员对象并决定了类应该做什么,那么你的转发函数就会变得更合理。

          有助于解决此问题的一件事是保持班级规模小。如果接口很小,每个代理类就只有很小的接口,接口不会经常变化。

          【讨论】:

          • 类确实做某事。为了这个问题,我的例子被简化了。
          猜你喜欢
          • 1970-01-01
          • 2014-02-14
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多