我被分配了清理班级层次结构的任务,但我陷入了一种困境。我现在留下的东西大致如下:
class Base
{
Base() = 0;
function1();
...
function5();
protected:
int variable1_;
...
int variable10_;
};
class DerivedOne
: public Base
{
DerivedOne() = 0;
function6();
...
function10();
protected:
int variable11_;
...
int variable20_;
};
class DerivedTwo
: public DerivedOne
{
DerivedTwo()
: DerivedOne()
{
... Fill variable1_ to variable25_ with data read from file ...
variable1_ = ...
}
function11();
...
function15();
private:
int variable21_;
...
int variable25_;
};
因此,在DerivedTwo中为25变量分配了它们的值,这样就很容易出错。当另一个类继承自DerivedOne时,几乎可以肯定该人将忘记初始化其中一个变量。
我一直在玩这种层次结构的不同方式,但没有什么感觉真的。
我理解在不知道这些类实际做什么的情况下很难说出具体的东西,但我有兴趣知道这个设计是否存在根本性的错误,或者我是否忽略了一些优雅的初始化方法所有的变数。
答案 0 :(得分:1)
推导的原则是首先构造基础对象,然后构造基础对象。这需要Base和DerivedOne构造函数自己生成一个有效的对象。
构建DerivedTwo时,您的代码清楚地表明了这一点:
DerivedTwo()
: DerivedOne() // First the base object constructor is called, before anything else
{
// then remaining initialisation, after DerivedOne() was created
}
因此每个类至少应该将自己的变量初始化为一个初始的有效状态,它自己的函数可以以一致的方式处理它。
Base() : variable1_(/*default value here*/), variable10_(/*default value here*/) {}
Base(int v1, int v10) : variable1_(v1), variable10_(v10) {} // for convenience
之后,一个派生类可能会覆盖其基类的变量。使用getter / setter当然会更安全,更优雅,但还可以。
如果你采用这种设计,如果一个子类来源忘记初始化其父变量之一,这不应该导致灾难,因为至少基础对象是以一种体面的方式初始化的。
现在问题是您还通过读取文件来启动DerivedTwo。记住,首先创建Base,然后创建DerivedOne,然后只有DerivedTwo读取值。当文件无法读取或不一致时会发生什么?除非抛出异常,否则最终可能会出现一个不一致的对象。所以你必须管理它并确保DerivedTwo处于稳定状态:
DerivedTwo()
: DerivedOne() // First the base object constructor is called
{
// then initialise all own members to a consitent state
// then try to read the file and manage potential errors
}
答案 1 :(得分:0)
每个班级都应负责初始化自己的数据成员。如您所述,Base
假设DerivedX
将初始化其数据成员是危险的。所以......
Base
应初始化variable1_
... variable10_
DerivedOne
应初始化variable11_
... variable20_
DerivedTwo
应初始化variable21_
... variable25_
......等等。
当然,这并没有解决为什么课程以这种方式布局的问题......