界面中的虚拟解构器 - >抽象 - >具体类设计

时间:2011-10-14 22:14:52

标签: c++ inheritance virtual

我试图通过在StackOverflow上查找几个问题来自己回答这个问题。虽然我认为我理解正确,但我无法解决这个问题。其中,给我留下了唯一明显的观察结果:我仍然没有得到它。

我在这篇文章的底部总结了一些问题,其间的一切都是我收集的信息和这个问题的背景。

所以,我知道当你有一个基类和一个派生类时,你的解构函数应该在基类中标记为虚拟。允许多态。

但是,我似乎无法将我的代码编译,或者当它编译时,它没有链接到'undefined references'。我一直在来回变换,但我似乎永远不会离开这个循环。

基本上我有一个interace,定义如下:

#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-&GT; GuiShape-&GT; 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-&gt; C?
  • C应该只是具体虚拟吗?如果是这样,您如何释放仅在B中定义和处理的资源? (A = GuiElement,B = GuiShape,C = GuiButton)
  • 为什么我会直接实现A-&gt; B获得'未定义的引用'? (GuiElement-&GT; GuiWindow)

提前感谢您的帮助!

2 个答案:

答案 0 :(得分:5)

  

使用虚拟解构器的最佳方法是什么,其中对象来自A-> B-> C?

将基础(或所有)析构函数标记为虚拟。

  

C应该只是具体虚拟吗?如果是这样,您如何释放仅在B中定义和处理的资源? (A = GuiElement,B = GuiShape,C = GuiButton)

不确定“具体虚拟”是什么意思,但是需要销毁的成员的类应该在它自己的析构函数中销毁它们。没有例外。当调用~C时,它会破坏它的自己的内容,然后~B将自动调用 。虚拟只是确保首先调用~C

  

为什么我会直接实现A-&gt; B获得'未定义的引用'? (GuiElement-&GT; GuiWindow)

virtual ~GuiElement();告诉编译器该类有一个稍后定义的析构函数。你想要:

// There is no definition, cannot make a local "GuiElement" variable
// They can only make local "GuiButton" or other derived.
// You can still have pointers to a GuiElement.
// This is called "pure virtual"
virtual ~GuiElement() = 0; 

或:

// There is a definition, someone can make a local "GuiElement" variable
virtual ~GuiElement()  {};

答案 1 :(得分:2)

  

我认为在GuiWindow课程中有一个实现就足够了吗?这是对的吗?

没有。如果在类中声明了虚函数(不是纯虚函数,作为GuiElement的析构函数),则必须定义它。

析构函数更进一步:它们必须始终实现,即使它是纯虚[1]。如果你还没有声明它,编译器会为你创建一个(隐式非虚拟,但如果它会覆盖虚拟析构函数则为虚拟)。在C ++ 11中,您可以将其标记为“默认”(这意味着“编译器,为我实现”)和“删除”,这意味着“程序可能永远不会,隐式或显式地破坏此类对象”。 / p>

  
      
  1. 使用虚拟解构器的最佳方法是什么,其中对象来自A-> B-   C?
  2.   

您通常希望将最顶层的析构函数设为虚拟,这意味着层次结构中的所有析构函数都是虚拟的。

  

如果是这样,你如何释放仅在B中定义和处理的资源? (A = GuiElement,B = GuiShape,C = GuiButton)

~B(),自然。

[1]:

  

12.4 / 7:析构函数可以声明为虚拟(10.3)或纯虚拟(10.4);如果该类的任何对象或任何   派生类是在程序中创建的,应该定义析构函数。如果一个类有一个基类   虚析构函数,它的析构函数(无论是用户还是隐式声明)都是虚拟的。