web-dev-qa-db-fra.com

Utilisation pratique des fonctions virtuelles en c #

Quelle est l'utilisation pratique des fonctions virtuelles en c #?

48
odiseh

Donc, fondamentalement, si dans votre classe ancêtre vous voulez un certain comportement pour une méthode. Si votre descendant utilise la même méthode mais a une implémentation différente, vous pouvez remplacer , s'il a un virtuel mot-clé.

using System;
class TestClass 
{
   public class Dimensions 
   {
      public const double pi = Math.PI;
      protected double x, y;
      public Dimensions() 
      {
      }
      public Dimensions (double x, double y) 
      {
         this.x = x;
         this.y = y;
      }

      public virtual double Area() 
      {
         return x*y;
      }
   }

   public class Circle: Dimensions 
   {
      public Circle(double r): base(r, 0) 
      {
      }

      public override double Area() 
      { 
         return pi * x * x; 
      }
   }

   class Sphere: Dimensions 
   {
      public Sphere(double r): base(r, 0) 
      {
      }

      public override double Area()
      {
         return 4 * pi * x * x; 
      }
   }

   class Cylinder: Dimensions 
   {
      public Cylinder(double r, double h): base(r, h) 
      {
      }

      public override double Area() 
      {
         return 2*pi*x*x + 2*pi*x*y; 
      }
   }

   public static void Main()  
   {
      double r = 3.0, h = 5.0;
      Dimensions c = new Circle(r);
      Dimensions s = new Sphere(r);
      Dimensions l = new Cylinder(r, h);
      // Display results:
      Console.WriteLine("Area of Circle   = {0:F2}", c.Area());
      Console.WriteLine("Area of Sphere   = {0:F2}", s.Area());
      Console.WriteLine("Area of Cylinder = {0:F2}", l.Area());
   }
}

Modifier: Questions en commentaire
Si je n'utilise pas de mot-clé virtuel dans la classe de base, cela fonctionnera-t-il?

Si vous utilisez le mot clé override dans vos classes descendantes, cela ne fonctionnera pas. Vous générerez une erreur du compilateur CS0506 'fonction1': ne peut pas remplacer le membre hérité 'fonction2' car il n'est pas marqué "virtuel", "abstrait" ou "remplacer"

Si vous n'utilisez pas la substitution, vous obtiendrez le CS0108 avertissement 'desc.Method ()' masque le membre hérité 'base.Method ()' Utilisez le nouveau mot-clé si le masquage était prévu.

Pour contourner ce problème, placez le mot clé new devant la méthode que vous cachez .

par exemple.

  new public double Area() 
  {
     return 2*pi*x*x + 2*pi*x*y; 
  }

.. et est-il obligatoire de remplacer une méthode virtuelle dans une classe dérivée?
Non, si vous ne remplacez pas la méthode, la classe descendante utilisera la méthode dont elle hérite.

82
Johnno Nolan

La clé pour comprendre l'utilisation pratique des fonctions virtuelles est de garder à l'esprit qu'un objet d'une certaine classe peut être affecté à un autre objet d'une classe dérivée de la classe du premier objet.

Par exemple.:

class Animal {
   public void eat() {...}
}

class FlyingAnimal : Animal {
   public void eat() {...}
}

Animal a = new FlyingAnimal();

