81 votes

Pourquoi ne pouvons-nous pas déclarer un std :: vector <AbstractClass> ?

Après avoir passé un certain temps à développer en C#, j'ai remarqué que si vous déclarez une classe abstraite pour le but de l'utiliser comme une interface vous ne peut pas instancier un vecteur de cette classe abstraite pour stocker les instances des classes d'enfants.

#pragma once
#include <iostream>
#include <vector>

using namespace std;

class IFunnyInterface
{
public:
    virtual void IamFunny()  = 0;
};

class FunnyImpl: IFunnyInterface
{
public:
    virtual void IamFunny()
    {
        cout << "<INSERT JOKE HERE>";
    }
};

class FunnyContainer
{
private:
    std::vector <IFunnyInterface> funnyItems;
};

La ligne de déclarer le vecteur de la classe abstraite causes de cette erreur dans MS VS2005:

error C2259: 'IFunnyInterface' : cannot instantiate abstract class

Je vois une solution évidente, qui est de remplacer IFunnyInterface avec les éléments suivants:

class IFunnyInterface
{
public:
    virtual void IamFunny()
    {
        throw new std::exception("not implemented");
    }
};

Est-ce une solution acceptable C++ sage ? Si non, est-il un tiers de la bibliothèque comme boost qui pourrait m'aider à contourner ce problème ?

Je vous remercie pour la lecture de ce !

Anthony

117voto

Georg Fritzsche Points 59185

Vous ne pouvez pas instancier des classes abstraites, un vecteur de classes abstraites ne peut donc pas fonctionner.

Vous pouvez cependant utiliser un vecteur de pointeurs pour les classes abstraites:

 std::vector<IFunnyInterface*> ifVec;
 

Cela vous permet également d’utiliser réellement un comportement polymorphe - même si la classe n’est pas abstraite, le stockage par valeur poserait le problème du découpage en objet .

6voto

Matthieu M. Points 101624

Le traditionnel alternative est d'utiliser un vector de pointeurs, comme l'a déjà noté.

Pour celles qui apprécient les, Boost est livré avec une très intéressante bibliothèque: Pointer Containers , ce qui est parfaitement adapté à la tâche et vous libère des divers problèmes implicites par des pointeurs:

  • gestion de durée de vie
  • la double référence à des itérateurs

Notez que c'est nettement mieux qu'un vector des pointeurs intelligents, à la fois en termes de performances et de l'interface.

Maintenant, il y a une 3ème alternative, qui est de changer votre hiérarchie. Pour une meilleure isolation de l'utilisateur, j'ai vu un certain nombre de fois que le motif suivant utilisés:

class IClass;

class MyClass
{
public:
  typedef enum { Var1, Var2 } Type;

  explicit MyClass(Type type);

  int foo();
  int bar();

private:
  IClass* m_impl;
};

struct IClass
{
  virtual ~IClass();

  virtual int foo();
  virtual int bar();
};

class MyClass1: public IClass { .. };
class MyClass2: public IClass { .. };

C'est assez simple, et une variation de l' Pimpl idiome enrichi par un Strategy modèle.

Il fonctionne, bien sûr, que dans le cas où vous ne souhaitez pas manipuler les "vrais" objets directement, et implique de copie en profondeur. Donc il peut ne pas être ce que vous voulez.

6voto

Sergey Teplyakov Points 6556

Dans ce cas, nous ne pouvons même pas utiliser ce code:

 std::vector <IFunnyInterface*> funnyItems;
 

ou

 std::vector <std::tr1::shared_ptr<IFunnyInterface> > funnyItems;
 

Parce qu’il n’existe pas de relation IS FunnyImpl et IFunnyInterface et qu’il n’ya pas de conversion implicite entre FUnnyImpl et IFunnyInterface en raison d’un héritage privé.

Vous devriez mettre à jour votre code comme suit:

 class IFunnyInterface
{
public:
    virtual void IamFunny()  = 0;
};

class FunnyImpl: public IFunnyInterface
{
public:
    virtual void IamFunny()
    {
        cout << "<INSERT JOKE HERE>";
    }
};
 

2voto

KennyTM Points 232647

Parce que pour redimensionner un vecteur, vous devez utiliser le constructeur par défaut et la taille de la classe, ce qui oblige à la rendre concrète.

Vous pouvez utiliser un pointeur comme suggéré.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X