动态创建一个继承的类,使用STD :: MAP使用基类指针访问

Create an inherited class dynamically, access using base class pointer using std::map?

本文关键字:MAP STD 使用 访问 指针 基类 创建 继承 一个 动态      更新时间:2023-10-16

不确定我可以做到这一点。我有问题是[另一个问题]的变体(您可以创建继承类的std ::地图吗?(。

基本上,以下问题的答案是为继承的类创建指针的地图,该类可根据第一个地图条目搜索地图。然后,您调用指针来解决所需的任何虚拟功能。

我已经实现了一个带有几个命令的命令处理器应用程序。地图是:

std::map<string, BaseCmdClass*> cmd_map;

到目前为止都不错。但是,我们正在更新代码,以提供数百个派生的类。我不想在代码开始时在工厂类中创建所有这些,而是想使用过多的内存。

我想在需要时动态构造一个继承的类,然后使用基类指针删除。我想避免使用大案例声明来调用每个构造函数。

有没有一种方法可以创建std::map或使用另一个可以查找哪个构造函数的STL容器?然后,当我需要派生的构造函数时,我可以查找此地图以查找要调用的正确派生构造函数。

有没有一种方法可以创建一个std ::映射或使用另一个可以查找要调用的构造函数的STL容器?

当然。您不能直接将指针存储到构造函数上,但是您可以将指针存储到调用构造函数的工厂功能中。

using CmdFactory = BaseCmdClass*();
std::map<std::string, CmdFactory*> factory_map;

您可以使用助手模板生成工厂:

template<class T>
BaseCmdClass* factory() {
    return new T;
}

您可以添加这样的工厂:

factory_map["Derived1"] = factory<Derived1>;

我想在需要时动态构造一个继承的类,然后使用基类指针删除。我想避免使用大案例声明来调用每个构造函数。

使用基类指针删除就可以了,只要destructor是虚拟的。不需要案例语句。


进一步发展:

,如果您需要状态工厂,则可以使用std::function而不是功能指针。

我建议从工厂返回std::unique_ptr<BaseCmdClass>以避免记忆泄漏。

对于较低的内存开销,如果使用整数作为密钥,则可以使用数组而不是地图,但是构造数组的代码必须了解所有孩子。

解决方案之一是为创建者具有平行层次结构:

class BaseCmdClass {
  ...
};
class BaseCmdCreator;
class BaseCmdFactory {
public:
    static BaseCmdFactory &instance();
    void registerCreator( const std::string &name, BaseCmdCreator *cr );
    ...
}; 
class BaseCmdCreator {
public:
    BaseCmdCreator( const std::string &name )
    {
         BaseCmdFactory::instance().registerCreator( name, this );
    }
    virtual std::unique_ptr<BaseCmdClass> create() = 0;
};
template<class T>
class CmdCreator : public BaseCmdCreator {
public:
    CmdCreator( const std::string &name ) : BaseCmdCreator( name ) {}
    virtual std::unique_ptr<BaseCmdClass> create() override
    {
        return std::make_unique<T>();
    }
};

现在如何使用它 - 在.cpp文件中定义特定的cmdClass,您可以创建一个静态对象:

// Class FooCmdClass defined here
namespace {
    CmdCreator<FooCmdClass> registerFoo( "FooCmd" );
}

现在,如果您链接了由此创建的对象文件,则将注册您的class FooCmdClass。您甚至可以通过插件机制进行完全动态的操作。因此,添加新命令不需要基类的任何更改,只将新.cpp文件添加到项目中。

struct BaseCmdClass {
  virtual bool do_something() = 0;
  virtual ~BaseCmdClass() {}
};
using upCmd = std::unique_ptr<BaseCmdClass>;
using CmdFactory = std::function<upCmd()>;
using Command = std::string;
std::unordered_map<Command, CmdFactory>& command_factories() {
  static std::unordered_map<Command, CmdFactory> retval;
  return retval;
}
upCmd make_cmd( Command const& cmd ) {
  auto mit = command_factories().find(cmd);
  if (mit == command_factories().end() || !*mit) return {};
  return (*mit)();
}

// in CopyCmd.cpp
struct CopyCmd : BaseCmdClass
  bool do_something() override final {
    std::cout << "did copy";
  };
  static auto registered = command_factories().insert(
    "copy",
    []{ return std::make_unique<CopyCmd>(); }
  );
};

现在,任何人都可以make_cmd("copy")并通过其BaseCmdClass的唯一指针获得CopyCmd的实例。

相关文章: