You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从派生类对象获取其类型?解决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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 22:13:22