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

如何在同一容器中存储模板类不同实例并调用其专属方法

问题描述

现有如下类结构:

class A
{
   // 包含虚方法
};

template<typename T>
class B : public A
{
public:
    void ANewMethodSpecificOfClassB(/* 参数 */) { /* 实现 */ };
};

需要将不同实例化的B类对象(如B<instanciation1> south_park、B<instanciation2> family_guy)放入同一个容器(例如std::vector),并调用它们的ANewMethodSpecificOfClassB方法。

遇到的困境:

  • 无法直接声明std::vector<B>,因为B是模板类,只有特定实例化后的B<T>才是具体类。
  • 使用std::vector<std::shared_ptr<A>>存储时,无法直接调用ANewMethodSpecificOfClassB——该方法未在基类A中定义,且无法修改A的代码。
可行解决方案

方案1:类型擦除自定义包装器

通过创建包装类封装B<T>的方法调用逻辑,实现类型擦除,让不同B<T>实例可以统一存储。

实现步骤:

  1. 定义抽象接口类,声明需要调用的方法:
class BWrapperInterface {
public:
    virtual ~BWrapperInterface() = default;
    virtual void callANewMethod(/* 匹配ANewMethodSpecificOfClassB的参数 */) = 0;
};
  1. 实现模板子类,持有具体B<T>实例并实现接口方法:
template<typename T>
class BWrapper : public BWrapperInterface {
private:
    B<T>& instance; // 可替换为std::shared_ptr<B<T>>,根据对象生命周期需求调整
public:
    explicit BWrapper(B<T>& obj) : instance(obj) {}
    void callANewMethod(/* 参数 */) override {
        instance.ANewMethodSpecificOfClassB(/* 传递参数 */);
    }
};
  1. 创建容器存储包装器智能指针并调用方法:
#include <vector>
#include <memory>

int main() {
    B<instanciation1> south_park;
    B<instanciation2> family_guy;

    std::vector<std::unique_ptr<BWrapperInterface>> container;
    container.emplace_back(std::make_unique<BWrapper<instanciation1>>(south_park));
    container.emplace_back(std::make_unique<BWrapper<instanciation2>>(family_guy));

    // 遍历调用每个实例的方法
    for (auto& wrapper : container) {
        wrapper->callANewMethod(/* 传入参数 */);
    }
    return 0;
}

方案2:使用std::variant(已知所有B<T>类型时)

如果所有需要存储的B<T>实例类型明确已知,可通过std::variant存储不同类型,再用std::visit统一调用方法。

示例代码:

#include <vector>
#include <variant>

// 定义包含所有目标类型的variant
using BVariant = std::variant<B<instanciation1>, B<instanciation2>>;

int main() {
    B<instanciation1> south_park;
    B<instanciation2> family_guy;

    std::vector<BVariant> container;
    container.push_back(south_park);
    container.push_back(family_guy);

    // 定义调用方法的逻辑
    auto call_method = [](auto& b_instance) {
        b_instance.ANewMethodSpecificOfClassB(/* 参数 */);
    };

    // 遍历容器执行调用
    for (auto& var : container) {
        std::visit(call_method, var);
    }
    return 0;
}

该方法局限性在于必须提前明确所有要存储的B<T>类型,无法动态添加未知类型。

方案3:dynamic_cast类型转换(不推荐,代码冗余)

若能确定每个元素的具体类型,可将A*动态转换为对应B<T>*后调用方法,但需逐个判断类型,代码冗余且扩展性差。

示例代码:

#include <vector>
#include <memory>

int main() {
    std::vector<std::shared_ptr<A>> container;
    container.push_back(std::make_shared<B<instanciation1>>());
    container.push_back(std::make_shared<B<instanciation2>>());

    for (auto& ptr : container) {
        if (auto b1_ptr = dynamic_cast<B<instanciation1>*>(ptr.get())) {
            b1_ptr->ANewMethodSpecificOfClassB(/* 参数 */);
        } else if (auto b2_ptr = dynamic_cast<B<instanciation2>*>(ptr.get())) {
            b2_ptr->ANewMethodSpecificOfClassB(/* 参数 */);
        }
        // 新增类型需添加更多else if分支
    }
    return 0;
}

仅适合类型极少且固定的场景,不推荐用于复杂或需扩展的场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 08:10:39