作为C++中函数的成员属性

Member attributes that are functions in C++

本文关键字:成员 属性 函数 C++ 作为      更新时间:2023-10-16

我正在尝试自学一些C++,作为一个初始项目,我想创建代码来对单个变量的函数执行牛顿方法。我想创建一个类ObjectiveFunction,它存储目标函数、一阶导数和二阶导数的用户定义函数。

我希望ObjectiveFunction的构造函数采用0到3个参数,其中参数本身就是函数:

// ObjectiveFunction.h
// Class definition for an Objective Function object.
#ifndef OBJECTIVE_H
#define OBJECTIVE_H
class ObjectiveFunction
{
    public:
        // Constructors
        // Default constructor
        ObjectiveFunction();
        // Constructor with just objective function.
       ObjectiveFunction(double f(double));
       // Constructor with objective function and derivative function.
       ObjectiveFunction(double f(double), double fp(double));
       // Constructor with objective, derivative, and second derivative functions.
       ObjectiveFunction(double f(double), double fp(double), double fpp(double));
       // Methods
       void setObjectiveFunction(double f(dobule));
       void setDerivativeFunction(double f(double));
       void setSecondDerivativeFunction(double f(double));
       double evalObjectiveFunction(double);
       double evalDerivativeFunction(double);
       double evalSecondDerivativeFunction(double);
    private:
       // Storage for the functions.
       // This is the part I'm not sure of.
       // Attempt with function pointers
       double (*objFunc)(double);
       double (*d1Func)(double);
       double (*d2Func)(double);
};
#endif // OBJECTIVE_H

我将如何创建本身就是函数的私有数据成员。我想创建可以访问的函数对象(除了私有对象),如foo.obj_func(3.0)foo.deriv_func(3.0),其中obj_func由构造函数根据用户传递给类的函数设置。

做这件事的正确方法是什么?如果有一种方法不依赖于使用指向函数对象的指针,那将是最好的,但我想如果这是唯一的方法,那么这就是我必须学习的。

使用std::function<double(double)>。这将使您能够轻松地存储所有函数类型。

在决定实现技术之前,您需要在这里做出一些选择。。。。

创建ObjectiveFunction后,您是否需要一种方法来更改设置后的函数?你想在接受什么作为"函数"方面格外灵活吗(即"functors"(基本上是实现函数调用运算符的任何东西)是否可以接受)?您是否希望使用ObjectiveFunction的东西能够使用任何可互换的ObjectiveFunction,而不管在构建它时它被作为参数给定了什么函数?

你在这里选择了一种非常有活力的方法。您真正要做的唯一选择是使用函数指针还是::std::function对象。::std::function对象可以指实现函数调用运算符的任何对象(例如::std::bind的结果)。函数指针只能引用普通的旧函数。

就我个人而言,我会研究使用模板化的ObjectiveFunction。部分原因是它调用的函数将在编译时设置,编译器可以更好地优化它们。有了寻根技术,你会给他们打很多电话。因此,在某些情况下,这可能会大大加快速度。

函数指针可以工作,或者,如果您正在寻找一种在不更改调用代码的情况下允许多个实现的方法,则可以使用继承。

看看这里的函数指针与继承技术的比较。

继承的解决方案是这样的;首先创建一个实现所需接口的基类:

class BaseObjectiveFunction
{
    BaseObjectiveFunction();
    virtual ~BaseObjectiveFunction();
    virtual double EvalObjectiveFunction(double);
    virtual double EvalDerivativeFunction(double);
    virtual double EvalSecondDerivativeFunction(double);
}

然后实现一个具有所需功能的继承类:

class LogLikelihood: public BaseObjectiveFunction
{
    public:
        LogLikelihood();
        ~LogLikelihood();
        virtual double EvalObjectiveFunction(double);
        virtual double EvalDerivativeFunction(double);
        virtual double EvalSecondDerivativeFunction(double);
        // Example of a function to pass in some data which the calculations rely on
        bool SetInputData(double* somedata, int dataLen);
}

最后,为了调用此代码,您创建了一个指向基类的指针,并指向您感兴趣的实现(以类似于传递函数指针的方式):

LogLikelihood* pOF1 = new LogLikelihood(); // Create an instantiation of a specific solver
BaseObjectiveFunction* pCaller = pOF1; // Establish a pointer to the interface class and at the specific implementation.
// Now whatever calls the evaluate function can just use the pCaller and doesn't have to worry about the actual implementation.
pCaller->EvalObjectiveFunction(1.5);

这将调用两个底层实现,这(我认为)是您真正想要的。

#include <stdio.h>
class MyClass
{
public:
  typedef int(MyClass::*FunctionPointer)(int);
  FunctionPointer func;
  void Setup(int selector)
  {
        switch (selector)
        {
              case 1:
              {
                    this->func = (FunctionPointer)&MyClass::Test1;
                    break;
              }
              case 2:
              {
                    this->func = (FunctionPointer)&MyClass::Test2;
                    break;
              }
        }
  }
  void Call()
  {
        (this->*func)(10);
  }
  void Test1(int a)
  {
        printf("test1n");
  }
  void Test2(int a)
  {
        printf("test2n");
  }
};
int main()
{
  MyClass *instance = new MyClass();
  instance->Setup(1);
  instance->Call();
  instance->Setup(2);
  instance->Call();
  return 0;
}