You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 11:15:42