Reputation: 1
I'm trying to implement a numerical ODE solver in c++ but I'm having troubles with function pointers (I'm still trying to understand how they works inside classes). I have a parent class (ODEint) and subclasses in which I will implement different possible algorithms to solve an equation. I pass a function pointer to the parent class (the function represents the equation which is independent of the solver) but I need that function in the child class (different solvers threat that equation in different ways).
When I call the function via pointer in the child class I get the error
odeint.cpp:38:13: error: ‘((Euler*)this)->Euler::.ODEint::field’ cannot be used as a member pointer, since it is of type ‘pfunc {aka std::vector ()(double)}’ (this->*field)(y);
Here are classes definitions
typedef vector<double> (*pfunc)(double*);
class ODEint {
protected:
double h;
int neq;
double* init_cond;
int nsteps;
string method;
vector<vector<double>> y;
pfunc field;
public:
ODEint(int neq, int nsteps, pfunc);
void setInitCond(double* init_cond);
void solveEq();
virtual vector<double> advance(double h, double *y);
};
class Euler: public ODEint {
public:
Euler(int neq, int nsteps, pfunc, double h);
vector<double> advance(double h, double *y);
};
And here is part of the classes implementation
ODEint::ODEint(int neq, int nsteps, pfunc field){
this->neq = neq;
this->nsteps = nsteps;
this->y.resize(nsteps);
this->field = field;
for (int i = 0; i < nsteps; i++){
this->y[i].resize(neq);
}
}
Euler::Euler(int neq, int nsteps, pfunc field, double h) : ODEint(neq, nsteps, field){
this->h = h;
}
void ODEint::solveEq(){
int n;
cout << "Strarting solver..." << endl;
vector<double> x;
for (n = 0; n < this->nsteps; n++){
x = y[n];
y[n+1] = this->advance(this->h, &x[0]);
}
cout << "Solution termined. Nsteps: " << n << endl;
}
vector<double> Euler::advance(double h, double *y){
vector<double> ynext; ynext.resize(this->neq);
vector<double> f; f.resize(this->neq);
(this->*field)(y); <---------------------------------------------- here is the problem
for (int i = 0; i < this->neq; i++){
ynext[i] = y[i] + h*f[i];
}
}
Finally here is the main
vector<double> field(double *y){
vector<double> vf;
vf[0] = -y[0];
vf[1] = -y[1];
return vf;
}
int main(){
double init_cond[2] = {1.0, 2.0};
const int neq = 1;
Euler prova(neq, (int)1e4, field, 1e-4);
prova.setInitCond(&init_cond[0]);
prova.solveEq();
return 0;
}
I know there may be other problems but I'm still learning c++ and actually the priority is to understand the reason of this error. Thank you in advance and sorry if the code is a bit confused but as I said previously I'm a kind of beginner.
Upvotes: 0
Views: 101
Reputation: 11410
Your example is a bit large, I didn't use it as-is. But I can spot a fix, with a smaller repro: (I kept your style)
#include <vector>
typedef std::vector<double> (*pfunc)(double*);
class Foo
{
public:
pfunc field;
};
std::vector<double> Bar(double*)
{
return std::vector<double>{};
}
int main()
{
Foo f;
double x;
f.field = &Bar;
(&f)->field(&x);
}
The only meaningful change I needed is to remove the *
in front of the call to field()
.
Now, I will advise not using this pattern at all. The OOP way, IMO would be way cleaner here:
class BaseODE
{
public:
virtual std::vector<double> field(double*) = 0;
// put the rest of the code here.
// when field is called, the Euler version will be called.
};
class Euler:public BaseODE
{
public:
virtual std::vector<double> field(double*) override;
};
Basically, you have no need yet for function pointers, lambdas, std::function or anything complex.
Upvotes: 1