C++ 异构多态参数vector存储及get/set方法调用问题咨询
解决方案
以下是三种常用的可行实现方案,可根据你的项目C++版本和业务需求选择:
方案1:使用std::variant(C++17及以上,最简洁方案)
如果你的参数类型是有限可枚举的,优先选该方案,无需手动实现继承体系的多态,类型安全且无需管理裸指针:
#include <variant> #include <vector> #include <string> #include <optional> // 先枚举所有可能的参数值类型 using ParamValue = std::variant<int, double, std::string>; class Parameter { public: Parameter(std::string name, ParamValue val): name(std::move(name)), value(std::move(val)) {} // 泛型取值,返回std::optional判断类型是否匹配 template<typename T> std::optional<T> get_value() const { if (std::holds_alternative<T>(value)) { return std::get<T>(value); } return std::nullopt; } // 泛型赋值,返回bool判断是否赋值成功 template<typename T> bool set_value(T val) { if (std::holds_alternative<T>(value)) { value = val; return true; } return false; } std::string get_name() const { return name; } private: std::string name; ParamValue value; }; // 直接定义vector存储即可 std::vector<Parameter> param_list;
- 优点:无需手动管理内存、类型安全、代码简洁、性能最优
- 缺点:参数类型必须提前枚举,不能支持任意未知类型
方案2:正确使用dynamic_cast(兼容C++11及以上,保留原有继承体系)
你之前使用dynamic_cast失败是因为基类没有虚函数,dynamic_cast要求基类至少有一个虚函数,补充虚析构函数即可,顺便解决内存泄漏问题:
#include <vector> #include <string> #include <memory> class ParamBase { public: // 必须加虚析构:一是支持dynamic_cast,二是释放资源时不会漏派生类内容 virtual ~ParamBase() = default; std::string get_name() const { return name; } protected: std::string name; }; template<class T> class Parameter : public ParamBase { public: Parameter(std::string name, T val) { this->name = std::move(name); this->value = val; } T get_value() const { return this->value; } void set_value(T val) { this->value = val; } private: T value; };
调用示例:
// 用智能指针代替裸指针,避免内存泄漏 std::vector<std::unique_ptr<ParamBase>> param_list; param_list.push_back(std::make_unique<Parameter<int>>("age", 18)); param_list.push_back(std::make_unique<Parameter<double>>("weight", 65.5)); // 取值逻辑 for (auto& param : param_list) { if (auto* int_param = dynamic_cast<Parameter<int>*>(param.get())) { int val = int_param->get_value(); // 处理int类型参数 } else if (auto* double_param = dynamic_cast<Parameter<double>*>(param.get())) { double val = double_param->get_value(); // 处理double类型参数 } }
- 优点:支持任意类型的参数,不需要提前枚举
- 缺点:每次取值都要做类型判断,代码量稍大
方案3:类型擦除(统一操作接口,不需要调用方感知具体类型)
如果希望调用方可以用统一接口操作所有参数,不需要做类型判断,可以通过std::any实现类型擦除的通用接口:
#include <vector> #include <string> #include <memory> #include <any> class ParamBase { public: virtual ~ParamBase() = default; // 类型擦除的通用接口 virtual std::any get_value_any() const = 0; virtual bool set_value_any(std::any val) = 0; std::string get_name() const { return name; } protected: std::string name; }; template<class T> class Parameter : public ParamBase { public: Parameter(std::string name, T val) { this->name = std::move(name); this->value = val; } T get_value() const { return this->value; } void set_value(T val) { this->value = val; } // 实现通用接口 std::any get_value_any() const override { return value; } bool set_value_any(std::any val) override { if (val.type() == typeid(T)) { value = std::any_cast<T>(val); return true; } return false; } private: T value; };
调用示例:
for (auto& param : param_list) { std::any val = param->get_value_any(); // 可统一做序列化、打印等通用操作 }
- 优点:调用方可以用统一接口操作所有参数,无需提前知道类型
- 缺点:std::any取值仍需类型转换,性能略低于直接调用
内容的提问来源于stack exchange,提问作者Randy Price
相关产品推荐
相关产品推荐

