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

时间:2016-12-22 17:16:25

标签: c++

我的一般目的是设计一个优化器。它是一个搜索给定函数的最大值的类。我打算在代码的其他部分使用这个优化器,包括另一个类的方法。

我已经实现了这样的优化器:

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

我想在我的代码的其他部分中使用优化器作为库。例如:

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();
    }
    ...
};

但我不允许这样做,因为AnyClass::func的类型签名不同。

设计优化器以便在其他代码中使用方便的最佳方法是什么?一个代码示例将不胜感激。

我需要一个C ++ 1998/2003标准的解决方案。

4 个答案:

答案 0 :(得分:4)

C ++ 11解决方案(针对编辑之前的问题):

问题是AnyClass::func实际上需要两个参数,正式x但它还需要this。如果你能买得起C ++ 11,那么std::function就是你的朋友(或Callable模板):

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

然后,您可以将对象方法包装在lambda function

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

如果没有,您需要编写自己的包装类来存储this的值并公开operator()并传递此类对象而不是函数指针。

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

此类的实例现在可以像函数一样使用:double y = instance(x)。您需要对构造函数进行模板化(编辑:以及整个类,同时您还要存储函数),以便能够接受普通函数指针以及广义函数像这样的对象,使用两种语法相同的事实:

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

然后你可以将它用于非静态函数:

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

但是同一个班级也接受正常的功能:

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

请注意,上面的内容基本上是实现了lambda函数在幕后所做的事情。如果需要,您可以类似地向后移动std::function - 这将允许优化器不需要任何模板。

答案 1 :(得分:1)

最简单的解决方案是让 AnyClass 继承优化器。喜欢:this。 但是如果你的死设置在backCalling上,你应该知道你的C ++声明有错误。我会评论你的问题,而不是发布答案,但StackOv。要求至少50rep评论!

答案 2 :(得分:1)

您可以使用指针到成员的功能。对此的一个很好的描述是here

这是一个实现。

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

答案 3 :(得分:0)

如果您可以选择更改Print,请将其更改为类模板或使用MyOptimizer而不是函数指针as suggested by @TheVee

如果您无法更改std::function,我会提出一些建议。

要将MyMonitorAnyClass::func一起使用,您需要一个非成员函数或MyOptimizer::optimize成员函数。如果这些功能能够访问您要呼叫static的{​​{1}}对象,则这些功能都可以正常工作。

使用非会员功能

AnyClass

然后

func

使用// Global variable AnyClass* currentAnyClass = nullptr; // Non-member function double funcWrapper(double x) { assert(currentAnyClass != nullptr); return currentAnyClass->fun(x); } 会员功能

它遵循几乎相同的策略。我比第一次更喜欢这个,因为它将void aMethod() { currentAnyClass = this; MyOptimizer opt(funcWrapper, 0.0, 1.0); double bestArgument = opt.optimize(); currentAnyClass = nullptr; } static保持在`AnyClass的范围内。

currentAnyClass