Forum |  HardWare.fr | News | Articles | PC | S'identifier | S'inscrire | Shop Recherche
1331 connectés 

  FORUM HardWare.fr
  Programmation
  C++

  question de débutant, casts & héritage

 


 Mot :   Pseudo :  
 
Bas de page
Auteur Sujet :

question de débutant, casts & héritage

n°1692252
in_your_ph​ion
Posté le 25-02-2008 à 17:57:54  profilanswer
 

Bonjour,
je suis super débutant en c++ ... quelqu'un pourrait-il m"expliquer pourquoi quand je fait ce code :

 
Code :
  1. class A {
  2. public:
  3. void set_pos(int x, int y) {
  4. _x=x;
  5. _y=y;
  6. };
  7. int _aa;
  8. private:
  9. int _x;
  10. int _y;
  11. };
  12. class B : public A {
  13. public:
  14. void set_pos2(int x) {
  15. _bb=x;
  16. }
  17. private:
  18. int _bb;
  19. };
  20. int main(int argc, char *argv[]) {
  21.   A *un = new A;
  22.   A *deux = new B;
  23.   //un = deux;
  24.   deux->set_pos2(1);
  25.   return 0;
  26. }
 

j'obtiens l'erreur suivante :

 
Citation :


error: 'class A' has no member named 'set_pos2'

 

en fait je ne comprend pas pourquoi, si on fait un new B, on ne peut pas appeler une méthode de cette classe parce qu'un pointeur du type de la classe mere pointe dessus.

 

merci par avance


Message édité par in_your_phion le 25-02-2008 à 18:03:17
mood
Publicité
Posté le 25-02-2008 à 17:57:54  profilanswer
 

n°1692258
dwogsi
Défaillance cérébrale...
Posté le 25-02-2008 à 18:04:40  profilanswer
 

'deux' est de type A, donc pas de méthode set_pos2() qui n'est présente que dans B.


---------------
-- Debian -- Le système d'exploitation universel | Le gras c'est la vie! | /(bb|[^b]{2})/
n°1692262
in_your_ph​ion
Posté le 25-02-2008 à 18:06:54  profilanswer
 

dwogsi a écrit :

'deux' est de type A, donc pas de méthode set_pos2() qui n'est présente que dans B.

 

pourtant j'ai déjà vue plusieurs fois l'ecriture du type

Code :
  1. A * un = new B;
 

avec B qui dérive de A.
quel serait l'intérêt ?


Message édité par in_your_phion le 25-02-2008 à 18:07:25
n°1692269
dwogsi
Défaillance cérébrale...
Posté le 25-02-2008 à 18:10:57  profilanswer
 

Ba dans ma logique, on devrait toujours savoir de quel type est une variable. On évite ainsi d'appeler des méthodes qui n'existent pas dans l'objet par exemple.
 
Donc je serais tenté de te dire qu'une variable de type A ne peut contenir qu'un objet de type A (ça parait évident...).
 
Cela-dit, je ne suis pas un spécialiste, faudrait que quelqu'un confirme/infirme.


Message édité par dwogsi le 25-02-2008 à 18:11:22

---------------
-- Debian -- Le système d'exploitation universel | Le gras c'est la vie! | /(bb|[^b]{2})/
n°1692298
Ace17
Posté le 25-02-2008 à 19:06:34  profilanswer
 

google("polymorphisme" )

n°1692331
Joel F
Real men use unique_ptr
Posté le 25-02-2008 à 20:20:50  profilanswer
 

l'intérêt c'est par exemple d'avoir un vector de pointeur sur A que tu remplis de manière aveugle avec des
instances de filles de A pour ensuite appeler polymorphiquement des méthodes de l'interface de A.

 

exemple de mon cours.

 
Code :
  1. #include <iostream>
  2. #include <vector>
  3. using namespace std;
  4. class Vehicule
  5. {
  6.   public :
  7.   virtual ~Vehicule() {}
  8.   virtual void demarrer() = 0;
  9. };
  10. class Voiture : public Vehicule
  11. {
  12.   virtual ~Voiture() {}
  13.   virtual void demarrer()
  14.   {
  15.    cout << "demarrage Voiture" << endl;
  16.   }
  17. };
  18. class Camion : public Vehicule
  19. {
  20.   virtual ~Camion() {}
  21.   virtual void demarrer()
  22.   {
  23.    cout << "demarrage Camion" << endl;
  24.   }
  25. };
  26. class Bateau : public Vehicule
  27. {
  28.   virtual ~Bateau() {}
  29.   virtual void demarrer()
  30.   {
  31.    cout << "demarrage Bateau" << endl;
  32.   }
  33. };
  34. int main()
  35. {
  36.   vector<Vehicule*> parc;
  37.  
  38.   parc.push_back( new Voiture );
  39.   parc.push_back( new Camion );
  40.   parc.push_back( new Bateau );
  41.   parc.push_back( new Voiture );
  42.   parc.push_back( new Bateau );
  43.   parc.push_back( new Camion );
  44.   parc.push_back( new Bateau );
  45.   parc.push_back( new Camion );
  46.  
  47.   for( vector<Vehicule*>::iterator it=parc.begin();
  48.        it != parc.end();
  49.        it++
  50.      )
  51.   {
  52.     (*it)->demarrer();
  53.   }
  54.   return 0;
  55. }
 


