I have tried to answer this myself, by looking up several questions at StackOverflow. And although I think I understand this correctly, I can’t fix this. Which, leaves me with the only obvious observation: I still don’t get it.
I have made a summary of the questions at the bottom of this post, everything in between is information I have gathered and context for this question.
So, I get it that when you have a base class, and a derived class, your deconstructor should be marked virtual in the base class. To allow polymorphism.
But, I cannot seem to get my code to compile, or when it does compile, it does not link due ‘undefined references’. I have been changing back and forth, but I never seem to get out of this cycle.
Basically I have an interace, defined like this:
#ifndef GUIELEMENT_H_
#define GUIELEMENT_H_
class GuiElement {
public:
virtual ~GuiElement();
virtual void draw() = 0;
};
#endif /* GUIELEMENT_H_ */
I have several objects extending from this. A simple relation is GuiWindow (directly derives from GuiElement):
#ifndef CGUIWINDOW_H_
#define CGUIWINDOW_H_
#include <assert.h>
#include <cstddef>
#include "../GuiElement.h"
#include "../GuiInteractionDelegate.h"
class GuiWindow : public GuiElement {
public:
GuiWindow(GuiInteractionDelegate * guiInteractionDelegate) {
assert(guiInteractionDelegate);
interactionDelegate = guiInteractionDelegate;
}
~GuiWindow() {
//delete interactionDelegate;
}
// called each frame, delegates its behavior to the given concrete cGuiWindowDelegate class.
void interact() {
interactionDelegate->interact(this);
}
private:
GuiInteractionDelegate * interactionDelegate;
};
#endif /* CGUIWINDOW_H_ */
This code does not link, gives me:
undefined reference to `GuiElement::~GuiElement()’
I thought it was sufficient to have an implementation in the GuiWindow class? Is that correct?
The next thing, which is really bugging me, is that I also have an abstract class derived from GuiElement, and concrete implementations on top of that. Basically giving:
GuiElement->GuiShape->GuiButton
Here is the header of GuiShape:
#ifndef GUISHAPE_H_
#define GUISHAPE_H_
#include "../GuiElement.h"
#include "../../gameobjects/Rectangle.h"
class GuiShape : public GuiElement {
public:
GuiShape(Rectangle * rect);
GuiShape(int x, int y, int width, int height);
~GuiShape();
void draw();
void setX(int value) { rectangle->setStartX(value); }
void setY(int value) { rectangle->setStartY(value); }
Rectangle * getRectangle() { return rectangle; }
bool isMouseOverShape();
void setColors(int darkBorder, int lightBorder, int inner);
int getDarkBorderColor() { return darkBorderColor; }
int getLightBorderColor() { return lightBorderColor; }
int getInnerColor() { return innerColor; }
protected:
Rectangle * rectangle;
private:
bool rectangleOwner;
int darkBorderColor;
int lightBorderColor;
int innerColor;
};
And finally GuiButton:
#ifndef CGUIBUTTON_H_
#define CGUIBUTTON_H_
#include <sstream>
#include <string>
#include "allegro.h"
#include "../../gameobjects/Rectangle.h"
#include "GuiShape.h"
class GuiButton : public GuiShape {
public:
GuiButton(Rectangle * rect, std::string theLabel);
GuiButton(int x, int y, int width, int height, std::string theLabel);
~GuiButton();
void draw();
std::string * getLabel() {
return label;
}
BITMAP * getBitmap() { return bitmap; }
void setBitmap(BITMAP * value) { bitmap = value; }
void setHasBorders(bool value) { hasBorders = value; }
void setPressed(bool value) { pressed = value; }
bool shouldDrawPressedWhenMouseHovers() { return drawPressedWhenMouseHovers; }
bool shouldDrawBorders() { return hasBorders; }
void setDrawPressedWhenMouseHovers(bool value) { drawPressedWhenMouseHovers = value; }
bool isPressed() { return pressed; }
private:
std::string * label;
bool drawPressedWhenMouseHovers;
bool hasBorders;
bool pressed;
BITMAP * bitmap;
void drawBackground();
void drawLighterBorder();
void drawDarkerBorder();
void drawButtonUnpressed();
void drawButtonPressed();
};
#endif /* CGUIBUTTON_H_ */
Which leads me to the following questions:
- What is the best way to use virtual deconstructors where objects are derived from A->B->C ?
- Should C only be the concrete virtual? And if so, how do you release resources defined and handled only in B? (A=GuiElement, B=GuiShape, C=GuiButton)
- Why would I get ‘undefined references’ with the straight-forward implementation of A->B ? (GuiElement->GuiWindow)
Thanks in advance for your help!
mark the base’s (or all) destructor as virtual.
Not sure what you mean by “concrete virtual” but a class with members that need destroying should destroy them in it’s own destructor. No exceptions. when
~Cis called, it destroys it’s own stuff, and then~Bwill be called automatically. The virtual just makes absolutely sure that~Cis called first.virtual ~GuiElement();tells the compiler that the class has a destructor that will be defined later. You wanted either:or: