function pointers

Started by
11 comments, last by moucard 19 years, 9 months ago
Ok, new question in 10 minutes, I must be hitting a record. I have 2 classes, CGame and CNet. CNet has an instance in CGame. However, I have a method of CGame::NetMessageHandler, which I'd like to call from within CNet. What kind of a pointer do I need to create in CNet and how do I pass the address of the NetMessageHandler to it? I'll give it a try myself, but if anyone feels more comfortable with function pointers please help!
Advertisement
class Foo{public:  int member_function(double);};Foo f;Foo* pf = &f// Pointer to member functionint (Foo::*pmf)(double) = &Foo::member_function;int i = (f.*pmf)(1.5);    // call with objectint j = (pf->*pmf)(1.0);  // call with pointer to object
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." — Brian W. Kernighan
If CNet has an instance of CGame why not just invoke the function NetMessageHandler using the dot operator?

// CNet instance of CGame
CGame foo;
foo.NetMessageHandler( );
Quote:Original post by simba
If CNet has an instance of CGame why not just invoke the function NetMessageHandler using the dot operator?

// CNet instance of CGame
CGame foo;
foo.NetMessageHandler( );



I think you'll find that he said
Quote:CNet has an instance IN CGame

I dont think that you need function pointers as you can access the "parent" object.

These code fragments might help though

// headerclass CGame;class CNet{public:	CNet(CGame* pGame=NULL){ pGameObj=pGame;};	void SetGame(CGame* pGame){pGameObj=pGame;}	CGame* pGameObj;	void CallingFunction();};class CGame {public:	CGame()	CNet netItem;	void NetMessageHandler()	{          // other code	};};///////////////////////////////////// cpp for CGame...CGame::CGame() {    netItem.SetGame(this);}...////////////////////////////////////// cpp for void CNet::CallingFunction(){	//	assert(pGameObj!=NULL);        ...	pGameObj->NetMessageHandler();		...}


When the instance of CGame is created a "this" pointer is used to initialise the CNet object. After that accessing public members of CGame from CNet is easy.

Edited by Box2020
Box2020<CEng&,CRnd*>
Box2020 you were right that CNet is in CGame.
The problem is that I can't get CNet to see CGame. If I try
#include "CGame.h" a get some errors complaining it can't find some other classes. All header files are guarded by #ifndef's.
I'm almost there, but when I tried passing the method address, like:
CGame::CGame() {  m_cNet.GetGameMessageHandler(&NetMessageHandler);}

I could not, it gave an error of:
error C2276: '&' : illegal operation on bound member function expression.
Looking it up on MSDN it says that I'm trying to get the address of a virtual function. My function though is like this:
//headervoid NetMessageHandler(string cMessage_);//cppvoid CGame::NetMessageHandler(string cMessage_){	if (cMessage_ == "CONNECTED") {		m_cSounds[2].Play();	}}

Tried a lot of other stuff but still failed. Is there a way to do a cast or something to get it to work?
Search in the forum for "member function pointer" and you will find a lot of answers.
But in your case I would solve the original problem. For me, the pointer solution looks like a dirty hack (if the copilation problem is the only reason for your choice).
And boost::Function would allow binding of any function (even bound members).
Quote:
CGame::CGame() {  m_cNet.GetGameMessageHandler(&NetMessageHandler);}


I could not, it gave an error of:
error C2276: '&' : illegal operation on bound member function expression.


You cannot manipulate a bound member function, except by calling it. A bound member function is a member function that has already been associated (bound) with the object it is supposed to operate on (here, *this). What you need to pass around is a pointer to the unbound member function, which you get through &CGame::NetMessageHandler. Of course, you will also need to pass a pointer (or reference) to the appropriate CGame object you want that member function to be bound to (this).

Therefore, your code could look like

CGame::CGame() {  m_cNet.SetGameMessageHandler(&CGame::NetMessageHandler, this);}


with the SetMessageHandler function declared as void CNet::SetMessageHandler( void (CGame::*handler)(string), CGame* pobject);

And in your CNet code, you would bind the member function pointer and the object pointer together, as I have shown in my first post: (pobject->*handler)("hello");.

edit: Alternatively, as VolkerG points out, boost::function is an excellent solution.
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." — Brian W. Kernighan
Ok - if I understand you correctly the problem is that you can't include CGame.h in the CNet header.

simple answer - DONT. use a forward declaration like this

//////////////////////////////// cnet.hclass CGame;class CNet{public:    CNet(CGame* pGame=NULL){ pGameObj=pGame;};    void SetGame(CGame* pGame){pGameObj=pGame;}    CGame* pGameObj;    void CallingFunction();};

then include the CGame header within the CNet.cpp
////////////////////////////////// cnet.cpp#include "stdafx.h"#include "cgame.h"void CNet::CallingFunction(){    pGameObj->NetMessageHandler();}

cgame.h should have the cnet header
///////////////////////////////// cgame.h#include "cnet.h"class CGame {public:    CGame();    CNet netItem;    void NetMessageHandler()    {    };};

and finaly the code for cgame
//////////////////////////////////// cpp for CGame#include "stdafx.h"#include "cgame.h"CGame::CGame() {    netItem.SetGame(this);}

this appears to move the header dependancies around but should get you there
Box2020<CEng&,CRnd*>
Going to search right now. I need to redeclare something that maybe wasn't clear in my above posts. I can't use CGame in CNet.
CGame is the main game class and #include's CNet. So when your telling me to write CNet::GetGameMessageHandler(..., CGame *obj) I can't. If I don't include "CGame.h" naturally it doesn't see CGame and complains about unknown type. If I include it I get unknown types in other classes in CGame.h. I'm quite tired as well, but that's besides the point!
Quote:Original post by moucard
So when your telling me to write CNet::GetGameMessageHandler(..., CGame *obj) I can't. If I don't include "CGame.h" naturally it doesn't see CGame and complains about unknown type.


You don't need to have access to the full definition of CGame (which you have in CGame.h) to be allowed to declare functions taking CGame as a parameter (or returning CGame), nor do you need it for pointers to CGame. The full definition is required to know the size of CGame, but those things do not need that piece of information.

Therefore, your CNet.h header file can make do with a CGame class declaration instead of an actual definition:
class CGame;class CNet{  /* stuff */  void GetGameMessageHandler( void (CGame::*handler)(string), CGame *obj);  /* more stuff */};


On the other hand, the code for the functions that do use CGame (in CNet.cpp) will need to know how CGame is put together, and will require the CGame header file. However, at that point, you already have completed the CNet definition, and all goes well.

#include "CNet.h"  // CNet doesn't really need CGame.h #include "CGame.h" // CGame does need CNet.h for its CNet membervoid CNet::GetGameMessageHandler( void (CGame::*handler)(string), CGame *obj){  /* stuff */};
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." — Brian W. Kernighan

This topic is closed to new replies.

Advertisement