C++ 如何将类成员函数作为回调传递?

C++ 如何将类成员函数作为回调传递?,c++,callback,function-pointers,c++03,C++,Callback,Function Pointers,C++03,我使用的API要求我将函数指针作为回调传递。我试图从我的类中使用这个API,但是我得到了编译错误 以下是我在构造函数中所做的操作: m_cRedundencyManager->Init(this->RedundencyManagerCallBack); 这无法编译-我收到以下错误: 错误8错误C3867:“BloggerSinfra::RedundencyManagerCallBack”:函数调用缺少参数列表;使用“&BloggerSinfra::RedundencyManager

我使用的API要求我将函数指针作为回调传递。我试图从我的类中使用这个API,但是我得到了编译错误

以下是我在构造函数中所做的操作:

m_cRedundencyManager->Init(this->RedundencyManagerCallBack);
这无法编译-我收到以下错误:

错误8错误C3867:“BloggerSinfra::RedundencyManagerCallBack”:函数调用缺少参数列表;使用“&BloggerSinfra::RedundencyManagerCallBack”创建指向成员的指针

我尝试了使用
&bloggersinfra::RedundencyManagerCallBack
的建议,但对我无效

对此有何建议/解释

我正在使用VS2008


谢谢

Init接受什么参数?新的错误消息是什么


C++中的方法指针有点难用。除了方法指针本身,您还需要提供一个实例指针(在您的例子中是

this
)。可能
Init
希望它作为一个单独的参数?

我可以看到Init具有以下覆盖:

Init(CALLBACK_FUNC_EX callback_func, void * callback_parm)
其中
CALLBACK\u FUNC\u EX

typedef void (*CALLBACK_FUNC_EX)(int, void *);

m_CredudencManager
是否能够使用成员函数?大多数回调都设置为使用常规函数或静态成员函数。查看C++ FAQ Lite,了解更多信息。 更新:您提供的函数声明显示,
m_credudencymanager
需要以下形式的函数:
void yourCallbackFunction(int,void*)
。因此,在这种情况下,成员函数作为回调是不可接受的。静态成员函数可以工作,但是如果在您的情况下不能接受,那么下面的代码也可以工作。请注意,它使用了来自
void*
的邪恶施法


// in your CLoggersInfra constructor:
m_cRedundencyManager->Init(myRedundencyManagerCallBackHandler, this);

指向类成员函数的指针与指向函数的指针不同。类成员接受隐式额外参数(this指针),并使用不同的调用约定

如果您的API需要一个非成员回调函数,那么这就是您必须传递给它的内容。

我认为,这很好地涵盖了您的问题和答案中涉及的注意事项。我链接的网页中的短片段:

不要

因为没有对象调用,成员函数就没有意义 打开它,您不能直接执行此操作(如果X窗口系统 在C++中改写,它可能会传递对周围对象的引用, 不仅仅是指向函数的指针;对象自然会体现 所需的功能,可能还有更多)


这不起作用,因为成员函数指针不能像普通函数指针那样处理,因为它需要一个“this”对象参数

相反,您可以按如下方式传递静态成员函数,这在这方面与普通的非成员函数类似:

m_cRedundencyManager->Init(&CLoggersInfra::Callback, this);
该函数可以定义如下

static void Callback(int other_arg, void * this_pointer) {
    CLoggersInfra * self = static_cast<CLoggersInfra*>(this_pointer);
    self->RedundencyManagerCallBack(other_arg);
}
静态void回调(int-other_-arg,void*此_指针){
阻塞器sinfra*self=静态\u投射(此\u指针);
self->RedundencyManagerCallBack(其他参数);
}

这是一个简单的问题,但答案却异常复杂。简而言之,你可以用
std::bind1st
boost::bind
做你想做的事情。下面是较长的答案

