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 :

Vérifier à quelle classe appartient un objet issu d'une classe héritée


Sujet :

C++

  1. #1
    Nouveau membre du Club
    Inscrit en
    Août 2007
    Messages
    43
    Détails du profil
    Informations forums :
    Inscription : Août 2007
    Messages : 43
    Points : 31
    Points
    31
    Par défaut Vérifier à quelle classe appartient un objet issu d'une classe héritée
    Bonjour,

    Voici mon problème :
    J'ai une classe A et une classe B qui dérive de A.

    Je souhaite vérifier que B est bien de type A, comment dois-je faire ?

    J'ai trouver quelques info sur typeid, mais ça ne me donne pas le résultat que je souhaite car l'exécution de ces lignes:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    B *b=new B();
    cout << typeid(b).name() << endl;
    me renvoie "B" comme résultat, mais moi, je souhaite savoir si b est bien de type A ou pas.

    Ainsi, quand je fais :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    if(typeid(b) == typeid(A*)){
    ...
    }
    l'exécution ne rentre pas dans la condition (enfin si je me souviens bien...)

    Habitué à faire du Java, l'utilisation de "instanceof" me renvoyait le résultat que je souhaitais, mais là, je ne vois pas trop...

    Merci pour votre aide.

  2. #2
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Salut,

    Si tu as une relation d'héritage, tu peux avoir la certitude que tout objet de type dérivé est, également, un objet du type de la classe de base.

    Contrairement à java, tu n'as pas un héritage "caché" avec un quelconque "super objet"

    De la même manière, si tu essaye de passer (une référence ou un pointeur sur) un objet de la classe de base à une fonction, le compilateur se plaindra si, d'aventure, tu essaye de passer autre chose qu'une des classes entrant dans la hiérarchie de classe
    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

  3. #3
    Nouveau membre du Club
    Inscrit en
    Août 2007
    Messages
    43
    Détails du profil
    Informations forums :
    Inscription : Août 2007
    Messages : 43
    Points : 31
    Points
    31
    Par défaut
    Bonsoir et merci pour la réponse.

    Néanmoins, je ne suis pas sûr d'avoir compris exactement votre première phrase (ou du moins, je me suis mal fait comprendre dans mon premier message).

    Pour être plus clair, supposons que j'ai 4 classes maintenant : A, B, C et D. B et C dérivent de A. D ne dérive de rien.

    En fait, dans mon code, je souhaiterais vérifier si un objet est bien de type A pour ensuite y faire des opérations. Je me permets d'écrire le code en Java, étant donné que je ne sais pas comment faire en C++...

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    ArrayList<Object> obj=new ArrayList();
    A a=new A(); obj.add(a);
    B b=new B(); obj.add(b);
    C c=new C(); obj.add(c);
    D d=new D(); obj.add(d);
     
    for(Object o : obj) { //On itère sur la liste obj
       if(o instanceof A)
          // Ici, on traite tous les objets de type A, B ou C
       else
          //Ici, on traite les objets de type D
    }
    Maintenant du côté C++, comme typeid(b).name() me donne "B", j'ai l'impression que mon code ne marche pas... A moins que si, en fait ?

  4. #4
    zul
    zul est déconnecté
    Membre éclairé Avatar de zul
    Profil pro
    Inscrit en
    Juin 2002
    Messages
    498
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2002
    Messages : 498
    Points : 699
    Points
    699
    Par défaut
    Tu ne peux pas faire ça "directement" en C++. Comme l'a dit koala, il n'y a pas naturellement de notion de "super-objet" en C++, tu ne peux donc pas créer un tableau de super objet pour mettre n'importe quels objets dedans (et faire ce que ton code java fait).

    La question qu'on peut se poser, c'est pourquoi tu as besoin de ranger des choses sans aucun lien dans un seul conteneur ? Quel lien logique tous ces objets ont-il pour être managé par cette collection ? Quel est le problème que tu essaye de résoudre réellement ?

    Si vraiment il n'y a pas d'autre moyen de faire que ce que tu propose, tu peux t'en sortir via plusieurs moyens en C++, entre autre en utilisant boost::variant (si tu connais les différents types que peut contenir le conteneur) (tu utilisera alors un visitor pour agir dans les différents "types" possibles) ou boost::any (si ça peut être divers et varié) (et là il faut utiliser any_cast pour checker les types). De manière général, essayer de coder en C++ comme on code en Java est souvent contre productif.

    EDIT:
    pour savoir si un objet dérive de A, tu peux faire un dynamic_cast et vérifier la valeur de retour. Mais tu ne peux quan dmême pas stocker des B et des D dans le même vecteur.

  5. #5
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    En java, toute classe dérive implicitement de Object, ce qui fait que, même si tu as un code proche de
    Code java : 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
    public class A
    {
        /*...*/
    };
    pubic class B extend A
    {
        /*...*/
    };
    public class C extend A
    {
        /*...*/
    };
    public class D
    {
        /*...*/
    };
    bien que tu ne l'ai pas explicitement dit, A hérite de Object et D, qui n'a rien à voir avec A, hérite également de Object.

    Le résultat est que tu peux donc envisager (et c'est d'ailleurs peu recommandé, même en java) de faire cohabiter, dans une même collection des A, des B, des C et des D en les faisant passer pour des... Object.

    En C++, il n'y a pas cet héritage implicite venant de Object.

    Si on traduit le code précédent en C++, cela donne
    Code C++ : 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
    class A
    {
        /*...*/
    };
    class B : public A
    {
        /*...*/
    };
    class C : public A
    {
        /*...*/
    };
    class D
    {
        /*...*/
    };
    Et tu n'a aucun lien entre A (ou B ou C) et D.

    Tu peux donc faire cohabiter des A, des B et des C dans une même collection en les faisant passer pour ... des A, mais tu ne pourra jamais placer un D dans cette collection:
    Code C++ : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    int main()
    {
        std::vector<A*> tab; // un tableau de pointeur sur A
        tab.push_back( new A); // pas de problème: c'est bien un A
        tab.push_back( new B); // pas de problème : un B peut bien passer pour
                               // un A
        tab.push_back( new C); // pas de problème : un C peut bien passer pour
                               // un A
        /* tab.push_back( new D); !!! impossible : D ne peut en aucun cas passer
                                 !!! pour un D
         */
    }
    Si tu décommente tab.push_back( new D);, le compilateur t'enverra "sur les roses" en te disant qu'il est incapable de transformer un D* en un A*

    C'est, quelque part, beaucoup plus logique qu'en java, car, si on remplace A par "véhicule", B par "voiture", C par "camion" et D par... marguerite, il n'y a strictement aucune raison d'accepter de faire cohabiter des marguerites dans une collection... de véhicules

    Tu peux, bien sur, créer une collection de 10000 marguerites si tu veux, tu peux même (à condition de les faire hériter de fleur) décider de les faire cohabiter avec des tulipes ou avec des roses, mais il n'y a aucune raison d'essayer de les faire cohabiter avec des véhicules

    Toute tentative en ce sens tient, très certainement, du problème de conception

    Maintenant, il est effectivement possible, comme l'a indiqué zul, de contourner le problème avec boost.variant, par exemple.

    Mais avant de décider d'en venir à cette extrémité, il faut vraiment te poser la question de savoir s'il est intéressant pour toi d'y avoir recours, et, comme ta question porte sur la manière de t'assurer qu'un objet fait bel et bien partie d'une hiérarchie de classe donnée, j'aurais tendance à croire que ce n'est vraiment pas le cas
    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

  6. #6
    Nouveau membre du Club
    Inscrit en
    Août 2007
    Messages
    43
    Détails du profil
    Informations forums :
    Inscription : Août 2007
    Messages : 43
    Points : 31
    Points
    31
    Par défaut
    Bonjour.

    Merci pour vos réponses. Le bout de code que j'ai donné n'était qu'un exemple et les explications que vous me proposez ne font que déplacer le problème sur un autre niveau de l'héritage, à vrai dire.

    Je ne pense pas que la conception soit à revoir et je vais essayer de proposer un code plus parlant, pour illustrer mon 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
    18
    19
    20
    21
    22
    23
    class Fichier{...};
    class FichierPapier : public Fichier{...};
    class FichierElectronique : public Fichier{...};
    class Archive{
       private : 
       std::vector<Fichier*> lesFichiers; //Je stocke tous les types de fichiers dans ce vector
       std::vector<FichierPapier*> lesFichiersPapiers;
       std::vector<FichierElectronique*> lesFichiersElectroniques;
     
       public :
       void insererFichier(Fichier *f){
          lesFichiers.push_back(f);
       }
     
       void trierFichiers(){
          for(std::vector<Fichier*>::iterator it=lesFichiers.begin();it!=lesFichiers.end();it++){
             if(typeid(*it)==typeid(FichierElectronique*))
                lesFichiersElectroniques.push_back(*it);
             else
                lesFichiersPapier.push_back(*it);
          }
       }
    };
    Bien sûr, ceci est encore un bête exemple, mais illustre bien mon problème. Les conditions if marcheront-elles bien pour ma fonction membre trierFichiers() ? La directive "typeid" ne considèrerait-elle pas tous les objets du vector comme étant de type Fichier* et non du type de leur classe fille ?

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Et pourquoi ne crées tu pas, tout simplement, une surcharge de fonction pour chaque type de fichier particulier
    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
    class Archive
    {
        public:
            void addFichier(Fichier *f)
            {
                fichiers.push_back(f);
                do_addFichier(f);
            }
        private:
            std::vector<Fichier*> fichiers;
            std::vector<FichierElectronique *> fichierselectronique;
            std::vector<FichierPapier*> fichierspapier;
            void do_addFichier(FichierElectronique *f)
            {
                fichierselectronique.push_back(f);
            }
            void do_addFichier(FichierPapier * f)
            {
                fichierspapier.push_back(f);
            }
    };
    Grâce à l'inlining, cela ne demandera pas plus de temps de faire de la sorte, et, grâce à la surcharge de addFichier, c'est la fonction adaptée à chaque type qui sera appelée, sans que tu n'aies à t'inquiéter de vérifier le type de fichier transmis à addFichier.
    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
    Nouveau membre du Club
    Inscrit en
    Août 2007
    Messages
    43
    Détails du profil
    Informations forums :
    Inscription : Août 2007
    Messages : 43
    Points : 31
    Points
    31
    Par défaut
    Ha, je n'y avais pas pensé !

    Merci, je vais essayé ça et je vous tiens au courant.

  9. #9
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Citation Envoyé par Bash01 Voir le message
    Ha, je n'y avais pas pensé !

    Merci, je vais essayé ça et je vous tiens au courant.
    Héhé... tu as pourtant eu 3 occasions de lire ma signature (cela en fait une quatrième )...

    Médite peut être sur le sujet sur lequel elle propose de le faire
    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

  10. #10
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Points : 13 017
    Points
    13 017
    Par défaut
    Salut,
    Désolé Koala mais ta solution ne peut fonctionner. Les multiméthodes n'existent pas en C++. La résolution d'un appel pour les arguments (autres que l'objet sur lequel se fait l'appel de la fonction) se fait sur le type statique et non le type dynamique. do_addFichier(f); est donc un appel ambigüe.
    Je crains qu'avec le schéma que tu proposes la seule solution ne soit de passer par un dynamic_cast :
    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
     
    // il y a probablement plus élégant, mais à la volée :
    template<typename T>
    bool dispatch_fichier(Fichier*p_fic, std::vector<T*>&vect_)
    // on pourrait rajouter un static assert sur T dérive bien de Fichier (cf trait C++0X ou boost.Trait)
    {
        if(dynamic_cast<T*>(p_fic))
        {
            vect_.push_back(dynamic_cast<T*>(p_fic));
            return true;
        }
        return false;
    }
    void trierFichiers(){
      for(std::vector<Fichier*>::iterator it=lesFichiers.begin();it!=lesFichiers.end();it++){
         if(dispatch_fichier<FichierElectronique>(*it,lesFichiersElectroniques)){
             continue;
         }
         if(dispatch_fichier<FichierPapier>(*it,lesFichiersPapier)){
             continue;
         }
      }
    }

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Juste... j'avais "zappé" ce problème...

    Ben, le double dispatch nous vient alors en aide
    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. Réponses: 2
    Dernier message: 13/04/2015, 17h57
  2. [Vxi3] Savoir à quelle classe appartient un objet
    Par mafanta dans le forum Deski
    Réponses: 6
    Dernier message: 21/10/2011, 11h32
  3. Recuperer un objet panel ds une classe derivé d'une JFrame
    Par benthebest dans le forum Agents de placement/Fenêtres
    Réponses: 2
    Dernier message: 26/12/2005, 01h57
  4. Réponses: 3
    Dernier message: 24/10/2005, 10h07
  5. Référence à un objet existant depuis une classe
    Par Adrenalys dans le forum ASP
    Réponses: 2
    Dernier message: 21/07/2005, 00h44

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