如何制作*对象的向量而不降级为基类

时间:2014-02-11 07:26:53

标签: c++ c++11 object-slicing

在我的class实施中,我有类似的内容:

基类

class swcWidget :
     public swcRectangle
{
public:
    swcWidget();
    virtual ~swcWidget();

    void update(float dt);

protected:

    inline virtual void oPaintOnTop() { }
private:
};

派生类

class swcButton :
     public swcWidget
    ,public swcText
{
public:
    swcButton();
    virtual ~swcButton();

    static const int DEFAULT_SIZE = 20;

protected:
private:

    void oPaintOnTop();
};

class swcApplication
{
public:

    swcApplication(int argc, char *argv[]);
    virtual ~swcApplication();

    int run();

    struct Controls
    {
        typedef std::vector<swcWidget*> vWidgets;                 //option 1

        ~Controls();


          /////////////////////////////////
         //   M A I N   P R O B L E M   //
        /////////////////////////////////

        void add(swcWidget &&widgets);  //most preferred option
                                        //but gets demoted to base class.

        void add(swcWidget *widgets);   //second choice
                                        //but should I make a copy of it?
                                        //or just make a reference to it?
                                        //and this one does what I wanted to.
                                        //but still unsure on other things I don't know

        void add(swcWidget *&&widgets); //this compiles fine (?)
                                        //I don't know what kind of disaster I can make into this, but still does not do what I wanted.

        inline vWidgets &getWidgets() {
            return widgets;
        }

    private:

        vWidgets widgets;
    };

    Controls controls;

};

我知道一些像这样的工作选项:

制作

swcApplication::Controls::widgets

作为

的类型
std::vector<std::shared_ptr<swcWidget>>

但我的代码将绑定到std::shared_ptr,我不能像这样编写简单的语法:

swcButton btn;
app.controls.add(std::move(btn));

使用示例:

的main.cpp

int main(int argc, char *argv[])
{

    swcApplication app(argc, argv);

    app.windows.create(640, 480);

    if (font->load("fonts\\georgia.fnt") != BMfont_Status::BMF_NO_ERROR)
    {
        puts("failed to load \"georgia.fnt\"");
    }

    {
        swcButton btn;

        btn.setPosition(100, 100);
        btn.setFont(font);
        btn.text = "Ey!";

        app.controls.add(std::move(&btn));

//      btn.text = "Oy!";

    }


    return app.run();
}

更新

这里是swcApplication::Controls::add()的临时定义,尽管它可能仍然有所不同

void swcApplication::Controls::add(swcWidget &&widget)
{
    widgets.push_back(std::move(widget));
}

1 个答案:

答案 0 :(得分:1)

如果一个类是可移动的,那么它将依次移动它的成员。为了提高效率,这些成员必须是小POD或必须在堆上分配。您必须添加此功能,不要忘记移动任何成员,并且需要注意对象切片。

鉴于该类是非平凡的,当您直接使用指针时(当然是以堆分配时间为代价),您可以使用最有效的移动构造。没有切片是可能的,并且不会忘记移动任何成员,因为您可以一次移动整个对象。需要注意的一个障碍是跟踪谁拥有指针 - 你最好把它设置在石头上,但如果这样做了,那么就不再有问题了。

移动语义很棒,但是如果你的课程有些参与,我认为在这种情况下的指针更容易/更有效地使用。因此,我坚持使用指针变体,并确保您的集合将拥有指针(并通过RAII再次释放它们) - 在您的公共接口中自由使用注释这样说。您可以通过存储某种形式的智能指针(提示:小心使用unique_ptr!)或(安全性较低)make来执行此操作,并始终使用Clear()成员在清除()集合之前删除所有指针。

修改

将小部件成员定义为vector类型时,示例代码可以是:

要为swcApplication类添加:

  void swcApplication::Controls::ClearWidgets() {
    for (auto& nextWidget: widgets) {
      delete nextWidget;
    }
    widgets.clear();
  }

不要忘记在适当的时候调用ClearWidgets(比如在析构函数中)。

添加小部件可以通过以下方式完成:

// Note: any passed widget will not be owned by you anymore!
template <typename Widget>
void swcApplication::Controls::add(Widget*& widget) {
  widgets.push_back(widget);
  widget = nullptr;
}

从现在开始,您可以添加

等小部件
swcButton* btn = new swcButton;
app.controls.add(btn);
// btn is now owned by app.controls, and should be set
// to nullptr for you to prevent misuse like deleting it

在这里使用智能指针应该使它更安全,尽管存储unique_ptr使得访问它们有点容易出错(注意在访问它时从容器中取回所有权),而shared_ptr会给出可能不需要的开销。

相关问题