Es gibt einen Unterschied zwischen new
und virtual
/ override
.
Sie können sich vorstellen, dass eine Klasse, wenn sie instanziiert wird, nichts weiter als eine Tabelle von Zeigern ist, die auf die tatsächliche Implementierung ihrer Methoden verweisen. Das folgende Bild sollte dies ziemlich gut veranschaulichen:
Nun gibt es verschiedene Möglichkeiten, eine Methode zu definieren. Jedes verhält sich anders, wenn es mit Vererbung verwendet wird. Die Standardmethode funktioniert immer wie im obigen Bild dargestellt. Wenn Sie dieses Verhalten ändern möchten, können Sie Ihrer Methode verschiedene Schlüsselwörter hinzufügen.
1. Abstrakte Klassen
Der erste ist abstract
. abstract
Methoden zeigen einfach auf nichts:
Wenn Ihre Klasse abstrakte Elemente enthält, muss sie auch als markiert werden, da abstract
sonst der Compiler Ihre Anwendung nicht kompiliert. Sie können keine Instanzen von abstract
Klassen erstellen , aber Sie können von ihnen erben und Instanzen Ihrer geerbten Klassen erstellen und mithilfe der Basisklassendefinition darauf zugreifen. In Ihrem Beispiel würde dies so aussehen:
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!");
}
}
Wenn aufgerufen, ShowInfo
variiert das Verhalten von je nach Implementierung:
Person person = new Teacher();
person.ShowInfo(); // Shows 'I am a teacher!'
person = new Student();
person.ShowInfo(); // Shows 'I am a student!'
Sowohl Student
s als auch Teacher
s sind Person
s, aber sie verhalten sich unterschiedlich, wenn sie aufgefordert werden, Informationen über sich selbst einzugeben. Die Art und Weise, wie sie aufgefordert werden, ihre Informationen einzugeben, ist jedoch dieselbe: Verwenden der Person
Klassenschnittstelle.
Was passiert also hinter den Kulissen, wenn Sie von erben Person
? Bei der Implementierung ShowInfo
zeigt der Zeiger nicht mehr auf das Nirgendwo , sondern auf die tatsächliche Implementierung! Beim Erstellen einer Student
Instanz zeigt es auf Student
s ShowInfo
:
2. Virtuelle Methoden
Der zweite Weg ist die Verwendung von virtual
Methoden. Das Verhalten ist dasselbe, außer dass Sie eine optionale Standardimplementierung in Ihrer Basisklasse bereitstellen . Klassen mit virtual
Mitgliedern können instanziiert werden, geerbte Klassen können jedoch unterschiedliche Implementierungen bereitstellen. So sollte Ihr Code tatsächlich aussehen, um zu funktionieren:
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!");
}
}
Der Hauptunterschied besteht darin, dass das Basismitglied nicht mehr Person.ShowInfo
auf das Nirgendwo zeigt . Dies ist auch der Grund, warum Sie Instanzen von erstellen können Person
(und daher nicht mehr als gekennzeichnet abstract
werden müssen):
Sie sollten beachten, dass dies vorerst nicht anders aussieht als das erste Bild. Dies liegt daran, dass die virtual
Methode auf eine Implementierung "auf die Standardmethode " verweist . Mit virtual
können Sie feststellen Persons
, dass sie eine andere Implementierung für bereitstellen können (nicht müssen ) ShowInfo
. Wenn Sie eine andere Implementierung (mit override
) bereitstellen , wie ich es Teacher
oben getan habe , würde das Bild genauso aussehen wie für abstract
. Stellen Sie sich vor, wir haben keine benutzerdefinierte Implementierung für Student
s bereitgestellt:
public class Student : Person
{
}
Der Code würde so heißen:
Person person = new Teacher();
person.ShowInfo(); // Shows 'I am a teacher!'
person = new Student();
person.ShowInfo(); // Shows 'I am a person!'
Und das Bild für Student
würde so aussehen:
3. Das magische "neue" Schlüsselwort, auch bekannt als "Shadowing"
new
ist eher ein Hack um dieses. Sie können Methoden in verallgemeinerten Klassen bereitstellen, die dieselben Namen wie Methoden in der Basisklasse / Schnittstelle haben. Beide verweisen auf ihre eigene, benutzerdefinierte Implementierung:
Die Implementierung sieht wie die von Ihnen bereitgestellte aus. Das Verhalten hängt davon ab, wie Sie auf die Methode zugreifen:
Teacher teacher = new Teacher();
Person person = (Person)teacher;
teacher.ShowInfo(); // Prints 'I am a teacher!'
person.ShowInfo(); // Prints 'I am a person!'
Dieses Verhalten kann gewünscht werden, ist aber in Ihrem Fall irreführend.
Ich hoffe, das macht das Verständnis für Sie klarer!