其他类的成员函数对成员函数的嵌套引用

时间:2018-06-14 16:10:33

标签: c++ class static void-pointers member-function-pointers

我正在尝试构建一个由de_solver类编码的通用随机微分方程求解器,它采用由model类给出的一组微分方程。该模型通过类sde提供给求解器,该类在模型和求解器之间进行接口,在确定性+随机方程的两个子集中重构原始模型的方程。

目前我的代码存在一些问题,我认为必须处理继承和类型转换。特别是我无法将指定模型方程的成员函数传递给积分器。首先说我有这种类型的model类:

class model{
    ...
    public:
        size_t N_eq;
        model(...); // Assign N_eq and parameters and other stuff
        ...
        int equations_det(double t, const double y_[], double dy_[]); // Define deterministic RHS of equations
        static int equations_gsl_wrapper(double t, const double y_[], double dy_[],void *params); // A wrapper that make equations_det suitable for a GSL solver
        void equations_stoch(double t,double dt,const double y_[], double dy_[],); // The stochastic RHS of the model equations
        static void ode_s_wrapper(double t,const double y_[], double dy_[], void *params); // A wrapper to pass equations_det to the stochastic integrator (in the class `de_solver`).
        int simulate(t,tfin,tstep); // The actual simulator which will invoke the 'de_solver'
};

in this post指出的那样,static规范需要使用GSL积分器作为模型的确定性部分。

然后,接口类sde就是:

class sde{
    ...
    public:
        size_t N_eq;
        sde(size_t N_,
            int (*dtr)(double, const double*, double*, void*),
            void (*stc)(double, double, const double*, double*, void*));
        int (*deterministic)(double t, const double* y_[], double* dy_[], void * params);
        void (*stochastic)(double t,const double y_[], double dy_[], void *params);
        //Then again, akin to the model class, use some `wrappers`
        static int deterministic_wrapper(double t, const double y_[], double dy_[], void * params);
    static void stochastic_wrapper(double t, const double y_[], double *dy_, void *params);
};

我们的想法是在sde类中包含从给定的任何模型继承的成员函数。至于两个包装纸,'我将简要介绍一下我很快介绍它们的原因。

最后,de_solver类是这样的:

class de_solver{
    sde *sys;
    public:
        de_solver(sde *system); // Will initialize solver with the system put in the `sde` form
        ...
        void integrate(void *params, double *ts, double **sol);
};  

model在单独的文件(model.Hmodel.CPP)中声明/定义sdede_solver solvers.h和{ {1}})。

我们的想法是在solvers.cpp类中拥有simulate成员函数,以便

model

总之,int model::simulate(double t, double tfin, double dt){ // Prepare solver // 1. Create the `sde` object from model `sys` sde recast_sys(NEQ, model::deterministic_wrapper, model::stochastic_wrapper); // 2. Instantiate solver with recast system de_solver integrator(&recast_sys); // Run simulation double *ts = ... // Output time instants double **sol = ... // Output solution void *params_base = static_cast<void*>(std::addressof(this)); integrator.integrate(params_base); return 1; // In practice there is some error check on this return condition (omitted here for brevity) } 调用sys,它适用于integrator提供的模型方程的确定性和随机部分。因为积分器的确定性部分依赖于GSL求解器,所以我使用附加参数参数将指向解算器的指针传递给实际的类成员函数。以这种方式,在recast_sys成员函数内部(见above mentioned post

integrator.integrate

this post获取了一个指向空洞的两个指针的数组。但是,似乎曾经在包装器中使用它,它产生错误可能是因为void数组上的算术不清楚(如指出here)?

目前我无法针对上面报告的错误编译我的代码。也出于某种原因,编译器告诉我de_solver::integrate(void *params_base, ...){ ... // I allocate an array of two void pointers: the first to the `model` class (assumed to be passed by `params_base`), and the second to the `sde` class void **params = (void**)calloc(2,sizeof(void*)); params[0] = params_base; params[1] = reinterpret_cast<void *>(std::addressof(sys)); // the recast system as private member of the sde class gsl_odeiv2_driver * d; gsl_odeiv2_system system = {sys->deterministic_wrapper, nullptr, sys->NEQ, params}; d = gsl_odeiv2_driver_alloc_y_new (&system, gsl_odeiv2_step_bsimp, opts.dt, opts.atol, opts.rtol); ... } int sde::deterministic_wrapper(double t, const double y_[], double dy_[], void * params){ assert(params); return(static_cast<sde*>(params[1])->deterministic(t,y_,dy_,params)); // This will issue an error: ‘void*’ is not a pointer-to-object type } int model::equations_gsl_wrapper(double t, const double y_[], double dy_[], void * params){ assert(params); return(static_cast<model*>(params[0])->ode_gsl(t,y_,dy_)); // This will issue an error: ‘void*’ is not a pointer-to-object type } 成员函数中的this指针生成

model.simulate

我怀疑我正在搞乱静态和非静态成员函数,而我没有正确地传递它们。任何输入将不胜感激。

2 个答案:

答案 0 :(得分:0)

我还没有完全掌握你的整个问题,但答案似乎很简单:

  

错误:使用已删除的函数'const _Tp * std :: addressof(const _Tp&amp;&amp;)[with _Tp = model *]'

编译器告诉您正在尝试将指针的地址带到您的实例,因为您执行了std::addressof(this)this已经 您要查找的指针(model*),直接将其投放到void*

  

return(static_cast<model*>(params[0])->ode_gsl(t,y_,dy_)); // This will issue an error: ‘void*’ is not a pointer-to-object type

当您执行params[0]时,您已经取消引用指针一次(内置的x[y]完全等同于*(x + y))并最终得到一个普通的void,其中编译器不喜欢。你的数组的void指针有另一个间接层:

int deterministic_wrapper(double t, /* ... */ void * params) {
  void** voidPtrs = static_cast<void**>(params);
  return static_cast<sde*>(voidPtrs[1])->deterministic(t, /* ... */ params);
}

请参阅here

更好的解决方案是创建一个struct来保存指向你的类的指针(你的虚拟指针数组基本上就是那个,距离three star programming足够接近你犯了上面的错误):

struct myParams
{
  model* _model;
  sde* _sde;
};

// ...

int deterministic_wrapper(double t, /* ... */ void * params) {
  return static_cast<myParams*>(params)->_sde->deterministic(t, /* ... */ params);
}

请注意,无论如何,您都必须清理内存。如果您分配了该阵列,则需要将其释放,如果您new需要delete它所需的结构,并且如果您在堆栈上创建它,则需要确保它长寿命足以让所有这些功能完成。

答案 1 :(得分:0)

感谢Max Langhof的建议,代码现在运行正常。我提到的可见性问题与类方法地址的错误传递有关。

在上面的代码示例中,我在model::simulate方法中初始化了sde recast_sys

// Prepare solver
// 1. Create the `sde` object from model `sys`
sde recast_sys(NEQ, model::deterministic_wrapper, model::stochastic_wrapper);

而是传递::*_wrapper函数地址的正确方法是this指针,即

sde recast_sys(NEQ, this->deterministic_wrapper, this->stochastic_wrapper);