Héritage de classe et vector

Héritage de classe et vector - C++ - Programmation

Marsh Posté le 09-12-2003 à 00:08:57    

Alors une petite question surement conne mais ca coute rien de la poser...
 
Disons que j'ai 3 classes:
 
- une classe "animal" qui est la classe de base
- une classe "chat" qui hérite de "animal" et lui ajoute de nouvelles choses, etc...
- une classe "tortue" qui hérite aussi de "animal", etc...
 
Alors disons qu'ensuite je veux classer tout mes chats et mes tortues dans un "vector", je fais comment et est-ce possible ???
 
Parce que j'ai testé :
 

Code :
  1. vector<animal> listeanimaux;


 
Avec des push_back() on arrive à ajouter les animaux dans la liste, par contre lorsque je veux accéder aux propriétés ou méthodes, seules celles hérités de "animal" sont disponibles...
 
 

Reply

Marsh Posté le 09-12-2003 à 00:08:57   

Reply

Marsh Posté le 09-12-2003 à 00:16:16    

Je vais sans doute dire une grosse connerie :
un "cast" explicite, ça ne marche pas ?

Reply

Marsh Posté le 09-12-2003 à 00:19:46    

std::vector<animal*>
 
en C++, le polymorphisme passe par les pointeurs ou les références.
 
 
mais c'est quoi cette psychose des casts, c'est les fêtes qui vous font ça ou quoi? déjà que vous castez quand c'est inutile, voulez caster quand on ne peut pas. réfléchissez une peu sur ce que ça veut dire "caster" et pensez au types.

Reply

Marsh Posté le 09-12-2003 à 00:19:47    

Non j'ai essayé et puis j'y tiens pas trop au "cast" ca va être plus que crade si il faut que je caste à chaque fois que je veux lire une propriété qui n'est pas dans "animal"

Reply

Marsh Posté le 09-12-2003 à 00:21:44    

ben y a pas besoin de cast
 
 
si  
*v[0] est un chien, et *v[1] un chat
 
v[0]->crie() -> "Ouaf"
v[1]->crie() -> "Miaou"

Reply

Marsh Posté le 09-12-2003 à 00:25:17    

Taz a écrit :

ben y a pas besoin de cast
 
 
si  
*v[0] est un chien, et *v[1] un chat
 
v[0]->crie() -> "Ouaf"
v[1]->crie() -> "Miaou"


 
je comprends pas ca passe pas, en fait j'ai une propriété "taille" qui n'éxiste que dans la classe "tortue" et pas dans "chien" ni "animal" et je n'arrive pas à y accéder...

Reply

Marsh Posté le 09-12-2003 à 00:26:36    

ben là il faut caster vie un dynamic_cast. si tu utilises des propriétés personnelle à la tortue, il faut que ton objet soit une tortue et typé tel quel

Reply

Marsh Posté le 09-12-2003 à 00:29:30    

Taz a écrit :

ben là il faut caster vie un dynamic_cast. si tu utilises des propriétés personnelle à la tortue, il faut que ton objet soit une tortue et typé tel quel


 
Ok donc ca semble assez bancal comme facon de faire...
 
Comment ferais-tu pour classer dans un tableau des objets qui sont hérités de la même classe de base mais dont certaines propriétés ou méthodes sont personnelles et sans que cela soit trop infame comme solution ?

Reply

Marsh Posté le 09-12-2003 à 00:36:04    

ça l'est pas du tout !
si tu fais de la généricité, tu considères des propriétés génériques, si tu veux quelque chose de spécifique, il faut retrouver cette spécifité.
 
L'exemple célèbre de Stroustrup, c'est les Saab : une 900 et une 90 : un voiture et un avion. c'est des Saab, pas de problèmes, y a des propriétés commune. Maintenant, si tu prends la peine de t'assurer que telle Saab est bien une voiture, je te laisse imaginer ce qui se passe tu tente de la faire décoler

Reply

Marsh Posté le 09-12-2003 à 00:40:42    

Taz a écrit :

ça l'est pas du tout !
si tu fais de la généricité, tu considères des propriétés génériques, si tu veux quelque chose de spécifique, il faut retrouver cette spécifité.
 
L'exemple célèbre de Stroustrup, c'est les Saab : une 900 et une 90 : un voiture et un avion. c'est des Saab, pas de problèmes, y a des propriétés commune. Maintenant, si tu prends la peine de t'assurer que telle Saab est bien une voiture, je te laisse imaginer ce qui se passe tu tente de la faire décoler


 
Ok bon tant que ca te semble bien alors pourquoi pas ;)  
 