L'intérêt de l'héritage est de FACTORISER les comportements. Donc en général la classe mère expose une interface
commune à toutes ces filles.

Message cité 1 fois
Message édité par Joel F le 26-02-2008 à 14:44:17
n°1692645
in_your_ph​ion
Posté le 26-02-2008 à 11:12:50  profilanswer
 

Joel F a écrit :

l'intérêt c'est par exemple d'avoir un vector de pointeur sur A que tu remplis de manière aveugle avec des
instances de filles de A pour ensuite appeler polymorphiquement des méthodes de l'interface de A.

 

exemple de mon cours.

 
Code :
  1. #include <iostream>
  2. #include <vector>
  3. using namespace std;
  4. class Vehicule
  5. {
  6.   public :
  7.   virtual void demarrer() = 0;
  8. };
  9. class Voiture : public Vehicule
  10. {
  11.   virtual ~Voiture() {}
  12.   virtual void demarrer()
  13.   {
  14.    cout << "demarrage Voiture" << endl;
  15.   }
  16. };
  17. class Camion : public Vehicule
  18. {
  19.   virtual ~Camion() {}
  20.   virtual void demarrer()
  21.   {
  22.    cout << "demarrage Camion" << endl;
  23.   }
  24. };
  25. class Bateau : public Vehicule
  26. {
  27.   virtual ~Bateau() {}
  28.   virtual void demarrer()
  29.   {
  30.    cout << "demarrage Bateau" << endl;
  31.   }
  32. };
  33. int main()
  34. {
  35.   vector<Vehicule*> parc;
  36.  
  37.   parc.push_back( new Voiture );
  38.   parc.push_back( new Camion );
  39.   parc.push_back( new Bateau );
  40.   parc.push_back( new Voiture );
  41.   parc.push_back( new Bateau );
  42.   parc.push_back( new Camion );
  43.   parc.push_back( new Bateau );
  44.   parc.push_back( new Camion );
  45.  
  46.   for( vector<Vehicule*>::iterator it=parc.begin();
  47.        it != parc.end();
  48.        it++
  49.      )
  50.   {
  51.     (*it)->demarrer();
  52.   }
  53.   return 0;
  54. }
 


L'intérêt de l'héritage est de FACTORISER les comportements. Donc en général la classe mère expose une interface
commune à toutes ces filles.

 

salut,
merci pour ta réponse. Je comprend bien l'exemple, et je pense voire l'interêt du truc ? c'est a dire que c'est générique. Cependant, je ne comprend toujours pas bien pourquoi dans certains cas on fait

 
Code :
  1. A * un = new B;


avec B qui dérive de A, alors qu'on ne peut manifestement pas accéder aux champs de B (qui ne sont pas contenus dans A) par la suite  :(

 

ps : les destructeurs virtuels sont-ils nécessaires dans l'exemple ?


Message édité par in_your_phion le 26-02-2008 à 11:16:33
n°1692660
Joel F
Real men use unique_ptr
Posté le 26-02-2008 à 11:22:15  profilanswer
 

c'est pourtant bien ce que je fais ici , je mets un B* dans des A*.
Pour savoir de quelles types effectif un A* est, on utilise dynamic_cast.
 

Code :
  1. A*p = new B;
  2. // ... plein de code, on sait plus ce qui il y a dans A* p
  3. B* pb;
  4. if( pb = dynamic_vast<B*>(p) )
  5. {
  6.   cout << "p est de type B" << endl;
  7. }
  8. else // p n'etait pas de type B, pb vaut donc NULL
  9. {
  10.   cout << "p n'est pas de type B*" << endl;
  11. }


 
Les destructeurs virtuels assurent la présence et la prise en compte de la table de méthodes virtuelles. Il est de bon ton de les laisser comme ça ;)

n°1692696
in_your_ph​ion
Posté le 26-02-2008 à 12:19:32  profilanswer
 

ok, merci  :jap:

 

alors si j'ai bien tout lu Freud, je comprend que quand on fait :

Code :
  1. A * ab = new B;


avec B qui dérive de A, c'est qu'on fait du polymorphisme et que donc que A utilise au moins une fonction virtuelle. Autrement ca n'a aucun intérêt, non ?

 
Joel F a écrit :


Les destructeurs virtuels assurent la présence et la prise en compte de la table de méthodes virtuelles. Il est de bon ton de les laisser comme ça ;)

 

mais dans cet exemple, ca ne sert a rien de les mettre non ?  :??:


Message édité par in_your_phion le 26-02-2008 à 12:20:19
n°1692787
Tarabiscot​e
Posté le 26-02-2008 à 13:45:20  profilanswer
 

