Skip to main content
GameDev.net gamedev.net
🔒 Locked

C++ function pointers

Started by Muncher Nov 14, 2004 at 3:33 AM 10 replies 1.3k views
Original Post
Muncher
Muncher
Hi, i have written a quake-like console that associates a console command with a function. But i'm not sure how to use a function pointer to an objects function. eg void function (void) { // do stuff here } cConsole.addCommand(function,"command"); ^ This works perfectly, but when i try to add a class method i get errors, eg; cConsole.addCommand(cSomeObject.itsFunction,"command"); i hope i have explained that ok, basically i want the addCommand function to accept a function pointer from an object as well, does anyone know how to do this? Muncher
JohnBolton
JohnBolton
Member functions have a different calling convention (because of the implicit this parameter). That is why it doesn't work. However, you can pass static member functions.
John BoltonLocomotive Games (THQ)Current Project: Destroy All Humans (Wii). IN STORES NOW!
silvermace
silvermace
class method function pointers are a special case function pointer. because a class method operates on an instance of a class (unless it is a static member) they require an instance of the class.

class SomeClass {	std::string sig;public:	SomeClass( std::string _sig ) : sig(_sig) {}	void foo(int a) {		std::cout << sig.c_str() << " : " << a << std::endl;	}};typedef void (SomeClass::*MFNPTR)(int a);int main() {	SomeClass myObjA("Booom!");	SomeClass myObjB("KaPow!");	MFNPTR p = &SomeClass::foo;	(myObjA.*p)(12);	(myObjB.*p)(24);	return 0;}
what you need to do is create your console to support objects that can be passed by pointer or reference, so that you complete the function-call signature.

i will try figure out a simple callback implementation that you can use and i will post back here in about 10 mins.

-Danu
Muncher
Muncher
thanks :) so its not just a case of creating another function with a different calling convention :(
silvermace
silvermace
ok, heres a class type free implementation, its a bit advanced with the pointers, inheritence and templates, if you need anything explained post back.

NOTE: i'm not sure about the safety of this method, i devised it just now and it seems to work well enough BUT take it with a 'grain of salt'.

the type-free console
// command storage base classstruct CommandBase {	std::string name;};// stores a class-specific function pointertemplate< typename T >struct CommandSpecific : CommandBase {	CommandSpecific( std::string _name, void (T::*_fnp)(int a) ) {		name = _name;		fnp = _fnp;	}	// declare the function-pointer storage variable 'fnp'	void (T::*fnp)(int a);};class Console {private:	std::vector< CommandBase* > cmdlist;public:	// adds a command and stores its pointer	template< typename T >	void addCommand( void (T::*fnp)(int a), std::string cmd ) 	{		CommandBase *cb = new CommandSpecific< T >( cmd, fnp );		cmdlist.push_back( cb );	}	// attempt to call a command	template< typename T >	void attemptCommand( T& inst, std::string cmd ) 	{		std::vector<CommandBase*>::iterator i = cmdlist.begin();		// look for the command to see if its listed		for(; i!=cmdlist.end(); i++ ) 		{			if( (*i)->name == cmd ) 			{				// now we know the command calls match,				// cast the stored pointer to retreive the class-specific function pointer				CommandSpecific<T> *cp = static_cast< CommandSpecific<T>* > ( (*i) );				// do the funtion call, supply some random number for fun :)				(inst.*(cp->fnp))( rand() % 100 );			}		}	}	virtual ~Console() {		// cleanup fn ptrs		std::vector<CommandBase*>::iterator i = cmdlist.begin();		for( ; i != cmdlist.end(); i++ ) {			delete (*i);			*i = NULL;		}		cmdlist.clear();	}};


test it out!
// our test classesclass SomeClass {	std::string sig;public:	SomeClass( std::string _sig ) : sig(_sig) {}	void foo(int a) {		std::cout << "SomeClass: " << sig.c_str() << " : " << a << std::endl;	}};// our test classesclass SomeOtherClass {	std::string sig;public:	SomeOtherClass( std::string _sig ) : sig(_sig) {}	void foobar(int a) {		std::cout << "SomeOtherClass: " << sig.c_str() << " : " << a << std::endl;	}};int main() {	SomeClass myObjA("Booom!");	SomeOtherClass myObjB("KaPow!");	Console con;	con.addCommand< SomeClass >( &SomeClass::foo, "SomeClass_foo" );	con.addCommand< SomeOtherClass >( &SomeOtherClass::foobar, "SomeOtherClass_foobar" );		con.attemptCommand< SomeClass >( myObjA, "SomeClass_foo" );	con.attemptCommand< SomeOtherClass >( myObjB, "SomeOtherClass_foobar" );	return 0;}

the main problems with my simple implementation are that:
1 - there is no type checking to see if any of the cast's are valid!
2 - you need to be carefull that EACH class has a DIFFERENT console command associated with its type.
3 - pointers can get messy, use with caution!

-Cheers
Dan

PS. that was a fun problem to solve, mite use it myself!!
Muncher
Muncher
wow thankyou so much! i never would have come up with that by myself :)
Muncher
Muncher
oh god, ive been reading through that, and there is like 3 lines of code i understand. You have completely nooberised me :)
silvermace
silvermace
what exactly do you not understand?
ps. maybe its a wee bit too advanced, you might be able to simplyfy the idea a bit more...

have you considered using global callbacks?
very simple idea, the main drawback would be that you need to create a callback for every possible object type, and/or need to specificaly handle each type.

here's some simple code
 // DIRECTLY FROM FUNCTION-POINTER.ORG, COPYRIGHT (C) 2004-2005   class TClassA   {   public:      void Display(const char* text) { cout << text << endl; };      static void Wrapper_To_Call_Display(void* pt2Object, char* text);      /* more of TClassA */   };   // static wrapper-function to be able to callback the member function Display()   void TClassA::Wrapper_To_Call_Display(void* pt2Object, char* string)   {       // explicitly cast to a pointer to TClassA       TClassA* mySelf = (TClassA*) pt2Object;       // call member       mySelf->Display(string);   }   // function does something which implies a callback   // note: of course this function can also be a member function   void DoItA(void* pt2Object, void (*pt2Function)(void* pt2Object, char* text))   {      /* do something */      pt2Function(pt2Object, "hi, i'm calling back using a argument ;-)");  // make callback   }   // execute example code   void Callback_Using_Argument()   {      // 1. instantiate object of TClassA      TClassA objA;      // 2. call 'DoItA' for <objA>      DoItA((void*) &objA, TClassA::Wrapper_To_Call_Display);   }


for somemore usefull reading about function pointers and callbacks: http://www.function-pointer.org
jdhardy
jdhardy
Instead of using function pointers, take a long, hard look at Boost.Function & Boost.Bind. Both libraries make manipulating functions much simpler. Versions of both libraries are also likely to be part of the C++ standard library in the future.
CJH
CJH
Make member functions into free-standing friends. [Restrictions apply]
ajas95
ajas95
Anytime someone asks about member function pointers, I feel obliged to post this article about C++ delegates. Basically, it's exactly what the OP is looking for with a very convenient syntax, and totally cross-platform.

Of course, the article is mostly a discussion about why the problem is so hard, and it gets pretty technical... but he also gives his solution, which is the coolest thing evar.

Topic Locked

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

Sign in to reply to this topic.