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 :

Pb de downcasting


Sujet :

C++

  1. #1
    Membre éclairé
    Profil pro
    Inscrit en
    Juin 2002
    Messages
    577
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2002
    Messages : 577
    Par défaut Pb de downcasting
    Bonjour à tous,

    je me retrouve dans cette situation :

    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
    class Base
    {
     int m_a;
     virtual void f() = 0;
    };
     
     
    class Derivee1 : public Base
    {
      void f();
      int m_data;
    };
     
    class Derivee2 : public Base
    {
      void f();
      int m_size;
    };
     
    class Type
    {
       Base* m_p;
       int m_id;
       ...
     
    };
     
    class Test
    {
      list<Type*> m_list;
      Derivee1* GetPtrByIdType(int idType);
    };

    La liste m_list de la classe Test est construite avec des Type* dont le m_p est un Derivee1*.
    Ainsi, pour récupérer le m_p, j'utilise la fonction :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Derivee1* Test::GetPtrByIdType(int idType);
    Comment faire pour que dans ma fonction GetPtrByIdType() je n'ai pas de downcasting à faire ?
    En effet ma recherche par id me retourne un Base* que je dois caster en Derivee1*.

    Je ne trouve pas ça trés propre.
    Quelle est la solution à conseiller ?

    @+

  2. #2
    Membre Expert
    Avatar de Patriarch24
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Septembre 2003
    Messages
    1 047
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

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

    Informations forums :
    Inscription : Septembre 2003
    Messages : 1 047
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    template <typename T>
    class Type {
       T* m_p;
       //...
    };
     
     
    List<Type<Derivee1> *> m_list;
    est une solution (pas tout à fait complète, je ne vérifie pas que T dérive de base, la généricité n'étant pas contrainte en C++, on doit utiliser de la métaprog pour y arriver). Je suis cependant hyper sceptique sur la raison d'être d'une classe "Type". Peux-tu être plus clair sur son utilisation ? Et sur le but du programme ?

  3. #3
    Membre éclairé
    Profil pro
    Inscrit en
    Juin 2002
    Messages
    577
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2002
    Messages : 577
    Par défaut
    Un exemple serait :

    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
    class Enfant
    {
     int m_age;
     virtual void f() = 0;
    };
     
     
    class Garcon : public Enfant
    {
      void f();
      int m_data;
    };
     
    class Fille: public Enfant
    {
      void f();
      int m_size;
    };
     
     
    class Jouet
    {
    //On associe un enfant à chaque jouet
       Enfant* m_p;
       int m_id;
       ...  
    };
     
     
     
    class PlacardGarcon
    {
      list<Jouet*> m_list;
      Garcon* GetPtrByIdType(int idType);
    };

    Mais peut être ce modele n'est pas suffisamment correct ??

    @+

  4. #4
    Membre Expert
    Avatar de Patriarch24
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Septembre 2003
    Messages
    1 047
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

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

    Informations forums :
    Inscription : Septembre 2003
    Messages : 1 047
    Par défaut
    C'est
    Garcon* GetPtrByIdType(int idType);
    que je ne comprends pas. Tu as sans doute voulu dire getEnfantByIdJouet ? Si c'est ça, la solution donnée plus haut est convenable.

    En général, si on veut faire joujou avec les types, les templates sont une solutions.

  5. #5
    Membre éclairé
    Profil pro
    Inscrit en
    Juin 2002
    Messages
    577
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2002
    Messages : 577
    Par défaut
    Ben disons que je suis dans une classe "PlacardGarcon" où je sais que chacun des jouets de ma liste est associé à un Garcon*.

    Et c'est pour ça que je cherche à récupérer un Garcon*.

  6. #6
    Membre éclairé
    Profil pro
    Inscrit en
    Juin 2002
    Messages
    577
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2002
    Messages : 577
    Par défaut
    Si qqun pouvait m'éclairer sur le bon schéma à utiliser ?

  7. #7
    Membre Expert
    Avatar de Patriarch24
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Septembre 2003
    Messages
    1 047
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

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

    Informations forums :
    Inscription : Septembre 2003
    Messages : 1 047
    Par défaut
    Dans cas je te répète que la solution plus haut fonctionne. En revoilà une couche :
    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
     
    class Enfant {
       //...
    };
     
    class Garcon : public Enfant {
       //...
    };
     
    class Fille : public Enfant {
       //...
    };
     
    template<typename E>
    class Jouet {
            // généricité constrainte : E doit dériver de Enfant ou
            // être Enfant lui même (cas des jouets mixtes :mouarf: )
    	BOOST_STATIC_ASSERT((boost::is_base_of<Enfant,E>::value)
                               || (boost::is_same<Base, E>::value));
    public:
    	typedef E* pointer;
     
    	Jouet (const pointer& owner):
                       _owner(owner), id(Generator::generateID()) {}
    	pointer getOwner() { return _owner; }
    private:
            int id;
    	pointer _owner;
    };
     
    template <typename E>
    class Placard {
    public:
    	typedef E* pointer;
     
            pointer getOwnerOf(int id) {//...}
     
    private:
            std::list<Jouet<E>* > _list;
    };
    Il n'y a pas de downcast et les types sont checkés à la compilation.

    J'espère que ça répond à ton problème.

  8. #8
    Membre éclairé
    Profil pro
    Inscrit en
    Juin 2002
    Messages
    577
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2002
    Messages : 577
    Par défaut
    OK
    j'ai compris ta solution.
    Merci beaucoup.

    Par contre, est-ce que sans passer par des templates, on peut aussi y arriver ?
    Disons, en utilisant du polymorphisme (mais sans template), parce que dans mon cas, les types utilisés sont forcément de la même lignée (base ou dérivée) ?

    @+

  9. #9
    Membre chevronné
    Inscrit en
    Novembre 2006
    Messages
    362
    Détails du profil
    Informations forums :
    Inscription : Novembre 2006
    Messages : 362
    Par défaut
    Citation Envoyé par olive_le_malin
    OK
    j'ai compris ta solution.
    Merci beaucoup.

    Par contre, est-ce que sans passer par des templates, on peut aussi y arriver ?
    Disons, en utilisant du polymorphisme (mais sans template), parce que dans mon cas, les types utilisés sont forcément de la même lignée (base ou dérivée) ?
    Salut,

    Cette façon de présenter ton problème ne mènera à rien de bon.
    Il semble que tu aie un problème de modélisation, et tu cherches une solution syntaxique.

    Ce que te propose Patriarch24, c'est une modification de ton modèle (déguisée sous forme de template), et elle répond parfaitement à ta demande.

    Si elle ne te convient pas, c'est que tu peux mieux présenter ton problème.

    Donc si tu veux une réponse purement syntaxique, la voici :
    Non, on ne peut pas caster un Base* en Derivée* sans avoir recours à un cast.
    Si ce que tu cherches, c'est une meilleure façon de modéliser ton problème, il faut que tu explique ton problème, pas la solution que tu envisages.

    Bonne chance

  10. #10
    Membre éclairé
    Profil pro
    Inscrit en
    Juin 2002
    Messages
    577
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2002
    Messages : 577
    Par défaut
    Citation Envoyé par Feriaman
    Salut,

    Cette façon de présenter ton problème ne mènera à rien de bon.
    Il semble que tu aie un problème de modélisation, et tu cherches une solution syntaxique.
    Oui, c'est ce que je pense aussi, et justement je n'arrive pas à le modéliser autrement.

    Citation Envoyé par Feriaman
    Ce que te propose Patriarch24, c'est une modification de ton modèle (déguisée sous forme de template), et elle répond parfaitement à ta demande.
    Si elle ne te convient pas, c'est que tu peux mieux présenter ton problème.
    Et merci beaucoup à Patriarch24 pour sa solution.


    Citation Envoyé par Feriaman
    Si ce que tu cherches, c'est une meilleure façon de modéliser ton problème, il faut que tu explique ton problème, pas la solution que tu envisages.
    Je pensais que je l'avais bien expliqué avec l'exemple des jouets que j'ai donné.
    Mais je reprends :

    1/ Je veux stocker dans une classe X (dans mon exemple Jouet) un pointeur vers un objet associé à l'objet de la classe X.
    Or ce pointeur peut être de différents types (D1, D2 ...), chacun dérivant forcément d'un type de base (B).
    Cela représente le lien existant avec l'objet X, et donc dans mon exemple, qu'el est l'enfant propriétaire du jouet.

    Donc, une fonction doit permettre de retrouver le propriétaire d'un jouet, en récupérant le pointeur.
    Mais de quel type dois-je retourner ? un pointeur sur le type de base je suppose ?
    Donc :
    B* X::GetOwner();


    2/ Je veux stocker dans une classe Y une liste de pointeurs de X (donc une liste de Jouets).
    Et je désire pouvoir retrouver pour chaque jouet son propriétaire en appelant la fonction X::GetOwner().
    Je vais donc récupérer des B*.
    Le problème, c'est que j'y ai stocké des D1* ou D2* ...



    Ainsi de manière générale comment modéliser ce système, où on doit retrouver un pointeur sur un type dérivé.
    Est-ce possible autrement qu'en utilisant les templates proposés par Patriarch24 ?

    En espérant que j'ai été + clair.
    N'hésitez pas à me le dire sinon.

    @+

  11. #11
    Expert confirmé

    Homme Profil pro
    Ingénieur systèmes et réseaux
    Inscrit en
    Février 2007
    Messages
    4 253
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur systèmes et réseaux
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Février 2007
    Messages : 4 253
    Billets dans le blog
    3
    Par défaut
    En fait, ce que Feriaman disait c'est que ton probleme est un problême de modélisation.

    Tu veux que ton objet 'Y' puisse typer fortement (en retournant des D1) les 'owner' (B) des X qu'il contient.

    Pour qu'il puisse faire ca, il faut aussi qu'il type fortement les X qu'on lui ajoute, ou c'est la porte ouverte aux bugs.
    C'est à dire, que ton object Y ne doit accepter que des X pointant ayant un D1 comme owner.
    En bref, c'est l'ensemble des X contenus dans Y qui sont fortement typés !

    Il existe deux solutions princpales à ce problême:

    1. Le typage est effectué au moment de la compilation.
    Ou bien par l'entremise des templates... X<T> (T héritant de B) avec X<T>.getOwner() et Y<T> n'acceptant que des X<T>, et par conséquent pouvait les retourner tel quel...
    Ou bien par une class XD1 (héritant de X) et XD2 (héritant de X), mais ca tombe bien, c'est exactement ce que font les templates en C++

    2. Le typage est effectué au moment du runtime.
    Ou bien par un typage 'maison' (les B disent par une fonction virtuelle de quel type ils sont).
    Ou bien par le RTTI que propose obligatoirement ton compilateur d'une maniere ou d'une autre.

  12. #12
    Membre éclairé
    Profil pro
    Inscrit en
    Juin 2002
    Messages
    577
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2002
    Messages : 577
    Par défaut
    Citation Envoyé par nicroman
    En fait, ce que Feriaman disait c'est que ton probleme est un problême de modélisation.

    Tu veux que ton objet 'Y' puisse typer fortement (en retournant des D1) les 'owner' (B) des X qu'il contient.

    Pour qu'il puisse faire ca, il faut aussi qu'il type fortement les X qu'on lui ajoute, ou c'est la porte ouverte aux bugs.
    C'est à dire, que ton object Y ne doit accepter que des X pointant ayant un D1 comme owner.
    En bref, c'est l'ensemble des X contenus dans Y qui sont fortement typés !
    .
    ---> OUI c'est exactement ça !!


    Citation Envoyé par nicroman
    1. Le typage est effectué au moment de la compilation.
    Ou bien par l'entremise des templates... X<T> (T héritant de B) avec X<T>.getOwner() et Y<T> n'acceptant que des X<T>, et par conséquent pouvait les retourner tel quel...
    Ou bien par une class XD1 (héritant de X) et XD2 (héritant de X), mais ca tombe bien, c'est exactement ce que font les templates en C++
    ---> Si j'ai bien compris s'est la solution de Patriarch24.



    Citation Envoyé par nicroman
    2. Le typage est effectué au moment du runtime.
    Ou bien par un typage 'maison' (les B disent par une fonction virtuelle de quel type ils sont).
    ---> J'ai vu ce post par raaport à ça, je suppose que c'est ce dont tu parles :
    http://www.developpez.net/forums/sho...69&postcount=5

    Citation Envoyé par nicroman
    Ou bien par le RTTI que propose obligatoirement ton compilateur d'une maniere ou d'une autre
    ---> Je suppose que c'est du dynamic_cast dont tu parles, ou en utilisant le typeid/type_info

    Merci beaucoup pour toutes ces précisions.
    Je me rends compte que cette modélisation où le getOwner() retourne un pointeur fortement typé est à éviter si possible car ce n'est pas trés facile de la suivre, et j'imagine, de la maintenir.

    @+

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

Discussions similaires

  1. Downcasting ou copie a travers un heritage ?
    Par enrikomic dans le forum Langage
    Réponses: 7
    Dernier message: 29/06/2007, 17h17
  2. Réponses: 13
    Dernier message: 02/03/2007, 14h43
  3. Downcasting et type
    Par Alfred12 dans le forum C++
    Réponses: 7
    Dernier message: 28/02/2007, 08h57
  4. [downcasting] fonction d'une classe fille
    Par poukill dans le forum C++
    Réponses: 7
    Dernier message: 28/07/2006, 16h26
  5. Downcasting
    Par Mookie dans le forum C++
    Réponses: 18
    Dernier message: 12/01/2005, 23h21

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