Sign in to follow this  
Muncher

C++ function pointers

Recommended Posts

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

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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

Share this post


Link to post
Share on other sites
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 class
struct CommandBase {
std::string name;
};

// stores a class-specific function pointer
template< 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 classes
class 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 classes
class 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!!

Share this post


Link to post
Share on other sites
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

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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.

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