C++中列表的多态性

Polymorphism in lists in C++

本文关键字:多态性 列表 C++      更新时间:2023-10-16

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

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

  • 许多继承自Drawable和reimplement-draw()的类。

  • Scene类,其中包含指向Drawables的指针列表。

  • 我创建差异的main.cpp Drawable对象并将它们添加到列表中。

我遇到了以下问题:

  • 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();
...
}
...

我希望我能充分解释。

您想要使用的是一个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));
  1. Drawable必须有一个虚拟析构函数
  2. 您必须有某种对象所有权策略。换句话说,对于您分配的每一个对象,您必须对处理该对象有一个非常清晰的想法。与Java不同,C++就是这样做的。分配对象以添加到场景时,场景对象是否会成为组件的最终所有者?如果是,则场景必须在其自身消失之前(即在析构函数中)delete其组件的列表。如果场景对象不是所有者,而只是用户,那么谁是所有者?你能保证所有者的寿命比所有用户都长吗?如果没有,所有者将如何将所有权传递给下一个所有者?如果要复制对象,则必须为原始和副本决定此问题
  3. shared_ptrptr_list这样新奇的东西很不错,但我建议先学习基础知识。重要的是要了解为什么需要shared_ptrptr_list,它们声称要解决哪些问题,以及它们的解决方案在30000英尺外是什么样子。获得这种理解的最好方法是偶然发现并试图解决其中的一些问题
  4. Drawable必须有一个虚拟析构函数
  5. 如果你想以多态的方式复制对象,那么你需要一个多态函数来进行复制。您必须为每个派生类自己编写一个,就像为每个派生类别编写draw()一样。这种函数的常用名称是clone。对于每个类Fooclone将如下所示:

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

    所有类的clone版本看起来几乎相同,但您必须手动编写其中的每一个。请注意,这是使用Foo的复制构造函数,如果Foo拥有任何其他对象,或者有一个在其他方面不重要的复制操作,则必须自己编写该构造函数
  6. 我有没有提到Drawable必须有一个虚拟析构函数