简体   繁体   English

将类的方法作为参数传递给C ++中的另一个类

[英]Passing a method of a class as a parameter into another class in C++

My general purpose is to design an optimizer. 我的一般目的是设计一个优化器。 It's a class that searches for a maximum value for a given function. 这是一个为给定函数搜索最大值的类。 I intend to use this optimizer within other parts of code including methods of another classes. 我打算在代码的其他部分(包括其他类的方法)中使用此优化器。

I have implemented the optimizer like this: 我已经实现了这样的优化器:

class MyOptimizer {
public:
    typedef double (*FuncType)(double);

    MyOptimizer(FuncType f, double a, double b) : _f(f), _a(a), _b(b) {}

    double optimize() const {
        // do something with _f in order to find the maximum
        return maximum;
    }

private:
    double _a;
    double _b;
    FuncType _f;
}

I want to use the optimizer as a library in other pieces of my code. 我想在其他代码中将优化器用作库。 For example: 例如:

class AnyClass {
public:
    ...
    double func(double x) const {
        // using members of the instance
    }

    void aMethod() {
        MyOptimizer opt(func, 0.0, 1.0);
        double bestArgument = opt.optimize();
    }
    ...
};

But I'm not allowed to do it in this way because the type signature of AnyClass::func is different. 但是我不允许这样做,因为AnyClass::func的类型签名是不同的。

What is the best way to design the optimizer to make it convenient to use in other pieces of code? 设计优化程序以使其便于在其他代码段中使用的最佳方法是什么? A code example would be appreciated. 代码示例将不胜感激。

I need a solution for C++ 1998/2003 Standard. 我需要C ++ 1998/2003 Standard的解决方案。

C++11 solution (to the question prior to its edit): C ++ 11解决方案(针对其编辑之前的问题):

The problem is that AnyClass::func actually takes two parameters, formally x but it also needs this . 问题是AnyClass::func实际上接受两个参数,形式上x但它也需要this If you can afford C++11, std::function is your friend here (or a Callable template): 如果您负担得起C ++ 11,则std::function是您的朋友(或Callable模板):

MyOptimizer::MyOptimizer(std::function<double(double)> f, double a, double b);

You can then wrap an object method in a lambda function : 然后,您可以将对象方法包装在lambda函数中

MyOptimizer opt([this] (double x) -> double { return func(x); }, 0.0, 1.0);

If not, you would need to write your own wrapper class that stores the value of this and exposes an operator() and pass such object instead of the function pointer. 如果没有,您将需要编写自己的包装器类,该包装器存储this的值并公开operator()并传递此类对象而不是函数指针。

C++03 solution: C ++ 03解决方案:

template<class AnyClass>
class AnyClassWrapper {
  AnyClass *that;
  typedef double (AnyClass::*FuncType)(double);
  FuncType func;

public:
  AnyClassWrapper(AnyClass* _that, FuncType _func): that(_that), func(_func) { }
  double operator()(double x) {
    return that->*func(x);
  }
};

Instances of this class can now be used just like functions: double y = instance(x) . 现在可以像使用函数一样使用此类的实例: double y = instance(x) You'll need to template the constructor (edit: and along with it the whole class, given that you're storing the function) as well, to be able to accept a normal function pointer as well as a generalized function object like this, using the fact that the syntax is the same for both: 您还需要对构造函数进行模板化(编辑:以及整个类(假设您要存储函数)),以便能够接受普通的函数指针以及像这样的通用函数对象,使用以下两种语法相同的事实:

template<class Func>
MyOptimizer::MyOptimizer(Func& f, double a, double b);

Then you can use this with non-static functions: 然后,您可以将其与非静态功能一起使用:

// within AnyClass
AnyClassWrapper<AnyClass> callable(this, &AnyClass::f);
MyOptimizer opt(callable, 0.0, 1.0);

But the same class also accepts normal functions: 但是同一类也接受正常的功能:

