C++运行时动态创建指定类型对象:多态与模板的困境及求解
解决方案
针对你这种已知有限类型(2-5种)的场景,有几种简单的实现方式,不需要复杂的泛型或std::variant:
方法1:多态父类提供类型专属访问接口
在父类中为每种已知类型定义对应的虚访问函数,子类重写自己类型对应的函数,安全获取数据:
#include <iostream> #include <memory> // 用智能指针避免手动管理内存 using namespace std; struct Parent { virtual ~Parent() = default; // 必须声明虚析构,确保子类析构函数被调用 virtual void print_type() = 0; // 为每种已知类型定义专属getter virtual int* get_int() { return nullptr; } virtual float* get_float() { return nullptr; } }; template<class T> struct Child : public Parent { T data; void print_type() override { cout << typeid(T).name() << endl; } }; // 特化int子类的get_int方法 template<> int* Child<int>::get_int() { return &data; } // 特化float子类的get_float方法 template<> float* Child<float>::get_float() { return &data; } unique_ptr<Parent> Factory(int type_code) { if (type_code == 0) { return make_unique<Child<int>>(); } else { return make_unique<Child<float>>(); } } int main() { int type_code; cin >> type_code; auto p = Factory(type_code); p->print_type(); // 访问并修改数据 if (int* int_data = p->get_int()) { *int_data = 123; cout << "Int data: " << *int_data << endl; } else if (float* float_data = p->get_float()) { *float_data = 45.67f; cout << "Float data: " << *float_data << endl; } }
新增类型时,只需在父类添加对应虚函数,再特化子类的实现即可,逻辑直白易维护。
方法2:用dynamic_cast直接转换子类指针
利用C++动态类型转换,拿到父类指针后尝试转换为对应子类指针,成功则直接访问数据:
#include <iostream> #include <memory> using namespace std; struct Parent { virtual ~Parent() = default; virtual void print_type() = 0; }; template<class T> struct Child : public Parent { T data; void print_type() override { cout << typeid(T).name() << endl; } }; unique_ptr<Parent> Factory(int type_code) { if (type_code == 0) { return make_unique<Child<int>>(); } else { return make_unique<Child<float>>(); } } int main() { int type_code; cin >> type_code; auto p = Factory(type_code); p->print_type(); // 尝试转换为子类指针并操作数据 if (auto child_int = dynamic_cast<Child<int>*>(p.get())) { child_int->data = 789; cout << "Int data: " << child_int->data << endl; } else if (auto child_float = dynamic_cast<Child<float>*>(p.get())) { child_float->data = 10.11f; cout << "Float data: " << child_float->data << endl; } }
这种方式代码更简洁,不需要额外虚函数,缺点是需要显式判断每种类型,但对于2-5种类型的场景完全可以接受。
方法3:极简版类型擦除(用void*)
如果追求极致简单,可在父类用void*存储数据并记录类型标签,手动维护类型安全:
#include <iostream> #include <memory> using namespace std; enum class DataType { INT, FLOAT }; struct Parent { DataType type; void* data; virtual ~Parent() { // 根据类型手动释放内存 if (type == DataType::INT) { delete static_cast<int*>(data); } else if (type == DataType::FLOAT) { delete static_cast<float*>(data); } } void print_type() { cout << (type == DataType::INT ? "int" : "float") << endl; } }; unique_ptr<Parent> Factory(int type_code) { auto p = make_unique<Parent>(); if (type_code == 0) { p->type = DataType::INT; p->data = new int(); } else { p->type = DataType::FLOAT; p->data = new float(); } return p; } int main() { int type_code; cin >> type_code; auto p = Factory(type_code); p->print_type(); // 访问并修改数据 if (p->type == DataType::INT) { *static_cast<int*>(p->data) = 1234; cout << "Int data: " << *static_cast<int*>(p->data) << endl; } else if (p->type == DataType::FLOAT) { *static_cast<float*>(p->data) = 56.78f; cout << "Float data: " << *static_cast<float*>(p->data) << endl; } }
这种方式不需要模板和子类,缺点是类型安全全靠手动维护,适合类型极少的场景。
内容的提问来源于stack exchange,提问作者Gentlebool
相关产品推荐
相关产品推荐

