【发布时间】:2011-10-14 22:14:52
【问题描述】:
我自己尝试通过在 StackOverflow 上查找几个问题来回答这个问题。虽然我认为我理解正确,但我无法解决这个问题。其中,给我留下了唯一明显的观察结果:我仍然不明白。
我已经对这篇文章底部的问题进行了总结,中间的所有内容都是我收集的信息和这个问题的背景。
所以,我知道当你有一个基类和一个派生类时,你的解构函数应该在基类中标记为虚拟。允许多态性。
但是,我似乎无法编译我的代码,或者当它编译时,由于“未定义的引用”,它没有链接。我一直在来回变化,但我似乎永远无法摆脱这个循环。
基本上我有一个交互,定义如下:
#ifndef GUIELEMENT_H_
#define GUIELEMENT_H_
class GuiElement {
public:
virtual ~GuiElement();
virtual void draw() = 0;
};
#endif /* GUIELEMENT_H_ */
我有几个从这里延伸出来的对象。一个简单的关系是 GuiWindow(直接派生自 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_ */
此代码不链接,给我:
对 `GuiElement::~GuiElement()' 的未定义引用
我认为在 GuiWindow 类中有一个实现就足够了吗?对吗?
接下来真正让我烦恼的是,我还有一个派生自 GuiElement 的抽象类,以及在此之上的具体实现。基本上给: GuiElement->GuiShape->GuiButton
这是 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;
};
最后是 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_ */
这让我想到了以下问题:
- 在对象从 A->B->C 派生的情况下,使用虚拟解构器的最佳方法是什么?
- C 应该只是具体的虚拟吗?如果是这样,您如何释放仅在 B 中定义和处理的资源? (A=GuiElement,B=GuiShape,C=GuiButton)
- 为什么直接实现 A->B 会得到“未定义的引用”? (GuiElement->GuiWindow)
提前感谢您的帮助!
【问题讨论】:
-
在这里得到答案后,请执行以下操作:将调试输出放到所有的析构函数/构造函数中,并观察创建/删除对象时调用它们的顺序。然后你就会明白发生了什么。
-
虽然我想我知道答案我会试试看:)
-
我正在尝试我的代码的答案,但我最终得到了解构器的“多个实现”(尽管它是虚拟的,我也给它一个实现)。有什么提示吗?与此同时,我继续努力。
-
我搞定了。我做了什么: - 我制作了所有析构函数,除了最具体的类是虚拟的。 - 我创建了析构函数的实现,因此它们可以释放资源等。 - 我还确保接口类上的所有虚函数,在基类中也提到了虚函数(A->B->C 中的 B)。
-
你也应该对构造函数做同样的事情——你会看到破坏的顺序是构造的相反顺序,这当然是有道理的:)
标签: c++ inheritance virtual