我意识到五年后我会回答这个问题。也许从那时起这种语言已经发展了一点。如果我能正确理解这个问题,我想提供一些看起来正确的东西,如果只是为了帮助其他可能发现这个问题并想知道他们能做什么的人。
factory.hpp
#include "base.hpp"
namespace tvr
{
namespace test
{
class factory
{
public:
typedef base::ptr Ptr;
enum eSpecial
{
eDerived
};
template<typename Type>
Ptr create()
{
Ptr result;
result.reset(new Type());
return result;
}
template<typename Type, typename DataType>
Ptr create(const DataType& data)
{
Ptr result;
result.reset(new Type(data));
return result;
}
template<typename Type, typename DataType>
Ptr create(const DataType& data, eSpecial tag)
{
Ptr result;
result.reset(new Type());
static_cast<Type*>(result.get())->set_item(data);
return result;
}
};
}
}
base.hpp
#include <memory>
namespace tvr
{
namespace test
{
class base
{
public:
typedef std::shared_ptr<base> ptr;
public:
base() {}
virtual ~base() {}
virtual void do_something() = 0;
};
}
}
some_class.hpp
#include <ostream>
namespace tvr
{
namespace test
{
struct some_class
{
};
}
}
std::ostream& operator<<(std::ostream& out, const tvr::test::some_class& item)
{
out << "This is just some class.";
return out;
}
template_derived.hpp
#include <iostream>
#include "base.hpp"
namespace tvr
{
namespace test
{
template<typename Type>
class template_derived : public base
{
public:
template_derived(){}
virtual ~template_derived(){}
virtual void do_something()
{
std::cout << "Doing something, like printing _item as \"" << _item << "\"." << std::endl;
}
void set_item(const Type data)
{
_item = data;
}
private:
Type _item;
};
}
}
最后是 main.cpp
#include <vector>
#include "base.hpp"
#include "factory.hpp"
namespace tvr
{
namespace test
{
typedef std::vector<tvr::test::base::ptr> ptr_collection;
struct iterate_collection
{
void operator()(const ptr_collection& col)
{
for (ptr_collection::const_iterator iter = col.begin();
iter != col.end();
++iter)
{
iter->get()->do_something();
}
}
};
}
}
#include "template_derived.hpp"
#include "some_class.hpp"
namespace tvr
{
namespace test
{
inline int test()
{
ptr_collection items;
tvr::test::factory Factory;
typedef template_derived<unsigned int> UIntConcrete;
typedef template_derived<double> DoubleConcrete;
typedef template_derived<std::string> StringConcrete;
typedef template_derived<some_class> SomeClassConcrete;
items.push_back(Factory.create<SomeClassConcrete>(some_class(), tvr::test::factory::eDerived));
for (unsigned int i = 5; i < 7; ++i)
{
items.push_back(Factory.create<UIntConcrete>(i, tvr::test::factory::eDerived));
}
items.push_back(Factory.create<DoubleConcrete>(4.5, tvr::test::factory::eDerived));
items.push_back(Factory.create<StringConcrete>(std::string("Hi there!"), tvr::test::factory::eDerived));
iterate_collection DoThem;
DoThem(items);
return 0;
}
}
}
int main(int argc, const char* argv[])
{
tvr::test::test();
}
输出
Doing something, like printing _item as "This is just some class.".
Doing something, like printing _item as "5".
Doing something, like printing _item as "6".
Doing something, like printing _item as "4.5".
Doing something, like printing _item as "Hi there!".
这使用模板、函数重载和通过枚举标记的组合来帮助创建一个灵活的工厂类,它不需要了解它实例化的各个类,包括 OP 询问的模板化具体类。
“eDerived”标签(以枚举的形式)告诉编译器使用工厂的 create 函数版本,该函数采用像 template_derived 类这样的类,它有一个函数允许我将数据分配给其中一个其成员。从我在 main.cpp 中订购标头的方式可以看出,工厂对 template_derived 一无所知。调用基类的虚函数(do_something)的函数也没有。我认为这是 OP 想要的,但不必在该工厂可能生成的每个类中添加各种创建函数。
我还展示了如何不必为工厂应该创建的每个类显式创建函数。工厂的重载创建函数可以创建从基类派生的任何与适当签名匹配的东西。
我没有对这段代码进行广泛的性能分析,但我已经做了足够多的工作来发现大部分工作都发生在流式操作符中。在我的 3.30Ghz 四核机器上编译大约需要 1 秒。您可能需要尝试使用更健壮的代码,以了解它可能会使编译器陷入多么严重的困境(如果有的话)。
我已经在 VC++ 2015 中测试了这段代码,尽管它可能很容易在其他编译器中工作。如果要复制此内容,则需要添加自己的保护标头。无论如何,我希望这是有用的。