c++中的用户定义类方法

User Defined Class Method in C++

本文关键字:定义 类方法 用户 c++      更新时间:2023-10-16

我正在做弗朗西斯和怀特利的《c++科学计算》课本中的一个练习,不知道如何正确地实现练习7.3。

练习:目标是通过创建一个包含求解常微分方程方法的抽象类来学习类继承。派生类继承这个抽象类,并与求解ode的特定算法相关联,如显式欧拉、RK4等。抽象类中的两个方法是纯虚的,分别是SolveEquation和RightHandSide。该练习要求您使用编写派生类ForwardEuler的代码,该类实现了显式Euler方法。

问题:在练习中,他们要求你"派生一个名为FowardEulerSolver的类,允许用户指定函数RightHandSide",但RightHandSide是类的成员,我不知道如何让用户在主程序中指定类方法,我想这是他们要求的。

问题:有人能解释一下c++中允许用户指定类方法的正确方法吗?根据书中基类实现的方式,似乎必须有某种方式让用户在主程序中定义rightandside函数,然后调用SolveEquation方法来求解与该rightandside函数相关的ODE。

这是书中给出的抽象类的头文件。

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:
};

必须有某种方法让用户在主程序中定义rightandside函数,然后调用SolveEquation方法来求解与该rightandside函数相关的ODE。

对我来说仍然有点不清楚,你到底在要求什么,但从你的评论听起来你想在抽象类上下文中执行一个用户定义的函数。我认为这是可能的,但是你需要稍微改变一下接口:

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;
};

如果你在c++11环境中工作,你可以使用内联lambda函数定义来获得必要的函数指针:

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");
}

对于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");
}

这或多或少复制了所谓的模板方法模式,但处理了一个特殊的(边缘)用例,允许为算法的特定部分设置用户定义的实现函数。

您可以创建自己的ForwardEulerSolver::RightHandSide函数。

你不必在main函数中做任何特别的事情,只需创建ForwardEulerSolver类的实例并将其分配给指向AbstractODESolver的指针并调用该函数。编译器会为你处理剩下的。