我有一个文件: Base.h
class Base;
class DerivedA : public Base;
class DerivedB : public Base;
/*etc...*/
和另一个文件: BaseFactory.h
#include "Base.h"
class BaseFactory
{
public:
BaseFactory(const string &sClassName){msClassName = sClassName;};
Base * Create()
{
if(msClassName == "DerivedA")
{
return new DerivedA();
}
else if(msClassName == "DerivedB")
{
return new DerivedB();
}
else if(/*etc...*/)
{
/*etc...*/
}
};
private:
string msClassName;
};
/*etc.*/
有没有办法将这个字符串转换成实际的类型(类),这样BaseFactory就不必知道所有可能的派生类,并为每个派生类都使用if()?我能从这个字符串中产生一个类吗?
我认为这可以通过反射在C#中完成。在C++中有类似的东西吗?
发布于 2009-02-24 16:30:29
不,没有,除非你自己做映射。C++没有创建其类型在运行时确定的对象的机制。不过,您可以使用map自己完成该映射:
template<typename T> Base * createInstance() { return new T; }
typedef std::map<std::string, Base*(*)()> map_type;
map_type map;
map["DerivedA"] = &createInstance<DerivedA>;
map["DerivedB"] = &createInstance<DerivedB>;
然后你就可以
return map[some_string]();
正在获取新实例。另一个想法是让类型自己注册:
// in base.hpp:
template<typename T> Base * createT() { return new T; }
struct BaseFactory {
typedef std::map<std::string, Base*(*)()> map_type;
static Base * createInstance(std::string const& s) {
map_type::iterator it = getMap()->find(s);
if(it == getMap()->end())
return 0;
return it->second();
}
protected:
static map_type * getMap() {
// never delete'ed. (exist until program termination)
// because we can't guarantee correct destruction order
if(!map) { map = new map_type; }
return map;
}
private:
static map_type * map;
};
template<typename T>
struct DerivedRegister : BaseFactory {
DerivedRegister(std::string const& s) {
getMap()->insert(std::make_pair(s, &createT<T>));
}
};
// in derivedb.hpp
class DerivedB {
...;
private:
static DerivedRegister<DerivedB> reg;
};
// in derivedb.cpp:
DerivedRegister<DerivedB> DerivedB::reg("DerivedB");
您可以决定为注册创建一个宏
#define REGISTER_DEC_TYPE(NAME) \
static DerivedRegister<NAME> reg
#define REGISTER_DEF_TYPE(NAME) \
DerivedRegister<NAME> NAME::reg(#NAME)
不过,我相信这两个人还有更好的名字。这里使用的另一个可能有意义的东西是shared_ptr
。
如果你有一组没有公共基类的无关类型,你可以给函数指针一个返回类型boost::variant<A, B, C, D, ...>
。例如,如果你有一个类Foo,Bar和Baz,它看起来像这样:
typedef boost::variant<Foo, Bar, Baz> variant_type;
template<typename T> variant_type createInstance() {
return variant_type(T());
}
typedef std::map<std::string, variant_type (*)()> map_type;
boost::variant
就像一个联盟。通过查看用于初始化或赋值的对象,它知道存储在其中的是哪种类型。请看一下它的文档here。最后,原始函数指针的使用也有点陈旧。现代C++代码应该与特定的函数/类型解耦。您可能希望研究一下Boost.Function
以寻找更好的方法。它看起来就像这样(地图):
typedef std::map<std::string, boost::function<variant_type()> > map_type;
包括std::shared_ptr
在内的下一个版本的C++也将支持std::function
。
发布于 2009-02-24 16:08:49
没有。我对这个问题的首选解决方案是创建一个字典,它将名称映射到创建方法。想要像这样创建的类,然后用字典注册一个创建方法。在GoF patterns book中详细讨论了这一点。
发布于 2013-08-15 21:25:00
functional有一个非常灵活的工厂模板:http://www.boost.org/doc/libs/1_54_0/libs/functional/factory/doc/html/index.html
不过,我更喜欢生成隐藏映射和对象创建机制的包装类。我遇到的常见场景是需要将一些基类的不同派生类映射到键,其中派生类都有一个可用的公共构造函数签名。这是我到目前为止想出的解决方案。
#ifndef GENERIC_FACTORY_HPP_INCLUDED
//BOOST_PP_IS_ITERATING is defined when we are iterating over this header file.
#ifndef BOOST_PP_IS_ITERATING
//Included headers.
#include <unordered_map>
#include <functional>
#include <boost/preprocessor/iteration/iterate.hpp>
#include <boost/preprocessor/repetition.hpp>
//The GENERIC_FACTORY_MAX_ARITY directive controls the number of factory classes which will be generated.
#ifndef GENERIC_FACTORY_MAX_ARITY
#define GENERIC_FACTORY_MAX_ARITY 10
#endif
//This macro magic generates GENERIC_FACTORY_MAX_ARITY + 1 versions of the GenericFactory class.
//Each class generated will have a suffix of the number of parameters taken by the derived type constructors.
#define BOOST_PP_FILENAME_1 "GenericFactory.hpp"
#define BOOST_PP_ITERATION_LIMITS (0,GENERIC_FACTORY_MAX_ARITY)
#include BOOST_PP_ITERATE()
#define GENERIC_FACTORY_HPP_INCLUDED
#else
#define N BOOST_PP_ITERATION() //This is the Nth iteration of the header file.
#define GENERIC_FACTORY_APPEND_PLACEHOLDER(z, current, last) BOOST_PP_COMMA() BOOST_PP_CAT(std::placeholders::_, BOOST_PP_ADD(current, 1))
//This is the class which we are generating multiple times
template <class KeyType, class BasePointerType BOOST_PP_ENUM_TRAILING_PARAMS(N, typename T)>
class BOOST_PP_CAT(GenericFactory_, N)
{
public:
typedef BasePointerType result_type;
public:
virtual ~BOOST_PP_CAT(GenericFactory_, N)() {}
//Registers a derived type against a particular key.
template <class DerivedType>
void Register(const KeyType& key)
{
m_creatorMap[key] = std::bind(&BOOST_PP_CAT(GenericFactory_, N)::CreateImpl<DerivedType>, this BOOST_PP_REPEAT(N, GENERIC_FACTORY_APPEND_PLACEHOLDER, N));
}
//Deregisters an existing registration.
bool Deregister(const KeyType& key)
{
return (m_creatorMap.erase(key) == 1);
}
//Returns true if the key is registered in this factory, false otherwise.
bool IsCreatable(const KeyType& key) const
{
return (m_creatorMap.count(key) != 0);
}
//Creates the derived type associated with key. Throws std::out_of_range if key not found.
BasePointerType Create(const KeyType& key BOOST_PP_ENUM_TRAILING_BINARY_PARAMS(N,const T,& a)) const
{
return m_creatorMap.at(key)(BOOST_PP_ENUM_PARAMS(N,a));
}
private:
//This method performs the creation of the derived type object on the heap.
template <class DerivedType>
BasePointerType CreateImpl(BOOST_PP_ENUM_BINARY_PARAMS(N,const T,& a))
{
BasePointerType pNewObject(new DerivedType(BOOST_PP_ENUM_PARAMS(N,a)));
return pNewObject;
}
private:
typedef std::function<BasePointerType (BOOST_PP_ENUM_BINARY_PARAMS(N,const T,& BOOST_PP_INTERCEPT))> CreatorFuncType;
typedef std::unordered_map<KeyType, CreatorFuncType> CreatorMapType;
CreatorMapType m_creatorMap;
};
#undef N
#undef GENERIC_FACTORY_APPEND_PLACEHOLDER
#endif // defined(BOOST_PP_IS_ITERATING)
#endif // include guard
我通常反对大量使用宏,但在这里我有一个例外。上面的代码生成一个名为GenericFactory_N的类的GENERIC_FACTORY_MAX_ARITY +1个版本,对于0和GENERIC_FACTORY_MAX_ARITY之间的每个N,包括0和GENERIC_FACTORY_MAX_ARITY。
使用生成的类模板很容易。假设您希望工厂使用字符串映射创建BaseClass派生对象。每个派生对象都接受3个整数作为构造函数参数。
#include "GenericFactory.hpp"
typedef GenericFactory_3<std::string, std::shared_ptr<BaseClass>, int, int int> factory_type;
factory_type factory;
factory.Register<DerivedClass1>("DerivedType1");
factory.Register<DerivedClass2>("DerivedType2");
factory.Register<DerivedClass3>("DerivedType3");
factory_type::result_type someNewObject1 = factory.Create("DerivedType2", 1, 2, 3);
factory_type::result_type someNewObject2 = factory.Create("DerivedType1", 4, 5, 6);
GenericFactory_N类析构函数是虚拟的,以允许执行以下操作。
class SomeBaseFactory : public GenericFactory_2<int, BaseType*, std::string, bool>
{
public:
SomeBaseFactory() : GenericFactory_2()
{
Register<SomeDerived1>(1);
Register<SomeDerived2>(2);
}
};
SomeBaseFactory factory;
SomeBaseFactory::result_type someObject = factory.Create(1, "Hi", true);
delete someObject;
请注意,泛型工厂生成器宏的这一行
#define BOOST_PP_FILENAME_1 "GenericFactory.hpp"
假定通用工厂头文件名为GenericFactory.hpp
https://stackoverflow.com/questions/582331
复制相似问题