1

In order to make my code a bit clearer, I was trying to split a long piece of code into several methods (a little PHP-like).

I have a variable CurrentStep indicating the current screen to be rendered.

class Game
{
private:
    enum Step { Welcome = 0, Menu, };
    unsigned int CurrentStep;
}

Now I want to call the corresponding method when rendering the frame:

void Game::RenderFrame
{
    switch (CurrentStep)
    {
    case Welcome:
        // the actual work is done by WelcomeScreen() to keep this clean
        WelcomeScreen(); break;
    case Menu:
        // same here
        MenuScreen(); break;
    }
}

I hope it is understandable what I was trying to achieve. Eventually it is supposed to call the appropriate method (at runtime).

However, this way is just that redundant... Isn't there a "better" way to go with C++?

Nedec
  • 836
  • 10
  • 15
  • you may find this question http://stackoverflow.com/questions/659581/replace-giant-switch-statement-with-what useful – ascanio Jun 14 '11 at 20:11

5 Answers5

2

First off, your private variable should be declared as Step CurrentStep; and RenderFrame() needs parentheses. Next, it's hard to give specific advice given how general and vague the question is, but in principle you could do something with inheritance:

class AbstractGameState
{
    virtual ~AbstractGameState() { }
    virtual void renderFrame() = 0;
};

class WelcomeScreenState : public AbstractGameState
{
  void renderFrame(); // implement!
};

class MenuState : public AbstractGameState
{
  void renderFrame(); // implement!
};

class Game
{
  std::vector<std::shared_ptr<AbstractGameState> > gameStates;
public:
  void renderFrame()
  {
    std::shared_ptr<AbstractGameState> state = getCurrentState(); // implement!
    state->renderFrame();
  }
};
Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
  • Now I got it, thank you! :) Then do I have to create an instance of WelcomeScreenState or MenuState in every `getCurrentState` call? Or should I keep the instances somewhere? – Nedec Jun 14 '11 at 20:39
  • Yes, instances have to be kept somewhere, byt `getCurrentState` wouldn't have to create them, it could just look up an existing instance and return the right pointer. It's hard to give details without knowing more about your situation. If you only need one global object of each type, you could also use a map from `Step` enums to function pointers or something like that.... – Kerrek SB Jun 14 '11 at 20:48
2

I guess what you are looking for is the command pattern.

Read this detailed explanation (for C++)

http://www.dreamincode.net/forums/topic/38412-the-command-pattern-c/

to learn more about it.

Doc Brown
  • 19,739
  • 7
  • 52
  • 88
1

We're going to need more information. If you make RenderFrame a virtual function, you can use run-time polymorphism to call the correct case of RenderFrame.

John
  • 2,326
  • 1
  • 19
  • 25
  • Actually I would like to keep RenderFrame as it is since there is some stuff before and after the switch. I'm just trying to map CurrentStep == Welcome to a WelcomeScreen call, Menu to a MenuScreen call and so on... Do you need more code? – Nedec Jun 14 '11 at 20:14
  • @Nedec If there is common code that they all need, then this could be put in the base class, and the derived classes just do the little extra work. If you really dont want to use polymorphism, perhaps you could use a `std::map`, i.e. a map from the step to some functor that can be invoked to complete processing. You'd still need to do extra work to register all the handlers though. – Node Jun 14 '11 at 20:18
1

Besides the polymorphic approach that Kerrek posted (some would call it the classic object-oriented approach), there are other techniques that doesn't use polymorphism.

  • One of them are table driven methods

  • the other one worth mentioned is the visitor pattern, already efficiently implemented in the boost variant library. Here is an example that shows something similar to what you want to do

Community
  • 1
  • 1
lurscher
  • 25,930
  • 29
  • 122
  • 185
1

How many other states will you have?

Do the implementations of WelcomeScreen() and MenuScreen() have anything in common that can be moved into a common base class?

If the answer to the first question is "a few others" or the answer to the second is "not much" then your code is just fine. Keep things simple if you can.

Inheritance, the Command Pattern and other approaches that are suggested will complicate your code a bit while allowing more flexibility in adding more states in the future. You know your app better and know what its future holds.

Andrei
  • 4,880
  • 23
  • 30
  • Well, actually there will be just a few others, thank you... Haven't thought of it that way. :D – Nedec Jun 14 '11 at 20:33