[英]How to initialize a base member variable with customized virtual function in the subclass
StructComponent类的构造函数采用不同的逻辑来根据info的传入对象的类型初始化其成员变量。 在这里,我使用强制转换将传递参数转换为正确的子类对象。
class StructComponent
{
public:
StructComponent(const ClassA& info)
{
if (info.getType() == CLASS_B)
{
const ClassC& classC = dynamic_cast<const ClassC&> info;
...
apply a different logic for ClassB and init member accordingly
} else if (info.getType() == CLASS_C) {
apply a different logic for others
...
} else {
apply default
}
}
}
class ClassA
{
public:
ClassA(...)
{
m_shp = CreateStructComponent();
}
virtual boost::shared_ptr<StructComponent> CreateStructComponent()
{
return boost::shared_ptr<StructComponent> (new StructComponent(*this));
}
...
int getType() const { return CLASS_A; }
protected:
boost::shared_ptr<StructComponent> m_shp;
}
class ClassB : public ClassA
{
public:
...
virtual boost::shared_ptr<StructComponent> CreateStructComponent()
{
return boost::shared_ptr<StructComponent> (new StructComponent(*this));
}
...
int getType() const { return CLASS_B; }
}
class ClassC : public ClassA
{
public:
...
virtual boost::shared_ptr<StructComponent> CreateStructComponent()
{
return boost::shared_ptr<StructComponent> (new StructComponent(*this));
}
...
int getType() const { return CLASS_C; }
}
Q1>代码正确是否忽略了潜在的设计问题?
Q2>假定ClassA的所有子类都具有功能CreateStructComponent的相同实现体。 有没有一种方法可以节省空间,而不必重复执行以下相同的代码:
return boost::shared_ptr<StructComponent> (new StructComponent(*this));
Q3>是否可以使用更好的设计? 例如,有没有一种方法可以忽略StructComponent中的强制转换?
在执行类A
的构造函数期间,对象的类型为A
因此,将始终调用基本实现。 因此,您可以省去重新键入实现的麻烦。
该代码设计不正确; 设计错误的代码永远是不正确的,至少在“正确”一词的通常含义中是这样。
如果C ++规则不太适合您,则没有理由应使用构造函数进行初始化。 只需使其成为一种方法,然后调用Initialize
,您可以从Initialize
中调用所需的任何虚拟方法,并具有预期的效果。
1)不,这是不正确的,至少,它没有达到您的预期。 它在ClassA
的构造函数中调用一个虚函数,该虚函数将始终调用ClassA::CreateStructComponent()
而不是在派生类中调用重写函数,因为在ClassA
构造函数运行时,该动态类型为ClassA
。 出于相同的原因,在StructComponent
的构造函数中, getType()
调用将始终解析为ClassA::getType()
。
2)有很多方法可以解决该问题。 您可以将代码放在模板中,因此它取决于类型,或者您可以通过在其他位置进行初始化来摆脱重复代码的需要。
3)为什么不简单地给StructComponent
重载构造函数,一个带ClassB
,一个带ClassC
,另一个带ClassA
?
再说一次,更好的解决方案可能是摆脱StructComponent
构造函数,让ClassA
, ClassB
或ClassC
显式地进行初始化,以便每种类型都ClassC
希望的方式进行初始化。 如果初始化取决于创建它的类型,则初始化不属于StructComponent
构造函数。 当前,您有一个循环依赖项, StructComponent
需要了解所有使用它的类型,而所有使用它的类型都需要知道StructComponent
。 这通常是设计存在问题的迹象,所有类都紧密耦合在一起。 如果StrictComponent
对其他类型一无所知,那会更好。
无论如何,这是一个可能的解决方案,它展示了一种在不复制代码的情况下将正确的类型传递给StructComponent
,但是我认为这不是一个好的设计。 请注意, Structcomponent
构造函数传递给NULL,因此它可以根据类型做不同的事情,但不能访问传递的对象。
class StructComponent
{
public:
explicit StructComponent(const ClassA*)
{ /* something */ }
explicit StructComponent(const ClassB*)
{ /* something else */ }
explicit StructComponent(const ClassC*)
{ /* something completely different */ }
};
class Base
{
protected:
template<typename T>
explicit
Base(const T*)
: m_shp( boost::make_shared<StructComponent>((T*)NULL) )
{ }
boost::shared_ptr<StructComponent> m_shp;
};
class ClassA : virtual public Base
{
public:
ClassA() : Base(this) { }
};
class ClassB : public ClassA
{
public:
ClassB() : Base(this) { }
};
class ClassC : public ClassA
{
public:
ClassC() : Base(this) { }
};
这是另一种完全不同的方法,没有虚拟基础黑客,仍然删除重复的代码,并允许StructComponent
访问传递给它的对象(我认为这是一个坏主意):
class StructComponent
{
public:
explicit StructComponent(const ClassA& a)
{ /* something */ }
explicit StructComponent(const ClassB& b)
{ /* something else */ }
explicit StructComponent(const ClassC& c)
{ /* something completely different */ }
};
class ClassA
{
public:
ClassA() : m_shp( create(*this) ) { }
protected:
struct no_init { };
explicit
ClassA(no_init)
: m_shp()
{ }
template<typename T>
boost::shared_ptr<StructComponent> create(const T& t)
{ return boost::make_shared<StructComponent>(t); }
boost::shared_ptr<StructComponent> m_shp;
};
class ClassB : public ClassA
{
public:
ClassB()
: ClassA(no_init())
{ m_shp = create(*this); }
};
class ClassC : public ClassA
{
public:
ClassC()
: ClassA(no_init())
{ m_shp = create(*this); }
};
这是另一个选择,这次没有循环依赖关系,将不同的初始化代码移到了它所属的位置:
struct StructComponent
{
StructComponent() { /* minimum init */ }
};
class ClassA
{
public:
ClassA() : m_shp( createA() ) { }
protected:
struct no_init { };
explicit
ClassA(no_init)
: m_shp()
{ }
boost::shared_ptr<StructComponent> createA()
{
// something
}
boost::shared_ptr<StructComponent> m_shp;
};
class ClassB : public ClassA
{
public:
ClassB()
: ClassA(no_init())
{ m_shp = createB(); }
private:
boost::shared_ptr<StructComponent> createB()
{
// something else
}
};
class ClassC : public ClassA
{
public:
ClassC()
: ClassA(no_init())
{ m_shp = createC(); }
private:
boost::shared_ptr<StructComponent> createC()
{
// something completely different
}
};
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.