3

我在以下情况下有点挣扎:假设我有一个类“Base”,它需要一些信息才能正常工作。因此,我设置了一个带有适当参数的构造函数,例如:

class Base {
    public: Base(X x, Y y, Z z);
};

这适用于一般的“基地”。但我希望有代表特定“基础”的子类,这些“基础”经常使用,并且包含设置基类所需的所有信息,例如:

class Derived {
    public: Derived() {
        X x;
        x.addSomeInformation("foo bar");
        // ...
        // now what?
    }
};

这里的问题是我不能通过初始化列表调用父构造函数(通常会这样做),因为要移交的参数还不存在。

因此,我觉得我的设计存在严重问题。我可以通过引入一个受保护的默认构造函数和一个模仿普通构造函数的“配置”方法来完成这项工作,但我不确定这是否是一个好主意(主要是因为这样我不能确保子类实际调用“配置“ - 如果不是这样,那会给我留下一个未正确初始化的基类):

class Base {
    public: Base(X x, Y y, Z z) { configure(x, y, z); }
    protected: Base() {}
    protected: void configure(X x, Y y, Z z);
};

class Derived {
    public: Derived() {
        X x;
        // ...
        configure(x, y, z);
    }
};

如何以适当的方式处理这种情况?

4

3 回答 3

3

我的第一个建议是创建X一个有价值的构造函数,而不是强制它默认构造:

class Derived {
    public: Derived() : Base(X("foo bar"), <blah>) {
    }
};

如果这不是一个选项,请将 X-creation 逻辑拆分为另一个函数并使用它:

class Derived {
    public: Derived() : Base(make_X(), <blah>) {
    }
    private: static X make_X() {
        X x;
        x.addSomeInformation("foo bar");
        // Anything else needed.
        return x;
    }

};
于 2013-04-05T22:59:26.263 回答
2

整个configure(有时称为initialize)方法概念似乎确实是可行的方法。实际上,作为游戏开发项目的一部分,我自己过去曾遇到过这个问题,我只是使用了与您提出的类似的解决方案,而以后不会再被它咬伤。

只要此类不是某些公共 API 的一部分(即使确实如此),您也不应该担心如果有人不调用configure. 如果您真的想通过将参数设置为左右无效值来破坏很多 API,但这并不意味着这些 API 不好。只需确保清楚地记录此使用模式即可。

你会感到不安,因为事实上,人们认为正确性依赖于某个方法的代码必须在某个时间调用某个其他方法是不好的。他们是对的,只要这会影响代码的可读性(甚至可能影响性能),在您的情况下这根本不是真的。具有initialize(或任何您想调用的)方法以及构造函数的对象不是坏习惯,并且使用这样的方法实际上是编程中广泛使用的习惯用法。

另一件肯定有帮助的事情是将基类设计为在 X/Y/Z 坏时尽快失败。这样,任何可能因忘记调用而弹出的错误都configure可以在引起更大问题之前被捕获和修复。

另一种方法是重新考虑(如果可能的话)等对象的构建方式XY并为这些类的用户(在本例中为您)提供更多通过构造函数初始化它们的可能性。将这些对象划分为子组件(如果适用于您的情况)也可能有所帮助。

于 2013-04-05T22:52:03.547 回答
0

这是一个非常不同的答案,但您可以检查组合而不是继承。

即派生“真的”是一个基础吗?

另一种选择是考虑创建一个工厂方法,该方法负责完成最终使用所需参数调用构造函数所需的所有工作。(这基本上就是 Mark B 在他的第二个例子中展示的内容(差不多)。

或者,让 Derived 将 base.x 和 base.y 修改为它们需要的内容,并且由于使用了这些设置器,因此更新了基础构造中应该发生的任何事情。

听起来隐藏委托人可能是有益的,因此您可以通过工厂强制所有构建,该工厂始终可以在返回它创建的具体产品之前调用 product->config。

于 2013-04-05T23:21:01.143 回答