编译器建议您使用
&bloggersinfra::RedundencyManagerCallBack
,这是正确的。首先,如果
RedundencyManagerCallBack
是一个成员函数,则该函数本身不属于类
clockersinfra
的任何特定实例。它属于类本身。如果您以前调用过静态类函数,您可能已经注意到您使用了相同的
SomeClass::SomeMemberFunction
语法。由于函数本身是“静态”的,即它属于类而不是特定实例,因此使用相同的语法。'& & '是必要的,因为从技术上讲,你不能直接传递函数——函数不是C++中的真实对象。相反,从技术上讲,您传递的是函数的内存地址,即指向函数指令在内存中开始位置的指针。结果是一样的,你实际上是在“传递一个函数”作为一个参数

但在这种情况下,这只是问题的一半。正如我所说,
RedundencyManagerCallBack
该函数不“属于”任何特定实例。但听起来您似乎希望将其作为回调传递,同时考虑特定实例。要了解如何做到这一点,您需要了解成员函数真正是什么:在任何带有额外隐藏参数的类函数中都没有定义正则函数

例如:

class A {
public:
    A() : data(0) {}
    void foo(int addToData) { this->data += addToData; }

    int data;
};

...

A an_a_object;
an_a_object.foo(5);
A::foo(&an_a_object, 5); // This is the same as the line above!
std::cout << an_a_object.data; // Prints 10!
回到你的例子,现在有一个明显的问题Init'需要一个指向接受一个参数的函数的指针。但是,
&bloggersinfra::RedundencyManagerCallBack
是一个指向函数的指针,该函数有两个参数,一个是普通参数,另一个是秘密的“this”参数。这就是为什么仍然会出现编译器错误(附带说明:如果您曾经使用过Python,这种混淆就是为什么所有成员函数都需要一个“self”参数)

处理这个问题的详细方法是创建一个特殊对象,该对象包含一个指向所需实例的指针,并具有一个名为“run”或“execute”(或重载“()”运算符)的成员函数,该函数接受成员函数的参数,并仅使用存储实例上的这些参数调用成员函数。但这需要您将“Init”更改为使用您的特殊对象,而不是原始函数指针,而且听起来Init是其他人的代码。每次出现这个问题,都要创建一个特殊的类,这会导致代码膨胀

现在,最后是一个好的解决方案,
boost::bind
boost::function
,您可以在这里找到每个解决方案的文档:

,,

boost::bind
将让您获得一个函数和一个参数来实现这一乐趣
static void Callback(int other_arg, void * this_pointer) {
    CLoggersInfra * self = static_cast<CLoggersInfra*>(this_pointer);
    self->RedundencyManagerCallBack(other_arg);
}
class A {
public:
    A() : data(0) {}
    void foo(int addToData) { this->data += addToData; }

    int data;
};

...

A an_a_object;
an_a_object.foo(5);
A::foo(&an_a_object, 5); // This is the same as the line above!
std::cout << an_a_object.data; // Prints 10!
struct A {
    int data;
};

void a_init(A* to_init)
{
    to_init->data = 0;
}

void a_foo(A* this, int addToData)
{ 
    this->data += addToData;
}

...

A an_a_object;
a_init(0); // Before constructor call was implicit
a_foo(&an_a_object, 5); // Used to be an_a_object.foo(5);
// std::function<return_type(list of argument_type(s))>
void Init(std::function<void(void)> f);
auto cLoggersInfraInstance = CLoggersInfra();
auto callback = std::bind(&CLoggersInfra::RedundencyManagerCallBack, cLoggersInfraInstance);
Init(callback);
#include <functional>
#include <iostream>
#include <string>

class RedundencyManager // incl. Typo ;-)
{
public:
    // std::function<return_type(list of argument_type(s))>
    std::string Init(std::function<std::string(void)> f) 
    {
        return f();
    }
};

class CLoggersInfra
{
private:
    std::string member = "Hello from non static member callback!";

public:
    static std::string RedundencyManagerCallBack()
    {
        return "Hello from static member callback!";
    }

    std::string NonStaticRedundencyManagerCallBack()
    {
        return member;
    }
};

std::string NonMemberCallBack()
{
    return "Hello from non member function!";
}

