2

我正在使用 OpenGL 和 C++ 编写一个基本的图形场景编辑器,这是上下文:

  • 我有一个 Drawable 类,它是抽象的,只有一个纯虚函数 draw()。我使用这个类就像一个java接口。

  • 许多类继承自 Drawable 并重新实现 draw()。

  • 一个场景类,其中包含指向可绘制对象的指针列表。

  • 我在其中创建不同的 Drawable 对象并将它们添加到列表中的 main.cpp。

我有这个问题:

  • 在 main.cpp 中创建的对象不断超出范围,因此创建它们并使用引用的对象执行添加函数并不容易。(只是一直保持一个没有有效指针的列表)。

  • 一个苦乐参半的解决方案是使用 new 创建这些新对象,并让 Scene 类在列表被销毁时删除列表中的指针,或者以某种方式在 main.cpp 中删除它们。

我真的不喜欢这样,所以我想问一下是否有一些方法可以在 add 函数中复制对象,然后将副本存储在列表中,这不是问题,因为复制的对象很快就会被删除。在该函数中,我不知道我参加的是 Drawable 的哪个子类。我不能直接复制 Drawable 对象,因为 Drawable 是一个抽象类,不能用 new 来制作 Drawable 对象。只想拥有一个包含不同对象的列表,这些对象都可以执行 draw()。我留下一些代码以防万一:

class Drawable {
public:
    virtual void draw() = 0;

    virtual ~Drawable() = 0 {}
};


class Figure : public Drawable {
private:
    list<Point, allocator<Point>> _points;
    int _type;

public:
    ...

    void draw() {
        ...
    }   
};


class Scene : public Drawable {
private:
    list<Drawable*, allocator<Drawable*>> _drawables;
    ...

public:
    ...

    void add(Drawable* drawable) {
        _drawables.push_back(drawable);
    }

    ~Scene() {
        for(iterDrawable it = _drawables.begin(); it != _drawables.end(); ++it)
        delete (*it);
    }

    void draw() {
        for(iterDrawable it = _drawables.begin(); it != _drawables.end(); ++it)
            (*it)->draw();
    }   
};


main.cpp
...
void display() {
    ...

    Figure* square = new Figure(GL_POLYGON);

    square->add(Point(xSquare, ySquare));
    square->add(Point(xSquare + squareWidth, ySquare));
    square->add(Point(xSquare + squareWidth, ySquare + squareHeight));
    square->add(Point(xSquare, ySquare + squareHeight));

    cScene.add(square);
    cScene.draw();

    ...
}
...

我希望我解释得充分。

4

2 回答 2

3

您要使用的是 boost ptr 容器:

boost::ptr_list<Drawable>   drawlables;

/// STUFF

drawlables.add(new Square);

boost ptr 容器(优于智能指针容器)的优点是容器使对元素的访问看起来像对象(而不是指针)。这使得将它们与标准算法一起使用变得微不足道。

ptr 容器拥有插入到容器中的任何指针的所有权,因此涵盖了内存管理。所有其他位置都应该从容器中传递一个引用。

drawlables[0].draw();

// or drawl all of them
for_each(drawlables.begin(), drawlables.end(), std::mem_fun(&drawlables::draw));
于 2012-10-15T22:20:58.710 回答
1
  1. Drawable必须有一个虚拟析构函数。
  2. 您必须制定某种对象所有权政策。换句话说,对于您分配的每个对象,您必须非常清楚地了解如何处理该对象。这就是在 C++ 中做事的方式,而不是 Java。当您分配对象以添加到场景中时,场景对象是否成为组件的最终所有者?如果是这样,那么场景delete在它自己消失之前(即在析构函数中)必须拥有它的组件列表。如果场景对象不是拥有者,而仅仅是一个用户,那么谁是拥有者?你能保证所有者的寿命比所有用户都长吗?如果不是,所有者将如何将所有权传递给下一个所有者?如果你要复制一个对象,你必须为原件副本决定这个问题。
  3. shared_ptr像and这样的花哨的东西ptr_list很好而且花花公子,但我建议先学习基础知识。重要的是要了解为什么需要shared_ptrptr_list需要,他们声称要解决哪些问题,以及从 30000 英尺看他们的解决方案是什么样的。获得这种理解的最好方法是偶然发现并尝试解决其中一些问题。
  4. Drawable必须有一个虚拟析构函数。
  5. 如果你想多态地复制对象,那么你需要一个多态函数来进行复制。您必须自己为每个派生类编写一个,就像draw()为每个派生类编写一样。这种函数的普遍接受的名称是clone. 对于每个类Fooclone看起来像这样:所有类

    virtual Foo* clone() {
        return new Foo(*this);
    }

    的版本clone看起来几乎相同,但是您必须手动编写它们中的每一个。请注意,这是使用的复制构造函数,如果拥有任何其他对象,或者以其他方式具有非平凡的复制操作,则Foo必须自己编写该构造​​函数。Foo
  6. 我有没有提到Drawable必须有一个虚拟析构函数?
于 2012-10-15T22:53:30.910 回答