gpt4 book ai didi

c++ - 从抽象基类指针转换为派生类

转载 作者:搜寻专家 更新时间:2023-10-31 01:01:13 25 4
gpt4 key购买 nike

我正在尝试为我的游戏创建一个状态管理器,我有 4 个类:

游戏状态:

  // foward declaration to avoid circular-referency
class StateManager;

class GameState
{
public:
virtual ~GameState() { }
virtual void update(StateManager* gameManager) = 0;
virtual void draw(StateManager* gameManager) = 0;

protected:
GameState() { }
};

状态管理器:

  class StateManager
{
public:
StateManager();
virtual ~StateManager();

void addState(GameState* gameState);
void update(StateManager* stateManager);
void draw(StateManager* stateManager);

protected:
// store states in a unique_ptr to avoid memory leak
std::vector<std::unique_ptr<GameState> > states_;
};

游戏:

class Game : public StateManager
{
public:
void compute()
{
// call methos of statemanager
update(this);
draw(this);
}
}

和主菜单:

class MainMenu : public GameState
{
public:
// override the pure virtual methos of GameState
void update(StateManager* stateManager)
{
// problem here.
// I need to handle instance of Game in this class,
// but the pointer is one StateManager
}
void draw(StateManager* stateManager) {}
}

当我像这样初始化游戏时:game.addState(new MainMenu())

我可以在 MainMenu 中访问类 Game 的唯一方法是通过转换指针吗?

// MainMenu class
void update(StateManager* stateManager)
{
Game* game = (Game*) stateManager;
game.input.getKey(ANY_KEY);
//...
}

这样对吗?有些东西告诉我我做错了。

最佳答案

immibis 的答案非常适合解决技术类型转换问题。

不过,您的设计有些奇怪。所以我想提供一个替代答案,解决设计问题。

首先是StateManager本身不是 GameState .所以不需要为 update() 设置相同的签名和 draw() .你有没有预见到其中之一 StateManager与另一个 StateManager 一起调用的函数在争论?对于 Game ,我认为这是没有意义的。所以我建议重构类(并相应地调整 Game):

class StateManager {
public:
...
void update(); // they always know "this".
void draw();
protected:
...
};

接下来,似乎是 StateManager拥有 GameState (使用 unique_ptr<> 的 protected vector ,您的类型转换问题表明了这一点)。所以另一种设计也可能很有趣:

class GameState {
public:
virtual ~GameState() { }
virtual void update() = 0;
virtual void draw() = 0;
protected:
GameState(StateManager* gameManager) { } // GameStates are created for a StateManager
StateManager* gm; // this manager can then be used for any GameState functions that need it
};

按照这个逻辑,MainMenu将被重构为:

class MainMenu : public GameState
{
public:
MainMenu (Game* g) : game(g), GameState(g) {}
void update()
{
// NO LONGER NEEDED: Game* game = (Game*) stateManager;
game->input.getKey(ANY_KEY);
// NO MORE PROBLEMS HERE: you always refer to the right object without any overhead
}
void draw() {}
protected:
Game *game; // the owning game.
};

这种替代设计的优点是:

  • 代码会更简洁,也更不容易出错,因为您不必总是担心成员函数的参数。
  • StateManager指针仅用于 StateManager抽象。
  • 具体实现 GameState , 这依赖于 Game , 可以直接使用它,但应该只将它用于 Game 特定的抽象。

主要的不便有:

  • GameState必须始终为一个特定的 StateManager 创建.
  • 设计的稳健性是以所有GameState中的冗余指针为代价的。实现如 MainMenu .如果你有数百万个,它可能会成为一个内存问题。

关于c++ - 从抽象基类指针转换为派生类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29551075/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com