c++ - 有没有办法从保存类名的字符串中实例化对象?

标签 c++ inheritance factory instantiation

我有一个文件:Base.h

class Base;
class DerivedA : public Base;
class DerivedB : public Base;

/*etc...*/

还有另一个文件:BaseFactory.h

#include "Base.h"

class BaseFactory
{
public:
  BaseFactory(const string &sClassName){msClassName = sClassName;};

  Base * Create()
  {
    if(msClassName == "DerivedA")
    {
      return new DerivedA();
    }
    else if(msClassName == "DerivedB")
    {
      return new DerivedB();
    }
    else if(/*etc...*/)
    {
      /*etc...*/
    }
  };
private:
  string msClassName;
};

/*etc.*/

有没有办法以某种方式将此字符串转换为实际类型(类),这样 BaseFactory 就不必知道所有可能的派生类,并且每个都有 if() ?我可以从这个字符串生成一个类吗?

我认为这可以通过反射在 C# 中完成。 C++中有类似的东西吗?

最佳答案

不,没有,除非您自己进行映射。 C++ 没有创建类型在运行时确定的对象的机制。不过,您可以使用 map 自己进行映射:

template<typename T> Base * createInstance() { return new T; }

typedef std::map<std::string, Base*(*)()> map_type;

map_type map;
map["DerivedA"] = &createInstance<DerivedA>;
map["DerivedB"] = &createInstance<DerivedB>;

然后你就可以了

return map[some_string]();

获取一个新实例。另一个想法是让类型自己注册:

// in base.hpp:
template<typename T> Base * createT() { return new T; }

struct BaseFactory {
    typedef std::map<std::string, Base*(*)()> map_type;

    static Base * createInstance(std::string const& s) {
        map_type::iterator it = getMap()->find(s);
        if(it == getMap()->end())
            return 0;
        return it->second();
    }

protected:
    static map_type * getMap() {
        // never delete'ed. (exist until program termination)
        // because we can't guarantee correct destruction order 
        if(!map) { map = new map_type; } 
        return map; 
    }

private:
    static map_type * map;
};

template<typename T>
struct DerivedRegister : BaseFactory { 
    DerivedRegister(std::string const& s) { 
        getMap()->insert(std::make_pair(s, &createT<T>));
    }
};

// in derivedb.hpp
class DerivedB {
    ...;
private:
    static DerivedRegister<DerivedB> reg;
};

// in derivedb.cpp:
DerivedRegister<DerivedB> DerivedB::reg("DerivedB");

您可以决定为注册创建一个宏

#define REGISTER_DEC_TYPE(NAME) \
    static DerivedRegister<NAME> reg

#define REGISTER_DEF_TYPE(NAME) \
    DerivedRegister<NAME> NAME::reg(#NAME)

我相信这两个有更好的名字。在这里使用可能有意义的另一件事是shared_ptr .

如果你有一组没有公共(public)基类的不相关类型,你可以给函数指针一个返回类型boost::variant<A, B, C, D, ...>反而。就像你有一个类 Foo、Bar 和 Baz,它看起来像这样:

typedef boost::variant<Foo, Bar, Baz> variant_type;
template<typename T> variant_type createInstance() { 
    return variant_type(T()); 
}

typedef std::map<std::string, variant_type (*)()> map_type;

一个 boost::variant就像一个 union 。它通过查看用于初始化或分配给它的对象来知道其中存储了哪种类型。查看它的文档 here .最后,使用原始函数指针也有点陈旧。现代 C++ 代码应该与特定的函数/类型分离。您可能想查看 Boost.Function 寻找更好的方法。它看起来像这样( map ):

typedef std::map<std::string, boost::function<variant_type()> > map_type;

std::function也将在下一个 C++ 版本中提供,包括 std::shared_ptr .

关于c++ - 有没有办法从保存类名的字符串中实例化对象?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/582331/

相关文章:

constructor - Boost.Python : Defining a constructor outside a class

C++ - 创建几何体

巨大 CString 的 C++ 串联

c++ - 通过网络(远程屏幕广播应用程序)传输 JPEG 压缩的屏幕图 block 时,是否值得/推荐使用 zlib(或类似的)压缩?

具有继承性的 Python unittest 测试用例

c++ - 将动态仿函数传递给 STL

c++ - 什么是对象切片?

c# - 抽象和继承有什么区别?

php - 为 Laravel 的工厂在全局设置 Faker 的种子

java - 如何在 Java 中使用泛型实现工厂模式?