Method pointers / callbacks

  • Thread starter =?ISO-8859-1?Q?Martin_H=F6ller?=
  • Start date
?

=?ISO-8859-1?Q?Martin_H=F6ller?=

Hi!

I'm trying to make a button class for an SDL app. The button should be
able to store a callback to a member function of another class. For that
purpose I implemented a template class named CallBack<Class, ReturnType>
with operator() which works fine.
My problem now is the usage of CallBack in the button.
I want to create the button like this:

CallBack<MyClass, void> *cb = new CallBack(this, MyClass::buttonClick);
Button *my_button = new Button("This is a button", x, y, cb);

How do I tell the button to take ANY type of callback? I don't want to
make the button class a template class...

Thanks for the help,
Martin
 
R

Rolf Magnus

Martin said:
Hi!

I'm trying to make a button class for an SDL app. The button should be
able to store a callback to a member function of another class. For that
purpose I implemented a template class named CallBack<Class, ReturnType>
with operator() which works fine.
My problem now is the usage of CallBack in the button.
I want to create the button like this:

CallBack<MyClass, void> *cb = new CallBack(this, MyClass::buttonClick);
Button *my_button = new Button("This is a button", x, y, cb);

How do I tell the button to take ANY type of callback? I don't want to
make the button class a template class...

You could make CallBack a template, derived from an abstract base class.
 
B

bhanu

Hi Martin,

I wrote a sample for your problem. I hope it helps. The Button
class needs to know only the interface (pure virtual function) of base
class of the callback.

#include <iostream>
#include <string>

using namespace std;

class CBaseCallBack
{
public:
virtual int ProcessCallBack(int x, int y) = 0;
};

template<class TYPE1, class TYPE2>
class CCallback : public CBaseCallBack
{
public:
int ProcessCallBack(int x, int y)
{
cout << "\nx = " << x << "y = " << y << endl;
// process the event here
return 0;
}

private:
TYPE1 Var1;
TYPE2 Var2;
};


class CButton
{
public:
CButton(void *pCallBackObject) { m_pCallBackObject = pCallBackObject;
}
~CButton() { };
int OnEvent()
{
((CBaseCallBack*)m_pCallBackObject)->ProcessCallBack(10, 12);
return 0;
}

private:
void* m_pCallBackObject;
};

int main()
{
CCallback<void*,void*> clsCallBack;
CButton clsTestButton(&clsCallBack);
clsTestButton.OnEvent();
return 0;
}

Bhanu Gogineni.
 
?

=?ISO-8859-1?Q?Martin_H=F6ller?=

bhanu said:
Hi Martin,

I wrote a sample for your problem. I hope it helps. The Button
class needs to know only the interface (pure virtual function) of base
class of the callback.

Hi!

Thanks for your answer but this is not exactly what I'm looking for. I
want to be able to assign any member function to the callback. Your
solution works perfectly if you have to do the same thing everytime the
button is clicked. I want an all-purpose button class.

Martin
 
B

bhanu

In my example I have only one interface to the call back, if you need
more
inferfaces you have to declare them as pure virtual functions in the
base
class.

event flow is something like this:
some object <- call back object <- button object.

you can pass any member function to the call back object as void*, you
can
call it from the call back class, with proper arguments.

In your case, calling "any" function is not possible, without know
about the
the class. you need some abstaction if you want to make it generic.

Regards,

Bhanu Gogineni.
 
B

bhanu

In my example I have only one interface to the call back,
if you need more inferfaces you have to declare them as
pure virtual functions in the base class.

event flow is something like this:
some object <- call back object <- button object.

you can pass any member function to the call back object
as void*, you can call it from the call back class, with
proper arguments.

In your case, calling "any" function is not possible, without
knowing about the the class. you need some abstaction if you
want to make it generic.

Regards,

Bhanu Gogineni.
 
?

=?ISO-8859-1?Q?Martin_H=F6ller?=

Hi!

Thanks for all your answers. I found a suitable solution for my problem
with the help of your postings.
First I introduced a base callback class:

class BaseCallBack
{
public:
virtual void operator()() = 0;
};

Then I derived the main class and removed the return type template
parameter (which reduces the flexibility but is ok for my program):

template <class Class>
class CallBack : public BaseCallBack
{
public:
typedef void (Class::*Method)();

CallBack(Class* class_instance, Method method) :
class_instance_(class_instance), method_(method)
{
}

void operator()()
{
return (class_instance_->*method_)();
}

private:
Class *class_instance_;
Method method_;
};


The button class stores a BaseCallBack* which is handed over to the
constructor. So creating a button works like this:

CallBack<MyClass> *cb = new CallBack<MyClass>(this, &MyClass::foo);
button = new Button([...whatever...], cb);


Thanks again for your help!
Martin
 
M

Maxim Yegorushkin

On Sun, 12 Jun 2005 20:55:20 +0400, Martin Höller

[]
The button class stores a BaseCallBack* which is handed over to the
constructor. So creating a button works like this:

CallBack<MyClass> *cb = new CallBack<MyClass>(this, &MyClass::foo);
button = new Button([...whatever...], cb);

boost::function would save you from writing all the boilerplate code.

boost::function<void()> cb = boost::bind(&MyClass::foo, this);
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,020
Latest member
GenesisGai

Latest Threads

Top