int main()
{
    auto instance = RedundencyManager();

    auto callback1 = std::bind(&NonMemberCallBack);
    std::cout << instance.Init(callback1) << "\n";

    // Similar to non member function.
    auto callback2 = std::bind(&CLoggersInfra::RedundencyManagerCallBack);
    std::cout << instance.Init(callback2) << "\n";

    // Class instance is passed to std::bind as second argument.
    // (heed that I call the constructor of CLoggersInfra)
    auto callback3 = std::bind(&CLoggersInfra::NonStaticRedundencyManagerCallBack,
                               CLoggersInfra()); 
    std::cout << instance.Init(callback3) << "\n";
}
// A RGB image
int8_t* pixels = new int8_t[1024*768*4];
bool ok = toJpeg(writeByte, pixels, width, height);
void writeByte(unsigned char oneByte)
{
    fputc(oneByte, output);
}
class BadIdea {
private:
    FILE* m_stream;
public:
    BadIdea(FILE* stream)  {
        this->m_stream = stream;
    }

    void writeByte(unsigned char oneByte){
            fputc(oneByte, this->m_stream);
    }

};
FILE *fp = fopen(filename, "wb");
BadIdea* foobar = new BadIdea(fp);

bool ok = TooJpeg::writeJpeg(foobar->writeByte, image, width, height);
delete foobar;
fflush(fp);
fclose(fp);
class/struct BadIdea
{
    FILE* m_stream;
}
static class BadIdeaExtensions
{
    public static writeByte(this BadIdea instance, unsigned char oneByte)
    {
         fputc(oneByte, instance->m_stream);
    }

}
typedef void (*WRITE_ONE_BYTE)(unsigned char);
bool writeJpeg(WRITE_ONE_BYTE output, uint8_t* pixels, uint32_t 
 width, uint32_t height))
    { ... }
FILE *fp = fopen(filename, "wb");
auto lambda = [fp](unsigned char oneByte) { fputc(oneByte, fp);  };
bool ok = TooJpeg::writeJpeg(lambda, image, width, height);
typedef void (*WRITE_ONE_BYTE)(unsigned char);
using WRITE_ONE_BYTE = std::function<void(unsigned char)>; 
auto f = std::bind(&BadIdea::writeByte, &foobar);
./configure
make
make install

gcc main.c -l:libffcall.a -o ma
#include <callback.h>

// this is the closure function to be allocated 
void function (void* data, va_alist alist)
{
     int abc = va_arg_int(alist);

     printf("data: %08p\n", data); // hex 0x14 = 20
     printf("abc: %d\n", abc);

     // va_start_type(alist[, return_type]);
     // arg = va_arg_type(alist[, arg_type]);
     // va_return_type(alist[[, return_type], return_value]);

    // va_start_int(alist);
    // int r = 666;
    // va_return_int(alist, r);
}



int main(int argc, char* argv[])
{
    int in1 = 10;

    void * data = (void*) 20;
    void(*incrementer1)(int abc) = (void(*)()) alloc_callback(&function, data);
    // void(*incrementer1)() can have unlimited arguments, e.g. incrementer1(123,456);
    // void(*incrementer1)(int abc) starts to throw errors...
    incrementer1(123);
    // free_callback(callback);
    return EXIT_SUCCESS;
}
add_library(libffcall STATIC IMPORTED)
set_target_properties(libffcall PROPERTIES
        IMPORTED_LOCATION /usr/local/lib/libffcall.a)
target_link_libraries(BitmapLion libffcall)
target_link_libraries(BitmapLion ffcall)
class CallBack 
{
   virtual callMeBack () {};
};
class AnotherClass ()
{
     public void RegisterMe(CallBack *callback)
     {
         m_callback = callback;
     }

     public void DoSomething ()
     {
        // DO STUFF
        // .....
        // then call
        if (m_callback) m_callback->callMeBack();
     }
     private CallBack *m_callback = NULL;
};
class Caller : public CallBack
{
    void DoSomthing ()
    {
    }

    void callMeBack()
    {
       std::cout << "I got your message" << std::endl;
    }
};
CLoggersInfra* pLoggerInfra;

RedundencyManagerCallBackWrapper(int val)
{
    pLoggerInfra->RedundencyManagerCallBack(val);
}
m_cRedundencyManager->Init(RedundencyManagerCallBackWrapper);