C++如何无需创建子类对象,直接用类名作为构造函数参数?
问题:无需创建子类对象,直接以类名作为参数传入
fit构造函数 我有一些存储在struct F_data中的结构化数据,希望用抛物线、双曲线等多种函数拟合这些数据。为此定义了基类F_function及其子类(如parabola),拟合操作由fit类完成,其构造函数接收拟合函数对象与拟合数据两个参数。
现有代码如下:
#include <iostream> #include <cmath> // 补充pow所需头文件 struct F_data{ /*...*/ }; class F_function{ public: virtual int N_fparams() = 0; virtual double eval(double x, double* &fparams) = 0; F_function(){}; virtual ~F_function(){}; }; class parabola: public F_function{ public: int N_fparams() override {return 3;} // 添加override明确重写 double eval(double x, double* &fparams) override { return fparams[0]*pow(x,2)+fparams[1]*x+fparams[2]; } }; class hyperbola: public F_function{/*...*/}; class fit{ /*...*/ public: fit(F_function& fugg, const F_data& data){/*...*/}; /*...*/ }; int main(){ F_data diana; /* Loading data to diana*/ /* ... */ parabola petra; fit apple(petra,diana); // 正常运行 fit banana(parabola(),F_data()); // 语法可行,但数据为空 fit citrone(parabola,diana); // 报错:error: ‘diana’ is not a type ' return 0; }
现在需要实现无需创建子类对象,直接用子类类名(如parabola)作为参数传入fit构造函数,请问如何实现?
解决方案1:将fit改为模板类
让fit类接受一个模板参数代表拟合函数的类型,在构造函数内部创建该类型的实例,这样就能直接传递类名作为模板参数:
#include <iostream> #include <cmath> struct F_data{ /*...*/ }; class F_function{ public: virtual int N_fparams() = 0; virtual double eval(double x, double* &fparams) = 0; F_function(){}; virtual ~F_function(){}; }; class parabola: public F_function{ public: int N_fparams() override {return 3;} double eval(double x, double* &fparams) override { return fparams[0]*pow(x,2)+fparams[1]*x+fparams[2]; } }; class hyperbola: public F_function{/*...*/}; // 修改为模板类 template<typename FuncType> class fit{ private: FuncType func_instance; const F_data& data_ref; public: fit(const F_data& data) : data_ref(data) { // 可直接使用func_instance调用虚函数 int param_count = func_instance.N_fparams(); // ... 拟合逻辑实现 } /*...*/ }; int main(){ F_data diana; /* Loading data to diana*/ /* ... */ // 直接传递类名作为模板参数 fit<parabola> citrone(diana); fit<hyperbola> date(diana); return 0; }
解决方案2:类型标签传递(Tag Dispatch)
如果不想修改fit的整体结构,可借助类型标签传递类型信息,在构造函数内部创建对应子类的实例:
#include <iostream> #include <cmath> #include <type_traits> // 用于std::type_identity #include <memory> // 用于智能指针 struct F_data{ /*...*/ }; class F_function{ public: virtual int N_fparams() = 0; virtual double eval(double x, double* &fparams) = 0; F_function(){}; virtual ~F_function(){}; }; class parabola: public F_function{ public: int N_fparams() override {return 3;} double eval(double x, double* &fparams) override { return fparams[0]*pow(x,2)+fparams[1]*x+fparams[2]; } }; class hyperbola: public F_function{/*...*/}; class fit{ private: std::unique_ptr<F_function> func_ptr; // 用智能指针管理基类对象 const F_data& data_ref; // 辅助函数:根据类型创建子类实例 template<typename FuncType> void create_func() { func_ptr = std::make_unique<FuncType>(); } public: // 原有构造函数:接受对象引用 fit(F_function& fugg, const F_data& data) : data_ref(data) { // 处理传入的函数对象 } // 新增构造函数:接受类型标签和数据 template<typename FuncType> fit(std::type_identity<FuncType>, const F_data& data) : data_ref(data) { create_func<FuncType>(); // ... 后续拟合逻辑 } /*...*/ }; int main(){ F_data diana; /* Loading data to diana*/ /* ... */ // 通过类型标签传递类名 fit citrone(std::type_identity<parabola>{}, diana); fit date(std::type_identity<hyperbola>{}, diana); return 0; }
注意事项
- 方案1的模板类方式更高效,避免了虚函数的运行时开销,且类型在编译期确定。
- 方案2保留了原有的多态设计,适合需要运行时动态切换拟合函数的场景,但需注意智能指针的内存管理。
- 两种方案都要求拟合函数类(如
parabola)具备默认构造函数,若需传递初始化参数,需调整构造逻辑。
内容的提问来源于stack exchange,提问作者Tom Solid
相关产品推荐
相关产品推荐

