Skip to main content
gamedev.net
🔒 Locked

Function Pointers

Started by pete_2004 Mar 24, 2004 at 5:24 PM 5 replies 600+ views
Original Post
pete_2004
pete_2004
Hi I was just wondering if you can have a pointer to a method in a class. I have created a gui with callback functions and wanted the callbacks I created to be part of my main game class. It only works though if I make them static.( not desired ). Is there way around this. a sample of my code is: //in my gui CoreComponent header //this is my callback pointer typedef void(*ComponentCallback)( CoreComponent * caller ); class CoreComponent { ... void SetEventCallback( EventType event, ComponentCallback callback ); ... }; //in global space void testCallback( CoreComponent * caller ) { ...//some stuff here } //in game core class GameCore { ... void callback( CoreComponent * caller ); ... } void GameCore::Run() { CoreComponent c; c.SetEventCallback( testCallback ); //this works fine CoreComponent c2; c2.SetEventCallback( this->callback ); //doesn''t work unless //GameCore::callback //is static } Can I force this->callback above to be a vaild function pointer? The error I get is something like: cannot convert from void callback * to void (__cdecl) callback * casting to (__cdecl) doesn''t work. Any help is appreciated. Thanks. Pete
Beelzebub
Beelzebub
Do a search on the forms - I posted an answer to this sometime ago
ChaosEngine
ChaosEngine
there are a few ways around this.
1) you could pass a pointer to the object you want to call the method on to the static method ala


class GameCore
{

//.... inlined for simplicity


static void callBack(void* pObj)
{
if (GameCore* pCore = (GameCore*)pObj) {
pObj->callBack();
}
}

void callBack()
{
//whatever

}
};

that's how a lot of MS api's work but it's a bit nasty and type-unsafe

the other way is to define a callback interface and require callback classes to inherit from it, then just pass the object


struct ICallBack
{
virtual void callBack() = 0;
};

class GameCore : public ICallBack
{
void callBack()
{
//whatever

}
}

// then call the method on the object

void SetEventCallback( EventType event, ICallBack& callBack)
{
// do event handling


callBack.callBack();

}




AFAIK you can't pass a pointer to a non-static member function, although I could be way off on this.


[edited by - ChaosEngine on March 24, 2004 6:56:20 PM]
if you think programming is like sex, you probably haven't done much of either.-------------- - capn_midnight
Neophyte
Neophyte
You can definitely have pointers to non-static member functions, but they have some restrictions to them, specifically that the class the member function belongs to is considered part of the function signature for all practical purposes. And the actual syntax for calling the member function is ... odd.

For instance:

#include <iostream>
using namespace std;

class Foo {
public:
void bar() { cout << "Foo::bar" << endl; }
};

typedef void(Foo::*MemFn)();

int main() {
Foo foo;
MemFn fn = &Foo::bar;
(foo.*fn)();
Foo* pFoo = new Foo();
(*pFoo.*fn)();

return 0;
}


Hope that helps,
- Neophyte

EDIT: Forgot to close the source tag.

[edited by - Neophyte on March 24, 2004 7:32:50 PM]
pete_2004
pete_2004
I tried this:


////////////////////////////////////////////
#include <stdio.h>
#include <conio.h>

class ICB
{
public:
typedef void (ICB::*ICB_CALLBACK)();

void ICB_Func()
{
printf("\nIn ICB callback\n");
}

};

class A
{
public:
void SetCallBack( ICB::ICB_CALLBACK c ){ curCB = c; }
void RunCallBack(){ curCB(); }

protected:
ICB::ICB_CALLBACK curCB;
};


void main()
{

A aTest;
aTest.SetCallBack( ICB::ICB_Func );
aTest.RunCallBack();

getch();
};
///////////////////////////////////////


but in this line in class A :

void RunCallBack(){ curCB(); }

I get the error curCB() term does not evaluate to a function
Shannon Barber
Shannon Barber
You want a "signal and slots" library.

Have a look at boost, boost::function can help too.
The trade-off between price and quality does not exist in Japan. Rather, the idea that high quality brings on cost reduction is widely accepted.-- Tajima & Matsubara
pete_2004
pete_2004
I figured something out thats works well for me. It uses templates and means I can only set callbacks on a specific component from the one class. This is''nt to bad though and keeps the code very clean. Have a look:

////////////////////////////////////////////////////////////

#include <stdio.h>
#include <conio.h>


//the component is templated so that it can
//recieve callbacks from one specified class
template < class T >
class CoreComponent
{
public:

void SetCallBack( T::CALLBACK cb )
{
callback = cb;
}

void RunCallBack()
{
T cb;
(cb.*callback)();
}

T::CALLBACK callback;
};


//define a macro to define a callback pointer specific
//to the passed in class type T
#define DefineComponentCBPointer(T) typedef void(T::*CALLBACK)()


//GameCore will contain all callbacks in this program
class GameCore
{
public:

//make sure this is called BEFORE any CoreComponents are created
DefineComponentCBPointer(GameCore);

void Run()
{
CoreComponent< GameCore > test;
test.SetCallBack( testCallBack );
test.RunCallBack();
}

void testCallBack()
{
printf("\nIn Game Core::TestCallBack\n");
}
};


//test it
void main()
{
GameCore gc;
gc.Run();
getch();
};

///////////////////////////////////////////////////////////


This works great! Thanks for all the help everyone. It''s appreciated.

Pete

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.