Pourquoi ne pouvons-nous pas déclarer un std::vector<AbstractClass>?
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
Vous devez vous connecter pour publier un commentaire.
Vous ne pouvez pas instancier les classes abstraites, donc un vecteur de classes abstraites ne peuvent pas travailler.
Vous pouvez cependant utiliser un vecteur de pointeurs sur les classes abstraites:
Cela vous permet également d'utiliser effectivement polymorphe de comportement, même si la classe n'était pas abstraite, le stockage en valeur entraînerait le problème de objet de découpage.
Vous ne pouvez pas créer un vecteur d'une classe abstraite type parce que vous ne pouvez pas créer des instances d'une classe abstraite, et de la Norme C++ de la Bibliothèque de conteneurs comme std::vector stocker des valeurs (c'est à dire des cas). Si vous voulez faire cela, vous devrez créer un vecteur de pointeurs sur la classe abstraite type.
Votre contourner ne serait pas travailler en raison des fonctions virtuelles (qui est pourquoi vous voulez que la classe abstraite en premier lieu) uniquement lorsqu'il est appelé par le biais de pointeurs ou des références. Vous ne pouvez pas créer des vecteurs de références, donc c'est une deuxième raison pour laquelle vous devez utiliser un vecteur de pointeurs.
Vous devez réaliser que C++ et C# ont très peu en commun. Si vous avez l'intention d'apprendre le C++, vous devriez penser à ce que commence à partir de zéro, et lire un bon dédié tutoriel C++ comme Accelerated C++ par Koenig et Moo.
Dans ce cas, nous ne pouvons même utiliser ce code:
ou
Car il n'existe pas UNE relation entre l'FunnyImpl et IFunnyInterface et il n'est pas implicite de conversion entre FUnnyImpl et IFunnyInterface parce que privés de l'héritage.
Vous devez mettre à jour votre code comme suit:
Le traditionnel alternative est d'utiliser un
vector
de pointeurs, comme l'a déjà noté.Pour ceux qui apprécient,
Boost
est livré avec une très intéressante bibliothèque:Pointer Containers
qui est parfaitement adapté à la tâche et vous libère des divers problèmes implicites par des pointeurs:Noter que c'est nettement mieux qu'un
vector
de 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:
C'est assez simple, et une variation de la
Pimpl
idiome enrichi par unStrategy
modèle.Cela 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.
Parce que pour redimensionner un vecteur vous devez utiliser le constructeur par défaut et la taille de la classe, qui à son tour nécessite, pour être concret.
Vous pouvez utiliser un pointeur que d'autres ont suggéré.
std::vector va essayer d'allouer de la mémoire pour contenir votre type. Si votre classe est purement virtuel, le vecteur ne peut pas savoir la taille de la classe à laquelle il va consacrer.
Je pense qu'avec votre solution de contournement, vous serez en mesure de compiler un
vector<IFunnyInterface>
mais vous ne serez pas en mesure de manipuler FunnyImpl à l'intérieur. Par exemple, si IFunnyInterface (classe abstraite) est de taille 20 (je ne sais vraiment) et FunnyImpl est de taille 30 parce qu'il a plus de membres et de code, vous allez vous retrouver en essayant de s'adapter à 30 dans votre vecteur de 20La solution serait d'allouer de la mémoire sur le tas avec les "nouvelles" et de stocker des pointeurs dans
vector<IFunnyInterface*>
Je pense que la cause racine de cette vraiment triste de prescription est le fait que les constructeurs ne peuvent pas virtuel. Celle-ci compilateur ne peut pas générer du code qui copie l'objet sans le savoir de son temps dans le temps de compilation.