Skip to main content
gamedev.net
🔒 Locked

Function pointers in classes

Started by tool_2046 Oct 26, 2002 at 3:54 PM 16 replies 750+ views
Original Post
tool_2046
tool_2046
Okay, I''m sure this question has been asked a billion times, but I just can''t figure this out. Say I have some class like class SomeClass { public: void (* CurrentFunction)(void); void Init(void); void Blah(void); private: int Data; }; SomeClass Test; And then if you try to say something like CurrentFunction = Init; But then you get some conversion error, so you declare Init and Blah as static: static void Init(void); static void Blah(void); and then this allows you to set CurrentFunction equal to one of these but then static function can''t access any member data of the class. So say then in Init() you want to set Data = 0: void Init(void) { Data = 0; } This gives an error because static functions can''t access member data, nor do they have a this pointer. So then how do you do you have a class when a function pointer in it point to another function in the class so that the function its pointing to can access data in the class? Is this just impossible? I refuse to believe it, someone please help...
Grizwald
Grizwald
not too sure, but try using this:

void (_thiscall *CurrentFunction)(void);

that should do the ol'' trick
I love me and you love you.
tool_2046
tool_2046
Thank you guys SO much, that''s been bothering me for like a year now, how pathetic is that? I know I double posted this and Fruny responded to the other, but can you explain what you mean about template functions?
tool_2046
tool_2046
Okay, so I thought that fixed the problem, but now it won''t let me execute my function pointer, if I say
CurrentFunction();
I get some error:
error C2064: term does not evaluate to a function
Why is this?
Fruny
Fruny
Pointer to function :

void (*CurrentFunction)(void);
CurrentFunction = SomeFunction;
CurrentFunction();


Pointer to nonstatic member function:

void (SomeClass::*CurrentFunction)(void);
CurrentFunction = &SomeClass::SomeFunction;

SomeClass object;
object.*CurrentFunction();

SomeClass* ptr = &object
ptr->*CurrentFunction();


It is impossible to use one in place of the other.
( e.g. Win32 API expects function pointers as callbacks, not member function pointers. )

Borland C++ and g++ let you cast back a bound PMF to a function pointer, but it is not standard behaviour.

Consider using function objects called by templated functions, where the syntax, not the type, matters. e.g. boost::function, boost::bind, boost::mem_fn, boost::signal. Seee boost link in sig.


Documents [ GDNet | MSDN | STL | OpenGL | Formats | RTFM | Asking Smart Questions ]
C++ Stuff [ MinGW | Loki | SDL | Boost. | STLport | FLTK | ACCU Recommended Books ]
"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
seanw
seanw
Class virtual functions are normally implemented using function pointers, so you might want to try using virtual functions instead for the same effect and let the compiler deal with the implementation.
Amnesty
Amnesty
You would make your calls like this
(object.*CurrentFunction)();
(ptr->*CurrentFunction)();

Extra ()s are needed because * binds looser(sp) than a function call.
"I turned into a driveway I thought was mine and crashed into a tree I don't have."- a real insurance claim
Fruny
Fruny
.* and ->* are individual operators, not ., -> and * combinations.

Documents [ GDNet | MSDN | STL | OpenGL | Formats | RTFM | Asking Smart Questions ]
C++ Stuff [ MinGW | Loki | SDL | Boost. | STLport | FLTK | ACCU Recommended Books ]
"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
tool_2046
tool_2046
Okay, apparently I'm retarded because I just cannot get this to work. If I do the (Test.*CurrentFunction)() I get some error:
error C2065: 'CurrentFunction' : undeclared identifier
C:\Program Files\Microsoft Visual Studio\MyProjects\theorytest\main.cpp(160) : error C2297: '->*' : illegal, right operand has type 'int'
This comes despite the fact that Test CLEARLY has CurrentFunction in it. If I try just Test.*CurrentFunction I get the same two errors. I just don't get it... I can post some actual code if you want...

  
#include <iostream>
#include <fstream>
#include <stdio.h>
#include <string>
#include <conio.h>
#include "gamedefs.h"
#include "script.h"

typedef enum {SPHERE, CUBE, CYLINDER} TRIGGERBOUNDTYPE;
typedef enum {INIT, TITLE, SCRIPT, MAINGAME, ENDGAME} GAMESTATE;

class CTrigger
{
public:
void operator = (const CTrigger& Trig)
{
m_BoundType = Trig.m_BoundType;
m_Script = Trig.m_Script;
m_xLocation = Trig.m_xLocation;
m_yLocation = Trig.m_yLocation;
m_zLocation = Trig.m_zLocation;
m_Triggered = Trig.m_Triggered;
}

CTrigger(const CTrigger& Trig) { *this = Trig; }
CTrigger();
CTrigger(float x, float y, float z, TRIGGERBOUNDTYPE BoundType, CScript Script);
CheckForTrigger(void);

private:
TRIGGERBOUNDTYPE m_BoundType;
CScript m_Script;
float m_xLocation;
float m_yLocation;
float m_zLocation;
bool m_Triggered;
};

CTrigger::CTrigger()
{
m_Triggered = false;
}

CTrigger::CTrigger(float x, float y, float z, TRIGGERBOUNDTYPE BoundType, CScript Script)
{
m_BoundType = BoundType;
m_Script = Script;
m_xLocation = x;
m_yLocation = y;
m_zLocation = z;
m_Triggered = false;
}

