Vecteurs et le polymorphisme en C++
J'ai une situation délicate. Sa forme simplifiée est quelque chose comme cela
class Instruction
{
public:
virtual void execute() { }
};
class Add: public Instruction
{
private:
int a;
int b;
int c;
public:
Add(int x, int y, int z) {a=x;b=y;c=z;}
void execute() { a = b + c; }
};
Et puis dans une classe, je fais quelque chose comme...
void some_method()
{
vector<Instruction> v;
Instruction* i = new Add(1,2,3)
v.push_back(*i);
}
Et encore une autre classe...
void some_other_method()
{
Instruction ins = v.back();
ins.execute();
}
Et ils partagent cette Instruction vecteur d'une certaine manière. Ma préoccupation est la partie où je fais "exécuter" de la fonction. Ça va fonctionner? Il conserver son Add type?
Eh bien, avez-vous l'essayer?
Lisez à propos de objet de découpage.
Permettez-moi de modifier certaines choses
Votre
Changement de type de vecteur de pointeur de conteneur, et de supprimer la référence (*i). Et il va fonctionner.
Lisez à propos de objet de découpage.
Permettez-moi de modifier certaines choses
Votre
some_method()
fuites de mémoire à chaque appel.Changement de type de vecteur de pointeur de conteneur, et de supprimer la référence (*i). Et il va fonctionner.
OriginalL'auteur user44273 | 2013-04-21
Vous devez vous connecter pour publier un commentaire.
Non, il ne sera pas.
magasins de valeurs, pas de références. Cela signifie que peu importe comment vous mais que l'Instruction objet, il va être copié à un certain moment dans l'avenir.
En outre, puisque vous êtes l'allocation avec
new
, le code ci-dessus fuites de cet objet. Si vous voulez le faire correctement, vous allez avoir à faireOu, mieux encore:
J'aime ce ce blog pour expliquer
reference_wrapper
Ce comportement est appelé objet de la découper.
vector<std::reference_wrapper<Instruction>>
! Vous devez être absolument certain que ce que vous ajoutez au vecteur a une durée de vie plus longue que le vecteur, et que ce que vous ajoutez est supprimé à un certain point. Beaucoup mieux d'utiliser unvector<std::unique_ptr<Instruction>>
à la place.OriginalL'auteur jozefg
De sorte que vous aurez besoin d'une sorte de pointeur. Un
std::shared_ptr
fonctionne bien:Gardez à l'esprit que PInstruction de référence est compté, alors que le constructeur de copie de PInstruction permettra de créer une nouvelle "référence" pour le même objet.
Si vous souhaitez faire une copie de l'objet référencé, vous aurez à mettre en œuvre une méthode clone:
Si la performance est un problème que vous pouvez regarder
std::unique_ptr
, c'est un peu plus délicat à gérer que la sémantique de déplacement est toujours nécessaire, mais elle évite le coût de certaines opérations atomiques.Vous pouvez également utiliser des pointeurs et de gérer la mémoire manuellement avec une sorte de pool de mémoire de l'architecture.
Le problème sous-jacent est que pour avoir un type polymorphe, le compilateur ne sait pas comment les grandes sous-classes vont être, de sorte que vous pouvez pas seulement un vecteur de type de base, comme de ne pas avoir de l'espace supplémentaire requis par les sous-classes. Pour cette raison, vous aurez besoin d'utiliser par référence à la sémantique comme décrit ci-dessus. Il stocke un pointeur vers l'objet dans le vecteur et puis les magasins de l'objet sur le tas dans des blocs de différentes tailles en fonction de ce que la sous-classe doit.
shared_ptr
mise en œuvre de Boost ou de TR1.Comprenez-vous pourquoi pousser des objets par valeur ne fonctionne pas bien? C'est le point le plus important de cette réponse.
Pas complètement. Pouvez-vous m'éclairer?
Lire le lié Q&A sur l'objet-de la découper. Il définit précisément quel est le problème avec la façon dont vous vous approchez de cette, et cette réponse (et plusieurs autres) de l'enveloppe de la mécanique pour s'y attaquer. Il l'expliquera bien mieux que le commentaire-seul peut ici.
Eh bien... merci beaucoup! Je suis heureux, je ne suis pas allé sur la mise en œuvre du présent et de se taper ma tête sur le mur, plusieurs heures plus tard.
OriginalL'auteur Andrew Tomazos
Non, cela ne marchera pas; vous êtes "découpage" de la
Add
objet, et seule l'insertion de sesInstruction
partie dans le tableau. Je vous recommande de faire de la classe de base abstraite (par exemple en rendantexecute
virtuelle pure), de sorte que le tranchage donne une erreur de compilation plutôt que des comportements inattendus.Pour obtenir polymorphe de comportement, le vecteur doit contenir des pointeurs vers la classe de base.
Ensuite, vous devrez être prudent dans la façon de gérer les objets eux-mêmes, puisqu'ils ne sont plus contenus dans le vecteur. Pointeurs intelligents peuvent être utiles à cet effet; et, puisque vous êtes susceptibles d'être allouées dynamiquement ces objets, vous devez aussi donner de la classe de base d'un destructeur virtuel à assurez-vous que vous pouvez les supprimer correctement.
OriginalL'auteur Mike Seymour
Vous voudrez peut-être faire une ou deux choses, l'Une: modifier le type de "v" pour "vecteur", B: géré votre mémoire avec le "supprimer" de l'opérateur. Pour répondre à votre question, avec cette approche, oui, mais vous ne pourrez accéder à l'interface de "l'Instruction", si vous CONNAISSEZ le type de quelque chose d ' "Instruction" pointeur pointe vers je conseille dynamic_cast si vous devez accéder à l'interface à partir de, disons, "Ajouter".
Pas besoin d'excuses, j'étais tout simplement hypothétique avec le dynamic_cast.
OriginalL'auteur The Floating Brain