如何用c++实现一个命令模式 轻松实现撤销和重做功能【设计模式】


命令模式通过将请求封装为对象实现参数化、排队、日志记录及撤销重做;C++中需定义含execute()和undo()的抽象基类,具体命令保存必要上下文,用双栈管理执行与撤销历史。

命令模式的核心是把“请求”封装成对象,这样就能参数化、排队、记录日志,还能支持撤销和重做。C++ 实现的关键在于:定义统一的命令接口、让每个具体操作实现该接口、用栈管理执行历史。

定义命令基类(支持撤销)

所有命令都继承自一个抽象基类,至少包含 execute()undo() 两个纯虚函数:

class Command {
public:
    virtual ~Command() = default;
    virtual void execute() = 0;
    virtual void undo() = 0;
};

注意:命令对象应保存执行所需的所有上下文(比如目标对象、原始值、参数),不能依赖外部状态——否则 undo 可能失败。

实现具体命令(以文本编辑为例)

比如“插入文字”命令需要记住插入位置和内容,以便撤销时删除它:

class TextEditor {
    std::string content;
    size_t cursor_pos = 0;
public:
    void insert(const std::string& text) {
        content.insert(cursor_pos, text);
        cursor_pos += text.length();
    }
    void deleteAt(size_t pos, size_t len) {
        content.erase(pos, len);
    }
    const std::string& getContent() const { return content; }
    size_t getCursor() const { return cursor_pos; }
};

class InsertCommand : public Command {
    TextEditor& editor;
    std::string text;
    size_t pos;
public:
    InsertCommand(TextEditor& e, const std::string& t)
        : editor(e), text(t), pos(e.getCursor()) {}

    void execute() override {
        editor.insert(text);
    }

    void undo() override {
        editor.deleteAt(pos, text.length());
    }
};

类似地,可以实现 DeleteCommand、ReplaceCommand 等,每个都保存足够信息用于反向操作。

用栈管理历史(支持撤销/重做)

维护两个栈:executed 存已执行的命令(用于 undo),undone 存刚撤销的命令(用于 redo):

  • 执行命令时:调用 cmd->execute(),然后 push 到 executed
  • 撤销时:pop executed,调用其 undo(),再 push 到 undone
  • 重做时:pop undone,调用 execute(),再 push 回 executed
class CommandInvoker {
    std::stack> executed;
    std::stack> undone;

public:
    void execute(std::unique_ptr cmd) {
        cmd->execute();
        executed.push(std::move(cmd));
        undone = {}; // 清空重做历史(常见策略,也可保留)
    }

    void undo() {
        if (!executed.empty()) {
            auto cmd = std::move(executed.top());
            executed.pop();
            cmd->undo();
            undone.push(std::move(cmd));
        }
    }

    void redo() {
        if (!undone.empty()) {
            auto cmd = std::move(undone.top());
            undone.pop();
            cmd->execute();
            executed.push(std::move(cmd));
        }
    }
};

组合与扩展技巧

复杂操作可由多个命令组成,用 CompositeCommand 统一管理:

  • 它也继承自 Command
  • execute() 顺序调用子命令的 execute()
  • undo() 倒序调用子命令的 undo()

另外,为避免内存泄漏,建议用 std::unique_ptr 管理命令对象;若需重复执行同一命令(如快捷键连按),确保命令是无状态或可重入的。


#   # c++  # red  # 封装  # 继承  # 虚函数  # 纯虚函数  # 接口  # 对象  # 重做  # 就能  # 多个  # 还能  # 所需  # 也可  # 为例  # 可以实现  # 它也  # 关键在于 


相关栏目: 【 Google疑问12 】 【 Facebook疑问10 】 【 网络优化76771 】 【 技术知识130152 】 【 IDC云计算60162 】 【 营销推广131313 】 【 AI优化88182 】 【 百度推广37138 】 【 网站推荐60173 】 【 精选阅读31334


