1

我有一个Parent抽象类,以及派生FooBar。它们都有一个带string name参数的构造函数。它们有一个字符串 type() 成员函数,分别返回“foo”和“bar”。

现在我想用键“foo”和“bar”构建一个字典,值等于指向创建相应类的新实例的函数的指针。这意味着这些指针将具有类型Parent* (*) (const string &)并且执行它们将等效于调用new Foo(name)new Bar(name)

我可以避免为每个只会调用 new 的类创建一个静态函数,并获取指向该静态函数的指针吗?

谢谢!

编辑:实际上,这背后的目标是在我的应用程序中实现一个插件系统,插件添加新的派生类类型。插件作者通常是我的客户,出于这个原因,我想让他们尽可能简单和优雅的界面。所以声明和注册工厂函数应该尽可能简单和简短

4

3 回答 3

8

我可以避免为每个只会调用 new 的类创建一个静态函数,并获取指向该静态函数的指针吗?

是的,您可以创建一个通用函数:

template <typename T>
ptr_type<Parent> create() {
    return new T();
}

…然后获取它的地址(但您需要为每个派生类型获取一个地址)。

请注意,我没有明确地其用作T*返回类型——原始指针永远不应该拥有内存……应该在这里使用适当的智能指针。

于 2013-07-10T12:13:20.100 回答
4

您描述的是工厂方法模式。这是一个链接:http ://en.wikipedia.org/wiki/Factory_method_pattern 静态函数或某种工厂基本上是您想要的东西。

为什么要避免静态创建方法?

于 2013-07-10T12:12:36.453 回答
1

您需要为希望通过这种方式构建的每个类实例化一个工厂函数。以下代码向您展示了如何做到这一点,而不必重复使用静态成员,也无需手动编写许多不同的函数:

#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); 
} 
于 2013-07-10T12:12:25.397 回答