讲师中心 微信公众号
AI工具推荐 视频效率加速

C++实现简单的状态模式切换 _ 接口类与具体状态实现【源码】

冬枫姑娘_8511

冬枫姑娘_8511

发布时间:2026-04-11 18:45:52

|

403人浏览过

|

来源于php中文网

原创

状态模式应避免裸指针,Context需用std::unique_ptr持有状态所有权,State基类须有虚析构函数且仅含纯虚函数,状态切换通过onEnter/onExit钩子管理资源,禁止状态内主动切换或持有Context指针。

c++实现简单的状态模式切换 _ 接口类与具体状态实现【源码】

状态模式的核心不是继承,而是委托

直接用 class State 做基类、让具体状态继承它,再在上下文(Context)里存一个 State* 指针——这是最常见也最容易写错的起点。问题在于:状态切换时若忘记更新指针,或新状态构造失败导致悬空指针,segfault 就在下一秒。真正稳妥的做法是让 Context **持有状态对象的所有权**,且切换时通过值语义或智能指针完成交接,避免裸指针生命周期失控。

  • 推荐用 std::unique_ptr<state></state>,构造新状态后直接 std::move 赋值,旧状态自动析构
  • 所有状态类必须定义虚析构函数,否则 delete 通过基类指针会跳过派生类析构逻辑
  • 不要在状态内部调用 Context 的非 const 成员函数来“主动切换自己”,这会造成循环依赖;应由 Context 统一决策切换时机

接口类 State 必须只暴露行为契约,不暴露数据

State 类里只放纯虚函数,比如 handleInput()、update()、render(),绝不放任何成员变量。有人习惯在基类里加 m_context 指针,看似方便调用上下文方法,实则把 Context 变成了状态的依赖项,破坏了单向依赖(State → Context),还容易引发头文件循环包含。正确做法是:Context 在调用 state->handleInput(*this) 时,把自身引用传进去。

  • 接口函数参数用 Context& 而非 Context*,避免空指针检查干扰逻辑
  • 如果某个状态需要读取 Context 的私有数据,加一个 const Context& getConstContext() const 友元或公开只读访问接口,而不是开放全部接口
  • 别在 State 构造函数里尝试访问 Context 的未初始化成员——状态创建早于 Context 完全构造完毕是常见坑

具体状态实现要隔离副作用,尤其资源管理

比如 PlayingState 进入时要播放音频,退出时要暂停;PausedState 进入时记录暂停时间戳,退出时计算已暂停时长。这些逻辑不能堆在 handleInput() 里,而应拆到 onEnter() 和 onExit() 两个受控钩子中。Context 在切换状态前先调 oldState->onExit(),再构造新状态,再调 newState->onEnter()。

C++ Code Review Master
C++ Code Review Master

组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。

下载
  • onEnter() 和 onExit() 不是虚函数接口的一部分,而是每个具体状态自己实现的私有方法,仅被 Context 内部调用
  • 音频句柄、网络连接、OpenGL 上下文等资源,必须在 onExit() 中释放,不能等到析构——因为状态可能被反复切换多次,析构只发生一次
  • 避免在 onEnter() 中做耗时操作(如磁盘读取、网络请求),否则阻塞主线程;可改为异步触发+状态机响应事件

用 std::variant 替代虚函数基类?谨慎

有人想用 std::variant<playingstate pausedstate stoppedstate></playingstate> 避免虚函数开销和继承体系。理论上可行,但实际会迅速失控:每次新增状态都要改 variant 定义、重写所有 visit 分支、无法动态扩展(比如插件式加载新状态)。更麻烦的是,std::visit 调用无法像虚函数那样自然支持“当前状态决定是否处理某事件”——你得手动判断类型再 dispatch,代码膨胀且易漏分支。

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

  • 只有状态数固定 ≤ 3、且绝无扩展需求时,std::variant 才比虚函数简单
  • 一旦涉及状态间通信(如 PausedState 想通知 PlayingState 恢复播放),variant 很难优雅表达,而虚函数配合 Context 中转就很自然
  • 编译器对虚函数调用的优化(如 devirtualization)在现代 GCC/Clang 下已很成熟,性能差异通常可忽略

状态切换本身不难,难的是让每个状态清楚自己“能做什么、不能做什么、什么时候做”。最常被忽略的一点:没有为状态增加调试标识(比如 virtual const char* name() const = 0;),导致日志里只看到 0x7f8a1c0042a0,根本分不清当前是哪个状态实例。