La classe Animal a une fonction eat() qui décrit généralement comment un animal doit manger (par exemple, mettre l'objet en bouche et avaler).

Cependant, la classe FlyingAnimal doit définir une nouvelle méthode eat(), car les animaux volants ont une façon particulière de manger.

La question qui me vient à l'esprit est donc: après avoir déclaré la variable a de type Animal et lui avoir assigné un nouvel objet de type FlyingAnimal, qu'est-ce que a.eat() faire? Laquelle des deux méthodes est appelée?

La réponse est la suivante: parce que a est de type Animal, il appellera la méthode de Animal. Le compilateur est stupide et ne sait pas que vous allez affecter un objet d'une autre classe à la variable a.

Voici où le mot clé virtual entre en action: si vous déclarez la méthode comme virtual void eat() {...}, vous dites au compilateur "faites attention à ce que je fais des trucs intelligents ici que vous ne pouvez pas gérer parce que tu n'es pas aussi intelligent ". Ainsi, le compilateur n'essaiera pas de lier l'appel a.eat() à l'une des deux méthodes, mais à la place, il indique au système de le faire à l'exécution!

Donc, seulement lorsque le code s'exécute, le système va regarder atype de conten pas à son type déclaré et exécute la méthode FlyingAnimal.

Vous vous demandez peut-être: pourquoi diable voudrais-je faire ça? Pourquoi ne pas dire dès le début FlyingAnimal a = new FlyingAnimal()?

La raison en est que, par exemple, vous pouvez avoir de nombreuses classes dérivées de Animal: FlyingAnimal, SwimmingAnimal, BigAnimal, WhiteDog etc. Et à un moment donné, vous voulez définir un monde contenant de nombreux Animals, alors vous dites:

Animal[] happy_friends = new Animal[100];

Nous avons un monde avec 100 animaux heureux. Vous les initialisez à un moment donné:

...
happy_friends[2] = new AngryFish();
...
happy_friends[10] = new LoudSnake();
...

Et à la fin de la journée, vous voulez que tout le monde mange avant d'aller dormir. Vous voulez donc dire:

for (int i=0; i<100; i++) {
   happy_friends[i].eat();
}

Comme vous pouvez le voir, chaque animal a sa propre façon de manger. Ce n'est qu'en utilisant les fonctions virtuelles que vous pouvez obtenir cette fonctionnalité. Sinon, tout le monde serait obligé de "manger" de la même manière: comme décrit dans la fonction eat la plus générale de la classe Animal.

EDIT: Ce comportement est en fait par défaut dans les langages de haut niveau courants comme Java.

64
Bogdan Alexandru

Comme toute autre langue ... quand vous voulez du polymorphisme. Il y a des tonnes d'utilisation pour cela. Par exemple, vous voulez faire abstraction de la façon dont l'entrée est lue à partir d'une console ou d'un fichier ou d'un autre périphérique. Vous pouvez avoir une interface de lecture générique suivie de plusieurs implémentations concrètes utilisant des fonctions virtuelles.

7
Naveen

par exemple. méthodes de procuration. c'est-à-dire écraser les méthodes au moment de l'exécution. Par exemple, NHibernate l'utilise pour prendre en charge le chargement paresseux.

4

Cela permet d'obtenir une liaison tardive, c'est-à-dire de déterminer au moment de l'exécution plutôt qu'au moment de la compilation quel membre de l'objet sera invoqué. Voir Wikipedia .

4
Juri

Fondamentalement, les membres virtuels vous permettent d'exprimer le polymorphisme, une classe dérivée peut avoir une méthode avec la même signature que la méthode dans sa classe de base, et la classe de base appellera la méthode de la classe dérivée.

Un exemple de base:

public class Shape
{
    // A few example members
    public int X { get; private set; }
    public int Y { get; private set; }
    public int Height { get; set; }
    public int Width { get; set; }

    // Virtual method
    public virtual void Draw()
    {
        Console.WriteLine("Performing base class drawing tasks");
    }
}

class Circle : Shape
{
    public override void Draw()
    {
        // Code to draw a circle...
        Console.WriteLine("Drawing a circle");
        base.Draw();
    }
}
class Rectangle : Shape
{
    public override void Draw()
    {
        // Code to draw a rectangle...
        Console.WriteLine("Drawing a rectangle");
        base.Draw();
    }
}
class Triangle : Shape
{
    public override void Draw()
    {
        // Code to draw a triangle...
        Console.WriteLine("Drawing a triangle");
        base.Draw();
    }
}
3
CMS

De ici :

Dans la programmation orientée objet, une fonction virtuelle ou une méthode virtuelle est une fonction ou une méthode dont le comportement peut être remplacé dans une classe héritée par une fonction avec la même signature.

1
Burkhard

Par exemple, vous avez une classe de base Params et un ensemble de classes dérivées. Vous voulez pouvoir effectuer la même opération sur un tableau qui stocke toutes les classes possibles dérivées de params.

Pas de problème - déclarez la méthode virtuelle, ajoutez une implémentation de base à la classe Params et remplacez-la dans les classes dérivées. Maintenant, vous pouvez simplement parcourir le tableau et appeler la méthode via la référence - la bonne méthode sera appelée.

class Params {
public:
   virtual void Manipulate() { //basic impl here }
}

class DerivedParams1 : public Params {
public:
   override void Manipulate() {
      base.Manipulate();
      // other statements here
   }
};

// more derived classes can do the same

void ManipulateAll( Params[] params )
{
    for( int i = 0; i < params.Length; i++ ) {
       params[i].Manipulate();
    }
 }
1
sharptooth

Utilisation des fonctions virtuelles en c #

Les fonctions virtuelles sont principalement utilisées pour remplacer la méthode de classe de base dans la classe dérivée avec la même signature.

Lorsqu'une classe dérivée hérite de la classe de base, l'objet de la classe dérivée est une référence à la classe dérivée ou à la classe de base.

Les fonctions virtuelles sont résolues tardivement par le compilateur (c'est-à-dire la liaison au moment de l'exécution)

virtual dans la classe de base, l'implémentation de la fonction de la classe la plus dérivée est appelée en fonction du type réel de l'objet auquel il est fait référence, quel que soit le type déclaré du pointeur ou de la référence. Si ce n'est pas virtual, la méthode est résolue early et la fonction appelée est sélectionnée en fonction du type déclaré du pointeur ou de la référence.

1
Divya