相关推荐: c# 在高并发场景下,委托和接口调用的性能对比  php怎么下载安装后设置错误日志_phpini log配置教程【汇总】  Win11无法安装软件怎么办_Win11解除应用安装限制设置【修复】  如何在Golang中使用log包输出不同级别日志_Golang log日志管理与分类  Windows如何拦截2345弹窗广告_Windows拦截2345弹窗方法【步骤】  Windows蓝屏BAD_POOL_HEADER故障详解_蓝屏池损坏错误修复指南  Python技术债务管理_长期维护解析【教程】  Mac怎么给文件夹加密_Mac创建加密磁盘映像教程【安全】  Win11怎么关闭透明效果_Windows11辅助功能视觉效果设置  Win11怎么关闭应用权限_Windows11相机麦克风隐私管理  Windows如何使用BitLocker To Go加密U盘?(移动驱动器加密)  如何在 ACF 中正确更新嵌套多层的 Group 字段子字段  Win10如何设置双wan路由器 Win10双wan路由器设置方法【指南】  ACF 教程:正确更新嵌套在多层 Group 字段内的子字段  Win11怎么设置单手模式_Win11触控键盘布局调整教程【技巧】  windows系统找不到无线网络怎么办_windows WLAN适配器故障排查  如何使用Golang reflect检查方法数量_动态分析类型方法  php订单日志权限怎么设_php订单日志文件权限设置技巧【技巧】  Windows10蓝屏SYSTEM_SERVICE_EXCEPTION_Win10驱动冲突排查  如何使用Golang template生成文本模板_动态生成HTML或文本  Windows10系统怎么查看已安装更新_Win10控制面板卸载补丁  Windows蓝屏错误0x0000001E怎么修复_KMODEEXCEPTIONNOTHANDLED排查  如何使用Golang实现函数指针_函数变量与回调示例  Win11应用商店下载慢怎么办 Win11更改DNS提速下载【修复】  如何将文本文件中的竖排字符串转换为横排字符串  c# Task.ConfigureAwait(true) 在什么场景下是必须的  MAC怎么设置程序窗口永远最前_MAC窗口置顶插件安装与快捷设置【方法】  Win11怎么关闭任务栏小组件_Windows11隐藏任务栏天气图标  Win10任务栏天气和资讯怎么关闭 Win10禁用新闻和兴趣功能【教程】  php怎么下载安装并配置环境变量_命令行调用PHP技巧【技巧】  Win11怎么关闭系统透明度_Windows11个性化颜色透明效果  Windows10如何更改开机密码_Win10登录选项更改密码教程  Windows 10怎么录屏_Windows 10使用Xbox Game Bar录制屏幕视频教程  如何使用Golang配置安全开发环境_防止敏感信息泄露  如何在 Go 结构体中正确初始化 map 字段  Win11怎么设置默认终端应用_Windows11开发者选项终端  Mac怎么开启“任何来源”_Mac安装未签名应用的设置方法【解决】  Win11怎么关闭右下角弹窗_Win11拦截系统通知广告【设置】  Go 中的 := 运算符:类型推导机制与使用边界详解  mac怎么打开终端_MAC终端Terminal使用入门与常用命令【教程】  c# F# 的 MailboxProcessor 和 C# 的 Actor 模型  php嵌入式日志记录怎么实现_php将硬件数据写入本地日志文件【指南】  c++如何用AFL++进行模糊测试 c++ Fuzzing入门【安全】  用Python构建微服务架构实践_FastAPI与Django对比详解  Win10怎么限制单程序CPU占用上限_Win10任务管理器亲和性或第三方工具均衡负载【技巧】  mac怎么看硬盘大小_MAC查看磁盘存储空间与文件占用【详解】  c++20的std::format怎么用 比printf更安全高效的格式化方法【详解】  英国搜索:多数英国人认为语言搜索是未来搜索  如何在Golang中实现自定义Benchmark_Golang testing.B自定义性能测量示例  Win11怎么设置组合键快捷方式_Windows11自定义快捷键操作 

 2025-12-26

了解您产品搜索量及市场趋势,制定营销计划

同行竞争及网站分析保障您的广告效果

点击免费数据支持

提交您的需求,1小时内享受我们的专业解答。

致胜网络推广营销网


致胜网络推广营销网

致胜网络推广营销网专注海外推广十年,是谷歌推广.Facebook广告全球合作伙伴,我们精英化的技术团队为企业提供谷歌海外推广+外贸网站建设+网站维护运营+Google SEO优化+社交营销为您提供一站式海外营销服务。

 915688610

 17370845950

 915688610@qq.com

Notice

We and selected third parties use cookies or similar technologies for technical purposes and, with your consent, for other purposes as specified in the cookie policy.
You can consent to the use of such technologies by closing this notice, by interacting with any link or button outside of this notice or by continuing to browse otherwise.