Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pure Virtual Class and Collections (vector?)

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

like image 264
the_gastropod Avatar asked Mar 07 '10 00:03

the_gastropod


People also ask

What is a pure virtual class?

A pure virtual function or pure virtual method is a virtual function that is required to be implemented by a derived class if the derived class is not abstract. Classes containing pure virtual methods are termed "abstract" and they cannot be instantiated directly.

What is difference between pure virtual and virtual?

A virtual function is a member function of base class which can be redefined by derived class. A pure virtual function is a member function of base class whose only declaration is provided in base class and should be defined in derived class otherwise derived class also becomes abstract.

What is pure virtual class in C++?

A pure virtual function is a virtual function in C++ for which we need not to write any function definition and only we have to declare it. It is declared by assigning 0 in the declaration. An abstract class is a class in C++ which have at least one pure virtual function.

What is pure virtual class in Java?

Pure Virtual Function. A virtual function for which we are not required implementation is considered as pure virtual function. For example, Abstract method in Java is a pure virtual function.


1 Answers

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.

like image 50
Peter Alexander Avatar answered Oct 12 '22 05:10

Peter Alexander