必须用对象适配器:当adaptee非自研、无虚析构、含资源或需依赖注入时,组合实现安全可控;转发需处理参数单位、错误映射与语义对齐,并用std::unique_ptr管理生命周期及异常边界。

直接用对象适配器,别碰类适配器。C++里类适配器靠多重继承,一来破坏封装,二来遇到虚继承或非虚析构就容易崩;对象适配器用组合,干净、可控、符合现代C++习惯。
什么时候必须用对象适配器
当你要适配的类(Adaptee)不是你写的,或者你不能改它的头文件时,对象适配器是唯一安全的选择。比如第三方SDK里的 LegacyPaymentSys,它没有虚析构函数,也没有 virtual 方法,你不可能让它去继承你的 IPaymentGateway 接口。
- 第三方库对象生命周期由对方管理,你只能持有一个指针或引用,没法继承
- Adaptee 有资源(如句柄、线程、内存池),组合能明确控制其创建/销毁时机
- 目标接口(Target)带纯虚函数,而 Adaptee 是 concrete class,强行继承会导致菱形继承歧义
- 后续要加 mock 或替换实现(比如测试时换成
MockPaymentSys),组合天然支持依赖注入
Adapter 类里怎么转发调用
转发不是简单套壳,得处理三类转换:参数单位、错误传递方式、语义对齐。比如把 sendPayment(const char*, long, std::string&) 转成 pay(const std::string&, double),关键点在:
- 用
std::string构造时加nullptr检查,避免传入空指针导致未定义行为 - 金额从“分”转“元”要除以
100.0,不是整除,否则丢精度 - 错误信息不能只丢进
std::string&出参——PaymentResult要包含success、code、message字段,适配器里得做映射 - 原接口返回
bool,但失败时错误信息可能为空,得补默认文案,否则上层日志抓不到上下文
为什么 std::unique_ptr<adaptee></adaptee> 比裸指针更稳妥
裸指针(Adaptee*)看似轻量,但在构造、拷贝、异常路径下极易悬空或重复释放。用 std::unique_ptr<adaptee></adaptee> 能自动约束所有权,且兼容工厂模式。
- 构造时用
std::make_unique<legacypaymentsys>()</legacypaymentsys>,避免new后异常导致泄漏 - 如果 Adaptee 需要配置参数(如 host/port),可在 Adapter 构造函数里传入,再转发给
std::make_unique - 不支持拷贝?直接删掉
Adapter(const Adapter&)和operator=,强制移动语义 - 测试时想换实现?把
std::unique_ptr<adaptee></adaptee>改成模板参数,或接受std::unique_ptr<iadaptee></iadaptee>接口指针
最容易被忽略的是异常边界:Adaptee 的原始接口可能抛异常,也可能不抛,但你的 Adapter 必须统一行为。如果目标接口声明了 noexcept,而 Adaptee 可能抛,你就得在转发前用 try/catch 捕获并转成错误码——这点几乎没人写文档,但线上崩溃往往就栽在这儿。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











