Пользовательский метод класса в переполнении стека

Я работаю над упражнением Фрэнсиса и Уайтли в учебнике «Научные вычисления на С ++» и не могу понять, как правильно выполнить упражнение 7.3.

Упражнение: Цель состоит в том, чтобы узнать о наследовании классов, создав абстрактный класс, содержащий методы решения обыкновенных дифференциальных уравнений. Производные классы наследуют этот абстрактный класс и связаны с конкретными алгоритмами решения ODE, такими как явный Euler, RK4 и т. Д. Двумя методами в абстрактном классе являются чисто виртуальные, SolveEquation и RightHandSide. В упражнении требуется написать код для производного класса ForwardEuler, который реализует явный метод Эйлера.

Проблема: в этом упражнении они просят вас «Извлечь класс с именем FowardEulerSolver, который позволяет пользователю указывать функцию RightHandSide», но RightHandSide является членом класса, и я не могу понять, как позволить пользователю указать метод класса в основной программе, который, как я предполагаю, они просят.

Вопрос: Может ли кто-нибудь объяснить правильный путь в C ++, если он есть, для того, чтобы пользователь мог указать метод класса? Основываясь на способе реализации базового класса в книге, кажется, что должен быть какой-то способ, чтобы пользователь определил функцию RightHandSide в основной программе, а затем вызвал метод SolveEquation для решения ODE, связанного с этой функцией RightHandSide. ,

Вот заголовок для абстрактного класса, приведенного в книге.

class AbstractODESolver
{
public:
AbstractODESolver();
double (*RHS)(double, double);
void SetStepSize(double h);
void SetTimeInterval(double t0, double t1);
void SetInitialValue(double y0);
void setRHS(double (*RHS)(double, double));
double GetStepSize();
double GetInitialTime();
double GetFinalTime();
double GetInitialValue();
virtual double RightHandSide(double y, double t) = 0;
virtual void SolveEquation(std::string filename) = 0;
virtual ~AbstractODESolver();
private:
double stepSize;
double initialTime;
double finalTime;
double initialValue;
};

А вот и заголовок для производного класса.

class ForwardEulerSolver : public AbstractODESolver
{
public:
ForwardEulerSolver();
double RightHandSide(double y, double t);
void SolveEquation(std::string filename);
virtual ~ForwardEulerSolver();
private:
};

1

Решение

должен быть какой-то способ, чтобы пользователь определял функцию RightHandSide в основной программе, а затем вызывал метод SolveEquation для решения ODE, связанного с этой функцией RightHandSide.

Для меня все еще немного неясно, что именно вы просите, но из ваших комментариев кажется, что вы хотите, чтобы пользовательская функция выполнялась в контексте вашего абстрактного класса. Я думаю, что это возможно, но вам нужно немного изменить интерфейсы:

class AbstractODESolver
{
public:
AbstractODESolver();
// ...
void SolveEquation(std::string filename) {
// Have an abstract implementation of the algorithm involving
// a call to the RightHandSide() method.
}
virtual ~AbstractODESolver();

protected:
virtual double RightHandSide(double y, double t) = 0;
private:
double stepSize;
double initialTime;
double finalTime;
double initialValue;
};

class ForwardEulerSolver : public AbstractODESolver
{
public:
typedef double (*FnType)(AbstractODESolver*,double,double);

ForwardEulerSolver(FnType fn_) : fn(fn_) { assert(fn); }
virtual ~ForwardEulerSolver();
private:
virtual double RightHandSide(double y, double t)
{
return (*fn)(this,y,t);
}

FnType fn;
};

Если вы работаете в В среде вы можете использовать встроенное лямбда-определение функции, чтобы получить необходимый указатель на функцию:

int main()
{
ForwardEulerSolver::FnType rightHandSide =
[](AbstractODESolver* solver, double y, double t) {
// Replace with reasonable user implementation
return 0.0;
};

ForwardEulerSolver fwEulerSolver(rightHandSide);

fwEulerSolver.SolveEquation("MyInput.txt");
}

Для стандарта pre c ++ 11 вы можете использовать определение закрытой функции модуля для реализации желаемого поведения

namespace {
double RightHandSide(AbstractODESolver* solver, double y, double t) {
// Replace with reasonable user implementation
return 0.0;
}
}

int main()
{

ForwardEulerSolver fwEulerSolver(&RightHandSide);

fwEulerSolver.SolveEquation("MyInput.txt");
}

Это более или менее воспроизводит то, что называется Шаблон Метод Шаблон, но обрабатывая особый (крайний) вариант использования, чтобы позволить установить пользовательскую функцию реализации для определенной части алгоритма.

1

Другие решения

Вы делаете свой собственный ForwardEulerSolver::RightHandSide функция.

Вам не нужно делать ничего особенного в main функция, просто создайте экземпляр ForwardEulerSolver класс и назначить ему указатель на AbstractODESolver и вызвать функцию. Компилятор позаботится об остальном за вас.

1

По вопросам рекламы [email protected]