我正在尝试在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,这违反了我对运行时多态性的要求。
答案 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);
}
///////////////////////////////////
//...
};