Sign in to follow this  

Advanced C++ Help Request

This topic is 4249 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Greetings, I am having difficulty with calling class functions through a class array of class function pointers. Coming from a C background, I've recently started using more of the full C++ language. I've successfully compiled past programs with the same situation sans class scope (e.g. using regular functions and a regular array of function pointers). But I decided to be a good C++ programmer this time and encapsulate my state machine functions and data into a 'stateobj' class object. I had enough trouble with getting the initialization of the array of function pointers to successfully compile with that (horrific!) scope syntax you see below (in the .cpp file), but the Run() class function is generating a compiler error, specifically the "_proc[_numStates]()" segment. I'm using MS Visual C++ .NET 2003 on a WinXP system, and receive "Compiler Error C2064: term does not evaluate to a function taking 0 arguments." The MS help on that error suggests I haven't declared the array of function pointers correctly (MS examples: declaring "int i, j; i = j();" or "int i, *k; i = k();"). But it looks fine to me, except maybe the scope is off somehow? I'm still a bit fuzzy on working with scope syntax (getting the array declarations was a lucky guess!). Your help is much appreciated, thanks! Here's the relevant code:
// Within .h file...
class stateobj
	{
	public:
		enum state { _error, _init, _wait, _shutdown, _numStates };
		stateobj () { _curState = _prevState = _init; }
		~stateobj () {}
		...
		...
		...
		state run () { _prevState = _curState; _curState = _proc[_curState](); return _prevState; }
	private:
		state _curState;
		state _prevState;
		state error ();
		state init ();
		state wait ();
		state shutdown ();
		static state (stateobj::*_proc[_numStates])();
	};

// Within .cpp file...
stateobj::state (stateobj::*stateobj::_proc[stateobj::_numStates])() =
	{
	stateobj::error,
	stateobj::init,
	stateobj::wait,
	stateobj::shutdown
	};

Share this post


Link to post
Share on other sites
Lets take a step back and look at your design. I'm assuming that what you want to do is roughly in the function pointer, correct? Your original problem was that you wanted to get away from a "list of function pointers" approach to a more OOP way, also correct? In that case, it might be best to ditch the function pointers intirely. In C++, you might do it this way:

First have a base "interface" class called "State". Then derive from State and implement any state-specific jiggers in the subclasses. For instance, here is the theoretical State base class:

class State {
public:
virtual void DoStuph() = 0; // this means "pure virtual", i.e. can't create a "State" class by itself
~State();
protected:
State();
};


Now for each of the actual states you want in your project, you create a derived class like so:

class StateTitleScreen: public State {
public:
virtual void DoStuph() {
/* do state-specific stuph here */
}
~StateTitleScreen();
StateTitleScreen();
private:
/* state-specific vars here */
}


So in the main game loop, you basically end up with this:

State* current_state = new StateTitleScreen(); // first screen player sees
while (gameloop) {
current_state->DoStuph();
}


If the player changes the state through some mechanism, you would do something like this:

delete current_state; // out with the old
current_state = new StateWhateverElseYouWant(); // in with the new


This way, the gameloop doesn't much care what the current state is, as long as it has the DoStuph() interface.

Hope that helps a bit. Feel free to ask questions. And i appologize if i totally misjudged the problem.

Share this post


Link to post
Share on other sites
The problem is that function pointers to member functions require an object as well, this should do the trick ...

using ->* operator:
_curState = this->*_proc[_curState]();

using .* operator
_curState = (*this).*_proc[_curState]();

I hope that is right :O function pointers to member functions are scary.

EDIT: This is assuming of course that the function pointed to by _proc[_curState] should act on the object making that call, hence the "this" pointer.

Share this post


Link to post
Share on other sites
leiavoia - You have correctly judged what I'm trying to do. I see where you're going with this OOP approach and generally like the concept, thank you.

I have one concern though. In the old way of doing things, switching to a new state required minimal processing: simply change the data variable that indexes the array of function pointers (e.g. "prevState = curState; curState = newState;"). In your approach, I would have to deallocate the old state instance and and allocate a new state instance to accomplish the same. Would this not be a bit more costly in terms of performance?

EDIT: Perhaps I can aloc all game states during program init, then use a base object pointer to simply point to the current state... something like the following:

StateTitleScreen TitleScreen; StateOtherState OtherState; ... // alloc and init all states at program startup
...
State *curState = TitleScreen; // set initial state
...
curState = OtherState; // switch to new state



[Edited by - BrianMJC on April 28, 2006 10:13:15 PM]

Share this post


Link to post
Share on other sites
AsOne - Nice try, but I still get the same error. I'm not sure if that's the problem since the array of function pointers is static? Yes, they are very scary. :)

Share this post


Link to post
Share on other sites
Quote:
I have one concern though. In the old way of doing things, switching to a new state required minimal processing: simply change the data variable that indexes the array of function pointers (e.g. "prevState = curState; curState = newState;"). In your approach, I would have to deallocate the old state instance and and allocate a new state instance to accomplish the same. Would this not be a bit more costly in terms of performance?

EDIT: Perhaps I can aloc all game states during program init, then use a base object pointer to simply point to the current state... something like the following:


Wow, you really are a C programmer! The answer is: no, it would not hurt performance. If you want to work with C++ it is best not to think on this level of performance (that is, bit-shifting hax0rz extratrickery). On modern machines, these kinds of micro-optimizations mean nothing. To illustrate: I built a particle system that animated thousands of particles every frame. In order to produce the particles, i could either create a list of them ahead of time in a "dead" or "live" state and "recycle" the dead ones when i needed to create a new one, OR i could just allocate and deallocate them as needed. In rigorous testing, i determined that it made absolutely no difference on the frame rate either way.

So don't worry about it :-)

If on the other hand, changing state requires a lot of activity (dumping and loading textures, creating a new world/environment, and other high-CPU things), then you might consider doing that, but you would then be eating up a lot of memory, i'm sure.

Share this post


Link to post
Share on other sites
leiavoia - Very good, thanks. Yes, years ago I professionally programmed in assembly language (on Intel 80386/486 PCs, plus on some microcontrollers) and later in C. I've come to terms with using 32 bit boolean values (instead of making every bit count with logical operators), but treating memory allocations & deallocations as similar in performance to a couple of simple data assignments will take some getting used to! :)

Share this post


Link to post
Share on other sites
There are still platforms where it makes a big difference. Your PC is not one of them. :)

Anyway, there is probably something wrong with your design if state changes happen often enough to have even the slightest chance of being a "hotspot" when you profile your code, compared to the work done within the states themselves. :)

Share this post


Link to post
Share on other sites

This topic is 4249 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

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