Examinons ce code :
Quand je lance ce code, ce qui suit est émis :
Je suis personne
Toutefois, vous pouvez voir que c’est une instance si , pas de
. Pourquoi le code que faire ?
Examinons ce code :
Quand je lance ce code, ce qui suit est émis :
Je suis personne
Toutefois, vous pouvez voir que c’est une instance si , pas de
. Pourquoi le code que faire ?
Il y a une différence entre new
et virtual
/override
.
Vous pouvez l'imaginer, qu'une classe, lorsqu'il est instancié, n'est rien de plus qu'un tableau de pointeurs pointant vers la mise en œuvre effective de ses méthodes. L'image suivante doit visualiser ce assez bien:
Maintenant, il ya différentes façons, une méthode peut être définie. Chacun se comporte de façon différente quand il est utilisé avec l'héritage. La manière standard fonctionne toujours comme l'image ci-dessus illustre. Si vous souhaitez modifier ce comportement, vous pouvez joindre des différents mots-clés de votre méthode.
Le premier est abstract
. abstract
méthodes tout simplement le point de nulle part:
Si votre classe contient membres abstraits, il doit également être marqué en tant que abstract
, sinon le compilateur ne va pas compiler votre application. Vous ne pouvez pas créer des instances d' abstract
classes, mais vous pouvez hériter d'eux et de créer des instances de votre hérité de classes et d'y accéder à l'aide de la base de la définition de la classe. Dans votre exemple, ce serait:
public abstract class Person
{
public abstract void ShowInfo();
}
public class Teacher : Person
{
public override void ShowInfo()
{
Console.WriteLine("I am a teacher!");
}
}
public class Student : Person
{
public override void ShowInfo()
{
Console.WriteLine("I am a student!");
}
}
Si la fonction est appelée, le comportement de l' ShowInfo
varie en fonction de la mise en œuvre:
Person person = new Teacher();
person.ShowInfo(); // Shows 'I am a teacher!'
person = new Student();
person.ShowInfo(); // Shows 'I am a student!'
Les deux, Student
s et Teacher
s Person
s, mais ils se comportent différemment lorsqu'elles sont posées à l'invite de l'information sur eux-mêmes. Cependant, la manière de les poser à l'invite de leurs informations, est la même: à l'Aide de l' Person
interface de classe.
Donc ce qui se passe derrière les coulisses, lorsque vous héritez de Person
? Lors de la mise en œuvre de ShowInfo
, le pointeur ne pointe pas vers nulle part , il pointe désormais à la mise en œuvre effective! Lors de la création d'un Student
de l'instance, c'points de Student
s ShowInfo
:
La deuxième façon est d'utiliser des virtual
méthodes. Le comportement est le même, sauf que vous êtes en fournissant une option par défaut de mise en œuvre dans votre classe de base. Classes avec virtual
des membres peut être instanciée, cependant les classes héritées peuvent fournir des implémentations différentes. Voici ce que votre code doit effectivement ressembler à travailler:
public class Person
{
public virtual void ShowInfo()
{
Console.WriteLine("I am a person!");
}
}
public class Teacher : Person
{
public override void ShowInfo()
{
Console.WriteLine("I am a teacher!");
}
}
La principale différence est que le membre de base, Person.ShowInfo
n'est pas en pointant nulle part plus longtemps. C'est aussi la raison pour laquelle vous pouvez créer des instances de l' Person
(et donc il n'a pas besoin d'être marqué en tant que abstract
plus):
Vous devriez noter, que ce n'est pas un aspect différent de la première image pour l'instant. C'est parce que l' virtual
méthode est orientée vers une mise en œuvre "de façon standard". À l'aide de virtual
, vous pouvez dire Persons
, qu'ils peuvent (et non doivent) fournir une implémentation différente pour ShowInfo
. Si vous fournissez une mise en œuvre différente (à l'aide d' override
), comme je l'ai fait pour l' Teacher
- dessus, l'image aurait l'air le même que pour l' abstract
. Imaginez, nous n'avons pas fournir une implémentation personnalisée pour Student
s:
public class Student : Person
{
}
Le code pourrait être appelé comme ceci:
Person person = new Teacher();
person.ShowInfo(); // Shows 'I am a teacher!'
person = new Student();
person.ShowInfo(); // Shows 'I am a person!'
Et l'image pour l' Student
ressemblerait à ceci:
new
est plus un hack autour de ce. Vous pouvez fournir des méthodes généralisée des classes, qui ont les mêmes noms que les méthodes de la classe de base/interface. Deux points de leur propre, la coutume de mise en œuvre:
La mise en œuvre ressemble à l'un, vous avez fourni. Le comportement est différent, basé sur la façon dont vous accédez à la méthode:
Teacher teacher = new Teacher();
Person person = (Person)teacher;
teacher.ShowInfo(); // Prints 'I am a teacher!'
person.ShowInfo(); // Prints 'I am a person!'
Ce comportement peut être voulu, mais dans votre cas, il est trompeur.
J'espère que cela rend les choses plus faciles à comprendre pour vous!
Vous devez faire de la méthode virtuelle et vous devez remplacer la fonction dans la classe enfant, afin d'appeler la méthode de la classe de l'objet que vous placez dans la classe parent de référence.
public class Person
{
public virtual void ShowInfo()
{
Console.WriteLine("I am Person");
}
}
public class Teacher : Person
{
public override void ShowInfo()
{
Console.WriteLine("I am Teacher");
}
}
Lorsqu'une méthode virtuelle est invoquée, le type à l'exécution de l'objet est vérifiée pour une impérieuse membre. Le principal membre dans la plupart des la classe dérivée est appelée, ce qui pourrait être le membre d'origine, si aucune dérivée de la classe a remplacé le membre. Par défaut, les méthodes sont non virtuel. Vous ne pouvez pas remplacer une non-méthode virtuelle. Vous ne pouvez pas utiliser le modificateur virtuel avec la statique, abstrait, privé ou de la remplacer les modificateurs, MSDN.
Vous utilisez le nouveau mot-clé au lieu de les remplacer, ce est ce que les nouveaux n'
Si la méthode dans la classe dérivée n'est pas précédée par de nouvelles ou de remplacer les mots clés, le compilateur émet un avertissement et la méthode se comporte comme si le mot-clé new étaient présents.
Si la méthode de la classe dérivée est précédé du mot-clé new, la méthode est définie comme étant indépendants de la méthode dans la classe de base, Cet article MSDN , l'explique très bien.
Nous avons une liaison anticipée au moment de la compilation pour la méthode normale (et non virtuel), qui est l'actuel cas, le compilateur va se lier appel à la méthode de classe de base qui est la méthode de référence type (classe de base) au lieu de l'objet est tenue dans la referece de la classe de base c'est à dire objet de classe dérivée. C'est parce qu' ShowInfo
n'est pas une méthode virtuelle. La liaison tardive est effectué au moment de l'exécution (virtuel / méthode de remplacement) à l'aide de table de méthode virtuelle (vtable).
Pour un fonctionnement normal, le compilateur peut travailler sur les numériques emplacement dans la mémoire. Alors quand la fonction est appelée, elle peut générer des une instruction d'appel de la fonction à cette adresse.
Pour un objet qui a des méthodes virtuelles, le compilateur va générer un v-table. C'est essentiellement un tableau qui contient les adresses de les méthodes virtuelles. Chaque objet possède une méthode virtuelle sera contenir un caché membre généré par le compilateur, qui est l'adresse de la v-table. Quand une fonction virtuelle est appelée, le compilateur va travailler sur ce qui en est de la méthode appropriée à l' v-table. Il va alors générer du code à la regarder dans les objets de la v-table et appel de la méthode virtuelle à cette position de Référence.
Je veux construire hors de Achratt de réponse. Pour être complet, la différence est que l'OP attend l' new
mot-clé dans la classe dérivée de la méthode pour remplacer la méthode de classe de base. Ce qu'il fait est de cacher la méthode de classe de base.
En C#, comme une autre réponse mentionné, traditionnelle la redéfinition de méthode doit être explicite; la méthode de classe de base doit être marqué en tant que virtual
et la classe dérivée doit spécifiquement override
la méthode de classe de base. Si cela est fait, alors il n'a pas d'importance si l'objet est traité comme étant une instance de la classe de base ou de la classe dérivée; la méthode dérivée est trouvé et l'a appelé. Ceci est fait de la même façon qu'en C++, une méthode marquée "virtuel" ou "remplacement", lors de la compilation, est résolu "en retard" (à l'exécution) par la détermination de l'objet référencé de type réel, et en parcourant la hiérarchie de l'objet à la baisse le long de l'arbre à partir de la variable de type de l'objet réel de type, de trouver la dérivée de la mise en œuvre de la méthode définie par le type de variable.
Cela diffère de Java, qui permet de "implicite remplace"; pour les méthodes d'instance (non statique), il suffit de définir une méthode de la même signature (nom et le nombre et le type des paramètres) sera la cause de la sous-classe de remplacer la super-classe.
Parce qu'il est souvent utile d'étendre ou de remplacer la fonctionnalité d'une non-méthode virtuelle vous ne contrôlez pas, C# inclut également l' new
mot-clé contextuel. L' new
mot-clé "cache" de la méthode parent au lieu de passer outre. Tout héritables méthode peut être caché si c'est virtuel ou pas, ce qui permet aux développeurs, à l'effet de levier les membres que vous souhaitez hériter d'un parent, sans avoir à contourner ceux qui ne le sont pas, tout en vous permettant de présenter le même "interface" pour les consommateurs de votre code.
Cacher fonctionne de façon similaire à la redéfinition du point de vue d'une personne à l'aide de votre objet à ou en dessous du niveau de la succession au cours de laquelle le cacher méthode est définie. À partir de la question de l'exemple, un codeur de la création d'un Enseignant et de la stocker dans une variable de l'Enseignant type va voir le comportement de la ShowInfo() de la mise en œuvre de l'Enseignant, qui se cache celui de la Personne. Cependant, quelqu'un qui travaille avec votre objet dans une collection d'enregistrements de personnes (comme vous) va voir le comportement de la Personne mise en oeuvre de ShowInfo(); parce que l'Enseignant de la méthode ne modifie pas ses parents (ce qui nécessiterait également la Personne.ShowInfo() pour être virtuel), le code de travail à la Personne niveau d'abstraction ne trouverez pas de l'Enseignant la mise en œuvre et de ne pas l'utiliser.
En outre, non seulement l' new
mot-clé le faire explicitement, C# permet de la méthode implicite à se cacher; il suffit de définir une méthode avec la même signature qu'une méthode de la classe mère, sans override
ou new
, cacher (mais il va produire un avertissement du compilateur ou d'une plainte de la part de certains refactoring des assistants comme ReSharper ou CodeRush). C'est le compromis de C#concepteurs venu avec entre C++explicite remplace vs Java est implicite, et tandis qu'il est élégant, il ne produit pas toujours le comportement que vous attendez si vous venez d'un arrière-plan de l'une des plus anciennes langues.
Voici les nouveautés: Cela devient complexe lorsque vous combinez les deux mots-clés dans une longue chaîne d'héritage. Considérez les points suivants:
class Foo { public virtual void DoFoo() { Console.WriteLine("Foo"); } }
class Bar:Foo { public override sealed void DoFoo() { Console.WriteLine("Bar"); } }
class Baz:Bar { public virtual void DoFoo() { Console.WriteLine("Baz"); } }
class Bai:Baz { public override void DoFoo() { Console.WriteLine("Bai"); } }
class Bat:Bai { public new void DoFoo() { Console.WriteLine("Bat"); } }
class Bak:Bat { }
Foo foo = new Foo();
Bar bar = new Bar();
Baz baz = new Baz();
Bai bai = new Bai();
Bat bat = new Bat();
foo.DoFoo();
bar.DoFoo();
baz.DoFoo();
bai.DoFoo();
bat.DoFoo();
Console.WriteLine("---");
Foo foo2 = bar;
Bar bar2 = baz;
Baz baz2 = bai;
Bai bai2 = bat;
Bat bat2 = new Bak();
foo2.DoFoo();
bar2.DoFoo();
baz2.DoFoo();
bai2.DoFoo();
Console.WriteLine("---");
Foo foo3 = bak;
Bar bar3 = bak;
Baz baz3 = bak;
Bai bai3 = bak;
Bat bat3 = bak;
foo3.DoFoo();
bar3.DoFoo();
baz3.DoFoo();
bai3.DoFoo();
bat3.DoFoo();
Sortie:
Foo
Bar
Baz
Bai
Bat
---
Bar
Bar
Bai
Bai
Bat
---
Bar
Bar
Bai
Bai
Bat
La première série de cinq est à prévoir, parce que chaque niveau a une mise en œuvre, et est référencé comme un objet du même type a été instancié, le moteur d'exécution résout chaque appel à l'héritage de niveau référencé par la variable type.
La deuxième série de cinq, c'est le résultat de l'attribution à chaque instance d'une variable de l'immédiat type parent. Maintenant, certaines différences de comportement à secouer; foo2
, qui est en fait un Bar
coulés Foo
, va encore trouver le plus de la méthode dérivée de l'objet réel de type Bar. bar2
est Baz
, mais contrairement à foo2
, parce que Baz n'a pas explicitement remplacer la Barre de mise en œuvre (il ne peut pas; Bar sealed
), il n'est pas vu par le moteur d'exécution lors de la recherche "top-down", de sorte que la Barre de mise en œuvre est appelée à la place. Notez que Baz ne pas avoir à utiliser l' new
de mots-clés; vous obtiendrez un avertissement du compilateur si vous omettez le mot-clé, mais le comportement implicite en C# est de cacher la méthode parent. baz2
est Bai
, ce qui remplace Baz
s' new
mise en œuvre, de sorte que son comportement est similaire à l' foo2
s'; le type de l'objet est mise en œuvre dans le Bai est appelé. bai2
est Bat
, à nouveau, qui cache son parent Bai
s'méthode de la mise en œuvre, et il a le même comportement que bar2
même si de la Bai de mise en œuvre n'est pas scellé, donc, théoriquement, chauve-souris pourrait avoir remplacé au lieu de caché la méthode. Enfin, bat2
est Bak
, ce qui n'a pas primordial de la mise en œuvre des deux types, et utilise simplement celle de son parent.
La troisième série de cinq illustre le plein de haut en bas de comportement de résolution. Tout est fait référence à une instance de la classe plus dérivée de la chaîne, Bak
, mais la résolution à chaque niveau de la variable type est effectuée en commençant au niveau de la chaîne d'héritage et de forage vers le bas pour la plupart des dérivés explicite substitution de la méthode, qui sont ceux en Bar
, Bai
, et Bat
. Méthode cachant ainsi les "pauses" le principal héritage de la chaîne; vous devez travailler avec l'objet à ou en dessous du niveau de l'héritage qui cache la méthode pour le masquage de la méthode à utiliser. Sinon, le caché, la méthode est "à découvert" et qui est utilisé à la place.
Vous devez le rendre virtual
, puis remplacer cette fonction en Teacher
. Lorsque vous héritez et utilisez le pointeur de base pour faire référence à une classe dérivée, vous devez la remplacer par virtual
. new
sert à masquer la méthode de la classe base
sur une référence de classe dérivée et non à une référence de classe base
.
Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.