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 :

Appel d'un méthode fille via la classe mère


Sujet :

C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Inscrit en
    Mars 2009
    Messages
    13
    Détails du profil
    Informations forums :
    Inscription : Mars 2009
    Messages : 13
    Par défaut Appel d'un méthode fille via la classe mère
    Bonjour,

    Nouveau problème dû au polymorphisme (c'est compliqué ce truc). Voici donc le problème :
    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
     
    Class mere{
         virtual void fonction1(int arg) = 0;
         void fonction2(double arg);
    }
     
    Class fille : public mere {
         void fonction1(int arg);
         int toto();
    }
     
    main{
         unique_ptr<mere> merePtr (fille());  //Code (faux ?) à titre d'exemple pour montrer que je travaille avec un pointeur.
         merePtr.get()->fonction1(10);     //Ca fonctionnne
         merePtr.get()->fonction2(3.14);  //Ca fonctionnne
         merePtr.get()->toto();               //Ca ne fonctionne pas
    }
    Y'a t'il une astuce pour appeler une méthode fille via la fonction mere sans que celle ci ne sache les méthodes spécifiques aux classes filles.
    Pour info certaines méthodes des classes filles seront communes, d'autres spécifiques à chaque fille.

    La méthode brutale que j'ai trouvé sur le net serait de déclarer chaque méthode spécifique de chaque classe fille dans la classe mere, ce qui n'est pas mon but. Je voudrais pouvoir ajouter de nouvelles classes fille (qui auront aussi des méthodes spécifiques) sans avoir à retravailler la classe mere.
    Est-ce possible ?

    Question subsidière : Quelle est la différence entre *merePtr et merePtr.get() ?

  2. #2
    Expert confirmé
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Février 2005
    Messages
    5 503
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Conseil

    Informations forums :
    Inscription : Février 2005
    Messages : 5 503
    Par défaut
    C'est une erreur de conception.
    S'il te faut utiliser les méthodes de la classe fille depuis un élément dans un conteneur de la classe mère, c'est que vous auriez du utiliser un conteneur de la classe fille.

    C'est quoi, concrètement des classes mères et filles ?

  3. #3
    Membre averti
    Inscrit en
    Mars 2009
    Messages
    13
    Détails du profil
    Informations forums :
    Inscription : Mars 2009
    Messages : 13
    Par défaut
    Voici le prototype de la classe mere :

    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
    class GPSSentence {
        public:
            virtual ~GPSSentence();
            GPSSentence();
            GPSSentence(std::string type);
     
            virtual void setType(std::string type)=0;
     
            unsigned short int getNbField() const;
            std::string getType() const;
     
        protected:
     
            unsigned short int nbField; 
            std::string type;
     
    };

    et celui de la classe fille :

    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
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    class GPGAA : public GPSSentence{
        public:
            GPGAA();
            virtual ~GPGAA();
     
            Time getTime();
            Latitude getLatitude();
            Longitude getLongitude();
            unsigned int getFixQuality();
            unsigned int getNbOfSat();
            double getHDilution();
            Altitude getSeaAltitude();
            Altitude getWsgAltitude();        
     
        protected:
            void setType(std::string type);
            void setTime(Time time);
            void setLatitude(Latitude latitude);
            void setLongitude(Longitude longitude);
            void setFixQuality(unsigned int fixQuality);
            void setNbOfSat(unsigned int nbOfSat);
            void setHDilution(double hDilution);
            void setSeaAltitude(Altitude seaAltitude);
            void setWsgAltitude(Altitude wsgAltitude);
     
        private:
            Time fixTime;
            Latitude latitude;
            Longitude longitude;
            unsigned int fixQuality;
            unsigned int nbOfSat;
            double hDilution;
            Altitude seaAltitude;
            Altitude wsgAltitude;
     
    };
    Je vais donc énoncer clairement mon objectif, ce sera plus simple.
    -Décortiquer plusieurs types de trames GPS, qui ont des champs différents.
    -Stocker ces champs dans des variables de classe
    -utiliser des méthodes spécifiques à chaque trame sans savoir à l'avance quelle type de trame je récupère.

    Je pensais qu'en faisant appel à une méthode inconnue de la classe mere, celle-ci regarderait si ses filles ont la méthode demandée et l’appellerais.
    Cependant plus je réfléchi et plus cela est illogique. Comment la classe mere pourrait-elle faire un traitement quelconque sur une chose totalement inconnue d'elle ?

    Si vous avez une technique qui résolve mon problème et soit évolutive (possibilité d'ajouter des types de trame en ajoutant simplement la classe correspondante sans toucher au reste du code), je suis preneur.

    Le dynamic_cast a l'air de faire ce que je souhaite, mais n'a pas l'air d'être trop recommander. Qu'en pensez-vous ?

  4. #4
    Expert confirmé
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Février 2005
    Messages
    5 503
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Conseil

    Informations forums :
    Inscription : Février 2005
    Messages : 5 503
    Par défaut
    Comment la classe mere pourrait-elle faire un traitement quelconque sur une chose totalement inconnue d'elle ?
    Utilisation de typage dynamique, non disponible en C++ ou des mécanismes de dispatching évolués comme en Objective-C ou le late-binding COM.
    Mais rien avec du C++ de base.

    soit évolutive (possibilité d'ajouter des types de trame en ajoutant simplement la classe correspondante sans toucher au reste du code), je suis preneur.
    Evolutif selon quel axe ???
    Si vous utilisez les fonctionnalités des nouvelles classes dans du code client de ces classes, cela veut dire que vous devez modifier votre code client avec l'arrivé de nouvelle classe. Et ça, c'est un problème de conception à l'extérieur de la hiérarchie des classes.

    Le dynamic_cast a l'air de faire ce que je souhaite, mais n'a pas l'air d'être trop recommander. Qu'en pensez-vous ? .
    Pareil, c'est faisable, mais cela ne fera que masquer les erreurs de conception qu'il serait plus efficace de corriger à la source.

    -Décortiquer plusieurs types de trames GPS, qui ont des champs différents.
    -Stocker ces champs dans des variables de classe
    Je vous laisse regarder la littérature sur les différents Design Pattern de création (Factory Template, Factory Method, Builder, etc...)

    -utiliser des méthodes spécifiques à chaque trame sans savoir à l'avance quelle type de trame je récupère.
    C'est là qu'est l'erreur de conception, il faut concevoir le mode d'interaction entre le code client et la hiérarchie de classe.

  5. #5
    r0d
    r0d est déconnecté
    Membre expérimenté

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    4 294
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Août 2004
    Messages : 4 294
    Billets dans le blog
    2
    Par défaut
    Bonjour,

    l'erreur qui est faite ici est de considérer une classe comme un conteneur, et non comme un service. La présence de tous ces get et set symbolisent bien le problème.
    C++ n'est pas du C dans lequel on a injecté quelques mécanismes "orienté objet". C++ est un langage propre, qui a sa philosophie propre. Une des façons de voir cette philosophie consiste à considérer les objets en tant que services. C'est à dire que le but de l'objet n'est pas de contenir de l'information (même s'il peut en contenir, ce n'est pas son but final), mais d'effectuer une opération (un service).

    Prenons un exemple: on souhaite afficher une image à l'écran. La première approche consiste à déclarer une classe Image qui contient les points, et une fonction affiche() qui parcours les points de l'image et les affiche:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    struct Image
    {
       std::vector<Point> points;
    };
     
    void affiche(const Image & image)
    {
       foreach( /* point in image.points */ ) my_graphic_li.draw(point);
    }
    Cette façon de faire correspond à ce que vous essayez de faire dans votre code. Elle n'est pas bonne dans le contexte du c++ pour tout un tas de raison, notamment parce que C++ est un langage compilé qui n'a aucune information sur le code généré après la compilation, en particulier sur les types. Ainsi donc, dans l'exemple ci-dessus, si vous voulez changer quoi que ce soit (type de points, cible de l'affichage, bibliothèque utilisée, ...), il faut refaire tout le code.

    La bonne façon de faire est de ne pas considérer Image comme un objet qui contient des données, mais comme un objet qui rend un service, ici le service est l'affichage. Le code ci-dessus devient alors:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    struct Image
    {
       void Affiche(Context & context) { /*foreach .... context.draw_point(point) */ }
    private/protected:
       std::vector<Point> points;
    };
    La différence, qui parait subtile sur un si petit bout de code, est en fait cruciale: c'est l'objet qui s'occupe d'implémenter la fonctionnalité qui légitime son existence.
    Un des gros avantages de cette méthode, c'est que votre objet va définir une liste de services (ensemble des fonctions publiques), qu'on appelle l'interface. L'interface est un concept fondamental en poo, et si l'interface d'un objet est bien pensée, alors ça permet tout un tas de choses très pratiques, notamment la substituabilité (cf. LSP).
    Un avantage moins théorique, plus pratique, c'est qu'en c++, il est très difficile d'avoir des informations sur les types, mais en revanche on connait les interfaces des classes avant même la compilation. On laisse donc à chaque classe le soin (la responsabilité) de faire ce qu'elle a à faire.

  6. #6
    Membre averti
    Inscrit en
    Mars 2009
    Messages
    13
    Détails du profil
    Informations forums :
    Inscription : Mars 2009
    Messages : 13
    Par défaut
    r0d,

    Votre explication m'a permis de comprendre mon erreur. J'utilise bien mes classes pour stocker les données et j'essaye en fait d’utiliser l'interface comme un morceau de classe et de la "concaténer" à une autre. Quelque chose du genre classe mère+classe fille = classe complète, alors qu'une interface n'a l'air que d'être un sommaire des fonction disponibles (et obligatoires ?) que les classes filles doivent implémenter.
    Cela m'amène donc à la question suivante : si les données ne sont pas stockées dans les classes, où sont elles ?

    J'essaie de faire un programme qui décortique des trames GPS qui sont reçues sous ce format :
    $GPGGA,130303.00,4910.28659,N,00521.52083,E,1,07,1.06,207.9,M,46.7,M,,*51
    ou
    $GPVTG,,T,,M,0.064,N,0.118,K,A*29
    Ce sont donc des string à peu près inutilisables en tant que telles. Je souhaite donc pouvoir les découper et les organiser correctement en faisant des objets (type, latitude, longitude, heure, ...) regroupés dans une classe.

    Si je suis bien votre raisonnement, je devrais avoir une classe (singleton ?) qui effectue le découpage en fonction du type de trame (GPGAA, GPVTG, etc ...), mais ensuite, que faire des données ainsi recueillies ? Je dois bien pouvoir les stocker quelque part pour les exploiter ... Sous quelle forme représenter des données si le rôle des classes n'est que de fournir une service (formatage, transformation et vérification dans mon cas) et non de stocker les données.

    Les exemples fournis dans tous les livres montrent bien cette notion de service : le cheval hennit, le chat miaule, etc. Mais dans ce cas, pourquoi mettre des variables dans les classes (couleur, vitesse, ...) si elles ne sont pas faites pour stocker des données ? Représenter les données sous une forme exploitable n'est-il donc pas un service de "formatage" et de mise à disposition (d'où les get et set) ?

    Je ne remet pas en cause la justesse de votre commentaire, je cherche simplement à comprendre le fond et la forme de la POO.

    C'est décourageant, plus on gratte, plus on s'enfonce.

Discussions similaires

  1. Réponses: 7
    Dernier message: 03/02/2012, 17h15
  2. Appel d'une méthode d'une autre classe à partir d'un actionListener
    Par bisouJava dans le forum Débuter avec Java
    Réponses: 4
    Dernier message: 31/10/2011, 09h05
  3. Réponses: 4
    Dernier message: 22/11/2010, 14h15
  4. Réponses: 6
    Dernier message: 27/06/2010, 23h51
  5. [Interface] Appeller toutes les méthodes héritées d'un class
    Par thibaut.d dans le forum Général Java
    Réponses: 4
    Dernier message: 25/01/2005, 08h42

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