Comme tu fais un new d'un type B, il serait logique de faire un delete d'un type B.
Or si tu fais un delete sur "ab" (dans l'exemple), s'il n'a pas de destructeur virtuel il utilisera le destructeur de A et non de B.
 
En gros, pour résumer ne pas avoir de destructeur virtuel c'est comme faire :

delete (A*)new B;


 
Sinon dans l'exemple comme Vehicule n'a pas de destructeur virtuel, même si y en a dans les classes filles, ca sera toujours celui de Vehicule qui sera appelé.

mood
Publicité
Posté le 26-02-2008 à 13:45:20  profilanswer
 

n°1692817
Joel F
Real men use unique_ptr
Posté le 26-02-2008 à 14:43:53  profilanswer
 

oops en effet, je corrige.

n°1693307
in_your_ph​ion
Posté le 27-02-2008 à 10:58:34  profilanswer
 

Tarabiscote a écrit :

Comme tu fais un new d'un type B, il serait logique de faire un delete d'un type B.
Or si tu fais un delete sur "ab" (dans l'exemple), s'il n'a pas de destructeur virtuel il utilisera le destructeur de A et non de B.
 
En gros, pour résumer ne pas avoir de destructeur virtuel c'est comme faire :

delete (A*)new B;


 
Sinon dans l'exemple comme Vehicule n'a pas de destructeur virtuel, même si y en a dans les classes filles, ca sera toujours celui de Vehicule qui sera appelé.


 
ok, merci :)  
ce que je voulais dire, c'est que dans l'exemple de Joel F. il faudrait un destructeur virtuel pour la classe de base, mais les destructeurs virtuels dans les classes dérivées (les non abstraites dans l'exemple) ne servent à rien (sauf si on dérive ces classes)
 
j'ai bon ? :sweat:  
 
 
 
 

n°1693485
Joel F
Real men use unique_ptr
Posté le 27-02-2008 à 13:27:07  profilanswer
 

oui, mais comme disait feu Bruno Garcia,
"virtual un jour, virtual toujours"

 

les mettre virtual alors que ca a part l'air de servir t'évitera des incongruités le jour ou tu dérivera de Voiture pour faire VoitureAmphibie et que tu auras oublié le virtual sur le destructeur

Message cité 1 fois
Message édité par Joel F le 27-02-2008 à 13:27:25
n°1693662
in_your_ph​ion
Posté le 27-02-2008 à 15:24:51  profilanswer
 

Joel F a écrit :

oui, mais comme disait feu Bruno Garcia,
"virtual un jour, virtual toujours"
 
les mettre virtual alors que ca a part l'air de servir t'évitera des incongruités le jour ou tu dérivera de Voiture pour faire VoitureAmphibie et que tu auras oublié le virtual sur le destructeur


 
ok, merci  :jap: cependant j'ai lu (je ne sais plus où) qu'il ne fallait pas rajouter de destructeurs virtual par défaut car ca ralenti l'execution

n°1693695
Joel F
Real men use unique_ptr
Posté le 27-02-2008 à 16:13:37  profilanswer
 

oui en  1878 avec gcc 0.0.1 c'était le cas mais depuis l'avènement des vrais compilo ... ça n'a aucun sens de dire ça.

n°1693792
in_your_ph​ion
Posté le 27-02-2008 à 17:46:26  profilanswer
 

Joel F a écrit :

oui en  1878 avec gcc 0.0.1 c'était le cas mais depuis l'avènement des vrais compilo ... ça n'a aucun sens de dire ça.

 

lol

 

ok!  :)

 

ps : mais je croyais que virtual & co c'etait "late binding", donc décidées au moment de l'execution (donc apres compilation); me trompe-je ?


Message édité par in_your_phion le 27-02-2008 à 17:50:18
n°1693816
Joel F
Real men use unique_ptr
Posté le 27-02-2008 à 18:10:45  profilanswer
 

non tu ne te trompes pas. Ma remarque portait sur le fait que cette LU du virtual qui coute date un peu des compilos foireux genre 2.95.2 et antérieur.


Aller à :
Ajouter une réponse
  FORUM HardWare.fr
  Programmation
  C++

  question de débutant, casts & héritage

 

Sujets relatifs
[MySQL] Héritage ?traitement de chaines de caractères (débutant)
[Debutant] Les mystères des LayoutManagersPetite question sur l'organisation d'un site
débutant, design et encapsulation ?Petite question sur la stl et les pointeurs.
[SGBD Access 2007 pro] Comment exécuter une requête en SQL (débutant)question technique sur sécurisation d'hergement mutualisé
Problème d'utilisation d'une tortue ( debutant )[Debutant] Modifier le code source de popa3d
Plus de sujets relatifs à : question de débutant, casts & héritage


Copyright © 1997-2022 Hardware.fr SARL (Signaler un contenu illicite / Données personnelles) / Groupe LDLC / Shop HFR