Skip to main content
gamedev.net
🔒 Locked

C++, Member Function Pointers

Started by Estauns 8 replies 4.6k views
Original Post
Estauns
Estauns
Hey all, I''m trying to hack together a "Think"ing system ala Half-Lifes (If you''ve ever worked with the SDK, you''ll know what I mean). Basically, you assign a function to do the "Think"ing for you, and than at some point, you run through all your objects Thinks and do what they specify. Gives it a bit of a delay to the action, in a clean manner. So something like: SetThink(BlowUp) NextThink = Time + 5 seconds. Then whatevers thinking to BlowUp, will do it in 5 seconds from now. NOW, I know the solution is going to be using Function Pointers, and I''ve never used ''em before, so I''m at a bit of a loss. Heres what I''ve got so far:
#include <windows.h>
#include <stdio.h>

#define SetThink( a ) m_pfnThink = static_cast <void (CBaseEntity::*)(void)> (a)

class CBaseEntity
{
public:
	CBaseEntity(void)
	{
		NextThink = -1;

		SetThink(Think);
	}

	void Think(void)
	{
		printf("I am attacking the darkness!\n");
		NextThink = -1;
	}
	DWORD NextThink; // Going to be used in a timing system, ignore for now.

	void(CBaseEntity::*m_pfnThink)(void);
};

int main(void)
{
	CBaseEntity Mage;
	
	// How do I call the function through the pointer now?

	Mage.m_pfnThink; // This does nothing.


	return 0;
}
I took the SetThink macro right out of the Half-Life SDK, so hopefully thats not the source of the problems (but you never know!) It uhh, does nothing right now =) It compiles fine, but Mage.m_pfnThink doesn''t seem to output the thinking text ("I am attacking the darkness!") Any ideas what I''m doing wrong? I''ve tried hacking it together from tutorials and such, but to no avail thusfar. Thanks a bunch for your help guys!
"Where genius ends, madness begins."Estauns
SpaceRogue
SpaceRogue
I''m not sure why you need the macro...since you can just do this to initialize m_pfnThink:

m_pfnThink = Think;

To call the function you need to dereference the pointer:

Mage.*m_pfnThink();
NumberXaero
NumberXaero

#include <windows.h>
#include <stdio.h>

class CBaseEntity;

void (CBaseEntity::*m_PFNTHINK)(void);

#define SetThink( a ) m_PFNTHINK = static_cast <void (CBaseEntity::*)(void)> (a)

class CBaseEntity
{
public:

CBaseEntity(void)
{
SetThink(Think);
//m_PFNTHINK = CBaseEntity::Think; // or = &CBaseEntity::Think;

}

void Think(void)
{
printf("I am attacking the darkness!\n");
}
};

int main(void)
{
CBaseEntity Mage;

(Mage.*m_PFNTHINK)();

return 0;
}


I think the problem was the funtion pointer inside the class. I couldnt figure out the syntax to access m_PFNTHINK when in the class (CBaseEntity) through an object (Mage)in main()I had to make the pfn global so that the class and main could see it. This is probably bug prone and not what you want
mputters
mputters
(this->* m_pfnThink)();
rypyr
rypyr
Didn''t think you needed to dereference the pointer at all, but you''re not calling the function. This:

Mage.m_pfnThink;

is like saying:

int v = 80;
v; // no action on C++ part here...

You need to call the function:

Mage.m_pfnThink();
mputters
mputters
You have to use .* and ->* because otherwise some code couldn't be compiled. Example :


struct object
{
void method();
};
struct example
{
void (object::* p)();
};
main()
{
object a;
example b;
b.p = &object::method;
a.b.p(); // Poor compiler having to understand this

(a.*b.p)();
}


A more obvious example where the syntax you want would break would be when the method pointer variable name is also a member of the object.

[edited by - mputters on August 29, 2003 10:38:56 AM]
Estauns
Estauns
Your method works just fine mputters (once you comment the error you were showing me), however, this now updated code, gives me these compiler errors (which baffle me):

C:\PROGRAMMING\C++\DOS WINDOWS\TimerTest\main.cpp(25) : error C2065: ''m_pfnThink'' : undeclared identifier
C:\PROGRAMMING\C++\DOS WINDOWS\TimerTest\main.cpp(25) : error C2297: ''.*'' : illegal, right operand has type ''int''

And heres the new source:

class CBaseEntity
{
public:
CBaseEntity(void)
{
m_pfnThink = Think;
}

void Think(void)
{
printf("I am attacking the darkness!\n");
}

void(CBaseEntity::*m_pfnThink)();
};

int main(void)
{
CBaseEntity Mage;
(Mage.*m_pfnThink)();

return 0;
}


So I don''t have a clue whats going on, any advice now?
"Where genius ends, madness begins."Estauns
Fruny
Fruny
Unlike regular functions, member function names do not implicitely decay to function pointers.

m_pfnThink = &Think;

You made the pointer a member of the class - proper access therefore is :

(Mage.*(Mage.m_pfnThink))();



[ Start Here ! | How To Ask Smart Questions | Recommended C++ Books | C++ FAQ Lite | Function Ptrs | CppTips Archive ]
[ Header Files | File Format Docs | LNK2001 | C++ STL Doc | STLPort | Free C++ IDE | Boost C++ Lib | MSVC6 Lib Fixes ]


[edited by - Fruny on August 29, 2003 1:00:06 PM]
"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
Satook
Satook
This was a problem I had recently myself, when I was writing a class to manage states in other classes. There is a critical difference between normal function pointers, and pointers to class methods. If you want to call a function on a class you need to tell the compiler which instance of the class that you are calling it on.

Eg, when calling class methods normally you may write

classp->function();

this says call function on the instance classp.

Same thing goes with pointers to class methods. As the class method pointer only holds a pointer to the code, and not the class, you need to use, as Fruny said

(Mage.*(Mage.m_pfnThink))();

this tells the compiler to call the function pointed to by "Mage.m_pfnThink" on the CBaseEntity instance "Mage".

Hope it helps
What''s a cleaver?
Estauns
Estauns
Thanks a bunch guys, works like a charm =)

I see this coming in VERY handy, not just for these Think methods but for many other things.

Thanks again.
"Where genius ends, madness begins."Estauns

Topic Locked

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

Sign in to reply to this topic.