Reputation: 2983
typedef void (*CALLBACK)();
class Filter
{
public:
void callback()
{
cout << "callback" << endl;
}
};
void SetCallback(CALLBACK pCallBack )
{
pCallBack();
}
int main()
{
Filter f;
SetCallback(f.callback);
}
In main, SetCallback(f.callback); statement is giving error. Can anyone help me to fix the issue
Upvotes: 10
Views: 12462
Reputation: 33
i just making a static variable _this, that a pointer on my class, and make method static, where this replaced with _this
class my_class
{
private:
inline static my_class *_this = nullptr;
int data{};
static void callback_method()
{
_this->data++;
}
public:
my_class()
{
_this = this;
legacy_c_func(callback_method);
_this = nullptr;
}
};
but tbh its not thread safe
Upvotes: 0
Reputation: 41
A simplier example about callback for 'non-static method' :
#include <iostream>
#include <string>
#include <functional>
using namespace std::placeholders;
class Test
{
public:
void SetValue(int i) { v = i;}
int v;
};
int main()
{
Test a { 123 };
std::cout << a.v << std::endl; // print 123
auto _callback = std::bind(&Test::SetValue, &a, _1); // create the callback
_callback(55); // call the callback
std::cout << a.v << std::endl; // print 55
return 0;
}
output :
123
55
Upvotes: 3
Reputation: 71899
The problem is that a member function isn't a plain function without parameters, because it always has the implicit this
parameter.
If you encounter a legacy C interface that requires a plain callback function without a user context parameter (a void*
that the function just passes on to the callback) you have a problem.
If you do have the user context, it's easy. Pass the object pointer as the context, and use a wrapper function as the actual callback:
typedef void (*CALLBACK)(void*);
class Filter
{
public:
static void CallbackWrapper(void* context) {
static_cast<Filter*>(context)->callback();
}
private:
void callback();
};
int main() {
Filter f;
SetCallback(&Filter::CallbackWrapper, &f);
}
If you don't have the context, here are some options:
qsort()
. At least this way, you don't get the thread safety issues. Still not an option for long-running callbacks.The final option still has lots of downsides: it's extremely platform-specific and may not even work at all on some (you can't disable execution protection in iOS, AFAIK), it's CPU-specific (since you need to generate the right code for each), and there's the issue of managing the memory for the stub. On the other hand, sometimes it's the only thing that works. Delphi does this kind of stuff for its window and hook procedures sometimes, and the ATL does so too.
Upvotes: 11
Reputation: 6424
Here is a method I've used to implement a callback to a pointer to member function.
It might require C++11.
#include <iostream>
#include <string>
#include <functional>
using namespace std;
struct MessageSource
{
function<void(const string& msg)> _callback;
template<typename A, typename B>
void connect(A func_ptr, B obj_ptr)
{
_callback = bind(func_ptr, obj_ptr, placeholders::_1);
}
void send_msg(const string& msg)
{
if (_callback)
_callback(msg);
}
void disconnect()
{
_callback = nullptr;
}
};
struct Printer
{
void print(const string& msg) { std::cout << msg << std::endl; };
};
int main()
{
{
Printer p;
MessageSource s;
s.connect(&Printer::print, &p);
s.send_msg("test");
s.disconnect();
s.send_msg("test again");
}
system("pause");
return 0;
}
Upvotes: 5
Reputation: 148880
You should think about what a callback really is and how a member function is called.
When you give a callback function, you just give the address of a function that will later be called with parameters on which you normally have little control.
When a member function is called, its first parameter is the this
pointer, that is a reference to the object on which the method is called.
That's the reason why it is not possible to use a member method as a callback. You can only use true functions or static member functions that do not need the special (implicit for programmer but real in a compiler point of view) parameter this
.
Upvotes: 0