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 et paramètres


Sujet :

C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    r0d
    r0d est déconnecté
    Membre expérimenté

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    4 290
    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 290
    Billets dans le blog
    2
    Par défaut héritage et paramètres
    Bonjour à tou-te-s,

    j'ai une petite question assez générique de conception, mais je cherche une solution en c++.

    Soit une classe mere M, et plusieurs classes fille F1, F2, etc... qui héritent de M.
    La classe M a une fonction virtuelle (pure ou pas, cela n'a - je crois - pas d'importance ici) qui va être surchargée/implémentée par les classes filles.
    Le problème est que chaque classe fille nécessite des paramètres de nature différentes pour effectuer cette fonction.
    L'idée étant que cette fonction va effectuer la même action (contrat) dans chaque classe fille; mais selon la nature de chaque classe, pour effectuer cette action, on aura besoin de paramètres différents.

    Un exemple concret:
    Prenons une classe IMessage (I pour interface), qui déclare une fonction Send( const std::string& text ).
    Prenons deux classe, Mail et Sms, qui héritent de IMessage.
    Pour la classe Mail, il va lui falloir une adresse mail, l'adresse d'un serveur STMP avec des données de connections etc. pour pouvoir effectuer la fonctionalité Send(); alors que pour la classe Sms, elle va avoir besoin juste d'un numéro de téléphone.

    Quelle est la solution la plus générique pour résoudre ce problème?

  2. #2
    Membre chevronné Avatar de Lavock
    Profil pro
    Inscrit en
    Octobre 2009
    Messages
    560
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2009
    Messages : 560
    Par défaut
    Bonjour,
    Il y a toujours moyen de passer par vector de boost.any... mais cela me semble bancale.

    En générale, je limite ce genre de truc au constructeur/factory.

    Pourquoi ? Parce que si tu fais des appelles différent, c'est que quelque part (en générale), tu sais à qu'elle implémentation tu as à faire. Au quel cas, la maintenance est aussi difficile que si tu fais un dynamic_cast.

    Après, il y a le cas ou tu ne connais pas non plus le type des arguments. Dans se cas, j'ai tendance a dissocié les deux (ce que je connais, et ce que je connais pas), en faisant par exemple deux méthodes : une setup(vector<any>) (ou un truc du genre), qui renvoie une référence vers this et l'autre. Mais je dois dire que c'est plus instinctif qu'autre chose !

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

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    4 290
    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 290
    Billets dans le blog
    2
    Par défaut
    Ha, j'ai oublié de dire que je n'ai pas droit à boost, ni aux quelques fonctionalités du c++0x implémentées dans quelques (bons) compilateurs.

    Sinon j'aurais utilisé la inplace_factory de boost.

    En fait, concrètement, mon problème c'est que je vais devoir implémenter beaucoup de ces classes filles, avec plusieurs niveaux d'héritage (bon, ça ne sera pas moi qui vais les implémenter mais ça ne change rien au problème). Je cherche donc un mécanisme qui permette d'implémenter ces classes filles "à la chaîne" sans se poser de questions.

  4. #4
    Membre chevronné Avatar de Lavock
    Profil pro
    Inscrit en
    Octobre 2009
    Messages
    560
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2009
    Messages : 560
    Par défaut
    Ben là, à part réimplementer un boost.any-like, il te reste l'ellipse :/...

    Sinon, tu peux toujours passer par des chaines de caractères, ou ce genre de truc...

    En faite, ce que je comprend pas trop, c'est pourquoi tu as besoins d'une fonction virtuel, disons le franchement, elliptique. Quel gus va s'amuser à manipuler ta classe de base et la dite méthode sans connaître ce qu'il lui passe ?

    Si c'est une factory, cf. première ligne... En faite, je sais pas si tu as le même "problème" que moi, mais je cherche à faire une factory dans le même genre ou nul part j'aurais besoin d'initialiser les classes filles.

    Dans un autre fil, on m'avais conseillé de ragarder du coté de l'abstract factory de Loki >< ! (J'ai pas encore eu le temps de le faire -_-'...)

  5. #5
    Inactif  
    Avatar de Mac LAK
    Profil pro
    Inscrit en
    Octobre 2004
    Messages
    3 893
    Détails du profil
    Informations personnelles :
    Âge : 51
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Octobre 2004
    Messages : 3 893
    Par défaut
    Citation Envoyé par r0d Voir le message
    Quelle est la solution la plus générique pour résoudre ce problème?
    Il y a pas mal de solutions à ce problème... En vrac :
    • Ne pas utiliser de méthodes virtuelles, mais redéfinir dans chaque classe fille un "Send" particulier.

      Problème : Impose de savoir quelle classe fille on utilise pour avoir le "bon" Send, donc avoir le RTTI ou un équivalent, et ça empêche l'envoi polymorphique.

    • Conserver des paramètres identiques MAIS qui seront alors des objets spécifiques (passés par polymorphisme), la classe mère pouvant être "maison" ou hérité d'une classe générique quelconque de ta librairie préférée.
      Ainsi, ton prototype est identique à chaque fois, tout en utilisant des données différentes. Chaque classe fille saura comment upcaster le paramètre, et donc comment le décoder.

      Problème : Requiert le RTTI, bien sûr, ce qui peut parfois poser des soucis.

    • Avoir une ellipse dans ton prototype, qui sera interprétée au niveau des classes filles.

      Problème : Tu peux oublier les aides à la complétion et autres assistances de l'IDE...

    • Rajouter un paramètre "const std::string configuration" à ton prototype initial de Send, et le désérialiser de façon spécifique dans les classes filles : chaque classe saura comment analyser son contenu.

      Par exemple, ta classe SMS attendra un numéro de téléphone, soit au format international, soit au format national. Si c'est autre chose, elle gueule.

      Ta classe SMTP, par contre, va par exemple attendre comme paramètres l'adresse mail, un serveur SMTP et un objet, séparés par un espace par exemple. Tu peux même le rendre plus ou moins tolérant à l'ordre des paramètres.

      Problème : Il faudra bien documenter le format de cette chaîne de configuration, car tu n'auras pas plus d'aide à la complétion qu'avec la méthode précédente.


    Il y a encore d'autres méthodes possibles, mais qui vont en partie dépendre de la manière dont tu vas utiliser ces classes et de leur nombre... Donc, des méthodes forcément moins génériques que les trois précitées.
    Mac LAK.
    ___________________________________________________
    Ne prenez pas la vie trop au sérieux, de toutes façons, vous n'en sortirez pas vivant.

    Sources et composants Delphi sur mon site, L'antre du Lak.
    Pas de question technique par MP : posez-la dans un nouveau sujet, sur le forum adéquat.

    Rejoignez-nous sur : Serveur de fichiers [NAS] Le Tableau de bord projets Le groupe de travail ICMO

  6. #6
    Membre Expert
    Avatar de Goten
    Profil pro
    Inscrit en
    Juillet 2008
    Messages
    1 580
    Détails du profil
    Informations personnelles :
    Âge : 34
    Localisation : France

    Informations forums :
    Inscription : Juillet 2008
    Messages : 1 580
    Par défaut
    ellipse + std::string ... ouch ><.
    Ce que je comprends pas c'est le besoin au final puisque quand tu vas envoyer un SMS, tu sais que tu envoies un sms, puisque tu dois passer les bons arguments, tu connais donc la classe, donc je vois pas l'intérêt de la virtualité là...

    Pour l'abstract factory c'est moi qui te l'avais conseillé, mais le besoin est différent, c'est celui de devoir créer des objets au runtime sans connaitre leur type à la compilation et/ou en ayant le type sous une forme non C++ienne. (string, fichier etc)

  7. #7
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Salut,

    Pourquoi ne pas envisager le double dispatch, basé sur deux hiérarchies de classes "parallèles" (une pour les message, l'autre pour l'envoi):
    class IMessageSender
    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
    37
    38
    39
    40
    41
    42
    43
    44
    {
        public:
            void send(Message const & m)
            {
                 m.accept(this);
            }
    };
    class MailSender : public IMessageSender
    {
        public:
            void sendMail(Mail const & m)
            {
                /*...*/
            }
    };
    class SMSSender : public IMessageSender
    {
        public:
            void sendSMS(SMS const & s)
            {
                /*...*/
            }
    };
    class Message
    {
        public:
            virtual void accept(IMessageSender * ) const = 0;
    };
    class Mail : public Message
    {
        public:
            virtual void accept(IMessageSender * ptr) const
            {
                static_cast<MailSender *>(ptr)->sendMail(*this); 
            }
    };
    class SMS : public Message
    {
        public:
            virtual void accept(IMessageSender * ptr) const
            {
                static_cast<SMSSender *>(ptr)->sendSMS(*this); 
            }
    };
    "simple et efficace", non
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

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

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    4 290
    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 290
    Billets dans le blog
    2
    Par défaut
    Qu'est-ce que vous appelez une ellipse?

    Sinon, pour répondre un peu à vos questions, j'ai deux contraintes:
    - permettre à ceux qui vont implémenter les classes filles de le faire le plus simplement possible sans avoir à toucher le reste du code (donc sans modifier la classe mère) et sans avoir même à y réfléchir (ce sont des développeurs débutants qui vont le faire, et on a pas le temps de réviser leur code).
    - permettre, autant que faire se peut, une utilisation "sérialisée" de ces classes filles.

    Pour le moment, voilà où j'en suis de mon design:
    - j'ai un conteneur qui contient des instances (sous forme de pointeurs, pour le polymorphisme) de ces classes filles.

    Le principal problème est que je ne sais pas, aujourd'hui, quels sont les paramètres dont auront besoin les classes filles qui seront implémentées demain.

    @koala: ça à l'air très bien ta solution, seulement... je comprends pô


    Sinon j'avais pensé à un solution qui ressemblerait à ceci (continuons avec mon exemple de Mail/SMS):
    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
    struct IParam{};
     
    class IMessage
    {
        public: virtual void Send( const std::string & message, const IParam * param ) = 0;
    };
     
    struct SMS_Param : public IParam {
        std::string num_tel;
    };
     
    class SMS : public IMessage
    {
        public: void Send( const std::string & message, const IParam* param )
        {
            DoSomething( reinterpret_cast<SMS_Param*>( param ) );
        }
    };
     
    // etc.
    En français: pour chaque nouvelle classe qui hérite de IMessage, je dois déclarer une structure qui hérite de IParam. Dans ma fonction Send, je vais recevoir ce param, que je vais caster comme il faut pour pouvoir l'utiliser.

    Mais, ceci ne resous pas mon problème qui est que je ne peux pas, aujourd'hui, construire ces XxxParams (qui héritent de IParam), alors qu'ils n'existent pas encore. Il faudrait qu'il se construisent eux-même...

    Pinaise... je me demande si c'est seulement possible ce que je suis en train d'essayer de faire...

  9. #9
    Membre chevronné Avatar de Lavock
    Profil pro
    Inscrit en
    Octobre 2009
    Messages
    560
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2009
    Messages : 560
    Par défaut
    Maintenant que tu as écris se bout de code, je viens de pensée a un des miens >< !

    J'ai fait comme tu l'as dit au dessus, et j'ai rajouter dans l'interface une méthode
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    IParam * configure();
    Au quel je donnais des truc assez génériques. Mais j'ai l'impression que dans ton cas c'est un peu le serpent qui se mort la queue...

    Mais sinon, question qui peut débloquer, d'ou vienne tes paramètres ?

    Sinon, l'ellipse, n'est stdarg, va_list, ..., etc.

    Pour le multi-dispatch, ça me semble bien gallère si tu as plein-de-fille-possible oO !

  10. #10
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Citation Envoyé par r0d Voir le message
    @koala: ça à l'air très bien ta solution, seulement... je comprends pô
    Te connaissant, tu dois être ou bien très distrait aujourd'hui et pas du tout à ce que tu fais, ou bien très fatigué

    Je reprend donc la réflexion depuis le début:

    Tu as à gérer différents types de messages, qui, tous, sont définis selon plusieurs informations propres (une chaine de caractères et un numéro de téléphone pour l'un, une chaine de caractère et une adresse IP pour l'autre, je ne sais quoi )

    Chaque type de message devra, fatalement, être géré par un système d'envoi "particulier".

    Ce que je te propose est de séparer la responsabilité du maintien en mémoire des différentes informations et celle de l'envoi du message, sachant qu'à chaque type de message correspondra
    • une structure de données à manipuler
    • une classe s'occupant d'effecteur le traitement correspondant à l'envoi

    Ainsi, tu aurais, pour envoyer un SMS, un "expéditeur de SMS" et une structure contenant... les informations propres, et, de même, pour envoyer un e-mail, tu aurais un expéditeur d'e-mail et... les informations nécessaires pour y arriver.

    L'expéditeur de SMS et l'expéditeur d'e-mail (et tous les autres ) sont autant "d'expéditeurs" et, à ce titre, ils héritent de la classe IMessageSender, et disposent donc de la fonction send qui prend en argument... l'information à transmettre.

    De la même manière les différentes structures regroupant les informations à expédier héritent d'une classe de base "Message" (que l'on pourrait renommer en "MessageInfo" ).

    A ce titre, elles exposent une méthode (virtuelle pure dans Message) accept qui prend en argument un pointeur (ou une référence) sur... l'expéditeur et qui est réimplémentée en fonction de l'information afin d'appeler explicitement... le comportement de l'expéditeur particulier (par exemple de l'expéditeur de SMS) qui permettra... de gérer l'information.

    Tu as donc:
    1. IMessageSender: classe de base des expéditeurs et présentant une fonction "sendMessage", dérivée en
      • SMSSender: classe permettant d'envoyer des SMS et présentant une fonction sendSMS
      • MailSender : classe permettant d'envoyer des e-mail et présentant une fonction sendMail
      • MMSSender : classe permettant d'envoyer des MMS et présentant une fonction sentMMS
      • ...
    2. Message (ou MessageInfo): classe de base des information présentant une fonction virtuelle pure "accept", dérivée en
      • MailInfo : classe disposant des informations propres aux E-mail, réimplémentant accept qui converti le IMessageSender en... MailSender, pour appeler la fonction sendMAil
      • SMSInfo :classe disposant des informations propres aux SMS, réimplémentant accept qui converti le IMessageSender en... SMSSender, pour appeler la fonction sendSMS
      • MMSInfo :classe disposant des informations propres aux MMS, réimplémentant accept qui converti le IMessageSender en... MMSSender, pour appeler la fonction sendMMS
      • ...
    Cela te parait il plus clair
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

Discussions similaires

  1. [POO/Template] Héritage de paramètre template.
    Par méphistopheles dans le forum Langage
    Réponses: 9
    Dernier message: 18/11/2008, 18h02
  2. Héritage de paramètres par défaut
    Par FunkyTech dans le forum C++
    Réponses: 3
    Dernier message: 31/01/2008, 17h36
  3. paramètre ... et héritage
    Par kinta dans le forum C++
    Réponses: 8
    Dernier message: 23/02/2006, 22h22
  4. Réponses: 7
    Dernier message: 30/09/2004, 12h55

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