正确的方法来使基类设置父类

时间:2013-04-05 22:32:56

标签: c++ oop

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

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

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

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

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

由于这个原因,我觉得我的设计出现了严重问题。我可以通过引入一个受保护的默认构造函数和模仿普通构造函数的“configure”方法来完成这项工作,但我不确定这是不是一个好主意(主要是因为这样我无法确保子类实际调用“configure” “ - 如果没有,那将使我没有正确初始化的基类:”

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

如何以正确的方式处理这种情况?

3 个答案:

答案 0 :(得分:3)

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

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

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

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

};

答案 1 :(得分:2)

整个configure(有时称为initialize)方法概念看起来像是要走的路。实际上,作为游戏开发项目的一部分,我自己实际上已经解决了这个问题,我只是使用了类似于你想出的解决方案,而不会让它在将来再次咬我。

只要这个类不是某些公共API的一部分(即使它确实是这样),你也不应该担心如果某人没有调用configure可能会出现的问题。如果你真的想通过左右设置参数到无效值,你可以打破很多API,但这并不意味着那些API是坏的。只需确保清楚地记录此使用模式。

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

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

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

答案 2 :(得分:0)

这是一个非常不同的答案,但你可以检查构成而不是继承。

即。派生'真的'是基地吗?

另一种选择是考虑创建一个工厂方法,负责完成最终使用您想要的参数调用构造函数所需的所有工作。 (这基本上是马克B在他的第二个例子中表现出来的(差不多)。

或者,Derived修改base.x和base.y到他们需要的东西,并且由于那些使用的setter更新了从构造base开始应该发生的任何事情。

听起来隐藏控制器可能是有益的,因此您可以通过工厂强制所有施工,在返回其创建的具体产品之前,该工厂始终可以调用product-&gt; config。