2010-03-06 16 views
3

je les deux classes suivantes, on hérite de l'autreC++ héritage, les fonctions de base continuent d'être appelés lorsque overriden

Class A{ 
    void print(){cout << "A" << endl;} 
} 

Class B : A{ 
    void print(){cout << "B" << endl;} 
} 
Class C : A{ 
    void print(){cout << "C" << endl;} 
} 

Puis dans une autre classe que je donne les résultats suivants:

vector<A> things; 
if (..) 
    things.push_back(C()); 
else if (..) 
things.push_back(B()); 

things[0].print(); 

ce toujours A
Je voudrais imprimer B ou C en fonction de ce que j'ai ajouté au vecteur
Comment est-ce que je fais cela?
J'ai essayé l'abstraction mais je ne suis pas entièrement sûr de l'utiliser en C++ et cela n'a pas fonctionné pour moi

Répondre

8

Comme mentionné, vous avez besoin de virtual fonctions pour activer le comportement polymorphique et ne peut pas stocker des classes directement par valeur dans le vector.

Lorsque vous utilisez un std::vector<A>, vous stockez par valeur et donc les objets que vous ajoutez, par ex. via push_back() sont copiés sur une instance d'un A, ce qui signifie que vous perdez la dérivée partie des objets. Ce problème est connu comme object slicing.

Comme nous l'avons suggéré, vous pouvez éviter cela en stockant des pointeurs (ou pointeurs intelligents) à la classe de base, alors que les pointeurs sont copiés dans le vector:

std::vector<A*> things; 
things.push_back(new B()); 
// ... use things: 
things[0]->print(); 

// clean up later if you don't use smart pointers: 
for(std::vector<A*>::iterator it = things.begin(); it != things.end(); ++it) 
    delete *it; 
+2

Gardez à l'esprit que si des exceptions se produisent pendant l'utilisation du vecteur, vous aurez une fuite. Une solution est bien sûr d'utiliser la bibliothèque de pointeurs de Boost. Mais si ce n'est pas possible, une solution très simple pourrait être de créer une classe 'pointer_vector ' qui a un «vecteur » privé auquel vous pouvez accéder avec une fonction 'get'. Le destructeur de cet encapsuleur effectue les suppressions.Maintenant, les objets sont garantis pour être supprimés. – GManNickG

3

Vous devez déclarer la fonction virtuelle dans votre classe de base, dans ce cas c'est la classe a:

class A{ 
    virtual void print(){cout << "A" << endl;} 
} 

Les autres classes vont ramasser ceci même si vous n'écrivez pas virtuel dans ceux-ci (mais vous pouvez). Virtual indique au compilateur que la fonction peut être remplacée.

Lorsque vous n'utilisez pas le virtuel, cela s'appelle se cacher et fonctionne différemment, comme vous l'avez constaté.

+0

quand je le fais cela ne fonctionne toujours pas travailler et si je leur fais des fonctions virtuelles pures alors j'obtiens une erreur due à l'instanciation des objets vectoriels d'une classe abstraite –

+0

L'autre réponse est * partiellement * correcte. Il est faux de dire que vous ne pouvez pas "stocker" des objets dans votre vecteur. Vous pouvez le faire, mais lorsque vous faites cela, vous obligez votre vecteur à stocker uniquement des objets A, même lorsque vous essayez d'y placer B et C, le vecteur crée réellement un objet A et copie le B ou C dedans . Vous devez stocker des pointeurs vers A dans votre vecteur pour obtenir le comportement souhaité. – SoapBox

8

1) Vous devez déclarer impression() comme virtuelle en classe A.

2) Votre vecteur est incorrecte - vous ne pouvez pas stocker des objets réels de la classe A là-dedans; vous aurez besoin de stocker des pointeurs pour leur comportement correct (et vous devrez les nettoyer plus tard) et/ou utiliser quelque chose comme boost :: shared_ptr.

+1

J'étais sur le point de dire que :) le polymorphisme est la plupart du temps seulement pertinent en utilisant des pointeurs/références .... –