Sign in to follow this  
moucard

function pointers

Recommended Posts

moucard    161
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!

Share this post


Link to post
Share on other sites
Fruny    1658

class Foo
{
public:
int member_function(double);
};

Foo f;
Foo* pf = &f;

// Pointer to member function
int (Foo::*pmf)(double) = &Foo::member_function;

int i = (f.*pmf)(1.5); // call with object
int j = (pf->*pmf)(1.0); // call with pointer to object

Share this post


Link to post
Share on other sites
simba    122
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( );

Share this post


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


// header

class 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

Share this post


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

//header
void NetMessageHandler(string cMessage_);
//cpp
void 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?

Share this post


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

Share this post


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

Share this post


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

Share this post


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

Share this post


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

void CNet::GetGameMessageHandler( void (CGame::*handler)(string), CGame *obj)
{
/* stuff */
};

Share this post


Link to post
Share on other sites
rypyr    252
Circular includes/dependencies like this can sometime be an indication that the design is poor. I also think that member function pointers can complicate the issue here.

Better to decouple the dependency between CGame and CNet. You can do this using interfaces:

New file, INetHandler.h:

#if !defined(__INETHANDLER_H)
#define __INETHANDLER_H
class INetHandler {
public:
virtual void NetMessageHandler() = 0;
}
#endif // __INETHANDLER_H


In CNet.h:

#if !defined(__CNET_H)
#define __CNET_H

#include "INetHandler.h"

class CNet {
INetHandler* pHandler;
public:
CNet(INetHandler* _handler) : pHandler(_handler) {}
virtual ~CNet() { }

void funcThatCallsNetMessageHandler() {
assert(pHandler); // or whatever
pHandler->NetMessageHandler();
}
};

#endif // __CNET_H


In CGame.h:

#if !defined(__CGAME_H)
#define __CGAME_H

#include "INetHandler.h"
#include "CNet.h"

class CGame : public INetHandler {
CNet netObject;
public:
CGame::CGame() : netObject(this) {}

void NetMessageHandler() { do whatever }
};
#endif // __CGAME_H


Regards,
Jeff

Share this post


Link to post
Share on other sites
rypyr    252
I'd also like to point out that storing a member function pointer requires more memory than storing a pointer to an interface instance :P

Share this post


Link to post
Share on other sites
moucard    161
Thanks to everyone for your help. In the end I found a simple solution that I've used before to bypass the problem, only I didn't see the relation right away.
In CGame I declare a pointer like this:
static CGame *m_cThis;
and then use a static function and a normal method to do it like this:

void CGame::StaticNetMessageHandler(string cMessage_)
{
/*if (cMessage_ == "CONNECTED") {
m_cSounds[2].Play();
}*/
m_cThis->NetMessageHandler(cMessage_);
}

void CGame::NetMessageHandler(string cMessage_)
{
if (cMessage_ == "CONNECTED") {
m_cSounds[2].Play();
}
}

Again I'd like to help everybody for their help. I was (and still am) quite tired. Going to see my friends now, relax. Another battle was won! Cheers.

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