Inheritance doesn't call overridden function, calls base version instead

So I'm here again with another question. I've almost finished the basis of my game engine, but when I want to test what I've made, it only renders a black screen, but displays no error messages or debug error messages at all. It seems to work fine except all that is shown is a black screen. The code is way to lengthy to show here, but if you want to see it I'll send a dropbox link or so.

EDIT:
I have brought down the problem to the following:
I have a base GameState class, which looks like this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#ifndef GAMESTATE_H
#define GAMESTATE_H

#include "StateManager.h"
#include "Graphics.h"

class StateManager;

class GameState
{
protected:
	StateManager* manager;
public:
	GameState();
	~GameState();
	
	virtual void update();
	virtual void draw();
	
	StateManager* getManager();
	void setManager(StateManager* m);
};

#endif 

And I create new game states from that using inheritance. However, when I call the draw function from the manager, it calls the base version, thus not drawing anything.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
//Statemanager.h
#ifndef STATEMANAGER_H
#define STATEMANAGER_H

#include <stack>
#include "GameState.h"
#include "Graphics.h"

class GameState;

class StateManager
{
private:
	std::stack<GameState*> states;
public:
	StateManager();
	~StateManager();
	
	void addState(GameState* s);
	void popState();
	void update();
	void draw(Graphics *g);
	bool isEmpty();
	GameState* getCurrentState();
};

#endif
//Statemanager.cpp
#include "StateManager.h"

StateManager::StateManager() { }
StateManager::~StateManager() { }

void StateManager::addState(GameState* s)
{
	s->setManager(this);
	states.push(s);
}

void StateManager::popState()
{
	states.pop();
}

void StateManager::update()
{
	if (!states.empty() && states.top() != nullptr)
		states.top()->update();
}

void StateManager::draw(Graphics *g)
{
	if (!states.empty() && states.top() != nullptr)
		states.top()->draw();
}

bool StateManager::isEmpty()
{
	return states.empty();
}

GameState* StateManager::getCurrentState()
{
	return states.top();
}

//splashstate.h
#ifndef SPLASHSTATE_H
#define SPLASHSTATE_H

#include "Core/GameState.h"
#include "Core/Graphics.h"
#include "Core/Image.h"
#include "Core/Input.h"
#include "Core/Sound.h"

class SplashState : public GameState
{
private:
	Input* input;
	Image backgroundImage;
	Image logoImage;
	Sound sound;
	
	int logoImageY;
	int logoImageX;
	bool soundPlayed;
	
	static const int TARGET_Y = 300;
	static const int LOGO_SPEED = 10;
public:
	SplashState();
	~SplashState();
	
	bool init(Input* i, StateManager* m, Graphics *g);
	void free();
	
	virtual void update();
	virtual void draw(Graphics *g);
};

#endif
//splashstate.cpp
#include "SplashState.h"

SplashState::SplashState()
{
}

SplashState::~SplashState()
{
}

bool SplashState::init(Input* i, StateManager *m, Graphics *g)
{
	input = i;
	setManager(m);
	
	if (!backgroundImage.load("graphics/splash/background.bmp", g))
		return false;
	if (!logoImage.load("graphics/splash/logo.bmp", g))
		return false;
	if (!sound.load("audio/splash/sound.wav"))
		return false;
	
	logoImageY = -logoImage.getHeight();
	soundPlayed = false;
	
	return true;
}

void SplashState::free()
{
	logoImage.free();
	backgroundImage.free();
	sound.free();
}

void SplashState::update()
{
	if (input->keyHit(SDL_SCANCODE_SPACE) || input->keyHit(SDL_SCANCODE_ESCAPE) || input->keyHit(SDL_SCANCODE_RETURN))
		getManager()->popState();
	if (logoImageY < TARGET_Y - logoImage.getHeight() / 2)
		logoImageY += LOGO_SPEED;	
	else
	{
		if (!soundPlayed)
		{
			sound.play();
			soundPlayed = true;
		}
	}
	std::cout << "Splash updated\n";
}

void SplashState::draw(Graphics *g)
{
	std::cout << "drawing splash...\n";
	backgroundImage.draw(0, 0, g);
	logoImage.draw(g->getWidth() / 2 - logoImage.getWidth() / 2, logoImageY, g);
//	g->drawRect(100, 100, 100, 100, 255, 255, 0, 255);
}
;
Last edited on
Well there are 1001 reasons why it could be rendering a black screen. Most likely thought is that you're not drawing anything after the screen is cleared. Post your/some rendering code and a sample of code where you attempt to render to the screen.
Fixed it. For anyone experiencing the same problems as me:

