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

如何创建包含多模板参数类型的模板接口向量?

解决方案:存储不同特化模板接口的派生类到向量

你的核心问题是:ITemplateInterface<T>的不同特化是完全独立的类型,DerivedClass1继承的是ITemplateInterface<std::string>,DerivedClass2继承的是ITemplateInterface<int>,这两个基类之间没有继承关系,因此无法将它们的指针直接存入同一个向量。要解决这个问题,需要引入一个非模板的公共基类来统一类型,再结合类型封装或访问者模式处理不同的返回值。

方法一:使用std::any封装返回值

这种方式灵活,适合派生类类型不确定或较多的场景:

#include <iostream>
#include <vector>
#include <any>
#include <typeinfo>

// 定义非模板公共基类,作为所有模板接口的统一父类
class IBaseInterface {
public:
    virtual void foo() = 0;
    virtual std::any getAnyValue() const = 0;
    virtual ~IBaseInterface() = default;
};

// 模板接口继承自非模板基类
template <typename T>
class ITemplateInterface : public IBaseInterface {
public:
    virtual T getValue() const = 0;
    
    // 实现基类方法,将强类型值封装为std::any
    std::any getAnyValue() const override {
        return getValue();
    }

    using type = T;
};

// 派生类1(特化为std::string)
class DerivedClass1 : public ITemplateInterface<std::string> {
public:
    void foo() override {
        std::cout << "DerivedClass1 foo" << std::endl;
    }

    std::string getValue() const override {
        return "Hello from Derived1";
    }
};

// 派生类2(特化为int)
class DerivedClass2 : public ITemplateInterface<int> {
public:
    void foo() override {
        std::cout << "DerivedClass2 foo" << std::endl;
    }

    int getValue() const override {
        return 42;
    }
};

int main() {
    // 向量存储非模板基类的指针
    std::vector<IBaseInterface*> myVector;

    DerivedClass1 obj1;
    DerivedClass2 obj2;

    myVector.push_back(&obj1);
    myVector.push_back(&obj2);

    // 遍历并使用对象
    for (auto item : myVector) {
        item->foo();
        
        std::any value = item->getAnyValue();
        // 根据类型取出值并打印
        if (value.type() == typeid(std::string)) {
            std::cout << "Value: " << std::any_cast<std::string>(value) << "\n\n";
        } else if (value.type() == typeid(int)) {
            std::cout << "Value: " << std::any_cast<int>(value) << "\n\n";
        }
    }

    return 0;
}

说明:

  • 非模板基类IBaseInterface提供了统一的接口,让所有派生类可以被放入同一个向量。
  • ITemplateInterface<T>实现getAnyValue方法,将getValue()的强类型结果封装为std::any,实现类型擦除。
  • 遍历通过std::any::type()判断实际类型,再用std::any_cast取出对应值。

方法二:访问者模式(类型安全)

如果派生类类型固定,推荐使用访问者模式,避免类型判断,保证类型安全:

#include <iostream>
#include <vector>

// 前向声明访问者类
class IVisitor;

// 非模板公共基类
class IBaseInterface {
public:
    virtual void foo() = 0;
    virtual void accept(IVisitor& visitor) = 0;
    virtual ~IBaseInterface() = default;
};

// 访问者基类,枚举所有需要处理的派生类
class IVisitor {
public:
    virtual void visit(DerivedClass1* obj) = 0;
    virtual void visit(DerivedClass2* obj) = 0;
    virtual ~IVisitor() = default;
};

// 模板接口
template <typename T>
class ITemplateInterface : public IBaseInterface {
public:
    virtual T getValue() const = 0;
    using type = T;
};

// 派生类1
class DerivedClass1 : public ITemplateInterface<std::string> {
public:
    void foo() override {
        std::cout << "DerivedClass1 foo" << std::endl;
    }

    std::string getValue() const override {
        return "Hello from Derived1";
    }

    // 实现accept方法,接受访问者
    void accept(IVisitor& visitor) override {
        visitor.visit(this);
    }
};

// 派生类2
class DerivedClass2 : public ITemplateInterface<int> {
public:
    void foo() override {
        std::cout << "DerivedClass2 foo" << std::endl;
    }

    int getValue() const override {
        return 42;
    }

    void accept(IVisitor& visitor) override {
        visitor.visit(this);
    }
};

// 具体访问者:打印对象信息
class PrintVisitor : public IVisitor {
public:
    void visit(DerivedClass1* obj) override {
        obj->foo();
        std::cout << "Value: " << obj->getValue() << "\n\n";
    }

    void visit(DerivedClass2* obj) override {
        obj->foo();
        std::cout << "Value: " << obj->getValue() << "\n\n";
    }
};

int main() {
    std::vector<IBaseInterface*> myVector;

    DerivedClass1 obj1;
    DerivedClass2 obj2;

    myVector.push_back(&obj1);
    myVector.push_back(&obj2);

    PrintVisitor visitor;
    // 遍历并通过访问者处理每个对象
    for (auto item : myVector) {
        item->accept(visitor);
    }

    return 0;
}

说明:

  • 访问者模式通过accept方法将对象自身传递给访问者,由访问者根据对象实际类型执行对应逻辑。
  • 不需要类型判断,完全类型安全,但需要提前枚举所有可能的派生类,适合派生类固定的场景。

内容的提问来源于stack exchange,提问作者codiac

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 09:30:57