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 et fonction virtuelle


Sujet :

C#

  1. #1
    r0d
    r0d est déconnecté
    Expert éminent

    Homme Profil pro
    Développeur de jeux vidéo
    Inscrit en
    août 2004
    Messages
    4 261
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur de jeux vidéo

    Informations forums :
    Inscription : août 2004
    Messages : 4 261
    Points : 6 603
    Points
    6 603
    Billets dans le blog
    2
    Par défaut polymorphisme et fonction virtuelle
    bonjour à tous.

    J'ai une classe Maillon qui hérite de UserControl. Ensuite, j'ai plusieurs classes qui héritent de Maillon: MaillonVert et MaillonRouge (ce n'est pas comme á en vérité mais c'est plus simple présenté ainsi).
    Ma classe Maillon possède une fonction virtuelle DoWork(), laquelle est implémentée par MaillonVert et MaillonRouge.

    Enfin, j'ai une Winform, ma form principale de l'appli, qui créée et affiche des Maillons dynamiquement. Ma form contient une Collection de controles (comme toutes les winforms), nommée Controls. C'est cette collection que je modifie pour manipuler mes maillons.

    Mais le problème, c'est que comme mes Maillons sont stockés dans cette collection en tant que UserControl, lorsque je veux appeler mes fonctions de Maillons, je dois d'abord caster les éléments en Maillon. Ce qui rend impossible l'utilisation du polymorphisme sur les fonctions membres.

    Mon code ressemble à 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
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    class Maillon : UserControl
    {
        internal virtual void DoWork() {}
    }
     
    class MaillonVert : Maillon
    {
       internal override void DoWork() { Console.Write( "vert" ) };
    }
     
    class MaillonRouge : Maillon
    {
       internal override void DoWork() { Console.Write( "rouge" ) };
    }
     
    // *****************************
    // et dans ma form principale:
    private void AjouterMaillonVert()
    {
        Controls.Add( new MaillonVert() );
    }
     
    private void AjouterMaillonRouge()
    {
        Controls.Add( new MaillonRouge() );
    }
     
    private void DoWork()
    {
       for (int i = 0; i < Controls.Count; i++)
          ((Maillon)Controls[ì]).DoWork(); // je suis obligé de caster en Maillon pour appeler doWork()
    }
    Note: La collection Controls n'est "pas à moi", c'est une variable membre de Winform.

    Le problème c'est que le code ci-dessus appelle la fonction DoWork de la classe mère (Maillon), et non des classes filles. Or moi je voudrais appeler DoWork() des classes filles (MaillonVert et MaillonRouge). Comment puis-je faire?
    Tester c'est douter, corriger c'est abdiquer.

  2. #2
    Expert éminent
    Avatar de StormimOn
    Homme Profil pro
    Développeur informatique
    Inscrit en
    mai 2005
    Messages
    2 593
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Sarthe (Pays de la Loire)

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

    Informations forums :
    Inscription : mai 2005
    Messages : 2 593
    Points : 7 660
    Points
    7 660
    Par défaut
    Tu es certain que c'est bien le DoWork de la classe Maillon qui est uniquement appelé ? Cela me semble bizarre, car le principe du polymorphisme c'est de pouvoir manipuler un objet via la classe de base (ici Maillon) tout en connaissant le type réel de l'objet (MaillonVert ou MaillonRouge). Et c'est le type réel qui est pris en compte lors des appels des méthodes en override.

    Donc ((Maillon)Controls[ì]).DoWork(); doit appeler la méthode MaillonVert.DoWork ou MaillonRouge.DoWork si Controls[i] est de type MaillonVert ou MaillonRouge.

    Au passage, il serait bon de tester le type de Controls[i] avant histoire d'éviter d'éventuelles erreurs
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    private void DoWork()
    {
       for (int i = 0; i < Controls.Count; i++)
       {
          Maillon maillon = Controls[i] as Maillon;
          if (maillon != null) { maillon.DoWork(); }
       }
    }
    Pas de questions techniques par MP

  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 : 35
    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 054
    Points
    8 054
    Par défaut
    Si c'est du 3.5, le plus élégant est :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    foreach(Maillon maillon in Controls.OfType<Maillon>())
    {
       maillon.DoWork();
    }

  4. #4
    r0d
    r0d est déconnecté
    Expert éminent

    Homme Profil pro
    Développeur de jeux vidéo
    Inscrit en
    août 2004
    Messages
    4 261
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur de jeux vidéo

    Informations forums :
    Inscription : août 2004
    Messages : 4 261
    Points : 6 603
    Points
    6 603
    Billets dans le blog
    2
    Par défaut
    Ha oui, effectivement vous avez raison. Je ne sais pas ce que j'avais fais, mais c'était toujours la fonction de la classe mère qui était appelée.
    C'est que le polymorphisme du C# est très différent de celui du C++. L'absence de fonctions virtuelles pures et d'héritage multiple me déroute

    Tester c'est douter, corriger c'est abdiquer.

  5. #5
    r0d
    r0d est déconnecté
    Expert éminent

    Homme Profil pro
    Développeur de jeux vidéo
    Inscrit en
    août 2004
    Messages
    4 261
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur de jeux vidéo

    Informations forums :
    Inscription : août 2004
    Messages : 4 261
    Points : 6 603
    Points
    6 603
    Billets dans le blog
    2
    Par défaut
    Citation Envoyé par Nathanael Marchand Voir le message
    Si c'est du 3.5, le plus élégant est :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    foreach(Maillon maillon in Controls.OfType<Maillon>())
    {
       maillon.DoWork();
    }
    Arf, je ne peux pas faire ça car en fait je commence la boucle à partir d'un indice donné, c'est à dire que je fais pas le DoWork sur tous les éléments. On a une "chaîne" de maillons, et cette boucle est appelée lorsqu'on en supprime un au milieu, donc en fait, je fais un décalage de tous ceux qui sont à droite de celui qui est supprimé.
    Tester c'est douter, corriger c'est abdiquer.

  6. #6
    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 : 35
    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 054
    Points
    8 054
    Par défaut
    Petit rappel sur le polymorphisme (ca ne fait jamais de mal):
    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
    void Main()
    {
    	Mere me = new Fille();
    	me.Toto();
    	me.Titi();
    }
     
    abstract class Mere
    {
    	public virtual void Toto()
    	{
    		Console.WriteLine("Luke, I'm your mother!");
    	}
     
    	public void Titi()
    	{
    		Console.WriteLine("Luke, I'm your mother!");
    	}
    }
     
    class Fille : Mere
    {
    	public override void Toto()
    	{
    		Console.WriteLine("Luke, I'm not your mother!");
    	}
     
    	public new void Titi()
    	{
    		Console.WriteLine("Luke, I'm not your mother!");
    	}
    }
    Produit:
    Luke, I'm not your mother!
    Luke, I'm your mother!

  7. #7
    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 : 35
    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 054
    Points
    8 054
    Par défaut
    Citation Envoyé par r0d Voir le message
    Arf, je ne peux pas faire ça car en fait je commence la boucle à partir d'un indice donné, c'est à dire que je fais pas le DoWork sur tous les éléments. On a une "chaîne" de maillons, et cette boucle est appelée lorsqu'on en supprime un au milieu, donc en fait, je fais un décalage de tous ceux qui sont à droite de celui qui est supprimé.
    Si tu as x éléments à sauter tu peux utiliser Skip()
    Si c'est x maillons:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    foreach(Maillon maillon in Controls.OfType<Maillon>().Skip(x))
    {
       maillon.DoWork();
    }
    Si c'est x controls:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    foreach(Maillon maillon in Controls.Skip(x).OfType<Maillon>())
    {
       maillon.DoWork();
    }

  8. #8
    r0d
    r0d est déconnecté
    Expert éminent

    Homme Profil pro
    Développeur de jeux vidéo
    Inscrit en
    août 2004
    Messages
    4 261
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur de jeux vidéo

    Informations forums :
    Inscription : août 2004
    Messages : 4 261
    Points : 6 603
    Points
    6 603
    Billets dans le blog
    2
    Par défaut
    Okay, merci pour ces précisions

    Mais au fait, lorsqu'une classe est déclarée abstract (je ne connaissais pas ce mot-clé), qu'est-ce que ça change? (par rapport à une classe qui n'est pas déclarée abstract).

    Décidément, le C# ne cesse de me surprendre. De façon positive s'entend. [troll[Dommage que c'est un peu lent [/troll]
    Tester c'est douter, corriger c'est abdiquer.

  9. #9
    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 : 35
    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 054
    Points
    8 054
    Par défaut
    Une classe abstraite ne peut pas être instanciée. Dans mon code, tu te feras jeter si tu fais un new Mere()

  10. #10
    Expert confirmé Avatar de DonQuiche
    Inscrit en
    septembre 2010
    Messages
    2 741
    Détails du profil
    Informations forums :
    Inscription : septembre 2010
    Messages : 2 741
    Points : 5 459
    Points
    5 459
    Par défaut
    Et pour compléter un peu, une classe abstraite peut contenir des méthodes abstraites, c'est à dire des méthodes pour lesquelles on ne fournit pas d'implémentation par défaut. Autre avantage : si jamais un dév oublie de surcharger une méthode abstraite dans une héritière pour en fournir l'implémentation, le compilateur signale une erreur (sauf si l'héritière est elle-même abstraite).

    Et sinon, C#... lent ? Boarf. Oublie ces préjugés, là aussi il te surprendra très agréablement, la différence avec le C++ est insignifiante 99% du temps.

  11. #11
    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 : 39
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : septembre 2007
    Messages : 2 160
    Points : 2 924
    Points
    2 924
    Par défaut
    Citation Envoyé par r0d Voir le message
    L'absence de fonctions virtuelles pures et d'héritage multiple me déroute
    Les méthodes virtuelles pures, ça existe, sauf que le mot clé correspondant est "abstract". Et pour rejoindre les réponses que tu as eues entre temps, une classe ayant au moins une méthode abstraite (ou dérivante d'une classe qui en a mais qui ne les surcharge pas toutes) doit être marquée avec le mot clé abstract, pour bien signifier qu'elle ne peut être instanciée.
    ಠ_ಠ

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

Discussions similaires

  1. Réponses: 2
    Dernier message: 05/03/2006, 20h29
  2. Compilation avec des fonctions virtuel pure
    Par vanitom dans le forum C++
    Réponses: 4
    Dernier message: 16/12/2005, 15h37
  3. masquage de fonction virtuelle
    Par julien.sagnard dans le forum C++
    Réponses: 3
    Dernier message: 27/01/2005, 15h00
  4. Réponses: 2
    Dernier message: 07/10/2004, 18h00
  5. fonctions virtuelles
    Par Mau dans le forum Autres éditeurs
    Réponses: 4
    Dernier message: 21/11/2003, 10h53

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