C ++ Abstract Factory使用模板

时间:2010-12-05 05:18:09

标签: c++ templates factory-pattern

我正在尝试在C ++中为多个抽象工厂创建一个抽象工厂模板,并想出了这个。

#define _CRTDBG_MAP_ALLOC
#include <crtdbg.h>
#include <map>
#include <stdio.h>

class Base
{
public:
    virtual ~Base() {}

    virtual bool Get() = 0;
};

class DerivedA : public Base
{
public:
    bool Get()
    {
        return true;
    }
};

class DerivedB : public Base
{
public:
    bool Get()
    {
        return false;
    }
};

template <class T>
class Creator
{
public:
    virtual ~Creator(){}
    virtual T* Create() = 0;
};

template <class T>
class DerivedCreator : public Creator<T>
{
public:
    T* Create()
    {
        return new T;
    }
};

template <class T, class Key>
class Factory
{
public:
    void Register(Key Id, Creator<T>* Fn)
    {
        FunctionMap[Id] = Fn;
    }

    T* Create(Key Id)
    {
        return FunctionMap[Id]->Create();
    }

    ~Factory()
    {
        std::map<Key, Creator<T>*>::iterator i = FunctionMap.begin();
        while (i != FunctionMap.end())
        {
            delete (*i).second;
            ++i;
        }
    }
private:
    std::map<Key, Creator<T>*> FunctionMap;
};

int main(int argc, char** argv[])
{
    _CrtSetDbgFlag(_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) | _CRTDBG_LEAK_CHECK_DF);

    //Register
    Factory<Base, char*> temp;
    temp.Register("DA", (Creator<Base>*)new DerivedCreator<DerivedA>);
    temp.Register("DB", (Creator<Base>*)new DerivedCreator<DerivedB>);

    //Pointer to base interface
    Base* pBase = 0;

    //Create and call
    pBase = temp.Create("DA");
    printf("DerivedA %u\n", pBase->Get());
    delete pBase;

    //Create and call
    pBase = temp.Create("DB");
    printf("DerivedB %u\n", pBase->Get());
    delete pBase;

 return 0;
}

它编译并运行良好,没有内存泄漏(win32 crtdbg),但我不知道这是否真的是一个抽象工厂模板的正确方法。

temp.Register("DA", (Creator<Base>*)new DerivedCreator<DerivedA>);

我也想知道上面这一行。我很困惑为什么我要演员。我不太了解模板,但我认为考虑到模板类和实际类都是派生的,它应该工作正常。

如上所示,该代码实际上工作正常,甚至删除没有内存泄漏的罚款。我对它感到不舒服。

我无法找到任何模板类的真实示例,除了来自MaNGOS(哇模拟器) - https://mangos.svn.sourceforge.net/svnroot/mangos/trunk/src/framework/Dynamic/ObjectRegistry.h

但是我不认为我可以在我的项目中使用该方法,因为我计划在项目的某个时刻使用DLL,它使用CRTP,这违反了我对运行时多态性的要求。

3 个答案:

答案 0 :(得分:12)

班级DerivedCreator<DerivedA>Creator<DerivedA>而不是Creator<Base>

您需要告诉派生模板基本类型是什么,以便通过创建派生类型的实例来实现Creator<Base>的接口:

// DerivedCreator is Creator<BaseType> which creates a 
// DerivedType, not a Creator<DerivedType>
template <class DerivedType, class BaseType>
class DerivedCreator : public Creator<BaseType>
{
public:
    BaseType* Create()
    {
        return new DerivedType;
    }
};

// Register
Factory<Base, std::string> temp;
temp.Register("DA", new DerivedCreator<DerivedA, Base>);
temp.Register("DB", new DerivedCreator<DerivedB, Base>);

// or if you want to create lots with the same base:
template <class DerivedType>
class DerivedBaseCreator : public DerivedCreator<DerivedType, Base> {};

//Register
Factory<Base, std::string> temp;
temp.Register("DA", new DerivedBaseCreator<DerivedA>);
temp.Register("DB", new DerivedBaseCreator<DerivedB>);

答案 1 :(得分:0)

改善设计的小言论: 1)使用shared_ptr而不是原始指针 2)使用std :: string而不是char *

你必须施放,因为类型造物主,造物主和造物主&lt; DerivedB&gt;是完全不同的类型。解决方法是删除强制转换:

//Register
Factory<Base, char*> temp;
temp.Register("DA", new DerivedCreator<Base>);
temp.Register("DB", new DerivedCreator<Base>);

答案 2 :(得分:-1)

您可以使Factory :: Register成为模板方法,并在

中使用boost mpl assert
#include <boost/mpl/assert.hpp>
#include <boost/type_traits.hpp>

template <class T, class Key>
class Factory
{
public:
///////////////////////////////////
template <typename _Base>
void Register(Key Id, Creator<_Base> * Fn)
{
    BOOST_MPL_ASSERT((boost::is_base_of<T, _Base>));

    FunctionMap[Id] = reinterpret_cast<Creator<T>*>(Fn);
}
///////////////////////////////////
//...
};