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 :

polymorphisme, héritage & co.


Sujet :

C++

  1. #1
    Membre averti
    Homme Profil pro
    [SciComp]
    Inscrit en
    Août 2013
    Messages
    134
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : [SciComp]

    Informations forums :
    Inscription : Août 2013
    Messages : 134
    Points : 323
    Points
    323
    Par défaut polymorphisme, héritage & co.
    Bonjour,

    J'ai un problème qui doit être conceptuel concernant l'héritage et le polymorphisme.

    J'ai défini une collection d'objects Ai Aj Ak qui héritent tous d'une classe mère A.
    La collection est stockée dans un vecteur de pointeurs sur A vector<A*> vect;.
    Le vecteur est sûr rempli en utilisant les constructeurs spécialisés, i.e. Ai, Aj, Ak (voire A).

    Chacune des classes possède une fonction spécialisée func (définie virtuelle) qui est propre à chaque type de classe.

    Aussi, dans mon programme, j'ai bien vérifié que la liaison dynamique fonctionne, c'est à dire que vect[i]->func() appelle bien A::func, Ai::func, Aj::func, ou Ak::func selon le type des instances parcourues.

    Mon problème: j'ai défini une fonction extérieure compare(A*,A*) afin de comparer les instances de mon vecteur.
    Cette fonction appelle ma fonction func. Mais quoiqu'il arrive, C++ n'arrive pas à faire la liaison dynamique vers les fonctions spécialisées, et appelle toujours A::func.
    Soit.
    J'ai tenté de surcharger compare avec tous les cas possibles :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    compare(A*,A*)
    compare(A*,Ai*)
    compare(A*,Aj*)
    compare(A*,Ak*)
    etc...
    Mais bien sûr cela ne fonctionne pas.

    Je vois bien que pour func, j'ai du déclarer la fonction virtual pour que les liaisons correctes se fassent, et que pour compare, je ne fait rien, donc je sens que mon problème est là. A moins que...

    Des indices ?

    Merci d'avance,
    xflr6

  2. #2
    Expert éminent sénior
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 630
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Analyste/ Programmeur

    Informations forums :
    Inscription : Juillet 2013
    Messages : 4 630
    Points : 10 556
    Points
    10 556
    Par défaut
    Est-tu sûr de ne pas toujours appeler compare(A*, A*)?

    Une petite trace et

    Édit 1: Une trace = cout ou printf.

    Édit 2: Merci pour le

  3. #3
    Membre averti
    Homme Profil pro
    [SciComp]
    Inscrit en
    Août 2013
    Messages
    134
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : [SciComp]

    Informations forums :
    Inscription : Août 2013
    Messages : 134
    Points : 323
    Points
    323
    Par défaut
    Merci de votre réponse.
    Si, si, techniquement, j'appelle toujours compare(A*, A*) car mon vecteur est un vecteur de pointeurs de type A (même si les instances qui sont dedans pointent vers les classes filles).
    Et c'est ce que j'aimerais faire, modulo que dans compare, j'aimerais faire comprendre au compilo que les méthodes à utiliser sont les méthodes spécialisées, et non pas la générique de la classe mère.
    Et sinon, une trace de quoi ???

  4. #4
    Membre averti
    Homme Profil pro
    [SciComp]
    Inscrit en
    Août 2013
    Messages
    134
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : [SciComp]

    Informations forums :
    Inscription : Août 2013
    Messages : 134
    Points : 323
    Points
    323
    Par défaut
    Pour l'edit 2, ce n'est pas mon vote. Ce n'est pas dans mes habitudes de critiquer les personnes qui me proposent leur aide.
    Concernant le reste, c'est effectivement mon problème qu'il passe (dans compare) dans A::func et pas dans les spécialisées filles (et ça, je l'avais vérifié par un cout, c'est même comme ça que je m'en suis aperçu).

  5. #5
    Membre expert
    Profil pro
    Inscrit en
    Mars 2007
    Messages
    1 415
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Mars 2007
    Messages : 1 415
    Points : 3 156
    Points
    3 156
    Par défaut
    Hello

    Je ne vais pas faire de débat sur l'utilité de comparer des objets de type réel différents, je suppose que ton use case le justifie. Avec les informations que tu donnes, cela devrait fonctionner. Est-ce que tu arrives à reproduire ton problème sur un code simplifié que tu pourrais poster ici ?
    Find me on github

  6. #6
    Membre averti
    Homme Profil pro
    [SciComp]
    Inscrit en
    Août 2013
    Messages
    134
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : [SciComp]

    Informations forums :
    Inscription : Août 2013
    Messages : 134
    Points : 323
    Points
    323
    Par défaut
    Effectivement, ce que j'ai dit devrait marcher (et ça marche). Il y a donc une différence entre ce que je fais et ce que j'ai dit.
    J'ai passé beaucoup de temps à tenter de comprendre pourquoi un programme simple fonctionnait et que mon programme ne fonctionnait pas.
    J'ai donc du censurer au maximum le programme pour limiter à la partie problématique. Effectivement je dois faire qque chose d'illégal mais je ne m'en sors pas.
    Voici le code concaténé :
    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
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    #include <string>
    #include <iostream>
    #include <vector>
     
    using namespace std;
     
    class a
    {
        protected:
        string type;
        public:
        a(string);
        string GetType();
        virtual void affiche();
        virtual bool compare(a*);
    };
    class ai : public a
    {
        protected:
        int dummy;
        public:
        ai(string,int);
        int GetDummy();
        virtual void affiche();
        virtual bool compare(ai*);
    };
     
    bool extcompare(a*, a*);
     
    a::a(string s) 
    { 
        this->type=s; 
    }
     
    string a::GetType()
    {
        return this->type;
    }
     
    void a::affiche() 
    { 
        cout << "a=  " << this->GetType() << endl;
    }
    bool a::compare(a* other) 
    {
        bool ok=true;
        if ( this->GetType() != other->GetType() ) ok=false;
        if ( this->GetType() != "mere" ) {ok=false; cout << "Shouldn't be there...   ";}
        cout << "In virtual bool a::compare(a*)   -   ok=" << ok << endl;
        return ok;
    }
     
    ai::ai(string s, int i) : a(s) 
    {
        this->dummy=i;
    }
     
    int ai::GetDummy()
    {
        return this->dummy;
    }
     
    void ai::affiche() 
    {
        cout << "ai= " << this->GetType() << " " << this->GetDummy() << endl;
    }
     
    bool ai::compare(ai* other) 
    {
        bool ok=true;
        if ( this->GetType()  != other->GetType()  ) ok=false;
        if ( this->GetDummy() != other->GetDummy() ) ok=false;
        cout << "In virtual bool ai::compare(ai*)    -    ok=" << ok << endl;
        return ok;
    }
     
    bool extcompare(a* a1, a* a2)
    {
        a1->affiche();
        a2->affiche();
        if ( a1->GetType() == a2->GetType() ) return a1->compare(a2); 
        return false;
    }
     
    int main()
    {
      vector<a*> vect;
      vect.push_back(new a("mere"));
      vect.push_back(new ai("fille",1));
      vect.push_back(new ai("fille",2));
      vect.push_back(new ai("fille",3));
      vect.push_back(new ai("fille",1));
      for (vector<a*>::iterator it1=vect.begin(); it1!=vect.end(); it1++ ) 
      {
          for (vector<a*>::iterator it2=vect.begin(); it2!=vect.end(); it2++ ) 
          {
              extcompare((*it1),(*it2));
          }
      }
      cout << endl;
      return 0;
    }
    Le pb: a chaque fois que le code passe par extcompare avec deux classes filles ai, il utilise la méthode a::compare à la place de ai::compare :-(, sachant que l'occurence (a*)->compare(ai*) ou inversement n'est jamais invoquée car protégée par la condition sur GetType dans extcompare.
    Merci de votre aide.

    Les fichiers avec le makefile en pièce jointe pour ceux qui veulent:
    Fichiers attachés Fichiers attachés

  7. #7
    Membre averti
    Homme Profil pro
    [SciComp]
    Inscrit en
    Août 2013
    Messages
    134
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : [SciComp]

    Informations forums :
    Inscription : Août 2013
    Messages : 134
    Points : 323
    Points
    323
    Par défaut
    Une réflexion: est-il possible de s'en sortir avec des pointeurs de fonctions ? Je pense qu'il y aurait toujours un problème avec les arguments pour distinguer les types des a::compare(a*) et ai::compare(ai*) je suppose (j'ai essayé, mais c'est ma première fois avec les pointeurs de fonctions... alors ça plus le fait que ce sont des méthodes de classes... j'avoue ne pas savoir).

  8. #8
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 115
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 115
    Points : 32 967
    Points
    32 967
    Billets dans le blog
    4
    Par défaut
    Pour l'appel d'une méthode c'est le type statique qui est utilisé.
    Ton vecteur contient des A*, que ce soit des Ai, Aj ou Atoto, ça reste des A statiquement.
    Pour "contrer" ça, faut faire du dispatch, mais ça me parait boiteux comme idée de vouloir faire du compare(A, Ai), et pourquoi pas compare(Ai,a), compare(Ai, Ai) .. ?
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  9. #9
    Membre averti
    Homme Profil pro
    [SciComp]
    Inscrit en
    Août 2013
    Messages
    134
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : [SciComp]

    Informations forums :
    Inscription : Août 2013
    Messages : 134
    Points : 323
    Points
    323
    Par défaut
    Edit: ps, le problème était mal cerné dans le premier post, sorry. c'est délimité correctement depuis l'exemple de code du post #6.

    Statique, ok, mais dans
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    bool extcompare(a* a1, a* a2)
    {
        a1->affiche();
        a2->affiche();
        if ( a1->GetType() == a2->GetType() ) return a1->compare(a2); 
        return false;
    }
    les [a,ai]::affiche() correspondantes sont appelées, en témoignent les 4 premiers outputs renvoyés par le programme:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    a=  mere
    a=  mere
    In virtual bool a::compare(a*)   -   ok=1
    a=  mere
    ai= fille 1
    a=  mere
    ai= fille 2
    a=  mere
    ai= fille 3
    où "a= " et "ai=" confirment caractère [a ou ai]::affiche(). Donc les liaisons dynamiques fonctionnent à plein. (sauf pour le cas compare qui m'intéresse, et qui nécessite un argument a*/ai*, je pense que c'est là le pb).
    Après, si par dispatch il me faut comprendre de mettre des conditions [if/switch/whatever] sur les types réels des classes, il n'en reste pas moins que vouloir refiler le bébé à une fonction externe comme extcompare va être coton:
    - le dispatching a lieu avant l'appel de extcompare, c'est le cas que je voulais éviter pour des raisons annexes.
    - le dispatching a lieu dans extcompare, et là, le compilo ne va pas être d'accord que je rentre des pointeurs de la classe mère (dénominateur commun) et que je fasse appel à des méthodes spécialisées, dans l'exemple, de ai.

    Vu que les liaisons dynamiques semblent fonctionner pour [a ou ai]::affiche(), je ne sais pas trop quoi en penser.

    ça me parait boiteux comme idée de vouloir faire du compare(A, Ai)
    Ne sont réellement comparés avec compare dans extcompare que des types réels identiques : if ( a1->GetType() == a2->GetType() ).

    Edit 3/08: Dans mon livre de chevet cette nuit je suis tombé sur les dynamic_cast. Avec ces derniers, serait-ce possible ?

  10. #10
    Membre expert
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2011
    Messages
    739
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

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

    Informations forums :
    Inscription : Juin 2011
    Messages : 739
    Points : 3 627
    Points
    3 627
    Par défaut
    Pas besoin de dynamic_cast ici, une simple fonction virtuelle suffit, mais pas comme tu le fais. Si la classe de base définit un compare(a*) alors la classe dérivée doit faire de même. En fait chaque classe dérivée devra le faire. Et comme dans la fonction compare le getType permet d'être sûr que le type est le même que celui de la classe utilisé, il suffit de caster le paramètre en celui de la classe. Si tu veux comparer des classes de types différents ça devient beaucoup plus compliquer (visiteur et multi/double dispath).

  11. #11
    Membre averti
    Homme Profil pro
    [SciComp]
    Inscrit en
    Août 2013
    Messages
    134
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : [SciComp]

    Informations forums :
    Inscription : Août 2013
    Messages : 134
    Points : 323
    Points
    323
    Par défaut
    il suffit de caster le paramètre en celui de la classe
    Que me faut-il comprendre ici ? Il me faut donc faire qque chose de spécial ?

    Mon problème si je déclare compare comme ai::compare(a*), c'est que si dans ce dernier il y a un appel à un argument extérieur à a (par exemple une méthode spécialisée de ai non présente dans a) alors le compilo ne veut pas, et je le comprends. Si je déclare en surcharge un ai::compare(a*) et un ai::compare(ai*) alors c'est toujours le ai::compare(a*) qui est appelé. Alors que lorsque j'arrive à a1->compare(a2), il est certain que les types réels sont identiques (a*,a* ou ai*,ai*).

  12. #12
    Membre expert
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2011
    Messages
    739
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

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

    Informations forums :
    Inscription : Juin 2011
    Messages : 739
    Points : 3 627
    Points
    3 627
    Par défaut
    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
    #include <iostream>
    #include <string>
     
    class A {
      std::string type;
     
    protected:
      A(std::string t)
      : type(std::move(t))
      {}
     
      bool sameType(A const & other) const
      { return other.type == type; }
     
    public:
      A()
      : type("A")
      {}
     
      virtual ~A()
      {}
     
      virtual bool compare(A const & a) const
      { return (type == a.type); }
    };
     
    class A1 : public A {
      int n;
     
    public:
      A1(int x)
      : A("A1")
      , n(x)
      {}
     
      virtual bool compare(A const & a) const
      {
        if (sameType(a)) {
          return static_cast<const A1&>(a).n == n;
        }
        return false;
      }
    };
     
    int main()
    {
      A1 a1_1(1);
      A1 a1_2(2);
     
      A a0;
      A& a1 = a1_1;
      A& a2 = a1_2;
     
      std::cout << "       A  A1(1)  A1(2)\n";
      std::cout << "A      " << a0.compare(a0) << "    " << a0.compare(a1) << "      " << a0.compare(a2) << '\n';
      std::cout << "A1(1)  " << a1.compare(a0) << "    " << a1.compare(a1) << "      " << a1.compare(a2) << '\n';
      std::cout << "A1(2)  " << a2.compare(a0) << "    " << a2.compare(a1) << "      " << a2.compare(a2) << '\n';
    }

  13. #13
    Membre averti
    Homme Profil pro
    [SciComp]
    Inscrit en
    Août 2013
    Messages
    134
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : [SciComp]

    Informations forums :
    Inscription : Août 2013
    Messages : 134
    Points : 323
    Points
    323
    Par défaut
    Perfect. Thanks. A très peu de frais en plus.
    redéfinition de ai::compare(a*) et cast de other dans if ( this->GetDummy() != static_cast<ai*>(other)->GetDummy() ) ok=false;.

    Merci beaucoup !

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 19
    Dernier message: 05/06/2007, 08h13
  2. polymorphisme d' héritage
    Par loacast dans le forum C++
    Réponses: 3
    Dernier message: 30/01/2007, 11h13
  3. [Héritage] [Polymorphisme] Question de débutant ?
    Par TSnarfK dans le forum Langage
    Réponses: 9
    Dernier message: 12/09/2006, 15h39
  4. [Héritage] Question sur le polymorphisme
    Par nikhil dans le forum C++
    Réponses: 7
    Dernier message: 28/12/2005, 20h33
  5. Réponses: 2
    Dernier message: 25/07/2004, 23h24

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