c ++ - 如何传递一个需要自由函数的成员函数?

问题如下:考虑这段代码:

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

如何使用aaClass::test作为function1的参数? 我坚持这样做。

我想访问该班级的成员。

7个解决方案
110 votes

使用函数指针没有任何问题。 但是,指向非静态成员函数的指针与普通函数指针不同:需要在对象上调用成员函数,该对象作为函数的隐式参数传递。 因此,上面的成员函数的签名是

void (aClass::*)(int, int)

而不是你尝试使用的类型

void (*)(int, int)

一种方法可以包括使成员函数std::function<...>,在这种情况下,它不需要调用任何对象,您可以使用类型void*

如果你需要访问你的类的任何非静态成员,你需要坚持使用函数指针,例如,因为该函数是C接口的一部分,你最好的选择是总是将std::function<...>传递给你的函数获取函数指针和 通过转发函数呼叫您的成员,该函数从void*获取对象,然后调用成员函数。

在适当的C ++接口中,您可能希望查看函数对函数对象使用模板化参数来使用任意类类型。 如果不希望使用模板化接口,则应使用类似于std::function<...>的内容:您可以为这些创建适当可调用的函数对象,例如,使用void*

使用类型的模板参数或合适的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);
}
Dietmar Kühl answered 2019-08-13T06:26:46Z
64 votes

@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;
}
Matt Phillips answered 2019-08-13T06:27:12Z
39 votes

指向成员函数的指针与指向函数的指针不同。 为了通过指针使用成员函数,您需要一个指向它的指针(显然)和一个要应用它的对象。 所以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);
Pete Becker answered 2019-08-13T06:27:45Z
3 votes

自2011年以来,如果您可以更改aClass a();,请执行以下操作,如下所示:

#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();声明了一个函数)。

Lightness Races in Orbit answered 2019-08-13T06:28:27Z
1 votes

我问了一个类似的问题(C ++ openframeworks从其他类中传递void),但我发现的答案更清晰,所以这里对未来记录的解释如下:

使用std :: function更容易,如:

 void draw(int grid, std::function<void()> element)

然后打电话给:

 grid.draw(12, std::bind(&BarrettaClass::draw, a, std::placeholders::_1));

甚至更容易:

  grid.draw(12, [&]{a.draw()});

在哪里创建一个lambda,它调用通过引用捕获它的对象

Nicola Bertelloni answered 2019-08-13T06:29:16Z
0 votes

你现在可以不停地敲打头了。 下面是成员函数的包装器,它支持以普通C函数作为参数的现有函数。 C指令是这里的关键。

[http://cpp.sh/9jhk3]

// 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]

Necktwi answered 2019-08-13T06:30:04Z
0 votes

我将成员函数设置为静态并且所有工作:

#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;
}
mathengineer answered 2019-08-13T06:30:31Z
translate from https://stackoverflow.com:/questions/12662891/how-can-i-pass-a-member-function-where-a-free-function-is-expected