Inheritance problems

I have a Button base class from which I create derived buttons. However, when I try to call the draw function, the program crashes:
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
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
//Button.h
#ifndef BUTTON_H
#define BUTTON_H

#include "Image.h"
#include "OutlineFont.h"
#include "Input.h"

#include "SDL2\SDL.h"

class Button
{
protected:
	Input *input;
	
	Image defaultImage;
	Image clickedImage;
	Image hoverImage;
	
	Image* currentImage;
	
	SDL_Rect rect;
	
	bool clicked;
public:
	/*Leave clickedImagePath and hoverImagePath empty for default values (nullptr)*/
	Button(Input *i, SDL_Rect aRect, Graphics *g,
		   const char* defaultImagePath,
		   const char* clickedImagePath = nullptr,
		   const char* hoverImagePath = nullptr);
	~Button();
	
	/*Override these functions for customized behaviour*/
	virtual void onClick();
	virtual void onHover();
	virtual void free();
	virtual void draw(Graphics *g);
	
	void update();
	
	Image* getDefaultImage();
	Image* getClickedImage();
	Image* getHoverImage();
	Image* getCurrentImage();
	
	SDL_Rect* getPosition();
	
	bool isClicked();
};

#endif

//Button.cpp
#include "Button.h"

Button::Button(Input *i, SDL_Rect aRect, Graphics *g,
			   const char* defaultImagePath,
			   const char* clickedImagePath,
			   const char* hoverImagePath)
			    
			   :
			   input(i),
			   rect(aRect)
{
	defaultImage.load(defaultImagePath, g);
	if (clickedImagePath != nullptr)
	{
		clickedImage.load(clickedImagePath, g);
	}
	else clickedImage = defaultImage;
	if (hoverImagePath != nullptr)
	{
		hoverImage.load(hoverImagePath, g);
	}
	else hoverImage = defaultImage;
	
	clicked = false;
	currentImage = &defaultImage;
	
	rect.w = defaultImage.getWidth();
	rect.h = defaultImage.getHeight();
}

Button::~Button()
{
	free();
}

void Button::free()
{
	defaultImage.free();
	clickedImage.free();
	hoverImage.free();
	
}

void Button::draw(Graphics *g)
{
	if (currentImage != nullptr)
	{
		currentImage->draw(rect.x, rect.y, g);
	}
}

void Button::update()
{
	/*Check if mouse in inside button*/
	if (input->getMouseX() >= rect.x &&
		input->getMouseY() >= rect.y &&
		input->getMouseX() <= rect.x + rect.w &&
		input->getMouseY() <= rect.y + rect.h)
	{
		if (input->mouseHit(Input::MOUSE_LEFT))
		{
			clicked = true;
			
			currentImage = &clickedImage;
			rect.w = clickedImage.getWidth();
			rect.h = clickedImage.getHeight();
			onClick();
		}
		else
		{
			currentImage = &hoverImage;
			rect.w = hoverImage.getWidth();
			rect.h = hoverImage.getHeight();
			onHover();
		}
	}
	else
	{
		currentImage = &defaultImage;
		rect.w = defaultImage.getWidth();
		rect.h = defaultImage.getHeight();
	}
}

void Button::onClick()
{
	
}

void Button::onHover()
{
	
}

Image* Button::getClickedImage() { return &clickedImage; }
Image* Button::getHoverImage() { return &hoverImage; }
Image* Button::getDefaultImage() { return &defaultImage; }
Image* Button::getCurrentImage() { return currentImage; }

SDL_Rect* Button::getPosition() { return &rect; }
bool Button::isClicked() { return clicked; }

//SoundButton.h
#ifndef SOUNDBUTTON_H
#define SOUNDBUTTON_H

#include "Button.h"
#include "Sound.h"

class SoundButton : public Button
{
protected:
	Sound effect;
public:
	SoundButton(Input *i, SDL_Rect aRect, Graphics *g, const char* imagePath, const char* soundPath);
	
	virtual void free();
	virtual void onClick();
};

#endif

//SoundButton.cpp
#include "SoundButton.h"

SoundButton::SoundButton(Input *i, SDL_Rect aRect, Graphics *g, const char* imagePath, const char* soundPath) : Button::Button(i, aRect, g,
																												  			   imagePath, 
																												  			   nullptr,
																												  			   nullptr)
{
	if (!effect.load(soundPath))
		std::cout << "Failed to load sound effect at path: " << soundPath << "\n";
}

void SoundButton::free()
{
	Button::free();
	effect.free();
}

