如何通过需要自由函数的成员函数?

时间:2012-09-30 16:28:02

标签: c++ arguments parameter-passing function-pointers pointer-to-member

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

#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的参数?我坚持这样做。

我想访问该班级的成员。

9 个答案:

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

live demo

还请注意,我已修复了损坏的对象定义(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指令是此处的关键。

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

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

Wandbox


请注意:如果aClass的构建成本很高或有副作用,那么这可能不是一个好方法。