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

如何在C++中创建未指定模板参数的模板基类数组?

问题分析与解决方案

首先明确原代码无法运行的核心原因:

  1. Any是模板类,必须指定模板参数才能成为具体类型,直接写Any types[2]属于语法错误。
  2. 即使改为Any<int> types[2] { Number(1), Number(3) },也会发生对象切片:数组存储的是Any<int>基类对象,子类Number的特有成员、虚函数覆盖都会被丢弃,无法实现多态或调用子类专属函数。

以下是几种可行的实现方式:


方式一:使用智能指针数组实现多态

适合需要多态调用子类方法的场景,通过基类指针指向子类对象,避免切片问题。首先需给基类添加虚析构函数(否则子类对象通过基类指针销毁时会内存泄漏),以及需要多态调用的虚函数。

修改后的代码:

#include <memory>
#include <iostream>

template<typename T>
class Any
{
public:
    T data;
    Any(T data) : data(data) {}
    // 虚析构是多态场景的必要条件
    virtual ~Any() = default;
    // 示例虚函数,用于多态调用
    virtual void print() const {
        std::cout << "Any data: " << data << std::endl;
    }
};

class Number : public Any<int>
{
public:
    // 继承基类构造函数
    using Any<int>::Any;
    // 覆盖基类虚函数
    void print() const override {
        std::cout << "Number data: " << data << std::endl;
    }
    // 子类专属减法函数
    Number subtract(const Number& other) const {
        return Number(data - other.data);
    }
};

int main()
{
    // 使用std::unique_ptr管理内存,避免手动释放的风险
    std::unique_ptr<Any<int>> types[2] {
        std::make_unique<Number>(1),
        std::make_unique<Number>(3)
    };

    // 多态调用print函数
    for (const auto& ptr : types) {
        ptr->print();
    }

    // 调用子类专属函数需向下转型(dynamic_cast)
    if (auto num1 = dynamic_cast<Number*>(types[0].get())) {
        auto num2 = dynamic_cast<Number*>(types[1].get());
        auto result = num1->subtract(*num2);
        std::cout << "减法结果:" << result.data << std::endl;
    }

    return 0;
}

方式二:使用std::variant(C++17+)

适合已知所有需要存储的子类类型的场景,std::variant是类型安全的联合类型,无需指针,编译时即可检查类型合法性。

示例代码:

#include <variant>
#include <string>
#include <iostream>

template<typename T>
class Any
{
public:
    T data;
    Any(T data) : data(data) {}
    virtual ~Any() = default;
    virtual void print() const {
        std::cout << "Any data: " << data << std::endl;
    }
};

class Number : public Any<int>
{
public:
    using Any<int>::Any;
    void print() const override {
        std::cout << "Number data: " << data << std::endl;
    }
};

class String : public Any<std::string>
{
public:
    using Any<std::string>::Any;
    void print() const override {
        std::cout << "String data: " << data << std::endl;
    }
};

int main()
{
    // 定义variant可存储的类型集合
    std::variant<Number, String> types[2] {
        Number(1),
        String("Hello")
    };

    // 使用std::visit访问variant中的对象
    for (auto& var : types) {
        std::visit([](auto& obj) { obj.print(); }, var);
    }

    return 0;
}

方式三:使用std::any(C++17+)

适合类型不确定或类型较多的场景,std::any是类型擦除的容器,可存储任意类型的对象,运行时进行类型检查。

示例代码:

#include <any>
#include <iostream>

template<typename T>
class Any
{
public:
    T data;
    Any(T data) : data(data) {}
    void print() const {
        std::cout << "Any data: " << data << std::endl;
    }
};

class Number : public Any<int>
{
public:
    using Any<int>::Any;
    void subtract(const Number& other) {
        data -= other.data;
    }
};

int main()
{
    std::any types[2] {
        Number(1),
        Number(3)
    };

    // 取出对象并调用方法需用std::any_cast进行类型转换
    if (auto num1 = std::any_cast<Number>(&types[0])) {
        num1->print();
        auto num2 = std::any_cast<Number>(&types[1]);
        num1->subtract(*num2);
        std::cout << "减法后的值:" << num1->data << std::endl;
    }

    return 0;
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 21:31:01