Est-il possible d'hériter de la mise en œuvre de conteneurs STL, plutôt que de déléguer?

J'ai une classe qui s'adapte std::vector pour modèle un conteneur de domaine d'objets spécifiques. Je veux exposer la plupart des std::vector API pour l'utilisateur, afin qu'il/elle peut utiliser les méthodes habituelles (taille, clair, à, etc...) et des algorithmes standard sur le conteneur. Cela semble être un motif récurrent pour moi dans mes dessins:

class MyContainer : public std::vector<MyObject>
{
public:
   //Redeclare all container traits: value_type, iterator, etc...

   //Domain-specific constructors
   //(more useful to the user than std::vector ones...)

   //Add a few domain-specific helper methods...

   //Perhaps modify or hide a few methods (domain-related)
};

Je suis au courant de la pratique de préférant la composition à l'héritage lors de la réutilisation d'une classe pour la mise en œuvre-mais il doit bien y avoir une limite! Si je ont été de tout déléguer à std::vector, il y aurait (selon mes calculs) 32 fonctions de transfert!

Donc mes questions sont... Est-il vraiment si mauvais pour hériter de la mise en œuvre dans de tels cas? Quels sont les risques? Est-il plus sûr moyen pour que je puisse mettre en œuvre ce sans pour autant taper? Je suis un hérétique pour l'utilisation de la mise en œuvre de l'héritage? 🙂

Edit:

Qu'en indiquant clairement que l'utilisateur ne doit pas utiliser MyContainer par l'intermédiaire d'un std::vector<> pointeur:

//non_api_header_file.h
namespace detail
{
   typedef std::vector<MyObject> MyObjectBase;
}

//api_header_file.h
class MyContainer : public detail::MyObjectBase
{
   //...
};

Les bibliothèques boost semblent faire ce genre de choses tout le temps.

Edit 2:

L'une des suggestions était d'utiliser les fonctions libres. Je vais montrer ici, sous forme de pseudo-code:

typedef std::vector<MyObject> MyCollection;
void specialCollectionInitializer(MyCollection& c, arguments...);
result specialCollectionFunction(const MyCollection& c);
etc...

Un plus OO façon de le faire:

typedef std::vector<MyObject> MyCollection;
class MyCollectionWrapper
{
public:
   //Constructor
   MyCollectionWrapper(arguments...) {construct coll_}

   //Access collection directly
   MyCollection& collection() {return coll_;} 
   const MyCollection& collection() const {return coll_;}

   //Special domain-related methods
   result mySpecialMethod(arguments...);

private:
   MyCollection coll_;
   //Other domain-specific member variables used
   //in conjunction with the collection.
}
  • Oh génial! Une autre chance de pousser mon blog à punchlet.wordpress.com - fondamentalement, écrire des fonctions libres, et d'oublier les "plus OO" wrapper approche. Il n'est pas plus OO - si c'était elle serait d'utiliser l'héritage, qui vous ne devriez probablement pas dans ce cas. Rappelez-vous OO != classe.
  • Mais, mais.. fonctions globales mal!!! Tout est un objet! 😉
  • Ils ne seront pas global, si vous les mettez dans un espace de noms.
  • Je sais, je sais. Était juste tourner autour. Blog intéressant. Les "fonctions spéciales" dont je parle ici, mais ne sont pas vraiment à usage général et n'ont de sens que dans mon application en particulier. C'est pourquoi j'hésite à les rendre libres les fonctions et souhaitez les regrouper dans une classe. J'ai révisé mon dernier exemple de code.
  • Si vraiment vous ne souhaitez exposer l'ensemble de l'interface de vecteur, alors il est probablement mieux en C++ pour utiliser la composition, et d'exposer une référence pour le vecteur par un getter (avec const et non const versions). En Java tu venais d'hériter, mais alors en Java certains numpty de ne pas venir, ignorer votre documentation, de supprimer votre objet via le pointeur incorrect (ou d'en hériter à nouveau et mess it up), et ensuite se plaindre. Pour un public restreint, peut-être, mais si les utilisateurs pourraient être dynamique-polymorphisme des monstres, ou, récemment, l'ex-programmeurs Java, vous êtes en train de concevoir une interface que vous pouvez être assez sûr que ils ne pas comprendre.
  • Vous ne pouvez pas les protéger contre les gens complètement ignorant de la documentation. Je ne vais pas être surpris de trouver une telle utilisation abusive provoque tant de problèmes en Java qu'en C++.
  • IMO C'est très bien. Nul ne devrait être prise pointeurs de vecteurs en raison des vecteurs déjà stocker leurs données de manière dynamique et il n'y a pas de polymorphisme possible. La seule vraie raison de l'utilisation d'un pointeur est std::shared_ptr et qui est conçue pour correctement détruire les types dérivés qui n'ont pas les destructeurs virtuels.