使用模板的 C++ 抽象工厂

标签 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 (wow emulator) - https://mangos.svn.sourceforge.net/svnroot/mangos/trunk/src/framework/Dynamic/ObjectRegistry.h 的模板类之外,我还没有找到任何真实的模板类示例。

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

最佳答案

类(class)DerivedCreator<DerivedA>Creator<DerivedA>不是 Creator<Base> .

你需要告诉派生模板是什么基类型,这样它才能实现Creator<Base>的接口(interface)。通过创建派生类型的实例:

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

关于使用模板的 C++ 抽象工厂,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4357500/

相关文章:

c++ - 如何为 KDChart BarDiagram 设置固定范围?

c++ - c++模板中的多个类型名参数? (可变参数模板)

c++ - GoogleMock,out参数返回,正常返回,消费数组

c++ - 编译器是否为每个 lambda 生成不同的类型?

c++ - 检查 lambda 是否为 noexcept

c++ - 多态对象复制

inversion-of-control - 命名对象列表的 IoC

c++ - 在函数调用中使用模板模板参数

c++ - 在哪种情况下 if(a=b) 是个好主意?

c++ - 强制退出时无法写入文件