2009-09-26 6 views
1

Je travaille en multi-plateforme C++, et ont des classes définies comme ceci: (très simplifié pour cet exemple)C++ Collection d'exemples de mise en œuvre d'une classe virtuelle pure

class ExampleBase 
{ 
public: 
    ExampleBase(int blah) : blah_test(blah) { } 

    virtual void DoSomething() = 0; 
private: 
    int blah_test; 
}; 

class ExampleImplementer : public ExampleBase 
{ 
public: 
    ExampleImplementer() : ExampleBase(5) { } 

    virtual void DoSomething() { /* unique implementation here */ } 
}; 

Au départ, je n'avais qu'une seule classe, que j'ai stocké un tas d'instances de dans un std :: vector et passé par la référence const. Mais maintenant je dois avoir une classe de base (que je veux garder pure virtuelle) et un certain nombre de classes d'implémentation polymorphes. Quelle est la meilleure façon d'avoir une collection d'instances d'implémentation, et d'avoir toujours une gestion facile de la mémoire sans fuites comme si une pile était allouée à std :: vector?

  • Je ne peux évidemment pas un std :: vecteur < ExampleBase> maintenant, puisque std :: vecteur nécessite la classe d'être virtuelle non pur (car il fait l'allocation interne/copie, etc.). Je ne veux pas que les utilisateurs de mon code créent accidentellement des instances de ExampleBase parce que c'est faux. Je tiens également à éviter toute possibilité de tranchage d'objets ou de toute autre méchanceté. Un tableau de std::auto_ptr ferait l'affaire, mais alors je dois les initialiser tous, à la recherche d'un "slot libre", pas d'itérateurs, etc. Il semble un peu fou de faire toute cette roue. inventer.

  • boost::ptr_vector semblait prometteur, mais il se comporte un peu bizarrement en ce que lorsque la construction sur Linux dont il a besoin ExampleBase être virtuel non pur - et je ne comprends pas pourquoi ... Alors boost::ptr_vector est sorti.

Cela semble être une situation simple et probablement très courante. Alors, quelle est la meilleure façon de faire cela? Je suis ouvert à tout autre moyen de promotion ou de promotion: celui qui est le «meilleur».

+1

Veuillez fournir le message d'erreur que vous obtenez pour 'ptr_vector'. Cela ne devrait certainement pas exiger que la classe de base soit non abstraite - quelque chose d'autre ne va pas. –

+0

Merci, bonnes réponses! – maxpenguin

+1

La suppression d'objets via un pointeur de type ABC * (classe de base abstraite) ne fonctionne tout simplement pas si ABC n'inclut pas de destructeur virtuel. L'erreur de compilation que vous obtenez vous protège réellement contre un comportement indéfini. – sellibitze

Répondre

6

boost::ptr_vector est la voie à suivre si vous pouvez avoir Boost. Cela devrait fonctionner pour votre scénario - si ce n'est pas le cas, alors quelque chose d'autre est faux, alors s'il vous plaît postez le message d'erreur. Vous pouvez aussi opter pour std::vector< boost::shared_ptr<ExampleBase> >. Ceci est moins idéal, car ce recomptage va ajouter une certaine surcharge, en particulier lorsque le vecteur est redimensionné, mais sinon une solution de travail.

Si votre implémentation prend en charge TR1 (dernières versions de g ++ et MSVC), vous pouvez utiliser std::tr1::shared_ptr à la place. Cela peut être supérieur, car l'implémentation STL est libre d'optimiser en fonction de certaines connaissances internes - par exemple, dans MSVC, std::vector sait qu'il peut utiliser swap au lieu du constructeur de copie pour std::tr1::shared_ptr, et fait juste cela, en évitant les changements constants de compte.

1

boost::shared_ptr

3

Il y a deux options.

  • Utilisez boost :: ptr_vector comme conteneur. Cela devrait fonctionner même avec une classe de base abstraite. Assurez-vous simplement que votre classe de base inclut un destructeur virtuel.
  • Utilisez plusieurs conteneurs qui gèrent directement différents objets de classes dérivées et créez-en un autre qui utilise uniquement des pointeurs. Cela peut être fastidieux et vous oblige à penser à quand/si les pointeurs sont invalidés. Mais il a aussi l'avantage de rapprocher les objets du même type.
  • Utilisez un pointeur intelligent (comme le pointeur de propriété partagée de boost) et stockez-le dans votre conteneur. C++ 0x offrira un autre bon pointeur intelligent avec moins de surcharge applicable si vous ne voulez pas partager la propriété: unique_ptr. Malheureusement, il n'y a pas de bonne émulation de C++ 03.
  • Utilisez une autre forme de "handle", un objet qui enveloppe et gère un objet polymorphe à l'aide d'un pointeur avec valeur sémantique (ce serait un autre pointeur intelligent que vous pourriez appeler "clone_ptr").
+0

Grande réponse aussi - souhaite que je puisse marquer plusieurs réponses comme accepté! – maxpenguin