纯虚拟类和集合(向量?)

发布于 2024-08-24 07:16:36 字数 2001 浏览 3 评论 0原文

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

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

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

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

    >

本质上,我的问题归结于实现图片类,它基本上用于存储形状的集合。我目前正在使用 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。小时:105: 错误:无法分配对象 抽象类型“形状”shape.h:12: 注意:因为以下虚拟 'Shape' 中的函数是纯函数: shape.h:58:注意:虚拟虚空 形状::get(std::istream&) shape.h:31: 注:虚空 形状::put(std::ostream&) const shape.h:36:注意:虚拟虚空 Shape::scale(const Point&, double) shape.h:40:注意:虚拟虚空 形状::翻译(双,双) shape.h:45:注意:虚拟虚空 形状::水平反射(双) shape.h:49:注意:虚拟虚空 形状::垂直反射(双) shape.h:52:注释:虚拟 矩形区域形状::boundingBox() const shape.h:21:注意:虚拟 形状* 形状::clone() const shape.h:55:注意:虚拟虚空 Shape::draw(Graphics&) const

那么存储这些形状的理想方式是什么。我应该使用什么样的集合来存储这些东西?

谢谢

I'm working on a graphics application that is using virtual classes fairly extensively. It has:

  • A picture class, which is essentially a collection of shapes.

  • A shapes class, which is purely virtual and has a few classes that inherit from it:

    • Circle
    • Polygon
    • Rectangle
  • A Figure shape, which is any graphical figure (also virtual), shape inherits from this.

Essentially, my problem comes down to implementing the picture class, which is basically being used to store a collection of shapes. I'm currently using a Vector to store shapes, however, it's apparent that this is the wrong decision since Vector instantiates these shapes, which is not good as they are purely virtual.

Below is my current code base (summarized a bit):

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

The error messages I'm getting are just a bunch of these:

picture.cpp:33: instantiated from
here
/opt/local/bin/../lib/gcc/sparc-sun-solaris2.10/4.4.1/../../../../include/c++/4.4.1/ext/new_allocator.h:105:
error: cannot allocate an object of
abstract type 'Shape' shape.h:12:
note: because the following virtual
functions are pure within 'Shape':
shape.h:58: note: virtual void
Shape::get(std::istream&) shape.h:31:
note: virtual void
Shape::put(std::ostream&) const
shape.h:36: note: virtual void
Shape::scale(const Point&, double)
shape.h:40: note: virtual void
Shape::translate(double, double)
shape.h:45: note: virtual void
Shape::reflectHorizontally(double)
shape.h:49: note: virtual void
Shape::reflectVertically(double)
shape.h:52: note: virtual
RectangularArea Shape::boundingBox()
const shape.h:21: note: virtual
Shape* Shape::clone() const
shape.h:55: note: virtual void
Shape::draw(Graphics&) const

So what is the ideal way to store these shapes. What kind of collection should I be using to store these things?

Thanks

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

凉城凉梦凉人心 2024-08-31 07:16:36

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

本质上将图片类的向量更改为:

std::vector<Shape*>

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

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

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

When you need polymorphism, you need to use either pointers or references. Since containers (or arrays) can't store references, you have to use pointers.

Essentially change your picture class's vector to:

std::vector<Shape*>

and appropriately modify the other member functions.

The reason why you can't/shouldn't store them as value types is because vector is a homogenous container i.e. it only stores data of one type (and only one type -- subclasses are not allowed!). The reason for this is because the vector stores its data in an array, which needs to know the size of the objects it's storing. If the sizes of these objects are different (which they might be for different shapes) then it can't store them in an array.

If you store them as pointers then they all have the same size (sizeof(Shape*)) and also have access to the shape's vtable, which is what allows polymorphic behaviour.

向地狱狂奔 2024-08-31 07:16:36

使用协变返回类型。请参阅常见问题解答 20.8 了解您的 克隆方法。您也可以依靠工厂方法来创建 Shape 对象。

另外,你不能拥有抽象类对象的容器,抽象类不能被实例化。相反,创建一个指向派生具体对象的指针/引用的容器。请注意,如果您使用指针,则您有责任清除它们。容器不会正确地取消分配内存。您可以使用智能指针而不是原始指针来更有效地处理这个问题。从 Boost 中查找 scoped_ptrshared_ptr

Use covariant return types. See FAQ 20.8 for your clone methods. You can rely on the factory method as well to create the Shape objects.

Also, you cannot have a container of abstract class objects, abstract classes cannot be instantiated. Instead, create a container of pointers/references to derived concrete objects. Note, if you are using pointer, it becomes your responsibility to clear them. The container will not de-allocate the memory properly. You can use smart pointers instead of raw pointers to handle this more efficiently. Look up scoped_ptr and shared_ptr from Boost.

孤寂小茶 2024-08-31 07:16:36

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

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>());

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

As already described in another answer polymorphism requires references or pointers. Instead of raw memory allocation you can use smart pointers. You can create a container with

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

and add elements with

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

The memory is freed when the vector is destroyed.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文