2010-01-05 62 views
1

所以我使用组合来汇集对象的集合,所有这些对象都是从基类派生的,可以说组件。 E.g:设计替代?组成和构造

class Component { 
public: 
    Component(); 
    ... 
private: 
    int m_address; 
    ... 
}; 

class SpecializedComponent: public Component { 
public: 
    SpecializedComponent() 
    ... //and so on 
}; 

class SpecializedComponent2: public Component { 
public: 
    SpecialIzedComponent2() 
    ... //and so on 
}; 

class ComponentHolder{ 
    SpecializedComponent* m_descriptiveName; 
    SpecializedComponent2* m_descriptiveName2; 
    // and so on... many different types of components 
} 

因此,每个SpecializedComponentX将通过网络进行通信与个人数据源,每一个都有自己独特的地址。这些地址在参数文件中指定。目前,我正在解析参数文件,m_address在派生类构造函数中初始化 - 这是因为每个m_address都是由我们正在初始化的对象类型指定的。

每个SpecializedComponentX都有一些我想在基类Component中执行的常用功能。所以,我启动了一个与基类Component相关的线程,对吧?当然 - 有道理。直到我意识到我还没有该组件的目标地址 - 因为该对象尚未完全构建。我想旋转ctor中的基类线程,但我还不知道m_address

我想到解决这个问题的唯一方法是提供一个(简单的)虚拟函数void start(),派生类可以调用一旦对象完全构造就旋转起来的线程。这是一个有效的适当的设计选择还是有一种模式,我可以忽略?谢谢。

回答

0

组件可以有一个构造函数,它具有一个用于初始化m_address的参数。

+0

是的,当然。有时候显而易见的事情是正确的。 – jdt141 2010-01-05 16:36:24

0

如果这个通用的功能以任何方式依赖于SpecializedComponent,SpecializedComponent2的状态,或者这是一个SpecializedComponent或SpecializedComponent2的事实,那么你不能在Component的构造函数中真正做到这一点,除非你传入参数到它。将类型标识符传递给Component构造函数以在那里进行这种初始化有时是一种必要的邪恶。

但是,在这种情况下,您可以创建派生类可以调用的虚函数。但是,假设您将此虚函数调用放置在SpecializedComponent构造函数中。如果你以后从这个(SuperSpecializedComponent)派生出另一个类并且使用这个虚函数,那么你从SpecialzedComponent构造函数调用的调用甚至不会触发这个函数。道德:不要从构造函数调用虚函数。

我认为最简洁的方法是建立一个2阶段结构。一个构造函数,用于完成对象的基本连接以及在使用它之前必须调用的Init()方法。客户端代码(ComponentHolder?)可以在所有对象完全构建后调用此Init。

0

为什么start()方法需要是虚拟的?

你可以把非虚拟和实现派生的构造函数 这样的:

SpecializedComponent::SpecializedComponent() { 
    m_address = getAddressFromParameterFile("SpecializedComponent"); 
    start(); 
} 

这是最好的对象后,调用start()是完全 构造,因为两步施工误差易发。 (如果你 需要两个步骤的建设,考虑工厂(或工厂方法),以 确保只有完全构造的对象存在。让构造 私营和工厂(方法)的朋友。)

另一种方式是将地址的计算移出 对象构造。这将导致这样的代码:

SpecializedComponent::SpecializedComponent(const std::string& address) 
: Component(address) 
{} 

Component::Component(const std::string& address) 
: m_address(address) 
{ 
    start(); 
} 

这种方法增加了衍生 SpecializedComponents的可测试性,因为它消除对 参数文件的依赖。

为了方便,你可以到实例提供静态工厂方法 您SpecializedComponents:

SpecializedComponent* SpecializedComponent::create() { 
    std::string address = getAddressFromParameterFile("SpecializedComponent"); 
    return new SpecializedComponent(address); 
} 

BTW:考虑持有,而不是原始指针的shared_ptr在ComponentHolder。