Sign in to follow this  
Graham

Creating callbacks

Recommended Posts

Graham    166
I am trying to implement a system of callbacks and I cant get it to compile. Can someone help me figure this out? I want a class to have a vector of function pointers that will be called when an event occurs. Similar to Windows.
#include <iostream>
#include <vector>

using namespace std;

class Func
{
public:
	int (*function) (void);
	Func(int (*Afunc) (void))
	{
		function = Afunc;
	}
};

class A
{
public:
	int var;
	vector<Func> callBacks;
	void Register(int (*f) (void))
	{
		callBacks.push_back(Func(f));
	}

};

class B
{
public:
	int stuff;
	int CallMe(void)
	{
		cout << "I was called" << endl;
	}
};
class C
{
public:
	int stuff;
	int CallMe(void)
	{
		cout << "I was called also" << endl;
	}
};


int main()
{
	A myA;
	B myB;
	C myC;
	
	myA.Register( (int (*) (void)) B::CallMe); // compile error
	myA.Register( (int (*) (void)) C::CallMe); // compile error
	
	myA.callBacks[0].function();
	myA.callBacks[1].function();
	return 0;
}


Share this post


Link to post
Share on other sites
nmi    978
The CallMe functions of classes B and C have another signature than you might have expected, because the compiler adds the implicit this parameter.

Share this post


Link to post
Share on other sites
pragma Fury    343
Your "CallMe" functions are scoped to their respective classes, where the Function pointer definition is for a C function pointer.

Also, Your "CallMe" functions require a return value, which you have not specified.

You can fix the callback issues by:

1: Make your callbacks global.
2: Make them static.
3: Create a wrapper class to call them.
4: Use a functor.. which is sort of similar to what you're already doing with Func.



I highly recommend This page. Specifically, the sections titled "How to Implement a Callback to a static/non-static C++ Member Function"

Share this post


Link to post
Share on other sites
rKallmeyer    396
... which means things get alot more tricky. Keywords to look for : member-function-pointers for the basics and Functors to impliment callbacks.

Just to give you a preview:

In order to call a non-static member-function from a function pointer, you will need supply a pointer to the object who's method you want to call, and the syntax for declaring member-function pointers is a little bit different.


// So this:
Func(int (*Afunc) (void))

// becomes
Func (const SomeClass* pObject, int (SomeClass::*pMethod) (void))

// and you all it like this
(pObject->*pMethod) ()



Of course this wont give you all the answers you need, but maybe help you search in the right direction.

Share this post


Link to post
Share on other sites
Graham    166
Okay thanks for the help, I know what I need to read more about. What if in my previous example B and C were derived from an abstract class with the pure virtual function CallMe. Then wouldnt the signiture for CallMe() be the same in class B and C?

Share this post


Link to post
Share on other sites
nmi    978
Quote:
Original post by Graham
Okay thanks for the help, I know what I need to read more about. What if in my previous example B and C were derived from an abstract class with the pure virtual function CallMe. Then wouldnt the signiture for CallMe() be the same in class B and C?


What would you put into your vector ?
You may either chose to put pointers to instances of the abstract base class in your vector, but then you need to take care of deleting all those objects afterwards. But that would require you to know the runtime type of the object.
The best option would be to use a functor, as already mentioned.

Share this post


Link to post
Share on other sites
rKallmeyer    396
Quote:
Then wouldnt the signiture for CallMe() be the same in class B and C?


You actually don't need it to be the same. You can just cast it to the right type*



class A
{
public:
void foo (int);
};

class B
{
public:
void foo (int);
};

class CallBack
{
public:
typedef const void* ObjectPtr;
typedef void (CallBack::*MethodPtr)(int);

CallBack (ObjectPtr pObject, MethodPtr pMethod)
{
m_pObject = pObject;
m_pMethod = pMethod;
}

void invoke (int i)
{
(m_pObject->*m_pMethod) (i);
}

private:
ObjectPtr m_pObject;
MethodPtr m_pMethod;
}

...

// in main
A a;
B b;

CallBack callbackA = CallBack (reinterpret_cast <CallBack::ObjectPtr>(&a),
reinterpret_cast <CallBack::MethodPtr>(&A::foo));

CallBack callbackB = CallBack (reinterpret_cast <CallBack::ObjectPtr>(&b),
reinterpret_cast <CallBack::MethodPtr>(&B::foo));




But in all honesty having to use those casts everywhere kindof sucks, so this is a great place for templates... (if you arn't very comfortable with them just stkip this.



class CallBack
{
public:
typedef const void* ObjectPtr;
typedef void (CallBack::*MethodPtr)(int);

template <class CLASS>
CallBack (const CLASS* pObject, void (CLASS::*pMethod)(int) )
{
m_pObject = reinterpret_cast <ObjectPtr> (pObject);
m_pMethod = reinterpret_cast <MethodPtr> (pMethod);
}

...


...

// in main

A a;
B b;

CallBack callbackA = CallBack (&a, &A::foo);
CallBack callbackB = CallBack (&b, &B::foo);




Much better... of course from there you can templatize parameters and return types but that goes beyond the scope of this post.



*You can only cast between different types of member-function pointers if they have the same size. They only have the same size IF they use the same inheritance OR you use the /vmg compiler option in MSVC++.

Hope that helps a little.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this