How do I implement a callback in C++?
Solution 1
The best solution, use boost::function
with boost::bind
, or if your compiler supports tr1/c++0x use std::tr1::function
and std::tr1::bind
.
So it becomes as simple as:
boost::function<void()> callback;
Target myTarget;
callback=boost::bind(&Target::doSomething,&myTarget);
callback(); // calls the function
And your set callback becomes:
class MyClassWithCallback{
public:
void setCallback(boost::function<void()> const &cb)
{
callback_ = cb;
}
void call_it() { callback_(); }
private:
boost::function<void()> callback_;
};
Otherwise you need to implement some abstract class
struct callback {
virtual void call() = 0;
virtual ~callback() {}
};
struct TargetCallback {
virtual void call() { ((*self).*member)()); }
void (Target::*member)();
Target *self;
TargetCallback(void (Target::*m)(),Target *p) :
member(m),
self(p)
{}
};
And then use:
myCaller.setCallback(new TargetCallback(&Target::doSomething,&myTarget));
When your class get modified into:
class MyClassWithCallback{
public:
void setCallback(callback *cb)
{
callback_.reset(cb);
}
void call_it() { callback_->call(); }
private:
std::auto_ptr<callback> callback_;
};
And of course if the function you want to call does not change you may just implement some interface, i.e. derive Target from some abstract class with this call.
Solution 2
One trick is to use interfaces instead, that way you don't need specifically to know the class in your 'MyClassWithCallback', if the object passed in implements the interface.
e.g. (pseudo code)
struct myinterface
{
void doSomething()=0;
};
class Target : public myinterface { ..implement doSomething... };
and
myinterface *targetObj;
void setCallback(myinterface *myObj){
targetObj = myObj;
};
doing the callback
targetObj->doSomething();
setting it up:
Target myTarget;
MyClassWithCallback myCaller;
myCaller.setCallback(myTarget);
Solution 3
The Observer design pattern seems to be what you're looking for.
Solution 4
You have a few basic options:
1) Specify what class the callback is going to use, so that the object pointer and member function pointer types are known, and can be used in the caller. The class might have several member functions with the same signature, which you can choose between, but your options are quite limited.
One thing that you've done wrong in your code is that member function pointers and free function pointers in C++ are not the same, and are not compatible types. Your callback registration function takes a function pointer, but you're trying to pass it a member function pointer. Not allowed. Furthermore, the type of the "this" object is part of the type of a member function pointer, so there's no such thing in C++ as "a pointer to any member function which takes an integer and returns void". It has to be, "a pointer to any member function of Target which takes an integer and returns void". Hence the limited options.
2) Define a pure virtual function in an interface class. Any class which wants to receive the callback therefore can inherit from the interface class. Thanks to multiple inheritance, this doesn't interfere with the rest of your class hierarchy. This is almost exactly the same as defining an Interface in Java.
3) Use a non-member function for the callback. The for each class which wants to use it, you write a little stub free function which takes the object pointer and calls the right member function on it. So in your case you'd have:
dosomething_stub(void *obj, int a) {
((Target *)obj)->doSomething(a);
}
4) Use templates:
template<typename CB> class MyClassWithCallback {
CB *callback;
public:
void setCallback(CB &cb) { callback = &cb; }
void callCallback(int a) {
callback(a);
}
};
class Target {
void operator()(int a) { /* do something; */ }
};
int main() {
Target t;
MyClassWithCallback<T> caller;
caller.setCallback(t);
}
Whether you can use templates depends whether your ClassWithCallback is part of some big old framework - if so then it might not be possible (to be precise: might require some more tricks, such as a template class which inherits from a non-template class having a virtual member function), because you can't necessarily instantiate the entire framework once for each callback recipient.
Solution 5
Also, look at the Observer Pattern and signals and slots . This extends to multiple subscribers.
nacho4d
C/C++/Objective-C/C#/Javascript/shell-script/Japanese/Go/Spanish/English I love this site. So Helpful! https://twitter.com/nacho4d http://nacho4d-nacho4d.blogspot.com/
Updated on August 02, 2020Comments
-
nacho4d almost 4 years
I want to implement a class in c++ that has a callback.
So I think I need a method that has 2 arguments:
- the target object. (let's say *myObj)
- the pointer to a member function of the target object. (so i can do *myObj->memberFunc(); )
The conditions are:
myObj can be from any class.
the member function that is gonna be the callback function is non-static.
I've been reading about this but it seems like I need to know the class of myObj before hand. But I am not sure how to do it. How can I handle this? Is this possible in C++?
This is something I have in mind but is surely incorrect.
class MyClassWithCallback{ public void *targetObj; void (*callback)(int number); void setCallback(void *myObj, void(*callbackPtr)(int number)){ targetObj = myObj; callback = callbackPtr; }; void callCallback(int a){ (myObj)->ptr(a); }; }; class Target{ public int res; void doSomething(int a){//so something here. This is gonna be the callback function}; }; int main(){ Target myTarget; MyClassWithCallback myCaller; myCaller.setCallback((void *)&myTarget, &doSomething);
}
I appreciate any help.
Thank you.
UPDATE Most of you said Observing and Delegation, well that's i exactly what i am looking for, I am kind of a Objective-C/Cocoa minded guy. My current implementation is using interfaces with virtual functions. Is just I thought it would be "smarter" to just pass the object and a member function pointer (like boost!) instead of defining an Interface. But It seems that everybody agrees that Interfaces are the easiest way right? Boost seems to be a good idea, (assuming is installed)
-
Artyom almost 14 yearsObserver pattern requires changes in "observed" class interface, sometimes it is much simpler and clearer use
function
andbind
instead of interfaces. Also note, if you using recent gcc, you already havefunction
andbind
so no need of boost. Using function/bind is functional programing patters while using interfaces is more using "standard" design pattern that has different meaning
-
nacho4d almost 14 yearsYes, I come from a Objective-C world and that is exactly what I want to implement.
-
Said algharibi almost 14 years+1, boost::bind is definitely the way to go for C++-only callback
-
nacho4d almost 14 yearsboost:bind is definitely the answer is was looking for. I probably will have to install boost though.
-
Artyom almost 14 years@nacho4d what compiler do you use? Many already have bind/function in their standard library, so no need for boost
-
nacho4d almost 14 yearsCurrently I am using gcc in my iMac, but actually I creating a library that should compile in windows principally.
-
Artyom almost 14 years@nacho4d Generally gcc-4.x from mingw has it and MSVC2010 should have.
-
ejgottl almost 14 yearsIn g++ 4.5 and msvc2010 you can use a lambda expression instead of bind. Your code will not be compatible with older compilers though.
-
Marchy about 11 years+1 for showing an approach for building your own callback (without using an external library). How would this look if it was templated?