Je vais essayer de voir ca d'un peu plus près, merci.

Reply

Marsh Posté le 09-12-2003 à 00:40:42   

Reply

Marsh Posté le 09-12-2003 à 01:34:14    

Taz a écrit :

ben là il faut caster vie un dynamic_cast. si tu utilises des propriétés personnelle à la tortue, il faut que ton objet soit une tortue et typé tel quel


 
:whistle:


Message édité par marmotte.tranquille le 09-12-2003 à 01:48:57
Reply

Marsh Posté le 09-12-2003 à 01:53:15    

oui ?

Reply

Marsh Posté le 09-12-2003 à 01:55:31    

Et la psychose des cast :o

Reply

Marsh Posté le 09-12-2003 à 02:01:30    

...

Reply

Marsh Posté le 09-12-2003 à 21:07:04    

rajoute un membre à ta classe qui indique le type, pour retrouver tes spécialités
 

Code :
  1. struct animal
  2. {
  3.   enum type_animal
  4.   {
  5.     type_chien,
  6.     ...
  7.   } type;
  8. };
  9. class chien : public animal
  10. {
  11.   chien()
  12.   : type(type_chien)
  13.   {
  14.   }
  15.   void aboie()
  16.   {
  17.   }
  18. };
  19. int main()
  20. {
  21.   vector<animal> animaux;
  22.   // remplissage
  23.   if(animaux[0]->type == animal::type_chien)
  24.   {
  25.     (dynamic_cast<chien*>(animaux[0]))->aboie();
  26.   }
  27.   return 0;
  28. }


---------------
-( BlackGoddess )-
Reply

Marsh Posté le 09-12-2003 à 21:09:03    

BlackGodess > droit dans le mur ! si on a inventé les RTTi, c'est justement pour pas avoir à écrire de genre de chose.
 
devine quoi, si le dynamic_cast<chien*> échoue, c'est àd ire que animaux[i] n'est pas une sort de chien, et bien le résultat vaut 0 (NULL) magique ?

Reply

Marsh Posté le 09-12-2003 à 21:10:20    

ah ? j'avais vu qu'il y avait une sécuritée supplémentaire entre le dynamic_cast et le static_cast, mais c'est donc a l'execution ?
 
bien, désolé pour les anneries :(


---------------
-( BlackGoddess )-
Reply

Marsh Posté le 09-12-2003 à 21:13:01    

static_cast -> transtypage sur, fonctionnel à la compilation, pas d'erreur. du genre chien* -> animal*
 
dynamic_cast -> non sur, nécessite des information de types dynamique, genre animal* -> chien* (et oui, impossible de savoir à la compilation si un animal est effectivement un chien). évidemment, on peut vérifier la réussite du transtypage, sinon ça n'a pas d'intéret)

Reply

Marsh Posté le 09-12-2003 à 21:49:35    

bien, merci :jap:


---------------
-( BlackGoddess )-
Reply

Marsh Posté le 10-12-2003 à 02:56:55    

Merci pour ces précisions ...

Reply

Marsh Posté le 10-12-2003 à 02:59:35    

dis le si tu t'en sors pas

Reply

Marsh Posté le 11-12-2003 à 23:41:50    

Taz a écrit :

BlackGodess > droit dans le mur ! si on a inventé les RTTi, c'est justement pour pas avoir à écrire de genre de chose.
 
devine quoi, si le dynamic_cast<chien*> échoue, c'est àd ire que animaux[i] n'est pas une sort de chien, et bien le résultat vaut 0 (NULL) magique ?  


 
Taz, donc dans ce cas, il faudrait d'abord faire un test prealable quand meme sur le dynamic_cast non ??
 
Style  

Code :
  1. chien* toutou= (dynamic_cast<chien*>(animaux[0]));
  2. if (0!=toutou) // Ouarf, c'est un toutou finalement
  3.    toutou->aboie();


 
Il y a plus elegant ?


Message édité par iraysyvalo le 11-12-2003 à 23:42:29
Reply

Marsh Posté le 11-12-2003 à 23:44:37    

moi je trouve pas si moche que ça (sauf tes parenthèse superflues)
évidemment, si on travaille avec des références, le try/catch est plus attractif.

Reply

Marsh Posté le 11-12-2003 à 23:51:10    

tu peux faire comme ça sinon

