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

C++如何通过模板让构造函数按输入type参数初始化不同策略类对象

错误原因

你遇到的编译错误核心是C++模板的实例化是编译期行为,而switch分支是运行时分支:
当你调用不同参数的SellContext构造函数时,编译器会为每一组Ts参数实例化一整个构造函数的实现,不管运行时会走到哪个switch分支,所有分支的代码都必须是合法可编译的。
举个例子:当你调用无额外参数的SellContext(SellContext::type::NORMAL)时,编译器实例化出的构造函数里,case DISCOUNT分支的代码是new SellDiscount(),但SellDiscount没有无参构造函数,自然编译报错,其他报错也都是同理。

优雅解决方案

方案1:C++17及以上,编译期标签分发(推荐,兼容策略模式同类型要求)

不需要修改现有策略类,也不需要重载多个构造函数,还能保证所有SellContext是同一个类型,可以存入同一个容器:

#include <iostream>
#include <memory> // 用智能指针避免内存泄漏
using namespace std;

// 原有Strategy、SellNormal、SellDiscount、SellReturn类逻辑不变,仅补全虚析构
class Strategy {
public:
    virtual double GetResult(double) = 0;
    virtual ~Strategy() = default; // 基类加虚析构,保证子类正确释放
};

class SellNormal: public Strategy {
public:
    double GetResult(double original) override {
        return original;
    }
};

class SellDiscount: public Strategy {
    double rate;
public:
    SellDiscount(double r){
        rate = r;
    }
    double GetResult(double original) override {
        return original * rate;
    }
};
class SellReturn: public Strategy {
    int fulfill;
    int reduce;
public:
    SellReturn(int f, int r): fulfill(f), reduce(r){}
    double GetResult(double original) override {
        return original - (int(original) / fulfill) * reduce;
    }
};

class SellContext{
    unique_ptr<Strategy> s; // 用智能指针自动管理内存
    // 空标签类型,用于编译期重载区分
    struct NormalTag {};
    struct DiscountTag {};
    struct ReturnTag {};

    // 编译期重载的创建逻辑,不匹配的分支不会被实例化
    template<typename... Ts>
    unique_ptr<Strategy> create(NormalTag, Ts&&... args) {
        return make_unique<SellNormal>(forward<Ts>(args)...);
    }
    template<typename... Ts>
    unique_ptr<Strategy> create(DiscountTag, Ts&&... args) {
        return make_unique<SellDiscount>(forward<Ts>(args)...);
    }
    template<typename... Ts>
    unique_ptr<Strategy> create(ReturnTag, Ts&&... args) {
        return make_unique<SellReturn>(forward<Ts>(args)...);
    }
public:
    enum type{
        NORMAL,
        DISCOUNT,
        RETURN
    };
    template<typename ...Ts>
    SellContext(type t, Ts... args){
        if constexpr (sizeof...(Ts) == 0) {} // 避免空参数包编译警告
        switch(t){
        case NORMAL:
            s = create(NormalTag{}, args...);
            break;
        case DISCOUNT:
            s = create(DiscountTag{}, args...);
            break;
        case RETURN:
            s = create(ReturnTag{}, args...);
            break;
        }
    }
    double getResult(double original){
        return s->GetResult(original);
    }
};
    
int main(){
    SellContext c1(SellContext::type::NORMAL);
    SellContext c2(SellContext::type::DISCOUNT, 0.8);
    SellContext c3(SellContext::type::RETURN, 300, 100);
    cout << c1.getResult(1000) << '\n'; // 输出1000
    cout << c2.getResult(1000) << '\n'; // 输出800
    cout << c3.getResult(1000) << '\n'; // 输出700
}

方案2:C++11兼容方案

如果只能用C++11标准,可以把策略创建逻辑抽到静态重载函数,避免模板全分支编译的问题:

// 其他策略类代码和上文一致,仅修改SellContext部分
class SellContext{
    Strategy* s;
    static Strategy* create(SellContext::type t) {
        if (t == NORMAL) return new SellNormal();
        abort(); // 参数不匹配直接终止,可自行替换为自定义错误处理
    }
    static Strategy* create(SellContext::type t, double rate) {
        if (t == DISCOUNT) return new SellDiscount(rate);
        abort();
    }
    static Strategy* create(SellContext::type t, int fulfill, int reduce) {
        if (t == RETURN) return new SellReturn(fulfill, reduce);
        abort();
    }
public:
    enum type{
        NORMAL,
        DISCOUNT,
        RETURN
    };
    template<typename ...Ts>
    SellContext(type t, Ts... args): s(create(t, args...)) {}

    ~SellContext() { delete s; }
    
    double getResult(double original){
        return s->GetResult(original);
    }
};

内容的提问来源于stack exchange,提问作者Coding-pupupu

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.26 05:54:04