热门AI工具

更多
墨刀AI
墨刀AI Hot

一款AI图像与设计工具,主要用于产品经理的专属智能体,适合需要提升相关任务效率的用户。

立刻MV
立刻MV Hot

立刻MV是一款AI文本写作工具,AI 音乐视频(MV)创作工具。

AionClaw
AionClaw Hot

AionClaw是一款面向办公、创作和编程任务的AI桌面智能体。

咔片AIPPT

一款在线AI演示文稿制作工具,可根据主题和内容需求辅助生成PPT结构与页面,提高演示材料制作效率。

Atoms
Atoms Hot

Atoms是一款AI智能体工具,第一支自动构建真实业务的 AI 团队。

豆包大模型

豆包大模型是一款由字节跳动推出的企业级大语言模型服务平台。

DeepSeek

DeepSeek是一款面向对话、写作、编程和推理场景的AI大模型工具。

Lovart
Lovart Hot

一款面向视觉设计创作的AI设计平台,可通过智能体和画布工作流辅助制作海报、Logo、网页、PPT及其他视觉内容。

WorkBuddy

一款AI办公效率工具,主要用于腾讯云推出的AI原生桌面智能体工作台,适合需要提升相关任务效率的用户。

相关专题

更多
c语言const用法
c语言const用法

const是关键字,可以用于声明常量、函数参数中的const修饰符、const修饰函数返回值、const修饰指针。详细介绍:1、声明常量,const关键字可用于声明常量,常量的值在程序运行期间不可修改,常量可以是基本数据类型,如整数、浮点数、字符等,也可是自定义的数据类型;2、函数参数中的const修饰符,const关键字可用于函数的参数中,表示该参数在函数内部不可修改等等。

2018

2023.09.20

C++ 智能指针与现代内存管理
C++ 智能指针与现代内存管理

深入讲解 C++ 现代内存管理的核心工具——智能指针,涵盖 unique_ptr 独占所有权语义、shared_ptr 引用计数机制与循环引用问题、weak_ptr 弱引用的应用场景、make_unique/make_shared 工厂函数的性能优势、自定义删除器的编写、RAII 资源管理思想的实践,以及从裸指针迁移到智能指针的重构策略,帮助开发者编写安全无泄漏的现代 C++ 代码。

319

2026.04.23

硬盘接口类型介绍
硬盘接口类型介绍

硬盘接口类型有IDE、SATA、SCSI、Fibre Channel、USB、eSATA、mSATA、PCIe等等。详细介绍:1、IDE接口是一种并行接口,主要用于连接硬盘和光驱等设备,它主要有两种类型:ATA和ATAPI,IDE接口已经逐渐被SATA接口;2、SATA接口是一种串行接口,相较于IDE接口,它具有更高的传输速度、更低的功耗和更小的体积;3、SCSI接口等等。

3068

2023.10.19

PHP接口编写教程
PHP接口编写教程

本专题整合了PHP接口编写教程,阅读专题下面的文章了解更多详细内容。

4469

2025.10.17

php8.4实现接口限流的教程
php8.4实现接口限流的教程

PHP8.4本身不内置限流功能,需借助Redis(令牌桶)或Swoole(漏桶)实现;文件锁因I/O瓶颈、无跨机共享、秒级精度等缺陷不适用高并发场景。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

3709

2025.12.29

java接口相关教程
java接口相关教程

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

406

2026.01.19

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

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

5007

2023.07.18

堆和栈区别
堆和栈区别

堆(Heap)和栈(Stack)是计算机中两种常见的内存分配机制。它们在内存管理的方式、分配方式以及使用场景上有很大的区别。本文将详细介绍堆和栈的特点、区别以及各自的使用场景。php中文网给大家带来了相关的教程以及文章欢迎大家前来学习阅读。

2228

2023.08.10

LLVM自定义Pass怎么写
LLVM自定义Pass怎么写

本专题聚焦LLVM自定义Pass开发,整理Pass类结构、run()方法、PreservedAnalyses、CMake构建、插件注册、-load-pass-plugin加载和测试用例编写流程。

40

2026.09.30

热门下载

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

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Conan 2 Essentials 免费课程
Conan 2 Essentials 免费课程

共0课时 | 0人学习

CMake 与 Conan 集成实践
CMake 与 Conan 集成实践

共0课时 | 0人学习

Conan 2 高级依赖模型介绍
Conan 2 高级依赖模型介绍

共0课时 | 0人学习

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

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn