c++如何实现装饰器模式_c++ 类包装与功能动态扩展【实战】

发布时间 - 2026-01-08 00:00:00    点击率:
C++装饰器模式需手动实现,核心是接口抽象+组合+RAII:定义含virtual析构与虚函数的Component基类,装饰器通过std::unique_ptr持有并转发被包装对象,利用移动语义链式构建,确保所有权清晰与资源安全。

装饰器模式在 C++ 中没有语言级支持,必须手动实现

C++ 没有 Python 那样的 @decorator 语法,所谓“装饰器模式”是设计模式层面的结构复用方案,核心是通过组合而非继承来动态添加行为。它不依赖语法糖,而是靠接口抽象 + 指针/引用 + RAII 控制生命周期来达成。

用抽象基类定义组件接口,所有装饰器和具体组件都继承它

这是最关键的一步:没有统一接口,就无法透明替换和嵌套。接口中至少要有一个虚函数(如 operation()),且析构函数必须是 virtual,否则通过基类指针 delete 派生对象会未定义行为。

class Component {
public:
    virtual ~Component() = default;
    virtual void operation() const = 0;
};

class ConcreteComponent : public Component { public: void operation() const override { std::cout << "ConcreteComponent executed\n"; } };

常见错误:忘记 virtual ~Component() → 内存泄漏或崩溃;把 operation() 声明为非虚 → 装饰器调用时静态绑定到基类空实现。

装饰器类持有 Component 指针,并在构造时接收被包装对象

装饰器不是派生自具体类,而是组合一个 Component*(或 std::unique_ptr)。它转发调用,再在前后插入额外逻辑 —— 这就是“动态扩展”的实质。

  • 推荐用 std::unique_ptr 管理所有权,避免裸指针悬空
  • 装饰器构造函数应接受右值引用(std::unique_ptr&&)以支持链式构建
  • 不要在装饰器里拷贝被包装对象 —— 否则失去“动态”特性,变成静态包装
class LoggingDecorator : public Component {
    std::unique_ptr wrapped_;
public:
    explicit LoggingDecorator(std::unique_ptr&& w)
        : wrapped_(std::move(w)) {}
void operation() const override {
    std::cout << "[LOG] before\n";
    wrapped_->operation();
    std::cout << "[LOG] after\n";
}

};

多层装饰需注意构造顺序和内存管理边界

new TimingDecorator(new LoggingDecorator(new ConcreteComponent)) 这种写法在 C++ 里极易出错。正确做法是用移动语义逐层包裹:

auto comp = std::make_unique();
comp = std::make_unique(std::move(comp));
comp = std::make_unique(std::move(comp));
comp->operation(); // 输出日志 + 计时 + 原操作

容易踩的坑:
- 用裸指针层层 new,忘了 delete → 泄漏
- 传入左值给装饰器构造函数 → 编译失败(因只接受右值)
- 在装饰器内部直接 new 具体类并裸存指针 → 所有权混乱,RAII 失效
- 忘记装饰器也需实现全部纯虚函数(哪怕只是转发),否则无法编译

C++ 的装饰器模式真正难的不是写几行代码,而是厘清谁拥有对象、谁负责释放、在哪一层做资源初始化 —— 这些在 Python 里由解释器托管的事,在 C++ 里全得你亲手掐着 RAII 的脉搏来安排。


# python  # app  # ai  # c++ 


相关栏目: 【 网站优化151355 】 【 网络推广146373 】 【 网络技术251813 】 【 AI营销90571


相关推荐: 使用spring连接及操作mongodb3.0实例  宙斯浏览器文件分类查看教程 快速筛选视频文档与图片方法  百度浏览器如何管理插件 百度浏览器插件管理方法  Windows驱动无法加载错误解决方法_驱动签名验证失败处理步骤  如何实现建站之星域名转发设置?  无锡营销型网站制作公司,无锡网选车牌流程?  Laravel中的Facade(门面)到底是什么原理  Laravel广播系统如何实现实时通信_Laravel Reverb与WebSockets实战教程  中山网站推广排名,中山信息港登录入口?  Laravel如何发送系统通知_Laravel Notifications实现多渠道消息通知  如何用y主机助手快速搭建网站?  如何在 Python 中将列表项按字母顺序编号(a.、b.、c. …)  Laravel如何使用Blade组件和插槽?(Component代码示例)  常州企业网站制作公司,全国继续教育网怎么登录?  千库网官网入口推荐 千库网设计创意平台入口  如何快速搭建安全的FTP站点?  Laravel如何实现API资源集合?(Resource Collection教程)  如何用低价快速搭建高质量网站?  Laravel如何编写单元测试和功能测试?(PHPUnit示例)  javascript中的数组方法有哪些_如何利用数组方法简化数据处理  制作无缝贴图网站有哪些,3dmax无缝贴图怎么调?  Laravel怎么生成二维码图片_Laravel集成Simple-QrCode扩展包与参数设置【实战】  Claude怎样写约束型提示词_Claude约束提示词写法【教程】  Laravel集合Collection怎么用_Laravel集合常用函数详解  米侠浏览器网页图片不显示怎么办 米侠图片加载修复  javascript事件捕获机制【深入分析IE和DOM中的事件模型】  在线ppt制作网站有哪些软件,如何把网页的内容做成ppt?  javascript基于原型链的继承及call和apply函数用法分析  HTML透明颜色代码在Angular里怎么设置_Angular透明颜色使用指南【详解】  Laravel如何实现API版本控制_Laravel版本化API设计方案  Laravel怎么实现模型属性转换Casting_Laravel自动将JSON字段转为数组【技巧】  高端网站建设与定制开发一站式解决方案 中企动力  HTML5段落标签p和br怎么选_文本排版常用标签对比【解答】  如何选择PHP开源工具快速搭建网站?  Laravel怎么做数据加密_Laravel内置Crypt门面的加密与解密功能  Laravel如何实现密码重置功能_Laravel密码找回与重置流程  太平洋网站制作公司,网络用语太平洋是什么意思?  哪家制作企业网站好,开办像阿里巴巴那样的网络公司和网站要怎么做?  Laravel如何使用Passport实现OAuth2?(完整配置步骤)  Laravel如何使用API Resources格式化JSON响应_Laravel数据资源封装与格式化输出  奇安信“盘古石”团队突破 iOS 26.1 提权  Python文件异常处理策略_健壮性说明【指导】  如何在万网自助建站中设置域名及备案?  Laravel中Service Container是做什么的_Laravel服务容器与依赖注入核心概念解析  如何批量查询域名的建站时间记录?  如何快速使用云服务器搭建个人网站?  高性价比服务器租赁——企业级配置与24小时运维服务  大同网页,大同瑞慈医院官网?  软银砸40亿美元收购DigitalBridge 强化AI资料中心布局  香港服务器网站测试全流程:性能评估、SEO加载与移动适配优化