我最近开始用C ++学习OOP概念,并尝试用类进行简单的Tic-Tac-Toe游戏。我的Game类的游戏循环从用户那里获得输入,这是我遇到这个问题的地方。我创建了一个InputHandler类,Game类有一个实例,在游戏循环中我调用inputHandler.input()。如果玩家输入"重启",我希望通过调用game.restart()重启游戏,但是我的InputHandler对象没有游戏实例。所以我目前的解决方案是通过引用传递游戏来调用InputHandler对象,这样我就可以从那里调用game.restart(),但是这对我所学到的关于OOP的一切看起来都是不好的做法。此外,对于每个与此类似的功能,我还需要通过引用传递游戏对象。我觉得我错过了一些关于OOP设计的基本知识。通过引用传递游戏对象是不是很糟糕,还是有更好的方法来解决这个问题?
//game.cpp
void Game::run() {
while(!gameOver) {
inputHandler.input(this);
}
}
//inputHandler.cpp
void InputHandler::input(Game& game) {
std::string input;
std::cin >> input;
if (input == "restart") {
game.restart();
}
}
答案 0 :(得分:1)
处理特殊操作的一种方法是传递处理函数(也称为回调)。 C ++方式是std::function<void()>
,可以在检测到特定事件时触发:
class SomeClass {
...
std::function<void()> d_restartHandler;
public:
void setRestartHandler(std::function<void()> handler) { d_restartHandler = handler; }
void doSomething() {
...
if (timeToRestart && this->d_restartHandler) {
this->d_restartHandler();
}
...
}
};
函数模板std::function<Signature>
实际上也可以通过合适的参数进行参数化,方法是使用合适的签名对其进行实例化。如果你觉得这种方法不是面向对象的:实际上就是这样!在内部,std::function<Signature>
包含一个带有基类的层次结构,可以是一个具体的类,用于保存实际的函数对象以进行调度。你甚至可以自己实现类似的东西,但我认为这会浪费时间。
假设您拥有SomeClass
实例sc
和Game
实例g
,您可以使用
sc.setRestartHandler([&](){ g.restart(); });