9

我正在开发一个相当广泛地使用虚拟类的图形应用程序。它有:

  • 图片类,本质上是形状的集合。

  • 一个 shape 类,它是纯虚拟的,并且有几个继承自它的类:

    • 圆圈
    • 多边形
    • 长方形
  • 图形形状,它是任何图形图形(也是虚拟的),形状继承自此。

本质上,我的问题归结为实现图片类,它基本上用于存储形状的集合。我目前正在使用 Vector 来存储形状,但是,很明显这是错误的决定,因为 Vector 实例化了这些形状,这并不好,因为它们是纯虚拟的。

以下是我当前的代码库(总结了一下):

class Figure {
public:
...
  virtual ~Figure();
...
};

class Shape: public Figure
{
public:
...
  virtual ~Shape() {}
  virtual Shape* clone() const = 0;
...
};

class Polygon : public Shape
{
public:
...
virtual Shape* clone() const {return new Polygon(*this);}
... 
private:
std::vector<Point> points;

};

class Picture: public Figure {
public:
...
  Picture(Graphics& gd);
  Picture (const Picture&);
  ~Picture();
  void clear();
  void add (const Shape&);
...
private:
std::vector<Shape> shapes;
Graphics* gfx;
};

//Picture implementation:
...
Picture::Picture(Graphics& gd)
{
gfx = &gd;
}


Picture::Picture(const Picture& a)
{
shapes = a.shapes;
}

Picture::~Picture() 
{
clear();
}

void Picture::clear()
{
shapes.clear();
}

void Picture::add (const Shape& shp)
{
Shape* nshp = shp.clone();
shapes.push_back(*nshp);
}
...

我收到的错误消息只是其中的一堆:

picture.cpp:33:从这里实例化 /opt/local/bin/../lib/gcc/sparc-sun-solaris2.10/4.4.1/../../../../include/c++ /4.4.1/ext/new_allocator.h:105:错误:无法分配抽象类型“Shape”shape.h:12的对象:注意:因为以下虚函数在“Shape”中是纯的:shape.h:58 : 注意: 虚拟 void Shape::get(std::istream&) shape.h:31: 注意: 虚拟 void Shape::put(std::ostream&) const shape.h:36: 注意: 虚拟 void Shape::scale (const Point&, double) shape.h:40: note: virtual void Shape::translate(double, double) shape.h:45: note: virtual void Shape::reflectHorizo​​ntally(double) shape.h:49: note: virtual void Shape::reflectVertically(double) shape.h:52: 注意:virtual RectangularArea Shape::boundingBox() const shape。h:21: note: virtual Shape* Shape::clone() const shape.h:55: note: virtual void Shape::draw(Graphics&) const

那么存储这些形状的理想方法是什么。我应该使用什么样的收藏品来存储这些东西?

谢谢

4

3 回答 3

20

当您需要多态性时,您需要使用指针或引用。由于容器(或数组)不能存储引用,因此您必须使用指针。

基本上将您的图片类的矢量更改为:

std::vector<Shape*>

并适当修改其他成员函数。

您不能/不应该将它们存储为值类型的原因是因为向量是同质容器,即它只存储一种类型的数据(并且存储一种类型——不允许使用子类!)。原因是向量将其数据存储在一个数组中,该数组需要知道它存储的对象的大小。如果这些对象的大小不同(它们可能用于不同的形状),则它不能将它们存储在数组中。

如果将它们存储为指针,那么它们都具有相同的大小 ( sizeof(Shape*)) 并且还可以访问形状的 vtable,这就是允许多态行为的原因。

于 2010-03-07T00:04:27.457 回答
4

使用协变返回类型。有关您的方法,请参阅常见问题解答 20.8 。clone您也可以依赖工厂方法来创建Shape对象。

此外,您不能拥有抽象类对象的容器,抽象类不能被实例化。相反,创建一个指向派生具体对象的指针/引用容器。请注意,如果您使用指针,则清除它们成为您的责任。容器不会正确释放内存。您可以使用智能指针而不是原始指针来更有效地处理此问题。从 Boostscoped_ptr向上查找。shared_ptr

于 2010-03-07T00:05:08.547 回答
1

正如另一个答案中已经描述的那样,多态性需要引用或指针。您可以使用智能指针代替原始内存分配。您可以创建一个容器

std::vector<std::unique_ptr<Shape>> shapes;

并添加元素

shapes.push_back(std::make_unique<Circle>());
shapes.push_back(std::make_unique<Polygon>());
shapes.push_back(std::make_unique<Rectangle>());

当向量被销毁时,内存被释放。

于 2020-11-28T21:36:29.983 回答