Utilisation de fonctions virtuelles en c#
9 réponses
Donc en gros si dans votre classe ancêtre vous voulez un certain comportement d'une méthode. Si votre descendant utilise la même méthode mais a une implémentation différente, vous pouvez remplacer il, Si elle a un virtual 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());
}
}
Edit: Questions en commentaire
si je n'utilise pas le mot-clé virtuel dans la classe de base, est-ce que ça marchera?
Si vous utilisez le override
mot-clé dans vos classes descendantes it ne fonctionnera pas. Vous générerez une erreur de compilation CS0506 'function1': ne peut pas outrepasser le membre hérité 'function2' parce qu'il n'est pas marqué "virtual", "abstract", ou "override"
Si vous n'utilisez pas le remplacer, Vous aurez l' CS0108 avertissement ' desc.Méthode()' cache la base de membre hérité'.Méthode()' Utiliser le nouveau mot-clé si cachette était prévu.
Pour contourner ce mettre le new
mot-clé devant la méthode que vous êtes se cacher.
e.g.
new public double Area()
{
return 2*pi*x*x + 2*pi*x*y;
}
..et est-il obligatoire de remplacer une méthode virtuelle dans la classe dérivée?
Non, si vous n'outrepassez pas la méthode, la classe descendante utilisera la méthode dont elle hérite.
la clé pour comprendre l'usage pratique des fonctions virtuelles est de garder à l'esprit qu'un objet d'une certaine classe peut être assigné à un autre objet d'une classe dérivé de la classe du premier objet.
par exemple:
class Animal {
public void eat() {...}
}
class FlyingAnimal : Animal {
public void eat() {...}
}
Animal a = new FlyingAnimal();
Animal
classe a une fonction eat()
cela décrit généralement comment un animal doit manger (par exemple, mettre l'objet dans la bouche et avaler).
cependant, le FlyingAnimal
classe doit définir un nouveau eat()
méthode, parce que les animaux volants ont une façon particulière de manger.
donc la question qui vient à l'esprit ici est: après que j'ai déclaré la variable a
de type Animal
et signé un nouvel objet de type FlyingAnimal
, ce qui va a.eat()
faire? Laquelle des deux méthodes est appelée?
la réponse ici est: parce que a
est de type Animal
, il va appeler Animal
'méthode. Le compilateur est stupide et ne sait pas que vous allez assigner un objet d'une autre classe à a
variable.
c'est Ici virtual
mot clé vient en action: si vous déclarez la méthode virtual void eat() {...}
, vous dites en gros au compilateur"faites attention que je fasse des choses intelligentes ici que vous ne pouvez pas gérer parce que vous n'êtes pas aussi intelligent". Ainsi le compilateur ne tentera pas de lier l'appel a.eat()
à l'une ou l'autre des deux méthodes, mais à la place il dit au système de le faire lors de l'exécution!
Donc seulement lorsque le code s'exécute, le système recherche a
type de contenu pas à son type déclaré et exécute FlyingAnimal
'méthode.
vous pouvez Vous demander: pourquoi diable voudrais-je faire? Pourquoi ne pas le dire dès le début FlyingAnimal a = new FlyingAnimal()
?
la raison en est que, par exemple, vous pouvez avoir beaucoup de classes dérivées de Animal
:FlyingAnimal
,SwimmingAnimal
,BigAnimal
,WhiteDog
etc. Et à un moment donné vous voulez définir un monde contenant beaucoup Animal
s, de sorte que vous vous dites:
Animal[] happy_friends = new Animal[100];
nous avons un monde avec 100 animaux heureux. Vous les initialiser à un certain point:
...
happy_friends[2] = new AngryFish();
...
happy_friends[10] = new LoudSnake();
...
Et à la fin de la journée, vous voulez tout le monde à manger avant d'aller dormir. Donc, vous voulez dire:
for (int i=0; i<100; i++) {
happy_friends[i].eat();
}
comme vous pouvez le voir, chaque animal a sa propre méthode de manger. Uniquement à l'aide de virtuel fonctions pouvez-vous atteindre cette fonctionnalité. Sinon, tout le monde serait forcé de "manger" exactement de la même manière: comme décrit dans le plus général eat
fonction à l'intérieur de la Animal
classe.
modifier: Ce comportement est en fait par défaut dans des langages communs de haut niveau comme Java.
comme n'importe quelle autre langue..lorsque vous voulez polymorphisme. Il y a des tonnes d'utilisation de ce. Par exemple, vous voulez abstrait de la voie d'entrée est lu à partir d'une console ou d'un fichier ou d'un autre dispositif. Vous pouvez avoir une interface de lecteur Générique suivie de multiples implémentations concrètes en utilisant des fonctions virtuelles.
par exemple les méthodes de proxy. c.-à-d. les méthodes d'écrasement à l'exécution. Par exemple, NHibernate utilise ceci pour supporter le chargement paresseux.
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();
}
}
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 outrepassez-la dans les classes dérivées. Maintenant vous pouvez simplement traverser le tableau et appeler la méthode par la référence - la méthode correcte 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();
}
}
utilisation de fonctions virtuelles en c#
les fonctions virtuelles sont principalement utilisées pour outrepasser la méthode de la classe de base dans la classe dérivée avec la même signature.
Quand 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 dérivée de la classe ou de la classe de base.
les fonctions virtuelles sont résolues tardivement par le compilateur(I. e fixation du temps d'exécution)
virtual
dans la classe de base, les classes les plus dérivées la mise en œuvre de la fonction est appelée, selon le type réel de l'objet visé, quel que soit le type déclaré de l'pointeur ou d'une référence. Si elle n'est pas virtual
, la méthode est résolu early
et la fonction appelée est sélectionné en fonction du type déclaré de l'pointeur ou d'une référence.