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 :

Problème de redéfinition d'une fonction virtuelle avec un type d'argument différent


Sujet :

C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Nouveau membre du Club
    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2004
    Messages
    4
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France

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

    Informations forums :
    Inscription : Avril 2004
    Messages : 4
    Par défaut Problème de redéfinition d'une fonction virtuelle avec un type d'argument différent
    Bonjour,
    Je voudrais savoir si d'une manière ou d'une autre, il est possible d'avoir une fonction membre virtual d'une classe mère qui serait redéfinie dans les classes filles mais avec un type d'argument différent!
    Je m'explique : mon programme est une application qui communique via des sockets avec plusieurs autres applications. J'ai donc créé une classe A (classe mère) qui représente globalement un correspondant pour mon appli, et des classe filles B, C, et D qui représentent chacune spécifiquement un de mes correspondants. Chaque fois que je reçois un "message" de l'un de ces correspondants, je dois faire un traitement spécifique derrière, donc j'ai une méthode de la classe mère "traiterMessage(TypeMessage &message)" implémentée dans chaque classe fille. Le problème, c'est que tous ces correspondants ne communiquent pas avec mon appli avec le même protocole, donc le type même de message reçu est différent (et la classe qui représente mon objet message).
    Or, mon appli ayant une interface serveur, elle ne sait pas au moment où elle reçoit le message de qui il provient.
    Un bout de code pour l'exemple :

    Dans mon .h :

    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
    class Protocole1
    {}
     
    class A
    {
        virtual void traiterMessage(Protocole1 &message)=0;
    }
     
    class B : public A
    {
        void traiterMessage(Protocole1 &message);
    }
     
    class C : public A
    {
        void traiterMessage(Protocole1 &message);
    }
     
     
    class D : public A
    {
       void traiterMessage(Protocole2 &message);
    }
    Et dans mon .cpp, j'ai 2 serveurs, pour les 2 protocoles différents, donc le premier j'ai :

    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
    Serveur1::donneesrecues()
    {
       A* monCorrespondant;
       Protocole1 message;
     
       ......
       moncorrespondant->traiterMessage(message); 
    }
     
     
    Serveur2::donneesrecues()
    {
       A* monCorrespondant;
       Protocole2 message;
     
       ...
     
      monCorrespondant->traiterMessage(message);
    }
    Voila, je ne sais pas si c'est tres clair, enfin toujours est it que ca ne compile pas puisque la méthode traiterMessage(Protocole1) n'est pas implémentée pour une des classe filles (la classe D).
    Je me demandais donc si il y avait de faire cela "proprement", sans etre obligée de définir directement dans la classe mère 2 méthodes :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    traiterMessage(Protocole1)
    traiterMessage(Protocole2)
    Merci!

  2. #2
    Membre émérite

    Profil pro
    Inscrit en
    Décembre 2008
    Messages
    533
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2008
    Messages : 533
    Par défaut
    Déclare une classe abstraite BaseProtocole que tu utilises comme paramètre dans A.
    Puis dérive Protocole1/2/3 de BaseProtocole et utilise-les respectivement dans B/C/D::donneesrecues().

    Il y aura probablement un ProtocoleN* ptr = dynamic_cast<ProtocoleN>(ptrInstanceBaseProto); à caser quelque part.

  3. #3
    Membre éclairé
    Avatar de Kalite
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Octobre 2006
    Messages
    310
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Octobre 2006
    Messages : 310
    Par défaut
    Citation Envoyé par cob59 Voir le message
    Il y aura probablement un ProtocoleN* ptr = dynamic_cast<ProtocoleN>(ptrInstanceBaseProto); à caser quelque part.
    Si tu peut evite le dynamic_cast c'est moche. Si ta classe de base est bien concue tu peut utiliser le polymorphisme.

  4. #4
    Membre chevronné

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juin 2007
    Messages
    373
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Royaume-Uni

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

    Informations forums :
    Inscription : Juin 2007
    Messages : 373
    Par défaut
    dynamic_cast n'est pas moche en soi, ça dépend comment on s'en sert.
    Prendre un pointeur et faire un dynamic_cast sur toutes les classes filles possibles pour implémenter différents comportements, ça c'est moche.

    Mais dans ce cas précis, on sait avec quel type de protocole on veut travailler, et on se trimbale un pointeur sur la classe mère pour un soucis d'interfaçage. Si le dynamic_cast échoue, alors l'utilisateur a fourni un mauvais protocole et on peut quitter la fonction, sinon on a directement un pointeur sur le bon protocole.

  5. #5
    Membre Expert

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Août 2004
    Messages
    1 391
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Doubs (Franche Comté)

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

    Informations forums :
    Inscription : Août 2004
    Messages : 1 391
    Par défaut
    Bonsoir,

    Personnelement je ferais ca sous forme d'un visiteur, quelque chose comme :
    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
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
     
    //Class de bases pour implémenter un visiteur acyclique
    struct Protocol
    { virtual ~Protocol(){} };
     
    struct A
    {
      virtual void recieved(Protocol&) =0; 
    };
     
     
    //Un premier type de correspondant et une classe de procole associée
    struct B : A
    { void recieved(Protocol&); };
     
    struct ProtocolB : Protocol
    { virtual void process(B&) =0; };
     
    void B::recieved(Protocol& m)
    {
      if ( ProtocolB* p = dynamic_cast<ProtocolB*>(&m) )
        p->process(*this);
      //Si le protocole ne peut être traiter
      //Ne rien faire
    }
     
     
    //Un second
    struct C : A
    { void recieved(Protocol&); };
     
    struct ProtocolC : Protocol
    { virtual void process(C&) =0; };
     
    void C::recieved(Protocol& m)
    {
      if ( ProtocolC* p = dynamic_cast<ProtocolC*>(&m) )
        p->process(*this);
      //Idem
    }
     
     
    //Un premier procole dédié aux correspondant de type B
    struct Protocol1 : ProtocolB
    {
      void process(B&)
      { /*implémentation*/ }
    };
     
    //Un deuxième pour les correspondant de type C
    struct Protocol2 : ProtocolC
    {
      void process(C&)
      { /*implémentation*/ }
    };
     
    //Un protocole qui fonctionne pour les deux
    struct Protocol3 : ProtocolB, ProtocolC
    {
      void process(B&)
      { /*implémentation*/ }
      void process(C&)
      { /*implémentation*/ }
    };
    (compile mais est lacunaire)

  6. #6
    Membre éclairé
    Avatar de Kalite
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Octobre 2006
    Messages
    310
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Octobre 2006
    Messages : 310
    Par défaut
    Citation Envoyé par Kalith Voir le message
    dynamic_cast n'est pas moche en soi, ça dépend comment on s'en sert.
    Prendre un pointeur et faire un dynamic_cast sur toutes les classes filles possibles pour implémenter différents comportements, ça c'est moche.

    Mais dans ce cas précis, on sait avec quel type de protocole on veut travailler, et on se trimbale un pointeur sur la classe mère pour un soucis d'interfaçage. Si le dynamic_cast échoue, alors l'utilisateur a fourni un mauvais protocole et on peut quitter la fonction, sinon on a directement un pointeur sur le bon protocole.
    Le fait de devoir faire cast dans le bon type indique que tu a fait une "mauvaise conception". Tu ne devrait pas avoir besoin de connaitre le type de l'objet. Seul l'objet connait son type et sait ce qu'il doit faire.

    Si tu fait du debug c'est toujours intéréssant mais dans le cas contraire il faut te poser une question sur ton interface de base dans laquelle il doit manqué quelque chose.

  7. #7
    Membre chevronné

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juin 2007
    Messages
    373
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Royaume-Uni

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

    Informations forums :
    Inscription : Juin 2007
    Messages : 373
    Par défaut
    Citation Envoyé par Kalite Voir le message
    Seul l'objet connait son type et sait ce qu'il doit faire.
    Oui, sauf que là tu te trouves dans une situation où il y a interaction (si l'on peut dire) entre deux objets, le protocole et le serveur. Si le comportement de l'un et de l'autre se borne (ou peut se résumer de manière logique) à redéfinir des fonctions virtuelles des classes de bases, alors tu n'as aucun problème. Sinon il faut obligatoirement, à un moment où un autre, que tu saches explicitement quels sont les types réellement mis en jeu.

    La première option c'est de déterminer le type du protocole dans la classe de serveur, la seconde à l'opposé et comme l'a décrit Flob90, c'est de déterminer le type de serveur dans une fonction du protocole.

    Si le dynamic_cast te pose vraiment un problème, imagine alors plutôt quelque chose du style :
    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
    45
    46
    47
    48
    49
    50
    51
    struct Protocol
    {
        enum Type
        {
            HTTP,
            HTTPS,
            FTP,
            ...
        } type;
     
     
        void* data; // ça c'est moche, il a moyen de faire plus propre 
        uint  size; // (type erasure, etc), mais c'est pour l'exemple
    };
     
    class Serveur
    {
    public :
     
        Serveur();
        virtual ~Serveur();
     
        virtual void traiterMessage(const Protocol& p) = 0;
        ...
    };
     
    class ServeurA : public Serveur
    {
    public :
     
        void traiterMessage(const Protocol& p)
        {
            if (p.type == Protocol::HTTP || p.type == Protocol::HTTPS)
            {
                ...
            }
        }
    };
     
    class ServeurB : public Serveur
    {
    public :
     
        void traiterMessage(const Protocol& p)
        {
            if (p.type == Protocol::FTP)
            {
                ...
            }
        }
    };
    Le principe est le même, mais on n'utilise pas de dynamic_cast

Discussions similaires

  1. Probléme d'appel d'une fonction avec EF
    Par kaka83185 dans le forum Accès aux données
    Réponses: 6
    Dernier message: 03/05/2012, 10h27
  2. Limiter la redéfinition d'une fonction virtuelle ?
    Par N0vember dans le forum Débuter
    Réponses: 5
    Dernier message: 30/11/2009, 09h58
  3. Réponses: 2
    Dernier message: 02/10/2008, 16h37
  4. Réponses: 7
    Dernier message: 05/05/2006, 09h48
  5. Creation d'une fonction temporaire avec droit datareader
    Par Bjuice2 dans le forum MS SQL Server
    Réponses: 5
    Dernier message: 26/10/2004, 14h26

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