在线搜索了工厂模式的不同方法后,我实现了自己的版本,我非常满意。 Register 成员函数为模板类型创建一个函数指针,使用索引作为键将其存储在 std :: map 中。下面的代码编译和运行没有麻烦(Windows 7 64位,Code :: Blocks 10.05与GCC)。
#ifndef OBJECT_FACTORY_HPP
#define OBJECT_FACTORY_HPP
#include <map>
namespace internal {
template<typename BaseType, typename ObjectType>
BaseType* CreateFunction() {
return new ObjectType;
}
}
template<typename BaseType, typename IndexType>
class ObjectFactory {
public:
ObjectFactory();
template<typename ObjectType>
bool Register(const IndexType& index);
bool Unregister(const IndexType& index);
BaseType* Create(const IndexType& index);
private:
typedef BaseType* (*creationCallback)();
typedef std::map<IndexType, creationCallback> Registry;
Registry registry;
// private:
// template<typename ObjectType>
// BaseType* CreateFunction();
};
template<typename BaseType, typename IndexType>
ObjectFactory<BaseType, IndexType>::ObjectFactory() {
registry.clear();
}
template<typename BaseType, typename IndexType>
template<typename ObjectType>
bool ObjectFactory<BaseType, IndexType>::Register(const IndexType& index) {
if (registry.find(index) != registry.end())
return false;
registry[index] = &internal::CreateFunction<BaseType, ObjectType>;
// registry[index] = &CreateFunction<ObjectType>; <-- FAILS!
return true;
}
template<typename BaseType, typename IndexType>
bool ObjectFactory<BaseType, IndexType>::Unregister(const IndexType& type) {
if (registry.find(type) == registry.end())
return false;
return (registry.erase(type) == 1);
}
template<typename BaseType, typename IndexType>
BaseType* ObjectFactory<BaseType, IndexType>::Create(const IndexType& index) {
if (registry.find(index) == registry.end())
return NULL;
return registry[index]();
}
//template<typename BaseType, typename IndexType>
//template<typename ObjectType>
//BaseType* ObjectFactory<BaseType, IndexType>::CreateFunction() {
// return new ObjectType();
//}
#endif
我最初的方法是将 CreateFunction 作为私有成员从用户隐藏它(查看注释部分,注意非成员函数需要一个额外的模板参数)。但是,这会失败并显示以下错误消息,所有这些消息都指向我将函数指针存储在 Register 成员函数中的行:
In member function 'bool ObjectFactory<BaseType, IndexType>::Register(const IndexType&) [with ObjectType = Triangle, BaseType = Shape, IndexType = std::basic_string<char, std::char_traits<char>, std::allocator<char> >]':|
instantiated from here
error: no matches converting function 'CreateFunction' to type 'class Shape* (*)()'|
error: candidates are: template<class ObjectType> BaseType* ObjectFactory::CreateFunction() [with ObjectType = ObjectType, BaseType = Shape, IndexType = std::basic_string<char, std::char_traits<char>, std::allocator<char> >]|
我写了一个小测试客户端进行测试:
#include "ObjectFactory.hpp"
#include <iostream>
class Shape {
public:
Shape() {}
virtual void print() { std::cout << "At heart, I'm a shape"; }
};
class Triangle : public Shape {
public:
Triangle() {}
void print() { Shape::print(); std::cout << ", but I'm truly a triangle" << std::endl; }
};
int main(int argc, char* argv[]) {
ObjectFactory<Shape, std::string> objectFactory;
objectFactory.Register<Triangle>("triangle");
Shape* triangle = objectFactory.Create("triangle");
triangle->print();
delete triangle;
return 0;
}
这甚至可能吗?我觉得它应该是,我明白我在某种程度上调用了不正确的成员函数,但我不明白为什么。在相关的说明中,由于有人可能会提及它,我计划使用* boost :: shared_ptr *进行分配而不是普通的新运算符;)也欢迎任何其他有关实现的建议或建议。
答案 0 :(得分:1)
在我们的文件中,我们匿名我们的命名空间:
// namespace internal {
namespace {
template<typename BaseType, typename ObjectType>
BaseType* CreateFunction() { ... }
}
现在可以按照最初编写的方式调用非静态函数,而无需命名空间限定:
// registry[index] = &internal::CreateFunction<ObjectType>;
registry[index] = &CreateFunction<ObjectType>;
文件范围的CreateFunction
函数对于翻译单元之外的代码是不可见的,只能由类ObjectFactory
调用。
这很好地接近问题中提出的private
{来自CreateFunction
)的ObjectFactory
访问说明符。
答案 1 :(得分:0)
创建函数应该是静态成员:
template<typename ObjectType> static BaseType* CreateFunction();
(上面的代码,没有static
,在您的示例中已注释掉了。)
现在您的其他已注释掉的代码有效:
registry[index] = &CreateFunction<ObjectType>;
编辑:澄清一些困惑:
这里的问题主要是语法问题。模板和private
在这里并不重要,所以让我们简化一下情况:
struct ObjectFactory {
void CreateFunction() {std::cout << "message";}
void AnotherFunction()
{
... = &CreateFunction; // what's that?
}
};
如果CreateFunction
是非静态成员函数,则语法&CreateFunction
不正确;我猜gcc抱怨的就是这个。然而,更糟糕的是,MS Visual Studio试图通过内部“纠正”&ObjectFactory::CreateFunction
的语法并尝试使用它来“帮助”你;但它失败了,有无法理解的错误信息(事实上,你有模板会使它们更加恶化)。
我不确定Visual Studio部分(我记得几年前在MSVC 6上遇到过这样的问题;较新版本的Visual Studio没有这个问题。)