class CEngine
{
public:
CEngine();
~CEngine();
void (CEngine::*CurrentFunction)(void);
void Run(void) { (this->*CurrentFunction)(); }
void SetState(GAMESTATE NewState);

// Various states the game can be running in


void Test(void);
void EndGame(void);
void Init(void);
void MainGame(void);
void ScriptRunning(void);
void Title(void);

private:
CScript *m_Script;
GAMESTATE m_State;
};
void CEngine::Test(void)
{
cout << "Test called so apparently there's hope after all..." << endl;
}

CEngine::CEngine()
{
m_State = INIT;
CurrentFunction = &CEngine::Init;
}

CEngine::~CEngine()
{
}

void CEngine::SetState(GAMESTATE NewState)
{
switch(NewState)
{
case INIT:
{
m_State = INIT;
CurrentFunction = &CEngine::Init;
} break;
case TITLE:
{
m_State = TITLE;
CurrentFunction = &CEngine::Title;
} break;
case SCRIPT:
{
m_State = SCRIPT;
CurrentFunction = &CEngine::ScriptRunning;
} break;
case MAINGAME:
{
m_State = MAINGAME;
CurrentFunction = &CEngine::MainGame;
} break;
case ENDGAME:
{
m_State = ENDGAME;
CurrentFunction = &CEngine::EndGame;
} break;
}
}

// Functions for the various states of the engine:

void CEngine::EndGame(void)
{
}
void CEngine::Init(void)
{
// Initialize everything that should be initialize ie graphics and such

// [...]

// Move on to the title

SetState(TITLE);
}
void CEngine::MainGame(void)
{
cout << "Alright here's the main game, awesome, eh?" << endl;
getch();
SetState(ENDGAME);
}

void CEngine::ScriptRunning(void)
{
}

void CEngine::Title(void)
{
cout << endl << "Welcome to the earliest version of Blue Snood 3d imaginable" << endl;
getch();
SetState(MAINGAME);
}

void main(void)
{
CEngine Engine;
CScript GameScript;
ifstream infile;
string filename;

Engine.CurrentFunction = &(CEngine::Test);
(Engine.*CurrentFunction)();
cout << "Enter the script file you want to open: ";
cin >> filename;

infile.open(filename.c_str());
if(infile.fail())
cout << "Unable to open script " << filename << "!" << endl;

infile >> GameScript;
infile.close();

}

void CharacterDialog(string text)
{
cout << "Dialog called" << endl;
cout << text << endl;
}

void Delay(float num)
{
cout << "Delay called with an argument of " << num << "!" << endl;
}

void LaunchGoblin(float x, float y, float z)
{
cout << "Goblin launched at (" << x << ", " << y << ", " << z << ")!" << endl;
}

There's alot of extra crap in there but maybe someone can tell me what's going on that I get these errors. I don't know if I mentioned this, but I'm using VC++ 6 and Windows XP (not like I think the OS would matter but whatever...)

[Edit: please use source tags when posting tons of code. -Yann]

[edited by - Yann L on October 31, 2002 12:44:10 PM]
Fruny
Fruny
Given that CurrentFunction is a member variable of Test and not a freestanding variable, I suppose that Test.*(Test.CurrentFunction)() would work better.



Documents [ GDNet | MSDN | STL | OpenGL | Formats | RTFM | Asking Smart Questions ]
C++ Stuff [ MinGW | Loki | SDL | Boost. | STLport | FLTK | ACCU Recommended Books ]
"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
tool_2046
tool_2046
Trying that gave me 25 errors and one warning. This can''t be that hard, I swear I did everything like that functionpointer websight said to. Is there just some random error in my code that I''m missing?
daerid
daerid
use the god damn [ source][ /source] tags, plz
daerid@gmail.com
tool_2046
tool_2046
Whoops, actually I typed in your suggestion wrong, but I still get one error:
C:\Program Files\Microsoft Visual Studio\MyProjects\theorytest\main.cpp(160) : error C2064: term does not evaluate to a function
Here''s the line where I try to call the function pointer:

Engine.*(Engine.CurrentFunction)();
[\CODE]
Pepe
Pepe
Why do you use something like?:
CurrentFunction = &CEngine::Init;

I thought that it was:
CurrentFunction = CEngine::Init;
(without the ampersand)

Take a look at http://community.borland.com/article/0,1410,17500,00.html
tool_2046
tool_2046
Regardless of how I assign the function to the function pointer, I still get the same errors when I try to execute the function pointer. I seriously didn''t think this would be that hard, is there just an error in my code that I missing? Didn''t I do everything just like I should?
Pepe
Pepe
I have been able to COMPILE and RUN your code.

I have only needed:

#include <fstream>
#include <string>
#include <conio.h>
#include <iostream>
using namespace std;

CScript { };


and a main like this:

void main(void)
{
CEngine Engine;

Engine.CurrentFunction = &(CEngine::Test);
(Engine.*Engine.CurrentFunction)();

Engine.SetState(INIT);
(Engine.*Engine.CurrentFunction)();
Engine.SetState(TITLE);
(Engine.*Engine.CurrentFunction)();
Engine.SetState(SCRIPT);
(Engine.*Engine.CurrentFunction)();
Engine.SetState(MAINGAME);
(Engine.*Engine.CurrentFunction)();
Engine.SetState(ENDGAME);
(Engine.*Engine.CurrentFunction)();
getch();
}

Topic Locked

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

Sign in to reply to this topic.