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 :

Différence précise entre virtual / override et new


Sujet :

C#

  1. #1
    Nouveau membre du Club
    Profil pro
    Étudiant
    Inscrit en
    Décembre 2007
    Messages
    54
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Décembre 2007
    Messages : 54
    Points : 39
    Points
    39
    Par défaut Différence précise entre virtual / override et new
    Bonjour à tous,

    J'essaye depuis quelques heures de comprendre le différence *exacte* les mots clefs virtual (qui semble aller de pair avec override) et new.

    Je prends un exemple de msdn : http://msdn.microsoft.com/fr-fr/libr...=vs.80%29.aspx
    Ils illustrent ici l'utilisation du mot cle override. Je pense l'avoir bien compris, rien de bien complexe.

    Seulement, lorsque j'apporte les modifs suivantes :
    - J'enlève le mot clef virtual de la méthode CalculatePay() dans la classe Employee
    - Je remplace public override decimal CalculatePay() par public new decimal CalculatePay() dans la classe SalesEmployee (qui hérite d'Employee)

    ...

    Le résultat est strictement identique...

    Après avoir arpenté pas mal de sites web, j'ai vu que l'utilisation de new était déconseillée... Mais j'ai pas vraiment compris pourquoi.

    Quelqu'un aurait-il une explication ou un exemple afin que je comprenne clairement ?

    D'avance merci

  2. #2
    Membre averti Avatar de Jerede
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Mai 2010
    Messages
    271
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 32
    Localisation : France

    Informations professionnelles :
    Activité : Développeur .NET

    Informations forums :
    Inscription : Mai 2010
    Messages : 271
    Points : 422
    Points
    422
    Par défaut
    Bonsoir,

    Ce n'est pas du tout pareil !
    Un exemple pour illustrer la chose :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    public class Entity
        {
            public virtual void Execute()
            {
                Console.WriteLine("salut, je suis dans entity");
            }
     
            public void Execute2()
            {
                Console.WriteLine("salut, je suis dans entity");
            }
        }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    public class Human : Entity
        {
            public override void Execute()
            {
                Console.WriteLine("salut, je suis dans Human");
            }
     
            public new void Execute2()
            {
                Console.WriteLine("salut, je suis dans Human");
            }
        }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    class Program
        {
            static void Main(string[] args)
            {
                Entity human = new Human();
     
                human.Execute(); // => Je suis dans Human
     
                human.Execute2(); // => Je suis dans Entity
     
                Console.Read();
            }      
        }
    Ici on caste notre "Human" en Entity.
    Dans le cas n°1, celui de l'override, la classe Human à écrasé la méthode de la classe Entity, comme tu peut le voir, c'est donc la méthode de Human qui est appelé.
    Dans le cas n°2 avec new, la méthode de la classe Entity n'a pas était écrasé, c'est donc celle-ci qui est appelé. "new" ne fait que cacher la méthode de Entity dans la classe Human.

  3. #3
    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
    Pour compléter l'explication de Jerede :

    La différence est en fait liée au polymorphisme. Quand tu overrides dans une classe Derived une méthode virtual M définie dans une classe Base, tu redéfinis son implémentation : ça reste la même méthode, mais c'est l'implémentation spécifique de la classe courante qui sera appelée. Si tu as une variable x de type Base qui fait référence à une instance de la classe Derived, x.M() fera appel à Derived.M() et non à Base.M().

    Quand tu fais un new sur une méthode, tu caches l'implémentation de la classe de base. Ca introduit une nouvelle méthode, qui n'a pas de lien avec la méthode de même nom de la classe de base. Cette méthode ne participe pas au polymorphisme, et sera appelée seulement via une variable de la classe dérivée. Pour reprendre l'exemple précédent, x.M() appelera Base.M(), pas Derived.M() (toujours en supposant que x est déclarée de type Base)

    Je reprends l'exemple de Jerede en le complétant un peu :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
                Human human = new Human();
                Entity entity = human;
     
                entity.Execute(); // => Je suis dans Human 
                human.Execute();  // => Je suis dans Human 
     
                entity.Execute2(); // => Je suis dans Entity
                human.Execute2(); // => Je suis dans Human
    On voit bien que dans le cas de la méthode virtuelle, c'est toujours l'implémentation de Human qui est appelée, même à partir d'une variable de type Entity.

    En revanche, les appels à Execute2 (non virtuelle) appellent en fait 2 méthodes différentes, selon le type de la variable, bien que les 2 variables fassent référence au même objet



    Si l'utilisation de new est déconseillée, c'est parce que si tu manipules l'objet via une variable de la classe de base, ta méthode redéfinie avec new ne sera pas appelée. Par exemple, dans un contrôle WinForms, si tu redéfinis OnPaint en faisant new au lieu de override, ta méthode ne sera pas appelée car l'appel est fait via une variable de type Control, et non le type de ton contrôle

  4. #4
    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 : 37
    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
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
                Human human = new Human();
                Entity entity = human;
     
                entity.Execute(); // => Je suis dans Human 
                human.Execute();  // => Je suis dans Human 
     
                entity.Execute2(); // => Je suis dans Entity
                human.Execute2(); // => Je suis dans Human
    Petite coquille non?

  5. #5
    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 Nathanael Marchand Voir le message
    Petite coquille non?
    Oups
    Merci, c'est corrigé

  6. #6
    Nouveau membre du Club
    Profil pro
    Étudiant
    Inscrit en
    Décembre 2007
    Messages
    54
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Décembre 2007
    Messages : 54
    Points : 39
    Points
    39
    Par défaut
    Merci pour ces réponses illustrées, je crois que je commence à saisir le principe

    En revanche, je vois pas dans quel(s) cas on a intérêt à écrire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Entity human = new Human();
    Je veux dire par là que je si veux créer une nouvelle instance de Human, j'aurai tendance à écrire tout simplement :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Human human = new Human();

  7. #7
    Expert éminent Avatar de Graffito
    Profil pro
    Inscrit en
    Janvier 2006
    Messages
    5 993
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2006
    Messages : 5 993
    Points : 7 903
    Points
    7 903
    Par défaut
    En revanche, je vois pas dans quel(s) cas on a intérêt à écrire ...
    Dans ce cas par exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    Entity MyEntity=null ;
    Switch (SelectComboBox.text)
    {
       case "Human"  : MyEntity=new Human () ; break ;
       case "Animal" : MyEntity=new Animal() ; break ;
       ...
    }
    MyEntity.Draw() ;
    " Le croquemitaine ! Aaaaaah ! Où ça ? " ©Homer Simpson

  8. #8
    Nouveau membre du Club
    Profil pro
    Étudiant
    Inscrit en
    Décembre 2007
    Messages
    54
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Décembre 2007
    Messages : 54
    Points : 39
    Points
    39
    Par défaut
    Mmmh, pas bête du tout ça, je n'y avais pas pensé !

    Merci à tous pour vos réponses (rapides en plus !), je vais pratiquer un peu histoire d'être sur d'avoir bien compris

  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 Ikki_2504 Voir le message
    En revanche, je vois pas dans quel(s) cas on a intérêt à écrire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Entity human = new Human();
    Je veux dire par là que je si veux créer une nouvelle instance de Human, j'aurai tendance à écrire tout simplement :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Human human = new Human();
    Sauf que selon les cas, tu ne voudras pas toujours créer le même type d'entité... (cf. l'exemple de Graffito)

    Autre exemple : tu crées une méthode qui peut manipuler n'importe quel type d'entité :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    public void DoSomething(Entity entity)
    {
        ...
        entity.Execute();
        ...
    }
    Là tu ne sais même pas de quel type d'entité il s'agit, mais tu n'as pas besoin de le savoir : Execute est virtuelle, donc ça appellera automatiquement l'implémentation du type réel. Alors que si tu avais appelé Execute2, ça aurait toujours appelé Entity.Execute2, jamais Human.Execute2, puisque Execute2 n'est pas virtuelle

  10. #10
    Nouveau membre du Club
    Profil pro
    Étudiant
    Inscrit en
    Décembre 2007
    Messages
    54
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Décembre 2007
    Messages : 54
    Points : 39
    Points
    39
    Par défaut
    Ok pour ton exemple tomlev

    En essayant d'appliquer l'exemple de Graffito... J'ai fait un GetType() sur ma variable MyEntity selon le case dans lequel je passe, et effectivement, MyEntity est bien un Human ou un Animal

    En revanche, je n'ai pas accès aux méthodes *spécifiques* d'Human ou d'Animal ; je n'ai accès qu'aux méthodes d'Entity... Est-ce normal ? Si oui pourquoi ? Une fois casté, un objet devrait avoir un accès complet aux méthodes de la classe dans laquelle il se trouve non ?

  11. #11
    Membre expert
    Profil pro
    Inscrit en
    Décembre 2004
    Messages
    2 210
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2004
    Messages : 2 210
    Points : 3 015
    Points
    3 015
    Par défaut
    Citation Envoyé par Ikki_2504
    En revanche, je n'ai pas accès aux méthodes *spécifiques* d'Human ou d'Animal ; je n'ai accès qu'aux méthodes d'Entity... Est-ce normal ? Si oui pourquoi ?
    Oui. Et c'est d'ailleurs exactement l'explication de tomlev avec la méthode Execute2 (voir son dernier post).

    Citation Envoyé par Ikki_2504
    Une fois casté, un objet devrait avoir un accès complet aux méthodes de la classe dans laquelle il se trouve non ?
    Oui.

  12. #12
    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 : 37
    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 Ikki_2504 Voir le message
    Ok pour ton exemple tomlev

    En essayant d'appliquer l'exemple de Graffito... J'ai fait un GetType() sur ma variable MyEntity selon le case dans lequel je passe, et effectivement, MyEntity est bien un Human ou un Animal

    En revanche, je n'ai pas accès aux méthodes *spécifiques* d'Human ou d'Animal ; je n'ai accès qu'aux méthodes d'Entity... Est-ce normal ? Si oui pourquoi ? Une fois casté, un objet devrait avoir un accès complet aux méthodes de la classe dans laquelle il se trouve non ?
    Tu peux toujours faire:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    public void DoSomething(Entity entity)
    {
        ...
        if(entitiy is Human)
            (entity as Human).Execute2();
        ...
    }
    Dans ce cas la ca sera celle avec le new qui sera executé
    Sacré noeud au cerveau hein?

  13. #13
    Nouveau membre du Club
    Profil pro
    Étudiant
    Inscrit en
    Décembre 2007
    Messages
    54
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Décembre 2007
    Messages : 54
    Points : 39
    Points
    39
    Par défaut
    Après avoir relu plusieurs fois vos différentes réponses ... Je commence à vraiment comprendre (je crois).

    Effectivement, c'est loin d'être l'évidence même pour moi, mais j'y vois quand même une certaine logique...

    Y'a pu qu'à (beaucoup) pratiquer pour que ça devienne naturel.

    Merci encore pour vos réponses éclairées !

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

Discussions similaires

  1. Différence entre virtual et abstract
    Par _LVEB_ dans le forum C#
    Réponses: 8
    Dernier message: 29/09/2015, 17h21
  2. Difference entre New et (virtual / override)
    Par shimomura22 dans le forum C#
    Réponses: 2
    Dernier message: 16/04/2015, 21h08
  3. difference entre virtual-override-Dynamic ?
    Par Jcpan dans le forum Débuter
    Réponses: 7
    Dernier message: 07/04/2010, 12h52
  4. Différence entre MaClasse m; et new MaClasse?
    Par Jean_Benoit dans le forum C++
    Réponses: 2
    Dernier message: 12/10/2006, 21h03
  5. [C#] Différences entre Virtual et Abstract
    Par kunfuka dans le forum C#
    Réponses: 2
    Dernier message: 11/11/2005, 12h14

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