假设我有一个类和一个函数
class A
{
int a;
int b;
int mul()
{
return a+b;
}
};
...
void func(int af, int bf, int (*fc)())
{
...
}
在main函数中,该函数应该使用A类的方法
int main
{
A as;
...
func(as.a, as.b, as.mul);
}
然而,我不能这样做,编译器一直告诉我,我正在传递
(int&, int&, 'unresolved overloaded function type')
成为候选人的功能
(int, int, void(*)()).
为什么会这样,以及如何将类的方法传递给另一个函数?
哦,我想我应该让问题更清楚一些。 func(...)
实际上是我正在研究的算法的函数。 class A
是一个使用算法进行模拟的模型。所以我不认为我会在函数B中专门使用A的实例,而只是传递A的方法和组件并使用它们。
更新:有人提到在A类中使用静态方法。但是,这仍然是部分解决方案。使用静态方法mul()
将迫使我声称a和b都是静态的。如果我必须使用A的多个实例,在我的main函数的每个实例中使用方法a,b不同,使用静态变量将会失败。
那么,是否有其他建议如何在不使用静态变量/方法的情况下解决这个问题?我记得在python等脚本语言中,传递任何类型的方法基本上都不是问题。为什么我不能在C ++中做类似的事情?或者C ++中是否有可以帮助我做到这一点的变通方法?
答案 0 :(得分:4)
首先,mul
是A
的成员函数,因此您无法像调用全局函数或{{1}一样调用它成员函数:它需要一个调用该函数的对象:
static
这就是说,可以更改A::mul(); // ERROR!
A a;
a.mul(); // OK
的定义以接受指向成员函数的指针:
func
但是,单独更改 不会让您进步太多,因为您仍然没有传递应该调用成员函数的void func(int af, int bf, void (A::*fc)())
// ^^^^^^^^^^^^^^^
的具体实例。换句话说,这将是非法的:
A
为了克服这个限制,你可以将一个fc(); // ERROR!
实例的引用或指针一起传递给A
,并按以下方式调用它:
func
但是,如果void func(A* pA, int af, int bf, void (A::*fc)())
{
...
(pA->*func)();
}
具有应该调用成员函数的对象作为参数传入,则不清楚func()
和af
的目的是什么。
可能,如果您的bf
成员函数不需要处理mul()
的任何具体实例,并且您仍希望将其作为A
的成员,则可以声明它作为A
:
static
这将使您对class A
{
int a;
int b;
static void mul();
// ^^^^^^
};
的原始调用进行编译。但是,在这种情况下,不清楚这是否有意义,因为func()
不接受任何参数这一事实表明它应该适用于mul()
和a
成员它被调用的对象。
答案 1 :(得分:1)
您要做的是传递成员函数指针(A::mul
)以及实例(a
)本身。没有任何额外的代码,这并不容易。
成员函数指针不与实例绑定(它们仅表示函数本身,而不是要调用的实例)。它们的类型与类名一起描述。 A
上具有func
签名的成员函数指针的类型将如下所示:
void (A::*)() // The type only, anonymous
void (A::*fc)() // An actual function pointer with the name `fc`
要调用这样的函数,您必须使用以下语法,正如您所看到的,必须参与调用该函数的实例:
(a->*fc)(); // If a is of type A*
(a.*fc)(); // If a is of type A or A&
要把事情放在一起,你基本上有两种选择。
除了成员函数指针之外,还传递实例(作为指针,引用,const或可修改)。然后,调用该实例上的成员函数指针。
你是函数的签名,实现将如下所示:
void func(int af, int bf, void (A::*fc)(), A *a) {
// When you want to call the function fc on a:
(a->*fc)();
}
要拨打func
,请使用以下代码:
func(as.a, as.b, &A::mul, a);
将成员函数指针与实例一起转换为可以按原样调用的仿函数。最好使用std::mem_fn
和std::bind1st
来完成此操作。
你是函数的签名,实现将如下所示:
void func(int af, int bf, std::function<void()> fc) {
// When you want to call the function fc:
fc();
}
要拨打func
,请使用以下代码:
func(as.a, as.b, std::bind1st(std::mem_fn(&A::mul), a));
答案 2 :(得分:1)
mul
是否为非静态成员,需要类型为A
的对象才能调用它?在这种情况下,您需要传递指向成员的指针:
void func(int af, int bf, void (A::*fc)())
{ // ^^^
A a = whatever();
(a.*fc)();
}
如果打算在没有对象的情况下调用它,那么它必须是static
。
答案 3 :(得分:1)
如果你真的想要将int (*fc)(int,int)
(void
返回和另一个例子中给出的空参数列表)视为常规函数指针(我的意思是不是类成员函数的函数指针),你可以做以下内容使用A
的功能并将其传递给func
。关键是将mul
声明为静态成员函数。我假设操作非常简单,比如乘法。
#include <iostream>
class A
{
public: //necessary otherwise not accessible in main
int a;
int b;
A(int p1, int p2):a(p1),b(p2){} //assume you need to somehow pass a,b into mul
static int mul(int p1, int p2) {return p1*p2;}; //mul should be static
};
void func(int af, int bf, int (*fc)(int,int))
//using void still work but you need to change declaration of mul in A
{
int res = fc(af,bf);
cout << res <<endl;
}
int main()
{
A as(2,4);
func(as.a, as.b, &A::mul); //call A::mul, use as regular function pointer, output 8
func(10,10, &A::mul); //will output 100
return 0;
}
这样你就可以使用A的静态成员函数,它可以被常规函数指针指向。它与课堂内的a
和b
无关。
答案 4 :(得分:1)
正如leemes所说,你可以用std::function
来做这个,这也是我推荐的,但是看看你的编译器支持什么,如果有的话,你可以使用{{1并让它工作。以下示例适用于Visual Studio 2012(并且应该适用于启用了C ++ 11标志的较新版本的GCC,并且在VS 2010上可能有效,也可能无效)
std::bind
致电:
void func(int af, int bf, std::function<void()> fc)
{
fc();
}
func(as.a, as.b, std::bind(&as::mul, &A));
的较新版本会在检测到成员函数时为您执行std::bind
部分。请参阅此处链接的文档: