Virtual methods and overriding [duplicate] - c++

This question already has answers here:
What is object slicing?
(18 answers)
Range based loop: get item by value or reference to const?
(5 answers)
Closed 10 months ago.
What am I doing?
I'm trying to do some basic inheritance for the game I'm working on. The idea is to have a base Entity class that the Player will inherit from. The Entity class has a virtual update or think method that each child will override to fit it's needs.
This is how the engine handles the update loop:
void Engine::update() {
for (Entity entity : entities) {
entity.update(deltaTime);
}
}
The code:
Entity.hpp
#pragma once
#include "Position.hpp"
#include "AssetManager.hpp"
#include "Logger.hpp"
#define SPATIAL 1
#define VISUAL 1 << 1
class Entity {
public:
Entity(Position *position, const char *visualPath);
int flags;
const char *visualPath;
Position position;
virtual void update(float deltaTime);
};
Entity.cpp
#include "Entity.hpp"
Entity::Entity(Position *position, const char *visualPath) {
flags = 0;
if (position) {
flags |= SPATIAL;
this->position = *position;
}
if (visualPath) {
flags |= VISUAL;
this->visualPath = visualPath;
}
}
void Entity::update(float deltaTime){
Logger::log("No update method");
};
Player.hpp
#pragma once
#include "../Entity.hpp"
#include "../Logger.hpp"
class Player : public Entity {
public:
Player();
void update(float deltaTime) override;
};
Player.cpp
#include "Player.hpp"
Player::Player() : Entity(new Position(0, 0), "assets/player.png") {}
void Player::update(float deltaTime) {
this->position.x += 10;
Logger::log("Player says hi");
}
What's the issue?
Even tho I have overridden the update method on the Entity within Player, Player still prints "No update method". It seems the override didn't do anything.

Change this:
void Engine::update() {
for (Entity entity : entities) {
entity.update(deltaTime);
}
}
To this:
void Engine::update() {
for (Entity& entity : entities) {
entity.update(deltaTime);
}
}
In the original implementation, your for loop makes a copy of the item in entities. You probably didn't want that, but more importantly, entity is just a copy of the base class, so the derived class information is lost. Pass by reference to avoid this issue and other bugs.

Related

C++ class as an argument of function not working [duplicate]

This question already has answers here:
Resolve build errors due to circular dependency amongst classes
(12 answers)
C++ circular include
(4 answers)
Closed 3 years ago.
I am working on a game, and right now I have followed a GameState manager tutorial but I'm not sure why isn't the code working. It might be because it's an older version of c++ in the tutorial but I can't seem to find how can I fix it.
#pragma once
#include "GameEngine.h"
class GameState
{
public:
virtual void Init() = 0;
virtual void Cleanup() = 0;
virtual void SplashScreen() = 0;
virtual void Pause() = 0;
virtual void Resume() = 0;
virtual void HandleEvents(GameEngine *game) = 0;
virtual void Update(GameEngine *game) = 0;
virtual void Draw(GameEngine *game) = 0;
void ChageState(GameEngine* game,
GameState* state) {
game->ChangeState(state);
}
protected: GameState() {}
};
If I don't game the GameEgine *game and GameState *state and remove every line that uses them my program works okay, my window appears but I can't change the game states which is really important.
If nobody has an answer that's okay :)
EDIT: I forgot to show the GameEngine.h file
#pragma once
#include "GameState.h"
#include "include.h"
class GameEngine
{
public:
Recources recource;
void Init(std::string name, int x, int y);
void Cleanup();
void SplashScreen();
void ChangeState(GameState* state);
void PushState(GameState* state);
void PopState();
void HandleEvents();
void Update();
void Draw(sf::RenderWindow &widnow);
bool Running() { return m_running; }
void Quit() { m_running = false; }
private:
// the stack of states
std::vector<GameState*> states;
bool m_running;
};
Variable game(which you pass to function) in ChangeState must be object GameEngine(which has function ChangeState,which is different from ChangeState of GameState), so you can call game->ChangeState, so if GameEngine object which you use have neccessary function and you pass correct arguments, all will be fine.

SFML Network Multithreading

I need to create a thread to run the Networking portion of my game. I would prefer to use SFML threads as my compiler doesn't yet support C++11 threads. However the class which contains the thread is created with make_shared(). Here is the code:
Game.cpp (not all the code just the declaration of GameScreen)
std::shared_ptr<Screen> Game::screen = std::make_shared<GameScreen>();
Screen is just a base class containing pure virtual functions. You should be able to figure out which ones are virtual based off the override keywords.
GameScreen.h
#ifndef GAMESCREEN_H
#define GAMESCREEN_H
#include <SFML/Graphics.hpp>
#include "Events.h"
#include "Screen.h"
#include "Map.h"
#include "Network.h"
class GameScreen : public Screen
{
public:
GameScreen();
void handleInput(sf::RenderWindow&) override;
void update(sf::RenderWindow&, sf::View&) override;
void render(sf::RenderWindow&) override;
private:
Map m_map;
Network network;
Events eventManager;
sf::Thread networkThread;
};
#endif // GAMESCREEN_H
GameScreen.cpp
#include <memory>
#include <iostream>
#include "GameScreen.h"
#include "Game.h"
GameScreen::GameScreen()
: networkThread(network.receive(eventManager))
{
network.Connect();
}
void GameScreen::handleInput(sf::RenderWindow& window)
{
/*Code*/
}
void GameScreen::update(sf::RenderWindow& window, sf::View& view)
{
/*Code*/
}
void GameScreen::render(sf::RenderWindow& window)
{
/*Code*/
}
Network.cpp (receive function only)
void Network::Recieve(Events& eManager)
{
sf::Packet m_rPacket;
m_socket.receive(m_rPacket, m_serverIP, port);
m_rPacket >> /*Data*/
eManager.addEvent(tmp);
}
You can use this in the constructor's initialization list:
MyClass::MyClass()
: AClass(&MyFunction(*this))
{
/*do stuff*/
}
However, this doesn't make sense in your example, because you are trying to pass a pointer to MyFunction (or its non-existent return value) to AClass(), and you can't quality a pointer with parameters. You can only pass parameters to MyFunction() when actually calling MyFunction(). Are you sure you don't actually mean something more like this instead:
MyClass::MyClass()
: AClass()
{
/*do stuff*/
MyFunction(*this);
}
Without seeing what AClass() actually is, or what it expects as input, it is difficult to know for sure what you are trying to do.
Update clearly you have not read the SFML documentation or SFML Tutorial on threading. The Thread constructor takes a pointer to a function/method as one input parameter, and an optional input value for the function/method as a separate parameter. Try this instead:
class MyClass : public sf::Thread
{
private:
static void MyFunction(MyClass &cls);
public:
MyClass();
};
MyClass::MyClass()
: sf::Thread(&MyClass::MyFunction, *this)
{
/*do stuff*/
}
void MyClass::MyFunction(MyClass &cls)
{
/*do stuff with 'cls'*/
}
Or this, as you can use a non-static class method with an SFML thread:
class MyClass : public sf::Thread
{
private:
void MyFunction();
public:
MyClass();
};
MyClass::MyClass()
: sf::Thread(&MyClass::MyFunction, *this)
{
/*do stuff*/
}
void MyClass::MyFunction()
{
/*do stuff with 'this'*/
}
Update: based on your new code, you are still not even close to constructing the sf::Thread object correctly (did you read the documentation/tutorial I linked to?). Also, your thread needs access to multiple objects owned by GameScreen, so you can't pass them all to the sf::Thread constructor. You need to do something more like this instead:
class GameScreen : public Screen
{
public:
GameScreen();
...
private:
...
Network network;
Events eventManager;
sf::Thread networkThread;
void networkThreadFunc();
};
GameScreen::GameScreen()
: networkThread(&GameScreen::networkThreadFunc, *this)
{
network.Connect();
}
void GameScreen::networkThreadFunc()
{
network.Receive(eventManager);
}

How to call a pure virtual base class method implemented by subclass function?

I have two classes: AbstractClass and SubClass.
This is basically my code (well, just some example code):
abstractclass.h
class AbstractClass
{
public:
AbstractClass();
void doSomething();
protected:
virtual void implementMe() = 0;
int a;
};
abstractclass.cpp
#include "abstractclass.h"
AbstractClass::AbstractClass(){}
void AbstractClass::doSomething()
{
implementMe(); // compiler error: "implementMe() was not declared in this scope"
a = 0; // same compiler error here...
}
subclass.h
#include "abstractclass.h"
class SubClass : public AbstractClass
{
public:
SubClass();
protected:
void implementMe();
};
subclass.cpp
#include "subclass.h"
SubClass::SubClass() {}
void SubClass::implementMe()
{
// do some stuff
}
In the AbstractClass, however, I keep getting a compiler error (for the virtual function as well as for the class variable):
implementMe() was not declared in this scope
The only way I found to get rid of this was to use forward-declaration:
void implementMe();
AbstractClass::doSomething()
{
implementMe();
}
I cannot believe that this is the correct way, though?
Thanks!
EDIT:
Ok, as my conceptual understanding of subclassing in C++ doesn't seem to be totally wrong (see the comments), I'm gonna share some of my original source code. Hopefully this will help to indentify the error.
This is my abstract / base class:
abstractenvironment.h
#ifndef ABSTRACTENVIRONMENT_H
#define ABSTRACTENVIRONMENT_H
#include <QObject>
class AbstractEnvironment : public QObject
{
Q_OBJECT
public:
AbstractEnvironment(QObject *parent = 0);
protected:
virtual void process() = 0;
quint32 counter;
private slots:
void handleTimeout();
};
#endif // ABSTRACTENVIRONMENT_H
abstractenvironment.cpp
#include "abstractenvironment.h"
#include <QTimer>
QTimer *myTimer;
AbstractEnvironment::AbstractEnvironment(QObject *parent) :
QObject(parent)
{
myTimer = new QTimer(this);
connect(myTimer, &QTimer::timeout, this, &AbstractEnvironment::handleTimeout);
myTimer->start(1);
counter = 0;
}
void handleTimeout()
{
process();
counter++;
}
And this is my subclass:
environment.h
#ifndef ENVIRONMENT_H
#define ENVIRONMENT_H
#include "abstractenvironment.h"
class Environment : public AbstractEnvironment
{
Q_OBJECT
public:
Environment(Controller *controller, QObject *parent = 0);
protected:
void process();
};
#endif // ENVIRONMENT_H
environment.cpp
#include "environment.h"
Environment::Environment(Controller *controller, QObject *parent) :
AbstractEnvironment(controller, parent) {}
void Environment::process()
{
// do something
}
PS: I've learned from the first part of this question and tried to compile the source code above inside Qt with MinGW. I get exactly two error messages (as expected):
..\untitled\abstractenvironment.cpp: In function 'void handleTimeout()':
..\untitled\abstractenvironment.cpp:17:13: error: 'process' was not declared in this scope
..\untitled\abstractenvironment.cpp:18:5: error: 'counter' was not declared in this scope
In case you want to try it yourself, I've zipped the Qt project and uploaded it to my Dropbox (of course I will remove this file at some point but the code is exactly the same as in the post above --> it's just for the sake of convenience, so you don't have to copy-paste it yourself)
EDIT: You just changed your question. So I can't tell if your original text was your actual source code or not. Good rule of thumb, paste your actual code rather than paraphrase it (then de-identify or reduce it if needed).
ORIGINAL ANSWER:
implementMe(); // compiler error: "implementMe() was not declared in this scope"
That is because doSomething() isn't declared properly in AbstractClass. You "declared" it in the base class with:
doSomething();
The compiler doesn't recognize AbstractClass::doSomething() out of line definition so nothing inside the implementation is resolved to the class scope.
Change that to:
void doSomething();
just like in your derived class.
and
AbstractClass::doSomething()
{
implementMe();
}
to
void AbstractClass::doSomething()
{
implementMe();
}
UPDATE:
void handleTimeout()
{
process();
counter++;
}
is a global function. That isn't the class implementation. It should be:
void AbstractClass::handleTimeout()
{
process();
counter++;
}
In abstractenvironment.cpp you define void handleTimeout(), which is non-member function and does not relate to AbstractEnvironment class. Thus, it doesn't look for AbstractEnvironment::process() and AbstractEnvironment::counter, but for ::process() and ::counter instead (which are not declared, hence the error).
Change it to void AbstractEnvironment::handleTimeout() and it should compile.

C++ creating an instance of a class

class Game {
private:
string title;
bool running;
State currentState;
public:
sf::RenderWindow window;
void setup();
void run();
};
I have a variable called currentState. This is State:
#ifndef STATE_HPP
#define STATE_HPP
using namespace std;
class State {
private:
public:
void start();
void update();
void render();
};
#endif
And then I have a class called PlayState, which inherits State:
#ifndef PLAY_STATE_HPP
#define PLAY_STATE_HPP
#include <SFML/Graphics.hpp>
#include "Game.hpp"
#include "State.hpp"
using namespace std;
class PlayState : public State {
private:
sf::CircleShape shape;
Game game;
public:
PlayState();
void start();
void update();
void render();
};
#endif
On my Game.cpp, I am creating currentState, by doing:
currentState = PlayState();
The problem is, though, that it's not working. currentState.update() is state.update(). It seems that I am not overriding the State methods when I create PlayState.
Here's PlayState.cpp:
#include <SFML/Graphics.hpp>
#include <SFML/Window.hpp>
#include <stdio.h>
#include "PlayState.hpp"
PlayState::PlayState() {
printf("heyyy\n");
}
void PlayState::start() {
shape.setRadius(100.f);
shape.setOrigin(20.0f, 20.0f);
shape.setFillColor(sf::Color::Green);
}
void PlayState::update() {
sf::Event event;
while (game.window.pollEvent(event)) {
if (event.type == sf::Event::Closed) {
game.window.close();
//running = false;
}
}
printf("here\n");
}
void PlayState::render() {
printf("here\n");
game.window.clear();
game.window.draw(shape);
game.window.display();
}
Any ideas about how I can 'override' those methods? Thank you.
EDIT
I had to make State.cpp functions virtual so that they can be overriden.
I also had to define State *currentState as a pointer and create PlayState with "currentState = new PlayState();".
Also, now I access .update and .draw with ->update() and ->draw().
Two problems. As #McAden said, the functions in State that are to be overridden in PlayState need to be marked virtual. The other problem is that the data member currentState in Game has type State. When you assign an object of type PlayState to it, it gets the State part of the PlayState object, but not the derived parts. This is called "slicing". To prevent it, make currentState a pointer to State, and when you create that PlayState object, assign its address to the Game object's currentState.
What you're looking for is the concept of virtual functions.
Wikipedia entry
State needs:
virtual void update();
PlayState needs:
void update();
You need to make your function's with the virtual modifier ie.
virtual void Update();
When calling currentState->Update() this will call the topmost overridden function, if you desire to call any of the parent classes functions inside of the classes methods simply specify ie. State::Update(); when calling the function.

i need help implementing my event manager and engine system (SDL && C++)

i need help with my attempt at writing a reusable game engine. it's not the best engine, but i definitely think it will be reusable once i am done. i am not asking for code or to be spoonfed, but i am asking for some advice :-).
my current layout:
i have an engine class, a game class, and an event manager class. the engine class extends the event manager class, and the game class extends the engine class. here is my current code for these 3 classes (ignore the Graphics class--it is just a reusable class i use to avoid rewriting fullscreen, initialize, and resize screen functions).
ENGINE.HPP
#ifndef _ENGINE_HPP
#define _ENGINE_HPP
#pragma once
#include <SDL/SDL.h>
#include "event_manager.hpp"
enum
{
ENGINE_SUCCESS = 0,
ENGINE_INITIALIZATION_ERROR
};
class Engine : public EventManager
{
public:
Engine();
virtual ~Engine();
int exec();
void handle_event(SDL_Event *);
void update_engine();
virtual bool init();
virtual void render();
virtual void update();
virtual void clean();
bool running_;
};
ENGINE.CPP
#include "./engine.hpp"
Engine::Engine()
{
running_ = false;
}
Engine::~Engine()
{
}
int Engine::exec()
{
if (!init())
{
clean();
return ENGINE_INITIALIZATION_ERROR;
}
SDL_Event event;
while (running_)
{
while (SDL_PollEvent(&event))
handle_event(&event);
update();
render();
}
clean();
return ENGINE_SUCCESS;
}
void update_engine()
{
}
void handle_event(SDL_Event *event)
{
EventManager::handle_event(event);
}
bool init() {return true;}
void render() {}
void update() {}
void clean() {}
EVENT_MANAGER.HPP
#ifndef _EVENT_MANAGER_HPP
#define _EVENT_MANAGER_HPP
#pragma once
#include <SDL/SDL.h>
class EventManager
{
public:
EventManager();
virtual ~EventManager();
virtual void handle_event(SDL_Event *);
// events here
virtual void event_exit();
};
#endif
EVENT_MANAGER.CPP
#include "./event_manager.hpp"
EventManager::EventManager()
{
}
EventManager::~EventManager()
{
}
void EventManager::handle_event(SDL_Event *event)
{
switch (event->type)
{
case SDL_QUIT:
event_exit();
break;
}
}
void on_exit() {}
GAME.HPP
#ifndef _GAME_HPP
#define _GAME_HPP
#include "./engine.hpp"
#include "./entity.hpp"
#include "./graphics.hpp"
class Game : public Engine
{
public:
Game();
bool init();
void render();
void update();
void clean();
private:
Graphics g;
};
#endif
GAME.CPP
#include "./game.hpp"
int main(int argc, char **argv)
{
Engine engine;
return engine.exec();
}
Game::Game() {}
bool Game::init()
{
if (!g.init(800, 600, 32, g.screen_flags()))
{
return false;
}
SDL_WM_SetCaption("Title", NULL);
return true;
}
void Game::update()
{
Engine::update_engine();
}
void Game::clean()
{
SDL_FreeSurface(g.screen_);
SDL_Quit();
}
void Game::render()
{
SDL_Flip(g.screen_);
}
i am getting this error:
engine.cpp: In function ‘void handle_event(SDL_Event*)’:
engine.cpp:40: error: cannot call member function ‘virtual void
EventManager::handle_event(SDL_Event*)’ without object
why is this happening? shouldn't i be able to do EventManager:: if the I did
class Engine : public EventManager
???
that is the only error i get, i am sure it is something simple. now i need a little bit of advice.
instead of handling events like
void Engine::event_exit()
in the engine, i'd rather do it in the game class.
class Game : public Engine
void Game::event_exit()
if that doesn't make sense, notice how i made Engine extend EventManager, and my Game class extends Engine
class Engine : public EventManager
class Game : public Engine
would it work if i called the snippet above these ^ two snippets? i can't test it because i get that error.
Happens to the best of us, but I think it's just a matter of forgetting to specify namespaces. When you implement the functions in engine.cpp, you forgot to prepend Engine::, so the code should be:
void Engine::update_engine()
{
}
void Engine::handle_event(SDL_Event *event)
{
EventManager::handle_event(event);
}
It's a classic case of C++ error messages not really telling you the root of the error.
A short explanation, just in case:
The compiler tried to compile the function void handle_event(SDL_Event *event), and saw a call to a method EventManager::handle_event(event);. Since the compiler thought the function was not part of the Engine class, it would expect you to call the method of a particular instance of the EventManager class, i.e.
someEventManager->handle_event(event);
As soon as you specify that the implementation you wrote is that of a method, belonging to the class Engine, the compiler essentially deduces:
void Engine::handle_event(SDL_Event *event)
{
this->EventManager::handle_event(event);
}
And therefore is happy.