C++14环境下实现持有A/B引用的TargetProxy以统一Sender虚send接口
TargetProxy实现方案
我们可以通过「类型标签+常量指针存储」的方式实现完全兼容C++14标准的TargetProxy,无第三方依赖,同时支持Google Mock的等值匹配断言,具体实现如下:
完整TargetProxy代码
class TargetProxy { public: // 支持隐式构造,上层传A/B时可自动转换,无需修改业务调用代码 TargetProxy(const A& a) : type_(Type::kA), ptr_(&a) {} TargetProxy(const B& b) : type_(Type::kB), ptr_(&b) {} // 类型判断接口,供虚函数实现逻辑区分地址类型使用 bool isA() const { return type_ == Type::kA; } bool isB() const { return type_ == Type::kB; } // 安全取值接口,调用前需先通过isA/isB确认对应类型 const A& getA() const { return *static_cast<const A*>(ptr_); } const B& getB() const { if (isA()) { // 利用A可转换为B的特性返回对应实例 return static_cast<B>(getA()); } return *static_cast<const B*>(ptr_); } // 重载==运算符,适配Google Mock的Eq匹配规则 bool operator==(const TargetProxy& rhs) const { if (type_ == rhs.type_) { return type_ == Type::kA ? (getA() == rhs.getA()) : (getB() == rhs.getB()); } // 跨类型比较时统一转成B再对比,可根据需求去掉该逻辑 return getB() == rhs.getB(); } // 支持直接和A/B实例做等值比较 bool operator==(const A& rhs) const { return isA() && getA() == rhs; } bool operator==(const B& rhs) const { return getB() == rhs; } private: enum class Type { kA, kB }; Type type_; const void* ptr_; }; // 补充全局==重载,支持A/B实例在左的比较场景,适配Eq参数顺序不固定的情况 inline bool operator==(const A& lhs, const TargetProxy& rhs) { return rhs == lhs; } inline bool operator==(const B& lhs, const TargetProxy& rhs) { return rhs == lhs; }
Sender类改造示例
对外API完全不变,业务侧无感知,底层合并为统一虚接口:
class Sender{ public: // 原有对外接口保留,仅修改内部实现 template<typename TReq> void send(const A& target, TReq req) { send(TargetProxy(target), make_request(std::move(req))); } template<typename TReq> void send(const B& target, TReq req) { send(TargetProxy(target), make_request(std::move(req))); } protected: // 合并后的统一虚接口 virtual void send(const TargetProxy& target, MessageProxy message); };
GMock适配说明
因为已经完整重载了所有等值比较场景的==运算符,你要求的测试用例可以直接正常使用:
EXPECT_CALL(mock, send(Eq(A{}), Message{}))... EXPECT_CALL(mock, send(Eq(B{}), OtherMessage{}))...
注意事项
- TargetProxy仅做引用透传,不持有地址对象的所有权,不要长期持有TargetProxy实例避免悬空引用,当前仅在send调用栈内使用是完全安全的
- 如果不需要跨类型等值比较,可以去掉跨类型转B对比的逻辑,减少不必要的B实例构造开销
内容的提问来源于stack exchange,提问作者Bartoszek
相关产品推荐
相关产品推荐

