C++中如何正确实现该场景下的模板装饰器模式
问题根因
你当前的写法无法编译通过,核心错误有4点:
- 类成员默认访问权限为
private,FooBase中的纯虚函数没有声明为public,子类无法重写、外部无法调用,且基类缺少虚析构函数,存在对象析构时的资源泄漏风险。 - 模板参数声明与使用不匹配:你将
Bar的第二个模板参数声明为接收具体类型的typename Foo,但类内部却以Foo<pair<T, int>>的形式把它当类模板使用,语法直接报错。 - 函数内变量名不一致:
push方法中定义的变量名为value,调用make_pair时却使用了未定义的变量v。 - 逻辑冗余+接口不匹配:你同时让
Bar继承Foo<pair<T, int>>、又在内部定义了同类型的foo_成员,且你写的push/pop签名和基类纯虚函数要求的签名不匹配,会导致Bar成为抽象类无法实例化。
正确实现方案
根据你想要的初始化写法,二选一即可。
方案1:传入已实例化的Foo类型
这个方案下Bar的第二个参数接收已经实例化好的具体Foo类,初始化时明确指定底层存储的类型为pair<T, int>。
修正后的基础类定义
#include <utility> #include <stack> // 假设这是你已有的全局函数实现 int get_val(); template <typename T> class FooBase { public: virtual void push(T& t) = 0; virtual T pop() = 0; // 基类必须加虚析构 virtual ~FooBase() = default; }; // 派生类实现示例,必须重写全部纯虚函数才能实例化 template<typename T> class FooDerived1: public FooBase<T> { private: std::stack<T> storage; public: void push(T& t) override { storage.push(t); } T pop() override { T res = storage.top(); storage.pop(); return res; } }; template<typename T> class FooDerived2: public FooBase<T> { // 自行实现push/pop逻辑即可 };
Bar装饰器实现
template<typename T, typename FooType> class Bar: public FooBase<T> { private: FooType foo_; public: void push(T& t) override { int value = get_val(); auto elem = std::make_pair(t, value); foo_.push(elem); } T pop() override { auto elem = foo_.pop(); return elem.first; } };
初始化写法
Bar<float, FooDerived1<std::pair<float, int>>> bar1; Bar<float, FooDerived2<std::pair<float, int>>> bar2;
方案2:使用模板模板参数,简化初始化写法
如果你不想每次初始化都手动写pair<T, int>,可以把Bar的第二个参数声明为接收类模板的模板模板参数,内部自动完成pair类型的实例化。
Bar装饰器实现
// 第二个参数为模板模板参数,接收仅需一个类型参数的类模板 template<typename T, template<typename> class FooTemplate> class Bar: public FooBase<T> { private: // 内部自动实例化为存储pair<T,int>的Foo对象 FooTemplate<std::pair<T, int>> foo_; public: void push(T& t) override { int value = get_val(); auto elem = std::make_pair(t, value); foo_.push(elem); } T pop() override { return foo_.pop().first; } };
初始化写法
// 第二个参数直接传类模板名,不需要加<>实例化 Bar<float, FooDerived1> bar1; Bar<float, FooDerived2> bar2;
补充说明
如果你需要Bar对外直接返回pair<T, int>类型的元素,只需要把Bar的继承基类改成FooBase<std::pair<T, int>>,对应调整pop的返回值逻辑即可,不需要改动其他部分。
内容的提问来源于stack exchange,提问作者user3443615
相关产品推荐
相关产品推荐

