[英]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的解决方案。
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()
并传递此类对象而不是函数指针。
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
. 如果这些函数中的任何一个都能访问要在其上调用
func
的AnyClass
对象,则它们都可以工作。
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. 我喜欢这种在第一,一旦因为它使
currentAnyClass
和funcWrapper
在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.