2014-08-29 3 views
1

Я реализовал фабричный класс на основе следующей статьи here.Проблемы с производством на уровне фабрики

У меня есть одна проблема, и я думаю, что это связано с оптимизацией компилятора.

У меня есть иерархия классов, где класс Node (в Node.h/Node.cpp) является базовым классом, и, например, BuildingLot (в BuildingLot.h/BuildingLot.cpp) является подклассом.

В обоих исходных файлах, объявленных как static, у меня есть класс регистратора.

node.cpp:

static Registrar<Node> _registrar(“Node”); 

BuildingLot.cpp:

static Registrar<BuildingLot> _registrar(“BuildingLot”); 

Если я пытаюсь использовать завод, она прекрасно работает для класса Node. Однако я должен сначала создать экземпляр BuildingLot для его регистрации на заводе.

В модульном тесте у меня есть:

NodePtr node = Factory::Instance()->Create(“Node”); 
NodePtr bl = Factory::Instance()->Create(“BuildingLot”); 

бл всегда nullptr. Конструктор регистратора никогда не выполняется, и поэтому класс Factory никогда не знает о классе BuildingLot. Если я это сделаю:

BuildingLot b; 
NodePtr node = Factory::Instance()->Create(“Node”); 
NodePtr bl = Factory::Instance()->Create(“BuildingLot”); 

Тогда все работает. Регистратор называется, а Factory создает BuildingLot.

Я думаю, поскольку BuildingLot не используется в первом примере, компилятор оптимизировал и даже не скомпилировал BuildingLot.cpp.

Возможно ли это? Как я могу это решить?

Редактировать: Класс регистратора - это, фактически, класс шаблона. Я просто забыл вставить параметры шаблона.

Вот мой код так просто, как я мог это сделать. Надеюсь, я ничего не оставил. Если я раскомментирую первую строку в main(), то все это сработает.

NodeFactory.h:

class NodeFactory{ 
private: 
    /// Map of factory functions 
    std::map<std::string, std::function<std::shared_ptr<Node>(void)>> mFactoryFunctions; 
public: 
    /// Get Singleton 
    static NodeFactory* Instance(); 

    /// Register Function. 
    void Register(const std::string &name, std::function<std::shared_ptr<Node>(void)> factoryFunction); 

    /// Factory Function. 
    std::shared_ptr<Node> Create(const std::string &name); 
}; 

NodeFactory.cpp:

/** 
* Get Singleton 
*/ 
NodeFactory* NodeFactory::Instance(){ 
    static NodeFactory factory; 
    return &factory; 
} 

void NodeFactory::Register(const std::string &name, std::function<std::shared_ptr<Node>(void)> factoryFunction){ 
    mFactoryFunctions[name] = factoryFunction; 
} 

std::shared_ptr<Node> NodeFactory::Create(const std::string &name){ 
    if(mFactoryFunctions.find(name) == mFactoryFunctions.end()) 
     return nullptr; 

    std::shared_ptr<Node> n = mFactoryFunctions[name](); 

    return n; 
} 

Registrar.h:

#define REGISTER_NODE_TYPE(NODE_TYPE) static NodeRegistrar<NODE_TYPE> _registrar(#NODE_TYPE); 

template<class T> 
class NodeRegistrar{ 
private: 

public: 

    NodeRegistrar(const std::string &name){ 
     NodeFactory::Instance()->Register(name, 
              [](void) -> std::shared_ptr<T> { return std::make_shared<T>(); } 
             ); 
    } 
}; 

node.h:

class Node{ 
private:   
    /// The node ID. 
    NodeID mID; 

public: 
    /* **************************** 
    * Construction & Destruction * 
    * ***************************/ 
    Node(); 
    Node(const NodeID &nodeID); 
    virtual ~Node(); 
}; 

node.cpp:

REGISTER_NODE_TYPE(Node); 

Node::Node(){ 
    mID = -1; 
} 
Node::Node(const NodeID &nodeID){ 
    mID = nodeID; 
} 

Node::~Node(){ 

} 

BuildingLot.h:

class BuildingLot : public Node{ 
public: 

    BuildingLot(); 
    BuildingLot(const NodeID &nodeID); 
    virtual ~BuildingLot(); 

}; 

BuildingLot.каст:

REGISTER_NODE_TYPE(BuildingLot); 

BuildingLot::BuildingLot(){ 

} 

BuildingLot::BuildingLot(const NodeID &nodeID):Node(nodeID){ 

} 

BuildingLot::~BuildingLot(){ 

} 

main.cpp:

int main(int argc, const char * argv[]){ 

// BuildingLot bl; // if I uncomment this, then it works 
std::shared_ptr<Node> node = NodeFactory::Instance()->Create("Node"); 
std::shared_ptr<Node> buildingLot = NodeFactory::Instance()->Create("BuildingLot"); 

if(node == nullptr) 
    std::cout << "node is nullptr" << std::endl; 
if(buildingLot == nullptr) 
    std::cout << "buildingLot is nullptr" << std::endl; 

return 0; 

}

+0

Какой у вас компилятор? Если я правильно помню, не должно быть разрешено оптимизировать конструкторы с побочными эффектами ... – Quentin

+0

В этой статье класс регистратора является шаблоном. В ваших фрагментах кода это не так. Итак, как это должно знать, какой класс зарегистрировать? – Sebastian

+3

Возможный дубликат: http://stackoverflow.com/q/1300836 Проблема заключается в фиаско порядка статического инициализации. – dyp

ответ

1

В конце концов, я выбрал вручную регистрации лямбда творцов в классе фабрики. Очень просто, если макрос создан и используется, а количество строк кода точно такое же.

Смежные вопросы