Я недавно реализовал один из алгоритмов управления транспортным средством, который решает проблему «рулевого управления». Сам алгоритм включает в себя решение множественной матрицы ODE, и я хотел реализовать свой основной класс алгоритма таким образом, чтобы он был независим от системы (ODE), которую мы хотим контролировать.Как использовать odeint solver с системой с использованием наследования и виртуального оператора()
Наиболее интуитивный подход, кажется:
class EquationBase
{
public:
virtual ~EquationBase();
/* Due to supposed bug in odeint this class is not abstract and operator() is not pure virtual */
virtual void operator() (const state_type &x, state_type &dxdt, const time_type t);
/* method specific for the considered algorithm, this should be part of the interface */
virtual void setLambdas(std::vector<double> lambdas);
};
class VehicleEquation: public EquationBase
{
public:
VehicleEquation();
~VehicleEquation();
void operator() (const state_type &x, state_type &dxdt, const time_type t) override;
void setLambdas(std::vector<double> lambdas) override;
private:
/* here some fields/methods specific for the system */
};
class MyAlgorithm
{
public:
MyAlgorithm();
MyAlgorithm(EquationBase *eq);
void start();
private:
EquationBase *eqPtr_;
};
Теперь каждая система, которая является дочерним EquationBase может быть использован с помощью eqPtr. К сожалению, второй аргумент (ODE System) для odeint :: integrate_adaptive должен быть объектом, а не указателем. Чтобы обойти это ограничение, я ввел оболочку, которая содержит фактический указатель на систему ОДУ, но не нужно использовать виртуальные функции самостоятельно:
class EquationWrapper
{
public:
void operator() (const state_type &x, state_type &dxdt, const time_type t)
{
(*eqPtr_)(x,dxdt,t);
}
void setEquation(EquationBase *eqPtr)
{
eqPtr_ = eqPtr;
}
private:
EquationBase *eqPtr_;
};
class MyAlgorithm
{
public:
MyAlgorithm();
/* somewhere here: eqWrapper_.setEquation(eq); */
MyAlgorithm(EquationBase *eq);
/* somewhere in the algorithm: odeint::integrate_adaptive(.... , eqWrapper_, ...) */
void start();
private:
EquationWrapper eqWrapper_;
};
Конечно, это решение работает, но я хотел бы знать, является ли это безопасно , clean (очевидно, odeint скопирует мой указатель на уравнение несколько раз, но не удалит его, если я не объявлю его явно в деструкторе оболочки), и есть ли лучший способ добиться желаемого поведения (я думал о шаблонах, но нашел это даже хуже)?
Поскольку я не нашел аналогичную проблему в другом месте, обратитесь к моему решению, если вам нужно использовать odeint таким образом.