C++ function pointers

Started by
10 comments, last by ajas95 19 years, 5 months ago
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
Advertisement
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!
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
"I am a donut! Ask not how many tris/batch, but rather how many batches/frame!" -- Matthias Wloka & Richard Huddy, (GDC, DirectX 9 Performance)

http://www.silvermace.com/ -- My personal website
thanks :) so its not just a case of creating another function with a different calling convention :(
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!!
"I am a donut! Ask not how many tris/batch, but rather how many batches/frame!" -- Matthias Wloka & Richard Huddy, (GDC, DirectX 9 Performance)

http://www.silvermace.com/ -- My personal website
wow thankyou so much! i never would have come up with that by myself :)
oh god, ive been reading through that, and there is like 3 lines of code i understand. You have completely nooberised me :)
Read this :)
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
"I am a donut! Ask not how many tris/batch, but rather how many batches/frame!" -- Matthias Wloka & Richard Huddy, (GDC, DirectX 9 Performance)

http://www.silvermace.com/ -- My personal website
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.

This topic is closed to new replies.

Advertisement