C++ 使基类设置为父类的正确方法

C++ 使基类设置为父类的正确方法,c++,oop,C++,Oop,我有点纠结于以下情况:假设我有一个类“Base”,它需要一些信息才能正常工作。因此,我使用适当的参数设置了一个构造函数,例如: class Base { public: Base(X x, Y y, Z z); }; 这适用于一般的“基础”。但我希望有一些子类,它们表示经常使用的特定“基”,并且包含设置基类所需的所有信息,例如: class Derived { public: Derived() { X x; x.addSomeInformati

我有点纠结于以下情况:假设我有一个类“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”-如果不调用,则会留下一个未正确初始化的基类):


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

整个
配置
(有时称为
初始化
)方法概念看起来确实是一条可行之路。事实上,我自己在过去的一个游戏开发项目中也遇到过这个问题,我只是使用了一个类似于您提出的解决方案,而没有让它在将来再次困扰我

只要这个类不是某些公共API的一部分(即使它真的是),您就不必担心如果有人不调用
configure
,可能会出现的问题。如果您真的想破坏很多API,只需左右将参数设置为无效值即可,但这并不意味着这些API不好。只需确保清楚地记录此使用模式即可

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

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


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

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

class Derived {
    public: Derived() : Base(X("foo bar"), <blah>) {
    }
};
派生类{
public:Derived():Base(X(“foo-bar”),){
}
};
如果这不是一个选项,请将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;
    }

};
派生类{
public:Derived():Base(make_X(),){
}
private:static X make_X(){
X;
x、 添加一些信息(“foo-bar”);
//还需要什么吗。
返回x;
}
};

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

i、 e.衍生“真的”是基础吗

另一个选项是考虑创建一个工厂方法,它负责完成最终调用具有所需参数的构造函数所需的所有工作。(这基本上就是马克B秀在他的第二个例子中所说的(几乎是)

或者,将modify base.x和base.y导出为它们需要的值,并作为使用这些setter的结果,更新构建base时应该发生的任何事情


这听起来像是隐藏控制器可能是有益的,这样你就可以通过一个工厂强制所有的施工,该工厂可以在返回它创建的具体产品之前调用product->config。

应用一些创作模式怎么样?例如“Builder”或“factory”?你考虑过它们吗?@spin_-eight“factory”对我来说似乎不太合适,但我不熟悉“构建器”模式。我会研究一下,谢谢!所以,你想改变你的设计,因为你不能将你的类放入初始值设定项列表中?我不明白为什么这比类完整性更重要。(或者我不理解这个问题。谁知道?)
class Derived {
    public: Derived() : Base(make_X(), <blah>) {
    }
    private: static X make_X() {
        X x;
        x.addSomeInformation("foo bar");
        // Anything else needed.
        return x;
    }

};