如何在C++中创建未指定模板参数的模板基类数组?
问题分析与解决方案
首先明确原代码无法运行的核心原因:
Any是模板类,必须指定模板参数才能成为具体类型,直接写Any types[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
相关产品推荐
相关产品推荐

