如何在C ++中实现静态工厂模式

时间:2015-10-22 22:01:04

标签: c++ static-methods smart-pointers factory-pattern

我尝试使用模板实现静态工厂模式a)void为每个派生类编写相同的代码片段,以及b)回收相同类型的对象。下面的代码编译但不起作用。不确定这是不是因为我使用了智能指针。

这是我的代码:

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");

顺便说一句,我使用了一个向量来保存对象,以便以后可以回收相同类型的对象。

有人能告诉我我做错了什么并告诉我如何纠正它吗?

2 个答案:

答案 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我将进行簿记,以查看特定类型的对象是否已经存在,以便我可以回收它。

答案 1 :(得分:0)

我想也许是你的Register(const char * name)方法和unordered_map&lt; string,...&gt;有冲突。将unordered_map更改为unordered_map&lt; const char *,...&gt;代替。

我无法编译你的代码。

以下代码有效:

请注意,我通常采用的方法是使用Singleton&lt; T&gt;。模板,因为它似乎总是想要获得相同的实例。

如果您希望能够返回不同的实例,请更改ObjectManager :: CreatorFunc中的代码,以便&#39;实例&#39;变量不是静态的,而是局部变量或将不同的CreatorFunc传递给Register。

stdafx.h中:

#include "targetver.h"

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

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

CPP:

#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;
}