Reputation: 61
I recently began learning OOP concepts in C++ and tried making a simple Tic-Tac-Toe game with classes. My Game class's game loop gets input from the user, which is where I am having this problem. I created an InputHandler class that the Game class has an instance of, and in the game loop I call inputHandler.input(). If the player types "restart", I want the game to restart by calling game.restart(), however my InputHandler object does not have an instance of the game. So my current solution is to pass the game by reference to the InputHandler object so I can call game.restart() from there, however this seems like bad practice from everything I have learned about OOP. Also, for every function that does something similar to this, I would need to pass the game object by reference there also. I feel like I am missing something fundamental about OOP design. Is it bad to pass the game object by reference, or is there a better way solve this problem?
//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();
}
}
Upvotes: 1
Views: 85
Reputation: 153830
One way to deal with special action is to pass a handler function (aka callback). The C++ way would be a std::function<void()>
which can be triggered upon specific events being detected:
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();
}
...
}
};
The function template std::function<Signature>
can actually be parameterized by suitable parameters, too, by instantiating it with a suitable signature. If you feel that this approach isn't object oriented: it actually is! Internally, std::function<Signature>
holds a hierarchy with a base class can a concrete class holding the actual function object to dispatch to. You can even implement something similar yourself but I'd think that would be a pointless waste of time.
Assuming you have your SomeClass
instance sc
and your Game
instance g
, you could register for a restart using something like
sc.setRestartHandler([&](){ g.restart(); });
Upvotes: 1