void SoundButton::onClick()
{
	effect.play();
	std::cout << "Button clicked!\n";
}

//ButtonDemo.h
#ifndef BUTTONDEMO_H
#define BUTTONDEMO_H

#include "Game.h"
#include "Image.h"
#include "SoundButton.h"
#include "RadioButtonGroup.h"

class ButtonDemo : public Game
{
protected:
	SoundButton *btn;
	RadioButtonGroup *grp;
	OutlineFont mainFont;
public:
	ButtonDemo();
	~ButtonDemo();
	
	virtual bool init();
	virtual void free();
	virtual void update();
	virtual void draw(Graphics *g);
};

#endif

//ButtonDemo.cpp
#include "ButtonDemo.h"

ButtonDemo::ButtonDemo()
{
}

ButtonDemo::~ButtonDemo()
{
}

bool ButtonDemo::init()
{
	initSystem("Buttons!", 800, 600, false);
	btn = new SoundButton(getInput(), {350, 50, 0, 0}, getGraphics(), "graphics/soundButton.bmp", "audio/soundEffect.wav");
	if (btn == nullptr)
		return false;
		
	mainFont.load("bbrick.ttf", 25);
	
	grp = new RadioButtonGroup();
	grp->addButton(new RadioButton(getInput(), {250, 250, 0, 0}, getGraphics(), grp, "Option 1", &mainFont, "graphics/soundButton.bmp",
	nullptr, nullptr, 255, 0, 255, 255));
	grp->addButton(new RadioButton(getInput(), {250, 350, 0, 0}, getGraphics(), grp, "Option 2", &mainFont, "graphics/soundButton.bmp",
	nullptr, nullptr, 255, 0, 255, 255));
	
	return true;
}

void ButtonDemo::free()
{
	btn->free();
	delete btn;
	
	grp->free();
	
	delete grp;
	
	freeSystem();
}

void ButtonDemo::draw(Graphics *g)
{
	if (btn != nullptr)
		btn->draw(g);
	grp->draw(g);
}

void ButtonDemo::update()
{
	btn->update();
	grp->update();
	
	if (grp->getSelectedButton() != nullptr)
		std::cout << grp->getSelectedButton()->getText() << "\n";
}


Maybe also worth noting: First, the button worked fine. Then I added the radiobutton system, that has a button inheriting from the base class, but I had to make the draw function virtual to do so. When I did that, the program started to crash. The radiobuttons work fine.
Last edited on
Have you at least tried attaching a debugger to see what the program was trying to do when it crashed?
I have tried, but I will need a new IDE that comes with a better debugger. Currently I use devC++, but the debugger always crashes the program, even with a simple Hello World program.
I tried using MS Visual Studio, and after some research, I found out how to create a project and debug it. However, when I try to debug my program with it, it throws the following exception:

Exception thrown at 0x0000000000000000 in GameEngine.exe: 0xC0000005: Access violation executing location 0x0000000000000000.
Access violation executing location 0x0000000000000000.


Null pointer. You have a pointer that, instead of pointing to an object, is pointing to NULL, or zero. If you're running your code using the debugger, it should show you the exact line of code.
Last edited on
It doesn't show any line, but only this:
https://imgur.com/a/Uh2Z8

Also, when I try to compile my program, I go to Build->rebuild solution. But when I try to debug then it says that it can't find the executable. So I go to the project location and copy the exectuable to the project_folder/Debug. Then It executes, but any changes I made are not there.

Also, as you can see in this screenshot https://imgur.com/a/VZCnU , there are red marks next to my source files. I guess this has to do with errors, but my code compiles fine, so that can't be it.

Sorry for asking so many questions, but this is my first time working with VS and nothing seems to be working...
Last edited on
That means that at some point your code tried to follow an uninitialized function pointer. I see that you're using inheritance. Are you maybe calling a virtual function in a constructor/destructor?

Take a look at the call stack window. When there's a crash t will usually look like
<a runtime function for throwing exceptions> <-- deepest stack frame
<a runtime function for throwing exceptions>
<one of your functions> <-- usually the crash happened here
<one of your functions>
<one of your functions>
<a runtime function serving as an entry point for the thread>
<a runtime function serving as an entry point for the thread>
<a runtime function serving as an entry point for the thread>
I just realise, that I indeed call a virtual function from a destructor. I removed it, and the program doesn't crash anymore. Thanks alot for your help. I will put my questions about Visual Studio in a seperate thread.
Topic archived. No new replies allowed.