c++无原生装饰器语法,需手动实现decorator类层次:定义组件接口、具体组件和装饰器基类,通过组合与多态委派扩展行为;关键在于用std::unique_ptr管理所有权,避免切片与悬挂指针。

C++ 没有原生装饰器语法,所谓“用装饰器模式”其实是手动实现 Decorator 类层次,靠组合 + 接口抽象来扩展行为——不是加个 @ 就完事。
为什么 C++ 不能直接写 @logging 这种装饰器
C++ 编译期不支持运行时元编程(如 Python 的函数对象劫持),也没有反射机制自动包裹调用。所有“装饰”必须显式构造、显式委托。
-
std::function或函数指针可以模拟简单包装,但丢失类型信息和性能 - 宏(如
#define LOG_DECORATE(f) ...)能生成代码,但调试困难、不支持重载、破坏 IDE 跳转 - 真正可靠的方案是定义接口基类 + 具体装饰器子类,靠多态委派
标准装饰器模式的最小可行结构(C++17)
核心是三个角色:组件接口、具体组件、装饰器基类(也实现该接口)。装饰器持有指向组件的 std::unique_ptr<component></component> 或引用,构造时传入被装饰对象。
- 接口必须是纯虚类,避免值语义导致的切片问题
- 装饰器的构造函数应接受
std::unique_ptr<component></component>(转移所有权)或Component&(要求外部管理生命周期) - 不要在装饰器里存储
Component值对象——会触发拷贝且无法装饰多层
示例关键片段:
立即学习“C++免费学习笔记(深入)”;
class Component {
public:
virtual ~Component() = default;
virtual void operation() = 0;
};
<p>class ConcreteComponent : public Component {
void operation() override { /<em> 实际逻辑 </em>/ }
};</p><p>class Decorator : public Component {
protected:
std::unique<em>ptr<Component> component</em>;
public:
explicit Decorator(std::unique<em>ptr<Component> c) : component</em>(std::move(c)) {}
void operation() override { component_->operation(); }
};</p><p>class LoggingDecorator : public Decorator {
public:
using Decorator::Decorator;
void operation() override {
std::cout << "log: start\n";
Decorator::operation();
std::cout << "log: end\n";
}
};</p>容易踩的坑:生命周期与内存管理
装饰器链越长,对象归属越容易出错。常见崩溃源于悬挂指针或重复释放。
- 如果用裸指针(
Component*)传入装饰器,必须确保原始对象比所有装饰器活得久——几乎不可控 - 混用
std::shared_ptr和std::unique_ptr容易引发循环引用(比如装饰器又存回 shared_ptr 给被装饰者) - 移动语义没写对:忘记在
Decorator构造函数中用std::move,导致component_为空,调用时崩溃 - 多线程下,若装饰器内部缓存状态(如计数器),需额外加锁——接口本身不保证线程安全
最麻烦的从来不是写对第一层装饰,而是第三层装饰还依赖第二层的状态变更,这时就得检查每层的构造顺序和所有权移交是否连贯。稍不注意,component_->operation() 就调到了已析构的对象上。









