Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/159.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/design-patterns/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 使用工厂模式按名称实例化类_C++_Design Patterns_Class - Fatal编程技术网

C++ 使用工厂模式按名称实例化类

C++ 使用工厂模式按名称实例化类,c++,design-patterns,class,C++,Design Patterns,Class,假设我有一个类列表a,B,C,…,它们都从Base继承 我从用户那里得到一个字符串形式的类名,我想实例化正确的类并返回一个指向Base的指针。您将如何实现这一点 我考虑使用一个以类名为键的哈希表,以及一个指向实例化正确类并返回Base*的函数的函数指针 不过,我想我可以在这里使用factory模式,让它更简单,但我只是记不太清楚,所以我想征求一下建议。在很多领域,最快但非常有用的方法是 Base* MyFactoryMethod( const std::string& sClass )

假设我有一个类列表
a,B,C,…
,它们都从
Base
继承

我从用户那里得到一个字符串形式的类名,我想实例化正确的类并返回一个指向
Base
的指针。您将如何实现这一点

我考虑使用一个以类名为键的哈希表,以及一个指向实例化正确类并返回
Base*
的函数的函数指针


不过,我想我可以在这里使用factory模式,让它更简单,但我只是记不太清楚,所以我想征求一下建议。

在很多领域,最快但非常有用的方法是

Base* MyFactoryMethod( const std::string& sClass ) const
{
  if( sClass == "A" )
    return CreateNewA();
  else if( sClass == "B" )
    return new CreateClassB();
  //....
  return 0;
}

A* CreateClassA() const
{
  return new A();
}

首先,是的,这正是工厂模式的目的。
(顺便说一下,您的另一个想法是工厂模式的可能实现)

如果你打算为一个大项目做这个(如果不是的话,就随它去),你可能想考虑使用一个关联容器而不是显式分支,甚至可能把注册责任移到类

  • 避免在另一个地方(您的工厂)更改代码
  • 反过来,在添加类时,可以避免很长的重新编译时间(对于头内实现)
为了在类中实现方便的注册,您可以使用类似的方法,并向实例化派生类并返回指向基的指针的条目添加函数指针或指针。
如果你不怕宏,那么你可以通过只在声明中添加一个小宏来向工厂添加类。

下面是一个通用实现:

template<class Interface, class KeyT=std::string>
struct Factory {
    typedef KeyT Key;
    typedef std::auto_ptr<Interface> Type;
    typedef Type (*Creator)();

    bool define(Key const& key, Creator v) {
        // Define key -> v relationship, return whether this is a new key.
        return _registry.insert(typename Registry::value_type(key, v)).second;
    }
    Type create(Key const& key) {
        typename Registry::const_iterator i = _registry.find(key);
        if (i == _registry.end()) {
            throw std::invalid_argument(std::string(__PRETTY_FUNCTION__) +
                                        ": key not registered");
        }
        else return i->second();
    }

    template<class Base, class Actual>
    static
    std::auto_ptr<Base> create_func() {
        return std::auto_ptr<Base>(new Actual());
    }

private:
    typedef std::map<Key, Creator> Registry;
    Registry _registry;
};
模板
结构工厂{
typedef键;
typedef std::自动_ptr类型;
typedef Type(*Creator)();
布尔定义(键常量和键,创建者v){
//定义键->v关系,返回是否为新键。
return _registry.insert(typename registry::value_type(key,v)).second;
}
类型创建(键常量和键){
typename注册表::常量迭代器i=\u注册表.find(键);
if(i==\u registry.end()){
抛出std::无效的参数(std::string(\uuu PRETTY\u函数)+
“:密钥未注册”);
}
否则返回i->second();
}
模板
静止的
std::auto_ptr create_func(){
返回std::auto_ptr(new Actual());
}
私人:
typedef std::map注册表;
注册处;;
};
这并不意味着在任何情况下都是最好的,但它是一种第一近似值,是一种比手动实现stijn提到的函数类型更有用的默认值。工厂并不强制要求每个层次结构如何注册自身,但您可能喜欢上面提到的gf(它简单、清晰、非常有用,是的,这克服了本例中宏的固有问题)

这是工厂的一个例子:

struct Base {
    typedef ::Factory<Base> Factory;
    virtual ~Base() {}
    virtual int answer() const = 0;

    static Factory::Type create(Factory::Key const& name) {
        return _factory.create(name);
    }
    template<class Derived>
    static void define(Factory::Key const& name) {
        bool new_key = _factory.define(name,
            &Factory::template create_func<Base, Derived>);
        if (not new_key) {
            throw std::logic_error(std::string(__PRETTY_FUNCTION__) +
                                   ": name already registered");
        }
    }

private:
    static Factory _factory;
};
Base::Factory Base::_factory;

struct A : Base {
    virtual int answer() const { return 42; }
};

int main() {
    Base::define<A>("A");
    assert(Base::create("A")->answer() == 42);
    return 0;
}
struct Base{
typedef::工厂;
虚拟~Base(){}
虚拟int answer()常量=0;
静态工厂::类型创建(工厂::键常量和名称){
返回_factory.create(名称);
}
模板
静态void定义(工厂::键常量和名称){
bool new_key=_factory.define(名称,
&工厂::模板创建(func);
如果(不是新的_键){
抛出标准::逻辑错误(标准::字符串(uuu漂亮的函数)+
“:名称已注册”);
}
}
私人:
静态工厂(u工厂),;
};
基地::工厂基地::工厂;
结构A:基础{
虚int answer()常量{return 42;}
};
int main(){
基::定义(“A”);
断言(Base::create(“A”)->answer()==42);
返回0;
}

您还可以研究Boost类的实现

  • 如果只有几个派生类,则可以使用“If,else”列表
  • 如果您计划有许多派生类,那么最好对类注册过程进行排序(如前所述),而不是使用“If,else”列表
下面是一个使用Boost factory方法和类注册的简单示例:

typedef boost::function<Parent*()> factory;

// ...

std::map<std::string, factory> factories;

// Register derived classes
factories["Child1"] = boost::factory<Child1*>();
factories["Child2"] = boost::factory<Child2*>();

// ...

// Instantiate chosen derived class
auto_ptr<Parent> pChild = auto_ptr<Parent>(factories["Child1"]());
typedef boost::函数工厂;
// ...
地图工厂;
//寄存器派生类
工厂[“Child1”]=boost::factory();
工厂[“Child2”]=boost::factory();
// ...
//实例化所选的派生类
auto_ptr pChild=auto_ptr(工厂[“Child1”]());

你关于使用函数指针的哈希表的想法听起来很像工厂。是的,我通常也从类似的东西开始——类和类似的“create”方法。然后,如果有很多类(或者库用户应该添加一些),我会在它后面添加带有注册的“真”工厂(映射、哈希等等)。。。我不记得它是如何实现的。嗨,我尝试过这个解决方案,但无法使它编译。我遇到的问题是第
factories[“Child1”]=boost::factory()行存在类型检查问题,未定义相等性。如果我写
boost::factory()它可以工作,但没有用处。我遗漏了什么吗?你为什么把它定义为结构?有什么原因吗?