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++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre confirmé
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    179
    Détails du profil
    Informations personnelles :
    Localisation : France

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



    Merci

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

    Informations forums :
    Inscription : Février 2006
    Messages : 2 155
    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 : 44
    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
    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 expérimenté Avatar de Ksempac
    Inscrit en
    Février 2007
    Messages
    165
    Détails du profil
    Informations forums :
    Inscription : Février 2007
    Messages : 165
    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 : 44
    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
    Par défaut
    Oui oui, c'est le polymorphisme décrit plus haut.

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

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

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

  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 : 44
    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
    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")
       {
        ......
       }
    }

  8. #8
    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 : 44
    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
    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
    .....

  9. #9
    Membre expérimenté Avatar de Ksempac
    Inscrit en
    Février 2007
    Messages
    165
    Détails du profil
    Informations forums :
    Inscription : Février 2007
    Messages : 165
    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 : 44
    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
    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 expérimenté Avatar de Ksempac
    Inscrit en
    Février 2007
    Messages
    165
    Détails du profil
    Informations forums :
    Inscription : Février 2007
    Messages : 165
    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.

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