IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C++ Discussion :

Héritage : problème d'appel de méthodes


Sujet :

C++

  1. #1
    Membre du Club
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    179
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 179
    Points : 50
    Points
    50
    Par défaut Héritage : problème d'appel de méthodes
    Bonjour,



    Merci

  2. #2
    Membre chevronné
    Avatar de poukill
    Profil pro
    Inscrit en
    Février 2006
    Messages
    2 155
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France

    Informations forums :
    Inscription : Février 2006
    Messages : 2 155
    Points : 2 107
    Points
    2 107
    Par défaut
    Normalement, dans le mécanisme d'héritage, la première chose à faire est d'appeler le construteur de la classe mère à l'aide de le liste d'initialisation....

  3. #3
    Membre éclairé
    Avatar de buzzkaido
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juillet 2004
    Messages
    821
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2004
    Messages : 821
    Points : 734
    Points
    734
    Par défaut
    Ben je sais pas trop comment t'as implementé les classes "Personnes" et "vacanciers", mais visiblement, ta fonction "achat_glace" ne fais pas partie de la classe "Personne".

    Tu as deux possibilités :

    1/ declarer tmp en tant que vecteur de vacanciers : vector<vacancier *> tmp;

    2/ declarer un fonction virtuelle "achat_glace" dans la classe "personne" et la redefinir dans la classe "vacanciers", comme ça :
    - elle fait partie de la classe "personne"
    - etant virtuelle, si tu crée une instance de "vacanciers" et que tu appelles la fonction "achat_glace" sur cette instance via un pointeur de type "personne", c'est la bonne implémentation qui est appelée (celle de type "vacanciers")

    La seconde solution est bien meilleure et permet de réelement tirer parti de l'héritage.

    Si tu n'es pas familier avec ça, je te conseille les tutoriaux sur l'heritage et le polymorphisme.

  4. #4
    Membre habitué Avatar de Ksempac
    Inscrit en
    Février 2007
    Messages
    165
    Détails du profil
    Informations forums :
    Inscription : Février 2007
    Messages : 165
    Points : 185
    Points
    185
    Par défaut
    C'est un objet Vacancier que tu crees mais tu le definis comme Personne. Vacancier derive de Personne donc un Vacancier est bien une Personne, le "cast" est autorisé. Cependant, une fois que c'est defini en Personne tu ne peux pas utiliser les methodes propres a la classe fille (Vacancier) a moins de recaster dans l'autre sens.

    Remplace donc simplement cette ligne par :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Vacancier * vacancier = new Vacancier();

  5. #5
    Membre éclairé
    Avatar de buzzkaido
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juillet 2004
    Messages
    821
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2004
    Messages : 821
    Points : 734
    Points
    734
    Par défaut
    Admettons que 10 classes héritent de Personne.
    Toutes ces classes auront une méthode "achat_glace" alors que seul la classe Vacancier en a besoin.
    C'est bien ce qui se passera ?
    Oui.

    Personne * vacancier = new Vacancier();
    C'est un objet Personne qui est crée ?
    Non, c'est un objet Vacancier, mais le pointeur *vacancier pointe sur un objet de type personne. Qui ne connait donc que les méthodes de la classe "personne"

    Je ne vois pas très bien l'intéret de mettre "achat_glace" dans la classe Personne car cette méthode ne concerne que des Vacancier.
    Ben l'interet, c'est justement de pouvoir utiliser un pointeur "generique" (ici un pointeur sur un objet "personne" et qu'en fonction du type d'objet instancié (ici Vacancier) les méthodes appelées ont le même nom mais pas la meme implémentation.

    Revoit peut-etre un peu l'architecture de tes classes. Dans la classe Personne, seul les fonctions communes doivent y figurer. Tu pourrais par exemple faire une fonction "achat(objet)" qui en fonction du type de personne et du type d'objet n'aura pas la meme fonctionnalité.

    Pour ça, tu fais une classe Objet qui a tous les parametres communs (prix, poids, taille...) et une procedure du type "getObjectType"

    Dans ta fonction achat (specifique à un vacancier), tu fais :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
     
    Vacancier::achat(Objet *objet)
    {
       if (objet->getObjectType() == "glace")
       {
        .........
       }
       if (objet->getObjectType() == "frite")
       {
        .........
       }
       if (objet->getObjectType() == "saucisse")
       {
        .........
       }
       if (objet->getObjectType() == "menuComplet")
       {
        ......
       }
    }

  6. #6
    Membre éclairé
    Avatar de buzzkaido
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juillet 2004
    Messages
    821
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2004
    Messages : 821
    Points : 734
    Points
    734
    Par défaut
    J'oubliais....

    L'interet de tout ca, c'est que dans ton code, apres tu peux faire :

    Objet *pObjet = new Biere();
    ou
    Objet *pObjet = new Glace();
    ou
    Objet *pObjet = new Saucisse();
    ou
    Objet *pObjet = new PaireDeTonguesEnPlastiques();

    et

    Personne *pPersonne = new Vacancier();
    ou
    Personne *pPersonne = new Vendeur();
    ou
    Personne *pPersonne = new Nudiste();
    ou
    Personne *pPersonne = new Policier();


    et appeler simplement :

    pPersonne->achete(pObjet);

    Tu auras automatiquement :

    "Un Vacancier a acheté une glace"
    ou
    "un vendeur ne peut acheter de saucisses"
    ou
    "A poil les nudistes, on met pas de tongues"
    ou
    "Pas de biere pour les policiers pendant le service"
    ou
    .....

  7. #7
    Membre éclairé
    Avatar de buzzkaido
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juillet 2004
    Messages
    821
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2004
    Messages : 821
    Points : 734
    Points
    734
    Par défaut
    Oui oui, c'est le polymorphisme décrit plus haut.

    Lit le tuto sur le polymorphisme, c'est tres instructif !

  8. #8
    Membre du Club
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    179
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 179
    Points : 50
    Points
    50
    Par défaut
    Merci pour toutes ses précisions.

  9. #9
    Membre habitué Avatar de Ksempac
    Inscrit en
    Février 2007
    Messages
    165
    Détails du profil
    Informations forums :
    Inscription : Février 2007
    Messages : 165
    Points : 185
    Points
    185
    Par défaut
    Il existe une 3eme solution.

    Comme parano le dit, la methode achat_glace ne concerne que les vacanciers. En consequence elle n'a rien a faire dans la classe parente. Le polymorphisme est utile seulement si plusieurs classes filles ont besoin de methodes similaires ce qui ne semble pas etre le cas ici.

    Donc la solution consiste a garder achat_glace dans Vacancier et a la sortie du vecteur de faire un dynamic_cast pour pouvoir appeler la methode de la classe fille. Si ce qui sort du vecteur n'est pas un vacancier, mais un autre type de personne, le dynamic_cast evitera les problemes.

    Vacancier* vacancier = dynamic_cast<Vacancier*>(tmp[j]);
    vacancier->achat_glace();

  10. #10
    Membre éclairé
    Avatar de buzzkaido
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juillet 2004
    Messages
    821
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2004
    Messages : 821
    Points : 734
    Points
    734
    Par défaut
    Ouais, mais le dynamic_cast, pour moi c'est un peu du bricolage...

    Et achat_glace n'a rien a faire dans personne, mais je presume qu'il n'y a pas que les vacanciers qui peuvent acheter, et pas que des glaces, donc autant mettre ca dans l'architecture des le depart...

    Dans ton code :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    Vacancier* vacancier = dynamic_cast<Vacancier*>(tmp[j]);
    vacancier->achat_glace();
    Il ne faudrait pas mieux faire

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    Vacancier* vacancier = dynamic_cast<Vacancier*>(tmp[j]);
    if (vacancier != NULL) vacancier->achat_glace();
    Parce que il me semble que dynamic_cast renvoit NULL si l'objet n'a pas pu etre casté. Et dans ce cas, l'appel à vacancier->achat_glace(); declenchera une exeption !

  11. #11
    Membre habitué Avatar de Ksempac
    Inscrit en
    Février 2007
    Messages
    165
    Détails du profil
    Informations forums :
    Inscription : Février 2007
    Messages : 165
    Points : 185
    Points
    185
    Par défaut
    Oui pardon , c'est justement ca qui protege (pouvoir verifier si le cast s'est bien passé)

    Dynamic_cast n'est pas du bricolage. Il est typiquement fait pour gerer pleins d'instances de classe fille comme des instances de la classe mere jusqu'au moment ou la distinction est necessaire.

    Quand je vois qu'il a un Glacier comme personne, il est peu probable que le Glacier achete quoiquecesoit (lui il vend). Donc une methode acheter n'a pas d'interet pour lui.

    Ou alors il faut rajouter un niveau de classe : Creer les classes Vendeur et Acheteur derivant de la classe Personne. Puis Deriver vendeur pour creer Glacier/Boulanger et de l'autre coté deriver Acheteur en Vacanciers/Nudiste/Villageois. Dans ce cas mettre achat dans la classe Acheteur et utiliser le polymorphisme a un sens. De meme qu'on pourrait mettre vendre dans Vendeur.

  12. #12
    Membre éclairé
    Avatar de buzzkaido
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juillet 2004
    Messages
    821
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2004
    Messages : 821
    Points : 734
    Points
    734
    Par défaut
    Ben le glacier, faut bien qu'il achete des fournitures, non ?

    Et s'il a envie de se ballader en tongues en buvant une biere, faut bien qu'il puisse les acheter ?

    Par contre une méthode "prepareUneGlace()" n'aurait pas de sens pour un policier, et une méthode "seFoutAPoil()" n'aurait pas de sens pour le glacier...

    En allant plus loin, nudiste pourrait etre une interface, car le policier peut se foutre à poil s'il fait partie des chippendales du samedi soir....

    Dans tout les cas, mieux vaut passer 3 jours avec un crayon et un papier pour reflechir et dessiner son shema de classes plutot que d'etre obligé de bricoler par la suite.

    @parano : je te conseilles vivement de lire les tutos, de reflechir à tes besoins réels, de tracer un schéma (meme approximatif).

    Ensuite le code viendra de lui-meme tellement il sera logique.

  13. #13
    Membre éclairé
    Avatar de buzzkaido
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juillet 2004
    Messages
    821
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2004
    Messages : 821
    Points : 734
    Points
    734
    Par défaut
    En fait, c'est paske pour utiliser le dynamic_cast, il faut que ta classe possede une v_table.

    Une v_table, c'est une table interne au compilateur qui contient les infos de types et les adresses des fonctions virtuelles.

    Donc pour generer une v_table, il te suffit de declarer une des fonctions en virtuelle.

    Par exemple le constructeur ou le destructeur.

    Du coup, le compilo genere une v_table, et le dynamic_cast fonctionne !

  14. #14
    Expert éminent

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Points : 6 911
    Points
    6 911
    Par défaut
    Citation Envoyé par buzzkaido
    En fait, c'est paske pour utiliser le dynamic_cast, il faut que ta classe possede une v_table.
    Une v_table, c'est une table interne au compilateur qui contient les infos de types et les adresses des fonctions virtuelles.[/quote[

    La vtable ne se trouve pas dans le compilateur, mais dans l'executable

    Donc pour generer une v_table, il te suffit de declarer une des fonctions en virtuelle.

    Par exemple le constructeur ou le destructeur.
    Tu m'expliques comment declarer un constructeur virtuel?
    Les MP ne sont pas là pour les questions techniques, les forums sont là pour ça.

  15. #15
    Membre éclairé
    Avatar de buzzkaido
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juillet 2004
    Messages
    821
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2004
    Messages : 821
    Points : 734
    Points
    734
    Par défaut
    Ben, tu met virtual devant la declaration du constructeur.

    Et t'obtiens une belle erreur de compilation.

    Et là tu passes pour un con, et tu retourne lire "Le C++ pour les nuls"



    Pour la v_table, "interne au compilateur" je voulais dire "que tu t'en occupes pas, ça se fait tout seul si tu le declenche"

    En tout cas, j'aime bien ce forum, ça me permet d'apprendre des trucs et aussi de preciser mes informations sur des domaines dans lesquels je croit savoir...

  16. #16
    Membre expérimenté
    Avatar de Patriarch24
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Septembre 2003
    Messages
    1 047
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Industrie

    Informations forums :
    Inscription : Septembre 2003
    Messages : 1 047
    Points : 1 640
    Points
    1 640
    Par défaut
    "if(achat)" suffit !

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    Vacancier::achat(Objet *objet)
    {
       if (objet->getObjectType() == "glace")
       {//.........
    }
    Quelle horreur !

    Tu m'expliques comment declarer un constructeur virtuel?
    note : si on ne peut déclarer un constructeur virtuel, les "constructeurs virtuels" existent bel et bien en C++ (c'est le pattern Factory Method) !

    Enfin j'ai une question : pour avoir une liste de Personne* alors que manifestement tu n'y mets que des Vacancier* ? Tu me diras, tu as bien les glaciers, que tu peux d'ailleurs mettre dans une autre liste, disons serviceDePlage.
    En premier lieu, utilisez un moteur de recherche.
    En second lieu, postez sur le forum adéquat !

Discussions similaires

  1. Problème d'appel de méthode d'objets COM
    Par tibobao dans le forum C#
    Réponses: 0
    Dernier message: 03/08/2010, 17h35
  2. Héritage et d'appel de méthode
    Par Sunsawe dans le forum Langage
    Réponses: 11
    Dernier message: 30/07/2009, 23h08
  3. Problème d'appel des méthodes OpenGL
    Par choko83 dans le forum OpenGL
    Réponses: 5
    Dernier message: 24/04/2008, 10h02
  4. Problèmes d'appels de méthodes
    Par parano dans le forum C++
    Réponses: 7
    Dernier message: 07/03/2007, 12h08
  5. Problème pour appeler une méthode d'une autre classe
    Par tse_tilky_moje_imja dans le forum Général Python
    Réponses: 7
    Dernier message: 03/03/2006, 13h33

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo