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)。它转发调用,再在前后插入额外逻辑 —— 这就是“动态扩展”的实质。
立即学习“C++免费学习笔记(深入)”;
- 推荐用
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 的脉搏来安排。











