0

0

如何在c++中实现一个简单的命令(Command)设计模式? (使用std::function)

冰火之心

冰火之心

发布时间:2026-01-10 07:53:08

|

584人浏览过

|

来源于php中文网

原创

用std::function实现Command更轻量,因其无需定义命令类继承体系,可直接捕获lambda、函数或成员函数;可撤销Command需同时存储execute_fn和undo_fn两个std::function,绑定成员函数推荐用lambda并注意捕获方式。

如何在c++中实现一个简单的命令(command)设计模式? (使用std::function)

为什么std::function 实现 Command 比虚函数更轻量?

因为不用定义一堆具体命令类和继承体系,std::function 能直接捕获 lambda、普通函数或成员函数,把“执行逻辑”变成一等公民。适合配置驱动、脚本化或临时任务调度场景,比如 UI 按钮绑定、宏录制回放、Undo 的简单实现。

但要注意:它不自带 undo() 或元信息(如命令名),若需这些,得额外包装一层结构体。

如何构造一个可撤销的 Command 类?

std::function 存执行逻辑,再加一个 std::function 存撤销逻辑。两者都支持捕获上下文,避免裸指针生命周期风险。

  • 撤销函数必须与执行函数语义对称,例如执行时 balance += 100,撤销时就得 balance -= 100
  • 避免在 lambda 中捕获局部变量的引用(除非确保生命周期足够长),优先用值捕获或 shared_ptr
  • 如果撤销逻辑不存在,可设为默认空函数:std::function undo_fn = []{};
struct Command {
    std::function execute_fn;
    std::function undo_fn;
void execute() { execute_fn(); }
void undo() { undo_fn(); }

};

立即学习C++免费学习笔记(深入)”;

怎么把成员函数绑定成 Command

不能直接传 &MyClass::doSave,必须绑定对象实例。用 std::bind 或 lambda 更直观,lambda 更推荐——类型推导干净、无隐藏拷贝开销。

  • 错误写法:Command cmd{&MyClass::doSave, &MyClass::undoSave}; —— 缺少对象,编译失败
  • 正确写法(lambda):[obj](){ obj.doSave(); },注意值捕获 obj 还是引用捕获 &obj,取决于是否需要修改原对象
  • 若对象是动态分配的,建议用 std::shared_ptr 捕获,防止悬垂
class Editor {
public:
    void save() { /* ... */ }
    void undo_save() { /* ... */ }
};

Editor editor; auto cmd = Command{ [&editor]() { editor.save(); }, [&editor]() { editor.undo_save(); } };

执行队列和 Undo 栈怎么配合 std::function

std::vector 当命令历史,每次 execute() 后 push,undo() 时 pop 并调用其 undo_fn。关键点在于:不要在 Command 构造后修改被捕获对象的状态,否则 undo 行为不可预测。

常见坑是多次 undo 后又 redo —— std::function 版本默认不支持 redo,除非你额外维护一个重做栈,或让每个 Command 自带 redo_fn 字段。

另外,std::function 有约 16–32 字节的额外开销(取决于实现),高频短命命令(如每帧几十个)要考虑是否值得;此时原始函数指针 + void* 上下文可能更高效。

相关专题

更多
golang结构体相关大全
golang结构体相关大全

本专题整合了golang结构体相关大全,想了解更多内容,请阅读专题下面的文章。

194

2025.06.09

golang结构体方法
golang结构体方法

本专题整合了golang结构体相关内容,请阅读专题下面的文章了解更多。

186

2025.07.04

javascriptvoid(o)怎么解决
javascriptvoid(o)怎么解决

javascriptvoid(o)的解决办法:1、检查语法错误;2、确保正确的执行环境;3、检查其他代码的冲突;4、使用事件委托;5、使用其他绑定方式;6、检查外部资源等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

174

2023.11.23

java中void的含义
java中void的含义

本专题整合了Java中void的相关内容,阅读专题下面的文章了解更多详细内容。

95

2025.11.27

lambda表达式
lambda表达式

Lambda表达式是一种匿名函数的简洁表示方式,它可以在需要函数作为参数的地方使用,并提供了一种更简洁、更灵活的编码方式,其语法为“lambda 参数列表: 表达式”,参数列表是函数的参数,可以包含一个或多个参数,用逗号分隔,表达式是函数的执行体,用于定义函数的具体操作。本专题为大家提供lambda表达式相关的文章、下载、课程内容,供大家免费下载体验。

202

2023.09.15

python lambda函数
python lambda函数

本专题整合了python lambda函数用法详解,阅读专题下面的文章了解更多详细内容。

189

2025.11.08

Python lambda详解
Python lambda详解

本专题整合了Python lambda函数相关教程,阅读下面的文章了解更多详细内容。

41

2026.01.05

堆和栈的区别
堆和栈的区别

堆和栈的区别:1、内存分配方式不同;2、大小不同;3、数据访问方式不同;4、数据的生命周期。本专题为大家提供堆和栈的区别的相关的文章、下载、课程内容,供大家免费下载体验。

382

2023.07.18

c++主流开发框架汇总
c++主流开发框架汇总

本专题整合了c++开发框架推荐,阅读专题下面的文章了解更多详细内容。

24

2026.01.09

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
CSS3 教程
CSS3 教程

共18课时 | 4.4万人学习

Sass 教程
Sass 教程

共14课时 | 0.7万人学习

Pandas 教程
Pandas 教程

共15课时 | 0.9万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号