不确定我能做到这一点。我有疑问是[这个其他问题]的变体(Can you create a std::map of inherited classes? )。
基本上,下面问题的答案是创建一个指向继承类的指针映射,其中映射可以根据第一个映射条目进行搜索。然后你调用一个指针来解决你想要的任何虚函数。
我已经使用一些命令实现了一个命令处理器应用程序。地图是:
std::map<string, BaseCmdClass*> cmd_map;
到目前为止一切顺利。但是,我们正在更新代码以提供可能数百个派生类。我不想在代码开头的工厂类中创建它们,使用太多内存。
我想在需要时动态构造一个继承的类,然后使用基类指针进行删除。我想避免一个大的case语句来调用每个构造函数。
有没有办法可以创建std::map
或使用另一个可以查找要调用的构造函数的STL容器?然后,当我需要派生的构造函数时,我可以查找此映射以找到要调用的正确派生构造函数。
答案 0 :(得分:0)
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")
通过指向其CopyCmd
的唯一指针获取BaseCmdClass
的实例。
答案 1 :(得分:0)
有没有办法可以创建一个std :: map或者使用另一个可以查找要调用的构造函数的STL容器?
不确定。您不能直接存储指向构造函数的指针,但可以存储指向调用构造函数的工厂函数的指针。
using CmdFactory = BaseCmdClass*();
std::map<std::string, CmdFactory*> factory_map;
您可以使用帮助程序模板生成工厂:
template<class T>
BaseCmdClass* factory() {
return new T;
}
您可以添加这样的工厂:
factory_map["Derived1"] = factory<Derived1>;
我想在需要时动态构造一个继承的类,然后使用基类指针进行删除。我想避免一个大的case语句来调用每个构造函数。
只要析构函数是虚拟的,删除使用基类指针就可以了。不需要案例陈述。
进一步发展:
如果您需要有状态工厂,可以使用std::function
而不是函数指针。
我建议从工厂返回std::unique_ptr<BaseCmdClass>
以避免内存泄漏。
对于较低的内存开销,如果使用整数作为键,则可以使用数组而不是映射,但构造数组的代码必须知道所有子代。
答案 2 :(得分:0)
其中一个解决方案是为创作者提供并行层次结构:
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>();
}
};
现在如何使用它 - 在你定义特定CmdClass的.cpp文件中创建一个静态对象:
// Class FooCmdClass defined here
namespace {
CmdCreator<FooCmdClass> registerFoo( "FooCmd" );
}
现在,如果您链接从此.cpp创建的目标文件,您的class FooCmdClass
将被注册。您甚至可以通过插件机制完全动态地完成此操作。因此,添加新命令不需要对基类进行任何更改,只需将新的.cpp文件添加到项目中。