我需要一种基于作为std :: string传递的类名来实例化对象的方法。这项目前正在发挥作用,但需要进行概括:
void* create(std::string name) {
if(name == "classOne") return new ClassOne();
else if(name == "classTwo") return new ClassTwo();
/* ... */
}
我没有:
还有其他事情。
最佳用例场景将是:
int main() {
void *obj = create("classTree"); // create object based on the string name
/* ... */
// once we know by context which specific class we are dealing with
ClassTree *ct = (ClassTree*)obj; // cast to appropiate class
std::cout << ct->getSomeText() << std::endl; // use object
}
作为一方,也许是不相关的注释,请注意要实例化的对象可能来自类或结构。
添加信息
我看到需要更多背景。这是我的特定用例,简化:
// registration mechanism
int main() {
std::map< std::string, void(*func)(std::string, void*) > processors; // map of processors by class name
processors["ClassFour"] = (void(*)(std::string, void*)) &classFourMessageProcessor; // register processor (cast needed from specific to generic)
}
// function receiving string messages
void externalMessageHandler(std::string msg) {
std::string objType = extractTypeFromMessageHeader(msg); // extract type from message
// now that we know what we are dealing with, create the specific object
void *obj = create(objType); // << creator needed
processors[objType](msg, obj); // dispatch message to process
}
// previously registered message processor
void classFourMessageProcessor(std::String msg, ClassFour *obj) {
std::string streetAddress = msg.substr(10, 15); // knowing the kind of message we can extract information
obj->moveTheEtherTo(streetAddress); // use the created object
}
添加信息
我正在使用C ++ 11和最新的GNU编译器。
答案 0 :(得分:3)
您可以为每个类类型存储工厂函数。一种简单的方法是使用模板
template <typename T>
void* creator() {
return new T();
}
并将其存储在地图中(即“ClassFour”链接到creator<ClassFour>
和ClassFourMessageProcessor
)。
编辑:为了澄清,processors
变为
typedef void* (*CreatorFunc)();
typedef void (*ProcessorFunc)(std::string, void*);
typedef std::pair<CreatorFunc, ProcessorFunc> Entry;
std::map< std::string, Entry > processors;
添加新类就像
一样简单processors["SomeClass"] = Entry(creator<SomeClass>, ClassFourMessageProcessor);
答案 1 :(得分:0)
这是一个:
现在您没有对类进行任何更改,并且可以添加更多类而无需重新编程工厂。 您可能至少将#1作为模板 - 确保编译器实例化特定实现。
答案 2 :(得分:0)
也许以下关于lokup表的方法将是一个很好的解决方案。
(注意:我不知道您使用的编译器是什么,因此这个解决方案适用于c ++ 03,如果您使用的是支持c ++ 11的编译器,则可以使用unordered_map代替map)
(注2:你也可以使用智能指针,并处理返回值,在这个例子中我只想表示一个方法)
#include <iostream>
#include <string>
#include <map>
#include <vector>
struct ClassMaker
{
virtual void* getInstance() const = 0;
virtual ~ClassMaker() {}
};
class Factory
{
private:
std::map<std::string, ClassMaker*> lokupTable;
typedef typename std::map<std::string, ClassMaker*>::iterator Iterator;
public:
void addClass(const std::string& key, ClassMaker* const newClassMaker)
{
lokupTable[key] = newClassMaker;
}
void* create(const std::string& key)
{
void* result = NULL;
Iterator it = lokupTable.find(key);
if(it != lokupTable.end())
result = (it->second)->getInstance();
return result;
}
void releaseTable()
{
for (Iterator it = lokupTable.begin(); it != lokupTable.end(); ++it)
delete it->second;
}
};
struct IntCreator : public ClassMaker
{
void* getInstance() const
{
return new int;
}
};
struct StringCreator : public ClassMaker
{
void* getInstance() const
{
return new std::string;
}
};
int main()
{
Factory myFactory;
myFactory.addClass("int", new IntCreator);
myFactory.addClass("string", new StringCreator);
int* myInt = reinterpret_cast<int*>(myFactory.create("int"));
*myInt = 10;
std::cout<< *myInt << std::endl;
delete myInt;
myFactory.releaseTable();
return 0;
}
答案 3 :(得分:-1)
你会考虑Boost.MPL吗?与STL不同,它允许创建包含类型而非实例的容器。从字符串到类型的地图会给你想要的工厂,不是吗?