Code :
  1. if(Dog *d = dynamic_cast<Dog*>(catsndogs[i]))
  2. {
  3.   d->bite();
  4. }

Reply

Marsh Posté le 13-12-2003 à 19:42:44    

Toujours une histoire d'animaux .. polymorphiques ?? ;)
 
Supposons que je veuille reconstruire un animal a partir de son etat-civil qui va donc m'indiquer si c'est une tortue, un chien ou un chat.
 
Comment construire un objet du bon type a la volee ?
Quelle est la bonne architecture ?
 
Ma piste: avoir une fonction de reconstruction virtuelle dans Animal, et profiter du polymorphisme ... mais je bloque.

Reply

Marsh Posté le 13-12-2003 à 19:44:49    

une grosse fonction avec un méga swith qui renvoie un pointeur Animal* vers la nouvelle bébette alouée dynamiquement.
cette fonction peut etre une fonction membre statique auquel cas elle est appelé « fabrique »

Reply

Marsh Posté le 13-12-2003 à 20:20:24    

Ce serait  
 
static Animal* Animal::fabrique(){ ?
   
.... mais si ce qu'on construit est, par exemple, un Chat, ca va pas etre bon vu que les Chats et les Chiens derivent d'Animal et ne sont pas encore connus ...  
 

Reply

Marsh Posté le 13-12-2003 à 20:24:50    

avec un paramètre quand même.
tu fais une fabrique dans Animal si tu connais déjà certaines sous-classes, évidemment.

Reply

Marsh Posté le 13-12-2003 à 20:35:41    


Apres essai :

Code :
  1. // fichier Animal.h
  2. // Forward declaration don't work
  3. // Put the two includes instead in Animal.cpp
  4. // fichier Chien.h
  5. #include "Animal.h"


 
Et apres pour implementer fabrique dans Animal, comme ceci ??

Code :
  1. static Animal* Animal::fabrique(Etatcivil etat){
  2.    Animal *bete;
  3.    switch(etat.nature){
  4.       case CHIEN:
  5.           // preparer le chien puis ..
  6.          return dynamic_cast<Chien*> (bete);
  7.    }
  8. }


Message édité par iraysyvalo le 14-12-2003 à 05:38:12
Reply

Marsh Posté le 13-12-2003 à 20:37:11    

ben non
 
return new Chien;


Message édité par Taz le 13-12-2003 à 20:37:26
Reply

Marsh Posté le 13-12-2003 à 20:38:27    

Et l'appel serait donc  
 

Code :
  1. Animal *bete= Animal::fabrique(etat);
  2. // et un peu plus tard
  3. if(Chien *d = dynamic_cast<Chien*> bete){
  4.   d->attaque();
  5. }


Message édité par iraysyvalo le 13-12-2003 à 22:30:01
Reply

Marsh Posté le 13-12-2003 à 20:41:58    

iraysyvalo a écrit :


Ca marche comme ca ? Viens que je t'embrasse Taz ..


 
Et oui, un chien est un animal. Contrairement à un animal qui n'est pas forcément un chien, capiche?


---------------
From now on, you will speak only when spoken to, and the first and last words out of your filthy sewers will be "Sir!"
Reply

Marsh Posté le 13-12-2003 à 20:42:46    

SchnapsMann a écrit :


 
Et oui, un chien est un animal. Contrairement à un animal qui n'est pas forcément un chien, caniche?

Reply

Marsh Posté le 13-12-2003 à 20:43:18    


[:lorill]


Message édité par schnapsmann le 13-12-2003 à 20:43:24

---------------
From now on, you will speak only when spoken to, and the first and last words out of your filthy sewers will be "Sir!"
Reply

Marsh Posté le 13-12-2003 à 20:54:40    


La suite d'appels precedente marche ?

Reply

Marsh Posté le 13-12-2003 à 22:17:21    

iraysyvalo a écrit :


La suite d'appels precedente marche ?


si animal peut attacker, alors chien le peut  :o


---------------
From now on, you will speak only when spoken to, and the first and last words out of your filthy sewers will be "Sir!"
Reply

Marsh Posté le 13-12-2003 à 22:29:38    


Erreur typographique .. j'edite ..

Reply

Marsh Posté le 14-12-2003 à 04:55:27    


Edit du code d'avant


Message édité par iraysyvalo le 14-12-2003 à 04:56:27
Reply

Marsh Posté le 14-12-2003 à 08:30:00    

Taz a écrit :

ben là il faut caster vie un dynamic_cast. si tu utilises des propriétés personnelle à la tortue, il faut que ton objet soit une tortue et typé tel quel

Pattern 1) Expert : celui qui a l'information s'occupe du traitement. Si tu n'as pas l'information alors ce n'est pas à toi de faire le traitement.
 
En l'occurence, dans cette situation on utilise un Visiteur.


---------------
trainoo.com, c'est fini
Reply

Marsh Posté le 14-12-2003 à 10:22:09    

Code :
  1. #include<iostream>
  2. using namespace std;
  3. class Animal;
  4. class Chien;
  5. class Chat;
  6. class VisiteurAnimalier;
  7. class Animal {
  8. public :
  9.         virtual string bruit() = 0;
  10. virtual void accepte(VisiteurAnimalier &vis) = 0;
  11.        
  12. };
  13. class FabriqueDAnimaux {
  14. public :
  15.     virtual Animal *creeAnimal() = 0;
  16. };
  17. class VisiteurAnimalier {
  18. public :
  19.     virtual void visiteChien(Chien *lechien) = 0;
  20.     virtual void visiteChat(Chat *lechat) = 0;
  21.     virtual ~VisiteurAnimalier() = 0;
  22. };
  23. class Chien : Animal {
  24.     class FabriqueDeChien : FabriqueDAnimaux {
  25.     public :
  26.         virtual Animal *creeAnimal() {
  27.             return new Chien();
  28.         };
  29.     };
  30.    
  31. public :
  32.     static const FabriqueDeChien *fabrique;
  33.    
  34.     virtual string bruit() {
  35.         return "OUAF";
  36.     }
  37.     void accepte(VisiteurAnimalier &vis) {
  38.         vis.visiteChien(this);
  39.     }
  40.     // ça connerie à lui
  41.     void mordre() {
  42.         cout << "je luis mords le mollet" << endl;
  43.     }
  44. };
  45. class Chat : Animal {
  46.     class FabriqueDeChat : FabriqueDAnimaux {
  47.     public :
  48.         virtual Animal *creeAnimal() {
  49.             return new Chat();
  50.         };
  51.     };
  52. public :   
  53.     static const FabriqueDeChat *fabrique;
  54.    
  55.     virtual string bruit() {
  56.         return "Miaou";
  57.     }
  58.     virtual void accepte(VisiteurAnimalier &vis) {
  59.         vis.visiteChat(this);
  60.     }
  61.    
  62.     // la connerie que lui seul peut faire
  63.     void grimperArbre() {
  64.         cout << "je grimpe et je suis trop con pour redescendre" << endl;
  65.     }
  66. };
  67. class VisiteurDeconneur : VisiteurAnimalier {
  68. public :
  69.     ~VisiteurDeconneur();
  70.     virtual void visiteChien(Chien *lechien) {
  71.         lechien->mordre();
  72.     };
  73.     virtual void visiteChat(Chat *lechat) {
  74.         lechat->grimperArbre();
  75.     };
  76. };
  77. const Chat::FabriqueDeChat *Chat::fabrique = new FabriqueDeChat();
  78. const Chien::FabriqueDeChien *Chien::fabrique = new FabriqueDeChien();


(j'imagine que Taz corrigera ce qui lui plait pas)
 
voilà l'esprit de tous les services que tu veux, en version bien typée et propre.
Il y a un Pattern Fabrique Abstraite (classe dont les instances sont des usines à instances) l'intérêt est de pouvoir fabriquer des animaux "à l'aveuglette", imagine par exemple un monde un peu crado où pour avoir un animal de compagnie on doive acheter un jeton pui passer le jeton à l'Administration qui va lui fabriquer le chien et l'enregistrer légalement par la même occasion. Le jeton contiendra une référence à la Fabrique idoine, mais le fonctionnaire ne saura pas quel annimal sera créé (il s'en fout).  
C'est pas top comme exemple, mais je vois pas à quoi pourrait te servir ta fabrique dans ton modèle.
 
Pour les traitements spécifique par animal, il y a tout le système de Visiteur, un objet qui a un traitement spécifique par animal est un VisiteurAnimalier (qui ne modélise pas une personne mais un trait de personnalité d'un objet).
 
Au passage, j'ai mis les fabriques en Singleton, c'est-à-dire qu'il n'existe qu'une seule instance de la classe FabriqueDeChat accessible dans la classe.


---------------
trainoo.com, c'est fini
Reply

Marsh Posté le    

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed