#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!
🔒 Locked
C++, Member Function Pointers
Advertisement
Original Post
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:
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();
m_pfnThink = Think;
To call the function you need to dereference the pointer:
Mage.*m_pfnThink();
#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
You have to use .* and ->* because otherwise some code couldn't be compiled. Example :
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]
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]
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:
So I don''t have a clue whats going on, any advice now?
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?
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]
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]
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
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
Topic Locked
This topic has been locked by a moderator. New replies are not allowed.
Sign in to reply to this topic.
Advertisement