Classe virtuelle pure et collections (vecteur?)

Je travaille sur une application graphique qui utilise assez souvent les classes virtuelles. Il a:

Mon problème réside essentiellement dans l’implémentation de la classe d’image, qui sert essentiellement à stocker une collection de formes. J’utilise actuellement un vecteur pour stocker des formes, mais il est évident que c’est une mauvaise décision, car Vector instancie ces formes, ce qui n’est pas bon car elles sont purement virtuelles.

Ci-dessous ma base de code actuelle (résumée un peu):

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 points; }; class Picture: public Figure { public: ... Picture(Graphics& gd); Picture (const Picture&); ~Picture(); void clear(); void add (const Shape&); ... private: std::vector 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); } ... 

Les messages d’erreur que je reçois ne sont que quelques exemples:

picture.cpp: 33: instancié à partir d’ici /opt/local/bin/../lib/gcc/sparc-sun-solaris2.10/4.4.1/../../../include/c++ /4.4.1/ext/new_allocator.h:105: erreur: impossible d’allouer un object de type abstrait ‘Shape’ shape.h: 12: remarque: car les fonctions virtuelles suivantes sont pures dans ‘Shape’: shape.h: 58 : note: void virtuel Shape :: get (std :: istream &) shape.h: 31: note: void virtuel Shape :: put (std :: ostream &) const shape.h: 36: remarque: void virtuel Shape :: scale (Const Point &, double) shape.h: 40: remarque: vide virtuel Shape :: traduire (double, double) shape.h: 45: remarque: vide virtuel Shape :: reflectHorizontally (double) shape.h: 49: remarque: void virtuel Shape :: reflectVertically (double) shape.h: 52: remarque: virtuel RectangularArea Shape :: boundingBox () const shape.h: 21: note: virtuel Shape * Shape :: clone () const shape.h: 55: remarque: void virtuel Shape :: draw (Graphics &) const

Alors, quel est le moyen idéal pour stocker ces formes. Quel type de collection devrais-je utiliser pour stocker ces objects?

Merci

Lorsque vous avez besoin de polymorphism, vous devez utiliser des pointeurs ou des références. Étant donné que les conteneurs (ou les tableaux) ne peuvent pas stocker de références, vous devez utiliser des pointeurs.

Modifiez essentiellement le vecteur de votre classe d’images en:

 std::vector 

et modifier de manière appropriée les autres fonctions membres.

La raison pour laquelle vous ne pouvez pas / ne devriez pas les stocker comme types de valeur est parce que le vecteur est un conteneur homogène, c’est-à-dire qu’il ne stocke que les données d’un type (et qu’un seul type – les sous-classes ne sont pas autorisées!). La raison en est que le vecteur stocke ses données dans un tableau, qui doit connaître la taille des objects qu’il stocke. Si les tailles de ces objects sont différentes (ce qui peut être le cas pour des formes différentes), il ne peut pas les stocker dans un tableau.

Si vous les stockez en tant que pointeurs, ils ont tous la même taille ( sizeof(Shape*) ) et ont également access à la table vtable de la forme, ce qui permet le comportement polymorphe.

Utilisez les types de retour covariants. Voir la FAQ 20.8 pour vos méthodes de clone . Vous pouvez également compter sur la méthode factory pour créer les objects Shape .

De plus, vous ne pouvez pas avoir un conteneur d’objects de classe abstraite, les classes abstraites ne peuvent pas être instanciées. Créez plutôt un conteneur de pointeurs / références à des objects concrets dérivés. Notez que si vous utilisez un pointeur, il vous incombe de les effacer. Le conteneur ne désaffectera pas la mémoire correctement. Vous pouvez utiliser des pointeurs intelligents au lieu des pointeurs bruts pour gérer cela plus efficacement. Recherchez scoped_ptr et shared_ptr partir de Boost.