2015-10-22 2 views
2

Я попытался реализовать статический шаблон фабрики с шаблоном: a) void писать одинаковый фрагмент кода для каждого производного класса и b) перерабатывать объекты того же типа. Код ниже компилируется, но не работает. Не уверен, что это было потому, что я использовал умные указатели.Как реализовать статический заводской шаблон в C++

Это мой код:

class ObjMgr 
{ 
public: 
    static ObjMgr & Instance(); 
    template <typename T> 
    void Register(const char* name) { 
     m_creators[name] = &(ObjCreator<T>); 
    } 
    Abstract & 
     GetObj(const string& objTypeCode); 

private: 
    ObjMgr(void) {}; 

    template <typename T> 
    static shared_ptr<Abstract>& ObjCreator() { 
     return move(std::shared_ptr<Abstract> (new T)); 
    } 
    typedef shared_ptr<Abstract>& (*PObjCreator)(); 
    std::unordered_map<std::string, PObjCreator> m_creators; 

    vector< shared_ptr<Abstract> > m_objs; 

    //singleton 
    static unique_ptr<ObjMgr> m_instance; 
    static std::once_flag m_onceFlag; 
    ObjMgr(const ObjMgr &) = default; 
    ObjMgr& operator=(const ObjMgr &) = default; 
}; 

Abstract& ObjMgr::GetObj(const string& objTypeCode) 
{ 
    const shared_ptr<Abstract>& obj = m_creators[objTypeCode](); 
    m_objs.push_back(move(obj)); 

    return *(m_objs.back()); 
} 

Код компилируется, но во время выполнения, пустая ссылка была возвращена GetObj. В main(), производный тип зарегистрирован как

objMgr.Register<Derived>("Derived"); 

BTV, я использовал вектор для хранения объектов таким образом, чтобы я мог позже переработать объект того же типа.

Может ли кто-нибудь сказать мне, что я сделал не так, и показать, как я могу это исправить?

+0

* BTW, я использовал вектор, чтобы удерживать объекты, чтобы впоследствии я мог перерабатывать объект того же типа. * - То же самое значит, что вы держите адрес адреса, который находится в векторе, чтобы быть используется для «последующей утилизации»? – PaulMcKenzie

+3

Можете ли вы предоставить [Минимальный, полный и проверенный пример] (http://stackoverflow.com/help/mcve), который может воспроизвести проблему? –

ответ

0

Я думаю, может быть, ваш регистр (const char * name) и строка unordered_map <, ... > находятся в конфликте. Измените unordered_map на unordered_map < const char *, ... >.

Я не мог скомпилировать ваш код.

Следующий код работает:

Обратите внимание, что обычный способ я сделал это, чтобы использовать Singleton < T> шаблон, так как он кажется, что вы хотите, чтобы всегда получать один и тот же экземпляр.

Если вы хотите, чтобы иметь возможность возвращать разные экземпляры, измените код в ObjectManager :: CreatorFunc, чтобы переменная 'instance' не была статичной, а скорее локальной переменной или передала другой CreatorFunc для регистрации.

stdafx.h:

#include "targetver.h" 

#include <stdio.h> 
#include <tchar.h> 

#include <unordered_map> 
#include <memory> 
#include <mutex> 
#include <iostream> 

каст:

#include "stdafx.h" 

class Abstract 
{ 
}; 

template <typename T> 
class Singleton : public Abstract 
{ 
private: 
    static T* m_singleton; 

public: 
    static T& Instance() 
    { 
     if (m_singleton == 0) 
     { 
      m_singleton = new T(); 
     } 
     return *m_singleton; 
    } 
}; 

template <typename T> T* Singleton<T>::m_singleton; 

class ObjectManager : public Singleton<ObjectManager> 
{ 
private: 
    typedef Abstract& (*CreatorFuncType)(); 
    std::unordered_map<const char*, CreatorFuncType> m_creators; 

    template <typename T> 
    static T& CreatorFunc() 
    { 
     static T* const instance = new T(); 
     return *instance; 
    } 

public: 
    template <typename T> 
    void Register(const char* name, CreatorFuncType creator = (CreatorFuncType)CreatorFunc<T>) 
    { 
     m_creators[name] = creator == 0 ? (CreatorFuncType)Singleton<T>::Instance : creator; 
    } 

    Abstract& ObjectManager::GetObj(const char* name) 
    { 
     CreatorFuncType creator = m_creators[name]; 
     return (creator)(); 
    } 
}; 

class TestClass : Singleton<TestClass> 
{ 
    static int count; 

    int myInstance; 
public: 

    TestClass() 
     : myInstance(++count) 
    { 
     std::cout << "hello in test class ctor instance #" << myInstance << std::endl; 
    } 

    void TestFunc() 
    { 
     std::cout << "I'm in the test func with instance #" << myInstance << std::endl; 
    } 
}; 

int TestClass::count = 0; 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    ObjectManager::Instance().Register<TestClass>("TestClass"); 
    TestClass &tc = (TestClass&)ObjectManager::Instance().GetObj("TestClass"); 
    TestClass &tc2 = (TestClass&)ObjectManager::Instance().GetObj("TestClass"); 

    std::cout << "tc == tc2 is " << (&tc == &tc2 ? "true" : "false") << std::endl; 
    std::cout << "tc.... "; 
    tc.TestFunc(); 
    std::cout << "tc2... "; 
    tc2.TestFunc(); 

    char buf[100]; 
    std::cin >> buf; 
    return 0; 
} 
1

Я нашел проблему: объект был создан на стеке в ObjCreator(). Я просто нужно создать статические переменные для хранения объектов:

template <typename T> 
static shared_ptr<Abstract>& ObjCreator() { 
    static vector<shared_ptr<Abstract>> objs; 
    objs.emplace_back(std::make_shared<T>()); 
    return (objs.back()); 
} 

И тогда в ObjMgr я буду делать бухгалтерию, чтобы увидеть, если объект определенного типа уже существует, так что я могу переработать его.

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