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 d'héritage et de transtypage


Sujet :

C#

  1. #1
    Membre confirmé
    Avatar de Higgins
    Inscrit en
    Juillet 2002
    Messages
    520
    Détails du profil
    Informations forums :
    Inscription : Juillet 2002
    Messages : 520
    Points : 543
    Points
    543
    Par défaut Problème d'héritage et de transtypage
    Bonjour
    je rencontre un problème de manipulation de mes classes héritées, voici mon code:
    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
     
    public class ClasseDeBase
    {
     
    }
     
    public class ClasseDerivee1:ClasseDeBase
    {
     
    }
     
    public class ClasseDerivee2:ClasseDeBase
    {
     
    }
     
    public classe AutreClasse
    { public void fonctionlambda(ClasseDerivee1 uneInstance)
       {
       }
     
    public void autrefonction(ClasseDerivee2 uneInstance)
       {
       }
    }
    Dans l'application, je manipule une variable du type "ClasseDeBase" qui "contient" une instance de "ClasseDerivee1" ou "ClasseDerivee2", comme ceci:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    ClasseDeBase maVariable;
    AutreClasse Variable2= new AutreClasse();
    .....
    maVariable= new ClasseDerivee1();
    ....
    Variable2.fonctionlambda((ClasseDerivee1) maVariable);
    A l'exécution, ça plante systématiquement avec l'erreur
    impossible de transtyper "ClasseDeBase" en "ClasseDerivee1"
    et si je ne transtype pas, ça ne passe pas la compilation (mauvais type passé en paramètre).
    ma variable contient pourtant une instance valide, du bon type. Existe-t-il un moyen de forcer le transtypage (sur certains langages, la validité du transtypage est laissé à l'appréciation du développeur, charge à lui de s'assurer que la conversion est valide sous peine de plantage)
    J'ai essayé avec les types génériques, mais tôt ou tard, quand une nouvelle classe hérite d'un de ces types génériques, le problème revient.
    7 fois à terre, 8 fois debout

  2. #2
    Membre habitué
    Profil pro
    Inscrit en
    Août 2009
    Messages
    147
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2009
    Messages : 147
    Points : 174
    Points
    174
    Par défaut
    Est tu sur de ce que tu post? Je ne vois pas l'intérêt de transtyper maVariable en ClasseDerivee1 si tu as fait
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    maVariable= new ClasseDerivee1();

  3. #3
    Rédacteur
    Avatar de Nathanael Marchand
    Homme Profil pro
    Expert .Net So@t
    Inscrit en
    Octobre 2008
    Messages
    3 615
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Expert .Net So@t
    Secteur : Conseil

    Informations forums :
    Inscription : Octobre 2008
    Messages : 3 615
    Points : 8 080
    Points
    8 080
    Par défaut
    Citation Envoyé par Higgins Voir le message
    Bonjour je rencontre un problème de manipulation de mes classes héritées, voici mon code:
    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
     
    public class ClasseDeBase
    {
     
    }
     
    public class ClasseDerivee1
    {
     
    }
     
    public class ClasseDerivee2
    {
     
    }
    Il est ou l'heritage la dedans?

  4. #4
    Rédacteur/Modérateur


    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2004
    Messages
    19 875
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2004
    Messages : 19 875
    Points : 39 749
    Points
    39 749
    Par défaut
    Citation Envoyé par davjan Voir le message
    Est tu sur de ce que tu post? Je ne vois pas l'intérêt de transtyper maVariable en ClasseDerivee1 si tu as fait
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    maVariable= new ClasseDerivee1();
    maVariable est déclarée comme ClasseDeBase, donc tu ne peux pas la passer en paramètre de la fonction sans transtyper. Toi, tu sais que c'est une instance de ClasseDerivee1, mais le compilateur ne le sait pas...

    Citation Envoyé par PitMaverick78 Voir le message
    Il est ou l'heritage la dedans?
    Effectivement, je pense plutôt que le problème vient de là

  5. #5
    Membre confirmé
    Avatar de Higgins
    Inscrit en
    Juillet 2002
    Messages
    520
    Détails du profil
    Informations forums :
    Inscription : Juillet 2002
    Messages : 520
    Points : 543
    Points
    543
    Par défaut
    Citation Envoyé par PitMaverick78 Voir le message
    Il est ou l'heritage la dedans?
    Désolé, j'ai tapé un peu trop vite
    J'ai édité le post.

    Citation Envoyé par davjan
    Est tu sur de ce que tu post? Je ne vois pas l'intérêt de transtyper maVariable en ClasseDerivee1 si tu as fait
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    maVariable= new ClasseDerivee1();
    Le problème, c'est que j'appelle une méthode qui prend un paramètre de type "ClasseDerivee1" et comme ma variable est déclarée du type "ClasseDeBase", le compilateur me dit que je n'ai pas le bon type de paramètre pour ma fonction. Je suis obligé de l'appeler comme ceci:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Variable2.fonctionlambda((ClasseDerivee1) maVariable);
    Là, ça compile, mais à l'exécution j'ai une erreur
    Impossible de transtyper implicitement "ClasseDeBase" en "ClasseDerivee", il doit manquer un cast.
    Comme ma variable contient bien un objet du bon type, je voudrais savoir comment le forcer à l'accepter.
    7 fois à terre, 8 fois debout

  6. #6
    Expert éminent sénior Avatar de Pol63
    Homme Profil pro
    .NET / SQL SERVER
    Inscrit en
    Avril 2007
    Messages
    14 172
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : .NET / SQL SERVER

    Informations forums :
    Inscription : Avril 2007
    Messages : 14 172
    Points : 25 112
    Points
    25 112
    Par défaut
    avec l'édition pour faire apparaitre l'héritage c'est mieux

    par contre moi je viens de tester et ca marche bien, d'ailleurs vu le message d'erreur je pense plutot que l'instance que tu penses être du type ClasseDerivee1 ne l'est tout simplement pas
    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
     
     
    public class Form1
    {
        private void Form1_Load(System.Object sender, System.EventArgs e)
        {
            Cbase b = new H1();
            traitement((H1)b);
        }
     
        private void traitement(H1 h)
        {
        }
    }
     
    public class Cbase 
    {
    }
    public class H1 : Cbase 
    {
    }
    public class H2 : Cbase 
    {
    }
    d'ailleurs en général quand on fait des choses comme ca il est conseillé d'ajouter avant si l'instance est pas du type que je pense alors throw une new ApplicationException("instance du type " + intance.gettype.name + " c'était pas prévu ...")

    et avec un traçage d'erreur tu vois les bugs

    croire en ce qu'on fait c'est bien, mais penser à mettre des infos quand ca sort de ce qu'on attend c'est encore mieux
    Cours complets, tutos et autres FAQ ici : C# - VB.NET

  7. #7
    Membre habitué
    Profil pro
    Inscrit en
    Août 2009
    Messages
    147
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2009
    Messages : 147
    Points : 174
    Points
    174
    Par défaut
    Oups, bien sur qu'il faut transtyper
    toutes mes excuses.

  8. #8
    Rédacteur
    Avatar de Nathanael Marchand
    Homme Profil pro
    Expert .Net So@t
    Inscrit en
    Octobre 2008
    Messages
    3 615
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Expert .Net So@t
    Secteur : Conseil

    Informations forums :
    Inscription : Octobre 2008
    Messages : 3 615
    Points : 8 080
    Points
    8 080
    Par défaut
    Pourquoi ne pas utiliser "is" et "as"? C'est plus souple et moins brutal

  9. #9
    Rédacteur/Modérateur


    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2004
    Messages
    19 875
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2004
    Messages : 19 875
    Points : 39 749
    Points
    39 749
    Par défaut
    Citation Envoyé par Higgins Voir le message
    Impossible de transtyper implicitement "ClasseDeBase" en "ClasseDerivee", il doit manquer un cast.
    Tu es sûr que c'est exactement ça le message ? Je n'ai jamais vu une exception avec un message de ce type, ça ressemble plutôt à une erreur de compilation...

    En plus ici le cast est explicite, pas implicite. Ce n'est pas plutôt dans le code de fonctionlambda que l'erreur se produit?

  10. #10
    Membre confirmé
    Avatar de Higgins
    Inscrit en
    Juillet 2002
    Messages
    520
    Détails du profil
    Informations forums :
    Inscription : Juillet 2002
    Messages : 520
    Points : 543
    Points
    543
    Par défaut
    Citation Envoyé par tomlev Voir le message
    Tu es sûr que c'est exactement ça le message?
    Le message exact est
    Impossible de convertir implicitement le type 'classeDeBase' en 'ClasseDerivee. Une conversion explicite existe,
    (un cast est-il manquant)?
    .
    Je crois plutôt que mon problème vient d'une mauvaise utilisation des classes génériques. Je n'ai pas voulu créer un post trop long et j'ai péché par excès de simplification. Voici un exemple plus complet:
    Je possède une classe de base appelée "article". Certains peuvent être assemblés. J'ai donc une classe générique "composant" qui décrit le comportement commun de ces articles.
    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
     
     public class Article
        {
            private int _identifiant;
            private string _nom;
     
            public int Identifiant
            {
                get { return _identifiant; }
                set
                {
                    if (value != _identifiant)
                        _identifiant = value;
                }
            }
     
            public string Nom
            {
                get { return _nom; }
                set
                {
                    if (value != _nom)
                        _nom = value;
                }
            }
        }
     
        public class composant<untype> : Article
        {
            private bool _venduSeul;
            public bool VenduSeul
            {
                get { return _venduSeul; }
                set
                {
                    if (value != _venduSeul)
                        _venduSeul = value;
                }
            }
        }
     
    public class Electronique : composant<Electronique>
        {
            private bool _courantContinu;
            public bool CourantContinu
            {
                get { return _courantContinu; }
                set
                {
                    if (value != _courantContinu)
                        _courantContinu = value;
                }
            }
     
        }
     
        public class Mecanique : composant<Mecanique>
        {
            public bool _recyclable;
            public bool Recyclable
            {
                get { return _recyclable; }
                set
                {
                    if (value != _recyclable)
                        _recyclable = value;
                }
            }
        }
    Les composants peuvent être assemblés. Un assemblage Electronique ne contient que des éléments électroniques, un assemblage mécanique ne contient que des éléments mécaniques.
    J'ai alors les classes suivantes:
    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
     
     public class Assemblage<untype> : Article
        {
            List<composant<untype>> _elements;
            public List<composant<untype>> Elements
            {
                get { return _elements; }
                set
                {
                    if (value != _elements)
                        _elements = value;
                }
            }
     
            public composant<untype> ElementAt(int position)
            {
                if ((_elements != null) && (_elements.Count > 0))
                {
                    return _elements[position];
                }
                else
                    return default(composant<untype>);
     
            }
        }
     
      public class solution1 : Assemblage<Mecanique>
        {
        }
        public class solution2 : Assemblage<Electronique>
        {
        }
    On arrive alors à mon problème:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
     public void main()
            {
               solution2 unevariable= new solution2();
               //divers traitements ici
               Electronique unElement=unevariable.ElementAt(0);                        //ligne1
               Electronique unAutreElement=(Electronique) unevariable.ElementAt(0);    //ligne2
     
            }
    La ligne 1 ne passe pas l'étape de la compilation, le message d'erreur est:
    Impossible de convertir implicitement le type 'composant<Electronique>' en 'Electronique. Une conversion explicite existe,
    (un cast est-il manquant)?
    la ligne 2 passe la compilation, mais plante à l'exécution avec le même message.

    Citation Envoyé par PitMaverick78
    Pourquoi ne pas utiliser "is" et "as"? C'est plus souple et moins brutal
    est-ce que
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Electronique unAutreElement=(unevariable.ElementAt(0) as Electronique);
    à la place de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Electronique unAutreElement=(Electronique) unevariable.ElementAt(0);
    fonctionnerait?
    7 fois à terre, 8 fois debout

  11. #11
    Membre habitué
    Profil pro
    Inscrit en
    Août 2009
    Messages
    147
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2009
    Messages : 147
    Points : 174
    Points
    174
    Par défaut
    Hello,
    j'espère que je ne vais pas dire de bêtise.

    En essayant ton code, avec la ligne 2, et en construisant une liste d'éléments comme ceci:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    unevariable.Elements = new List<composants<Electronique>();
    var com = new Electronique();
    com.Nom = "test".
    unevariable.Elements.Add(com);
    ca passe.
    Mais attention si au lieu de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
     var com = new Electronique()
    on met
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    var com = new composants<Electronique>()
    ca ne passe plus:
    logique.

    à +

  12. #12
    Membre émérite Avatar de Guulh
    Homme Profil pro
    Inscrit en
    Septembre 2007
    Messages
    2 160
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Septembre 2007
    Messages : 2 160
    Points : 2 925
    Points
    2 925
    Par défaut
    Hello,
    déjà, il est inutile de n'affecter que si la valeur est différente. ca rend ton code inutilement complexe.
    Donc ta classe Article devient par exemple
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    public class Article
        {
            public int Identifiant { get; set; }
     
            public string Nom { get; set; }
        }
    Ensuite, je vois pas trop pourquoi t'as besoin des génériques ici. Composant peut simplement hériter de Article, et Electronique / Mécanique hériter de Composant. Pour ton erreur, si on oublie le fait que tu utilises les generics, ton code revient à ça:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    class Mère { }
    class Fille : Mère { }
    Mère m = new Mère();
    Fille f = (Fille)m;
    ce qui ne marche évidemment pas, generics ou pas.

    Ensuite, si tu veux qu'un assemblage soit une collection ne contenant que des objets d'un même type de Composant, tu peux utiliser une contrainte "where", comme ceci:
    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
     
    public class Assemblage<T> : Article where T : Composant
        {
            public List<T> Elements { get; set; }
     
            public T ElementAt(int position)
            {
                if ((_elements != null) && (_elements.Count > 0))
                {
                    return _elements[position];
                }
                else
                    return null; 
            }
        }
     
    public class Solution1 : Assemblage<Mecanique> { }
    public class Solution2 : Assemblage<Electronique> { }
    ಠ_ಠ

  13. #13
    Rédacteur/Modérateur


    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2004
    Messages
    19 875
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2004
    Messages : 19 875
    Points : 39 749
    Points
    39 749
    Par défaut
    "Impossible de convertir implicitement le type 'composant<Electronique>' en 'Electronique. Une conversion explicite existe,
    (un cast est-il manquant)?"
    la ligne 2 passe la compilation, mais plante à l'exécution avec le même message.
    Ce message est une erreur du compilateur, et je n'ai jamais vu un tel message à l'exécution... donc à mon avis tu te mélanges un peu les pinceaux. Si c'est une erreur d'exécution, il doit y avoir une exception : quel est son type ? Sa stacktrace ?

Discussions similaires

  1. [C#] Problème d'héritage, aide svp :(
    Par choas dans le forum Windows Forms
    Réponses: 12
    Dernier message: 06/05/2006, 11h46
  2. problème constructeur + héritage
    Par BOLARD dans le forum C++
    Réponses: 10
    Dernier message: 13/04/2006, 08h11
  3. [AS2] Problème d'héritage
    Par wwave dans le forum ActionScript 1 & ActionScript 2
    Réponses: 2
    Dernier message: 27/01/2006, 09h26
  4. Problème d'héritage ?
    Par Romanops dans le forum WinDev
    Réponses: 2
    Dernier message: 16/11/2005, 17h18
  5. Problème d'héritage d'une méthode protégée
    Par shenron666 dans le forum C++
    Réponses: 9
    Dernier message: 28/04/2005, 23h17

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