您需要为希望通过这种方式构建的每个类实例化一个工厂函数。以下代码向您展示了如何做到这一点,而不必重复使用静态成员,也无需手动编写许多不同的函数:
#include <iostream>
#include <map>
#include <functional>
#include <string>
#include <memory>
struct Parent{
Parent(std::string){}
};
struct Child1 : public Parent{
Child1(std::string d) : Parent(d){
std::cout << "Child1 constructor: " << d << std::endl;
}
};
struct Child2 : public Parent{
Child2(std::string d) : Parent(d){
std::cout << "Child2 constructor: " << d << std::endl;
}
};
template <typename Product, typename Return, typename Parameter>
Return factory(const Parameter& a){
return Return(new Product(a));
}
std::map<std::string, std::function<Parent*(std::string)> > mrp;
std::map<std::string, std::function<std::shared_ptr<Parent>(std::string)> > msp;
int main(){
mrp["Child1"] = &factory<Child1, Parent*, std::string>;
mrp["Child2"] = &factory<Child2, Parent*, std::string>;
Parent* a = mrp["Child1"]("one");
delete a;
std::unique_ptr<Parent> b(mrp["Child2"]("two"));
msp["Child1"] = &factory<Child1, std::shared_ptr<Parent>, std::string>;
msp["Child2"] = &factory<Child2, std::shared_ptr<Parent>, std::string>;
msp["Child1"]("one");
msp["Child2"]("two");
}
在这里试试这个代码。此外,如您所见,此方法可以“配置”为使用 std::shared_ptr、原始指针……并具有不同的所有权语义,请注意以下行:
std::unique_ptr<Parent> b(mrp["Child2"]("two"));
但是,您在问题中简要描述的任何变体都是它的变体!您正在尝试做的是一个抽象工厂,它的“标准”实现完全依赖于为您要构建的每个类创建一个工厂函数。正如我所说,它不需要是类的静态成员,它也可以是非成员非友元函数,但这并没有太大变化(除了更好的封装,并且需要构造函数公开,或者让工厂成为朋友,这会以某种方式破坏封装)。
对象工厂在loki中以一种非常优雅的方式实现。有关设计模式本身以及 loki 给出的实现的详细讨论,请参阅 Modern C++ (Alexandrescu)。
至于您的编辑:在 loki 中的注册是甜蜜而简单的(从书中引用):
// Implementation module for class Line
// Create an anonymous namespace
// to make the function invisible from other modules
namespace
{
Shape* CreateLine()
{
return new Line;
}
// The ID of class Line
const int LINE = 1;
// Assume TheShapeFactory is a singleton factory
// (see Chapter 6)
const bool registered =
TheShapeFactory::Instance().RegisterShape(
LINE, CreateLine);
}