问题如下:考虑这段代码:
#include <iostream>
class aClass
{
public:
void aTest(int a, int b)
{
printf("%d + %d = %d", a, b, a + b);
}
};
void function1(void (*function)(int, int))
{
function(1, 1);
}
void test(int a,int b)
{
printf("%d - %d = %d", a , b , a - b);
}
int main (int argc, const char* argv[])
{
aClass a();
function1(&test);
function1(&aClass::aTest); // <-- How should I point to a's aClass::test function?
return 0;
}
如何使用a
的{{1}}作为aClass::test
的参数?我坚持这样做。
我想访问该班级的成员。
答案 0 :(得分:110)
使用函数指针没有任何问题。但是,指向非静态成员函数的指针与普通函数指针不同:需要在对象上调用成员函数,该对象作为函数的隐式参数传递。上面的成员函数的签名是
void (aClass::*)(int, int)
而不是您尝试使用的类型
void (*)(int, int)
一种方法可以包括使成员函数static
在这种情况下不需要调用任何对象,并且可以将其与void (*)(int, int)
类型一起使用。
如果您需要访问类和的任何非静态成员,您需要坚持使用函数指针,例如,因为该函数是C接口的一部分,所以最好的选择是始终将void*
传递给函数获取函数指针,并通过转发函数调用您的成员,该函数从void*
获取对象,然后调用成员函数。
在适当的C ++接口中,您可能希望查看函数对函数对象使用模板化参数来使用任意类类型。如果不希望使用模板化界面,则应使用类似std::function<void(int, int)>
的内容:您可以为这些创建适当可调用的函数对象,例如,使用std::bind()
。
使用类型类型的模板参数或合适的std::function<...>
的类型安全方法优于使用void*
接口,因为它们消除了由于强制类型转换而导致错误的可能性
为了阐明如何使用函数指针调用成员函数,这是一个例子:
// the function using the function pointers:
void somefunction(void (*fptr)(void*, int, int), void* context) {
fptr(context, 17, 42);
}
void non_member(void*, int i0, int i1) {
std::cout << "I don't need any context! i0=" << i0 << " i1=" << i1 << "\n";
}
struct foo {
void member(int i0, int i1) {
std::cout << "member function: this=" << this << " i0=" << i0 << " i1=" << i1 << "\n";
}
};
void forwarder(void* context, int i0, int i1) {
static_cast<foo*>(context)->member(i0, i1);
}
int main() {
somefunction(&non_member, 0);
foo object;
somefunction(&forwarder, &object);
}
答案 1 :(得分:64)
@Pete Becker的答案很好,但您也可以在不将class
实例作为显式参数传递给C ++ 11中的function1
的情况下执行此操作:
#include <functional>
using namespace std::placeholders;
void function1(std::function<void(int, int)> fun)
{
fun(1, 1);
}
int main (int argc, const char * argv[])
{
...
aClass a;
auto fp = std::bind(&aClass::test, a, _1, _2);
function1(fp);
return 0;
}
答案 2 :(得分:39)
指向成员函数的指针与指向函数的指针不同。为了通过指针使用成员函数,您需要一个指向它的指针(显然)和一个要应用它的对象。因此function1
的适当版本将是
void function1(void (aClass::*function)(int, int), aClass& a) {
(a.*function)(1, 1);
}
并称之为:
aClass a; // note: no parentheses; with parentheses it's a function declaration
function1(&aClass::test, a);
答案 3 :(得分:3)
自2011年以来,如果您可以更改function1
,请按照以下步骤进行操作:
#include <functional>
#include <cstdio>
using namespace std;
class aClass
{
public:
void aTest(int a, int b)
{
printf("%d + %d = %d", a, b, a + b);
}
};
template <typename Callable>
void function1(Callable f)
{
f(1, 1);
}
void test(int a,int b)
{
printf("%d - %d = %d", a , b , a - b);
}
int main()
{
aClass obj;
// Free function
function1(&test);
// Bound member function
using namespace std::placeholders;
function1(std::bind(&aClass::aTest, obj, _1, _2));
// Lambda
function1([&](int a, int b) {
obj.aTest(a, b);
});
}
还请注意,我已修复了损坏的对象定义(aClass a();
声明了一个函数)。
答案 4 :(得分:2)
不确定为什么如此难以置信的解决方案被遗忘了:
#include <stdio.h>
class aClass
{
public:
void aTest(int a, int b)
{
printf("%d + %d = %d\n", a, b, a + b);
}
};
template<class C>
void function1(void (C::*function)(int, int), C& c)
{
(c.*function)(1, 1);
}
void function1(void (*function)(int, int)) {
function(1, 1);
}
void test(int a,int b)
{
printf("%d - %d = %d\n", a , b , a - b);
}
int main (int argc, const char* argv[])
{
aClass a;
function1(&test);
function1<aClass>(&aClass::aTest, a);
return 0;
}
输出:
1 - 1 = 0
1 + 1 = 2
答案 5 :(得分:1)
我问了类似的问题(C++ openframeworks passing void from other classes),但我发现的答案更清楚了,因此在这里为以后的记录做解释:
使用std :: function更容易,如:
IDocXMLProcessor
然后调用为:
void draw(int grid, std::function<void()> element)
或更简单:
grid.draw(12, std::bind(&BarrettaClass::draw, a, std::placeholders::_1));
在其中创建一个lambda,该lambda调用通过引用捕获对象的对象
答案 6 :(得分:0)
您现在可以停止敲打头。这是成员函数的包装,以简单的 C 函数作为参数来支持现有函数。 thread_local
指令是此处的关键。
// Example program
#include <iostream>
#include <string>
using namespace std;
typedef int FooCooker_ (int);
// Existing function
extern "C" void cook_10_foo (FooCooker_ FooCooker) {
cout << "Cooking 10 Foo ..." << endl;
cout << "FooCooker:" << endl;
FooCooker (10);
}
struct Bar_ {
Bar_ (int Foo = 0) : Foo (Foo) {};
int cook (int Foo) {
cout << "This Bar got " << this->Foo << endl;
if (this->Foo >= Foo) {
this->Foo -= Foo;
cout << Foo << " cooked" << endl;
return Foo;
} else {
cout << "Can't cook " << Foo << endl;
return 0;
}
}
int Foo = 0;
};
// Each Bar_ object and a member function need to define
// their own wrapper with a global thread_local object ptr
// to be called as a plain C function.
thread_local static Bar_* BarPtr = NULL;
static int cook_in_Bar (int Foo) {
return BarPtr->cook (Foo);
}
thread_local static Bar_* Bar2Ptr = NULL;
static int cook_in_Bar2 (int Foo) {
return Bar2Ptr->cook (Foo);
}
int main () {
BarPtr = new Bar_ (20);
cook_10_foo (cook_in_Bar);
Bar2Ptr = new Bar_ (40);
cook_10_foo (cook_in_Bar2);
delete BarPtr;
delete Bar2Ptr;
return 0;
}
请对此方法的任何问题发表评论。
其他答案无法调用现有的简单的C
函数:http://cpp.sh/8exun
答案 7 :(得分:0)
我将成员函数设为静态并且所有工作正常
#include <iostream>
class aClass
{
public:
static void aTest(int a, int b)
{
printf("%d + %d = %d\n", a, b, a + b);
}
};
void function1(int a,int b,void function(int, int))
{
function(a, b);
}
void test(int a,int b)
{
printf("%d - %d = %d\n", a , b , a - b);
}
int main (int argc, const char* argv[])
{
aClass a;
function1(10,12,test);
function1(10,12,a.aTest); // <-- How should I point to a's aClass::test function?
getchar();return 0;
}
答案 8 :(得分:0)
如果您实际上不需要使用实例a
(即,您可以像@mathengineer的answer一样使其保持静态)
您可以简单地传递非捕获的lambda。 (会衰减到函数指针)
#include <iostream>
class aClass
{
public:
void aTest(int a, int b)
{
printf("%d + %d = %d", a, b, a + b);
}
};
void function1(void (*function)(int, int))
{
function(1, 1);
}
int main()
{
//note: you don't need the `+`
function1(+[](int a,int b){return aClass{}.aTest(a,b);});
}
请注意:如果aClass
的构建成本很高或有副作用,那么这可能不是一个好方法。