// anywhere    
MyOptimizer opt2(std::sin, 0.0, 1.0);

NB that the above is basically implementing what the lambda function is doing behind the scenes. 注意,以上内容基本上是在实现lambda函数在后台执行的操作。 You can similarly backport the std::function if needed - that would allow for the optimizer to not need any templates. 如果需要,您可以类似地向后移植std::function这将使优化器不需要任何模板。

The simplest solution would be to have AnyClass inherit from your optimizer. 最简单的解决方案是让AnyClass从优化器继承。 Like: this . 像: 这个 But if your dead set on backCalling, you should know that your C++ declarations have errors. 但是,如果在backCalling上死定了,您应该知道您的C ++声明有错误。 I would have commented your question instead of posting an answer but StackOv. 我本来会评论您的问题,而不是发表一个答案,而是StackOv。 requires at least 50rep to comment! 需要至少50rep才能发表评论!

You can use pointer-to-member function. 您可以使用指针到成员函数。 A good description of that is here . 这方面的一个很好的说明是这里

Here is one implementation. 这是一个实现。

template <class T>
class MyOptimizer {
public:
    typedef double (T::*FuncType)(double) const;

    MyOptimizer(T* instance, FuncType f, double a, double b) : _instance(instance),_f(f), _a(a), _b(b) {}

    double optimize() const {
        // do something with _f in order to find the maximum
        return 1.0;
    }

private:
    double _a;
    double _b;
    FuncType _f;
    T* _instance;
};

class AnyClass {
public:
    double func(double x) const {
        // using members of the instance
        return 0.0;
    }

    void aMethod() {
        MyOptimizer<AnyClass> opt(this, &AnyClass::func, 0.0, 1.0);
        double bestArgument = opt.optimize();
    }
};

If you have the option of changing MyOptimizer , change it to a class template or use a std::function instead of the function pointer, as suggested by @TheVee 如果您可以选择更改MyOptimizer ,请将其更改为类模板或使用std::function而不是@TheVee建议的函数指针

If you don't have the option of changing MyMonitor , I have couple of suggestions. 如果您没有更改MyMonitor的选择,那么我有几点建议。

In order to use AnyClass::func with MyOptimizer::optimize , you will need a non-member function or a static member function. 为了与MyOptimizer::optimize一起使用AnyClass::func ,您将需要一个非成员函数或一个static成员函数。 Either of those functions can work if they are able to access the AnyClass object on which you want to call func . 如果这些函数中的任何一个都能访问要在其上调用funcAnyClass对象,则它们都可以工作。

Using a non-member function 使用非成员函数

// Global variable
AnyClass* currentAnyClass = nullptr;

// Non-member function
double funcWrapper(double x)
{
   assert(currentAnyClass != nullptr);
   return currentAnyClass->fun(x);
}

and then 接着

void aMethod() {
    currentAnyClass = this;
    MyOptimizer opt(funcWrapper, 0.0, 1.0);
    double bestArgument = opt.optimize();
    currentAnyClass = nullptr;
}

Using a static member function 使用static成员函数

It follows almost the same strategy. 它遵循几乎相同的策略。 I prefer this over the first once since it keeps currentAnyClass and funcWrapper in the scope of `AnyClass. 我喜欢这种在第一,一旦因为它使currentAnyClassfuncWrapper在AnyClass的`范围。

class AnyClass {
   public:
      ...
         double func(double x) const {
            // using members of the instance
         }

      void aMethod() {
         currentAnyClass = this;
         MyOptimizer opt(funcWrapper, 0.0, 1.0);
         double bestArgument = opt.optimize();
         currentAnyClass = nullptr;
      }

      static AnyClass* currentAnyClass;
      static double funcWrapper(double x)
      {
         assert(currentAnyClass != nullptr);
         return currentAnyClass->func(x);
      }
};

AnyClass* AnyClass::currentAnyClass = nullptr;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM