如何从派生类对象获取其类型?解决Command日志的多态实例化问题
Command日志机制的设计与实现问题
在具备可变状态的命令语言中,存在命令日志(Log)机制:每个Command对象执行(Run)时会被加入Log,Log是语言状态(State)的字段之一,所有Command共享同一个State。从逻辑上讲,应向Log中存入std::unique_ptr<Command>,因为Command仅在Log内有意义,且每个Command在Log中是唯一实例。
我希望在Command类中实现一个通用方法(如代码中的SetRunGet),该方法可多态执行,无需依赖具体派生Command类型,避免每次创建Command都调用std::make_unique<具体派生类>来重复编写代码。但如果将Command设为抽象类,就无法创建其unique_ptr。因此有两种思路:
- 在每个派生Command中重写SetRunGet:缺点是代码量大、存在大量重复代码;
- 将Command设为非抽象类,为其方法编写无意义的默认实现(当前尝试的方案)。
但当前代码存在问题:在基类Command的SetRunGet方法中,尝试通过decltype(*this)获取派生类类型,但实际得到的是Command类型,导致存入Log的对象调用PrintType时输出"Base Command",而非派生类的类型信息。
我需要:
- 从派生类对象(而非派生类引用)中提取其类型,若无法实现,希望了解原因;
- 找到无需重复代码的解决方案;
- 欢迎针对Command日志存储的设计思路提供建议(比如是否必须用
std::unique_ptr)。
附代码
#include <iostream> #include <memory> #include <vector> class Command { public: Command() = default; virtual void Run(){ std::cout << "I'm Command and I don't have any sense except saving Command from being abstract" << std::endl; } virtual std::unique_ptr<Command> SetRunGet() { decltype(this) stuff = this; // type here is DerivedCommand* decltype(*this) stuff1 = *this; // type here is DerivedCommand& std::remove_reference<decltype(*this)>::type anotherstuff = *this; // type is std::remove_reference<Command&>::type // all other stuff that is done only once, for example creating // and setting inverted Command to be done when Undo using virtual Inverted method // and/or setting State which contains Log Run(); return std::make_unique<std::remove_reference<decltype(*this)>::type>(*this); } virtual void PrintType(){ std::cout << "Base Command" << std::endl; }; }; class DerivedCommand : public Command { public: DerivedCommand() = default; void Run() override { std::cout << "I'm Derived Command, Hi" << std::endl; } void PrintType() override { std::cout << "Derived Command" << std::endl; } }; class Log { public: Log() = default; void Push(std::unique_ptr<Command> command){ log_.push_back(std::move(command)); }; std::unique_ptr<Command>& Get(size_t position){ return log_[position]; }; private: std::vector<std::unique_ptr<Command>> log_{}; }; int main(){ Log log{}; DerivedCommand command{}; log.Push(command.SetRunGet()); auto& command_after_push = log.Get(0); command_after_push->PrintType(); // here prints "Base Command" }
内容的提问来源于stack exchange,提问作者Paul Ivanov
相关产品推荐
相关产品推荐