The parameters of virtual functions have to match.
EDIT: New problems, see post below
Last edited on
When you're overriding a virtual function, use the override keyword. Your compiler will then tell you if you're not actually overriding anything.
In addition to the override keyword, if you don't want to create any actual GameState objects (only create subclass objects), then consider making GameState an abstract base class. The functions that need to be overridden in the derived class (like draw()), should be declared pure virtual.

virtual void draw() = 0;

The base class will not have a definition of draw(), but all instantiate-able derived classes must. The compiler will make sure that this function is properly defined in the derived classes. In your case, this function would not have been defined in the derived class, and you would have found the error at compile time.
Now I get the following problem:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
//GameState.h
#ifndef GAMESTATE_H
#define GAMESTATE_H

#include "StateManager.h"
#include "Graphics.h"

class StateManager;

class GameState
{
protected:
	StateManager* manager;
public:
	GameState();
	~GameState();
	
	virtual void update() = 0;
	virtual void draw(Graphics *g) = 0;
	
	StateManager* getManager();
	void setManager(StateManager* m);
};

#endif
//GameState.cpp
#include "GameState.h"

GameState::GameState()
{
	
}

GameState::~GameState()
{
	if (getManager() != nullptr)
		getManager()->popState();
}


StateManager* GameState::getManager()
{
	return manager;
}

void GameState::setManager(StateManager *m)
{
	manager = m;
}
//SplashState.h
#ifndef SPLASHSTATE_H
#define SPLASHSTATE_H

#include "Core/GameState.h"
#include "Core/Graphics.h"
#include "Core/Image.h"
#include "Core/Input.h"
#include "Core/Sound.h"

class SplashState : public GameState
{
private:
	Input* input;
	Image backgroundImage;
	Image logoImage;
	Sound sound;
	
	int logoImageY;
	int logoImageX;
	bool soundPlayed;
	
	static const int TARGET_Y = 300;
	static const int LOGO_SPEED = 10;
public:
	SplashState();
	~SplashState();
	
	bool init(Input* i, StateManager* m, Graphics *g);
	void free();
	
	virtual void update();
	virtual void draw(Graphics *g);
};

#endif
//SplashState.cpp
#include "SplashState.h"

SplashState::SplashState()
{
}

SplashState::~SplashState()
{
}

bool SplashState::init(Input* i, StateManager *m, Graphics *g)
{
	input = i;
	setManager(m);
	
	if (!backgroundImage.load("graphics/splash/background.bmp", g))
		return false;
	if (!logoImage.load("graphics/splash/logo.bmp", g))
		return false;
	if (!sound.load("audio/splash/sound.wav"))
		return false;
	
	logoImageY = -logoImage.getHeight();
	soundPlayed = false;
	
	return true;
}

void SplashState::free()
{
	logoImage.free();
	backgroundImage.free();
	sound.free();
}

void SplashState::update()
{
	if (input->keyHit(SDL_SCANCODE_SPACE) || input->keyHit(SDL_SCANCODE_ESCAPE) || input->keyHit(SDL_SCANCODE_RETURN))
		getManager()->popState();
	if (logoImageY < TARGET_Y - logoImage.getHeight() / 2)
		logoImageY += LOGO_SPEED;	
	else
	{
		if (!soundPlayed)
		{
			sound.play();
			soundPlayed = true;
		}
	}
	std::cout << "Splash updated\n";
}

void SplashState::draw(Graphics *g)
{
	std::cout << "drawing splash...\n";
	backgroundImage.draw(0, 0, g);
	logoImage.draw(g->getWidth() / 2 - logoImage.getWidth() / 2, logoImageY, g);
	g->drawRect(100, 100, 100, 100, 255, 255, 0, 255);
}


When I try to run this, I get the following error:

GameEngine\SplashState.o	SplashState.cpp:(.rdata$_ZTV11SplashState[_ZTV11SplashState]+0x18): undefined reference to `GameState::draw()'
GameEngine\RunState.o	RunState.cpp:(.rdata$_ZTV8RunState[_ZTV8RunState]+0x18): undefined reference to `GameState::draw()'
GameEngine\collect2.exe	[Error] ld returned 1 exit status
26		C:\Users\michi_000\Desktop\C++\GameEngine\Makefile.win	recipe for target 'GameEngine.exe' failed

EDIT: I fixed all of it, thanks everyone for their help.
Last edited on
Topic archived. No new replies allowed.