Я реализовал фабричный класс на основе следующей статьи, доступной здесь.
Однако у меня есть одна проблема, и я думаю, что она связана с оптимизацией компилятора.
У меня есть иерархия классов, где класс Node (в Node.h / Node.cpp) является базовым классом и, например, BuildingLot (в BuildingLot.h / BuildingLot.cpp) является подклассом.
В обоих исходных файлах, объявленных как статические, у меня есть класс Registrar.
Node.cpp:
static Registrar<Node> _registrar(“Node”);
BuildingLot.cpp:
static Registrar<BuildingLot> _registrar(“BuildingLot”);
Если я попытаюсь использовать Factory, он отлично подойдет для класса Node. Однако мне нужно сначала создать экземпляр BuildingLot, чтобы он был зарегистрирован на фабрике.
В модульном тесте у меня есть:
NodePtr node = Factory::Instance()->Create(“Node”);
NodePtr bl = Factory::Instance()->Create(“BuildingLot”);
bl всегда имеет значение nullptr. Конструктор Registrar никогда не выполняется, и поэтому класс Factory никогда не знает о классе BuildingLot. Если я сделаю это:
BuildingLot b;
NodePtr node = Factory::Instance()->Create(“Node”);
NodePtr bl = Factory::Instance()->Create(“BuildingLot”);
Тогда все работает. Вызывается Регистратор, и Фабрика создает BuildingLot.
Я думаю, поскольку BuildingLot не используется в первом примере, компилятор оптимизировал и даже не компилировал BuildingLot.cpp.
Это возможно? Как я могу это решить?
Изменить: класс Registrar, по сути, является классом шаблона. Я просто забыл вставить параметры шаблона.
Вот мой код настолько простой, насколько я мог его сделать. Надеюсь, я ничего не упустил. Если я раскомментирую первую строку в 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.cpp:
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;
}
main
. Если инициализация откладывается на некоторый момент времени после первого оператораmain
, она должна произойти до первого odr-использования любой функции или переменной, определенной в той же единице трансляции, что и инициализируемая переменная. - person dyp   schedule 29.08.2014MyFactory::CreateInstance()
имеет очень странную реализацию. - person BЈовић   schedule 09.09.2014