C'è una differenza tra new
e virtual
/ override
.
Potete immaginare che una classe, quando istanziata, non è altro che una tabella di puntatori, che indica l'implementazione effettiva dei suoi metodi. L'immagine seguente dovrebbe visualizzarlo abbastanza bene:
Ora ci sono diversi modi, è possibile definire un metodo. Ognuno si comporta in modo diverso quando viene utilizzato con l'ereditarietà. Il modo standard funziona sempre come illustrato nell'immagine sopra. Se si desidera modificare questo comportamento, è possibile associare diverse parole chiave al metodo.
1. Classi astratte
Il primo è abstract
. abstract
i metodi indicano semplicemente il nulla:
Se la tua classe contiene membri astratti, deve anche essere contrassegnata come abstract
, altrimenti il compilatore non compilerà la tua applicazione. Non è possibile creare istanze di abstract
classi, ma è possibile ereditare da esse e creare istanze delle classi ereditate e accedervi utilizzando la definizione della classe di base. Nel tuo esempio questo sembrerebbe:
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!");
}
}
Se chiamato, il comportamento di ShowInfo
varia in base all'implementazione:
Person person = new Teacher();
person.ShowInfo(); // Shows 'I am a teacher!'
person = new Student();
person.ShowInfo(); // Shows 'I am a student!'
Tutti e due, Student
s e Teacher
s sono Person
s, ma si comportano in modo diverso quando viene chiesto di richiedere informazioni su se stessi. Tuttavia, il modo per chiedere loro di richiedere le loro informazioni è lo stesso: utilizzando l' Person
interfaccia di classe.
Quindi cosa succede dietro le quinte, quando erediti Person
? Durante l'implementazione ShowInfo
, il puntatore non punta più verso il nulla , ora punta all'implementazione effettiva! Quando si crea Student
un'istanza, indicaStudent
s ShowInfo
:
2. Metodi virtuali
Il secondo modo è usare i virtual
metodi. Il comportamento è lo stesso, tranne per il fatto che stai fornendo un'implementazione predefinita opzionale nella tua classe base. Le classi con virtual
membri possono essere istanziate, tuttavia le classi ereditate possono fornire implementazioni diverse. Ecco come dovrebbe effettivamente funzionare il tuo codice:
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 differenza fondamentale è che il membro di base Person.ShowInfo
non punta più verso il nulla . Questo è anche il motivo per cui è possibile creare istanze di Person
(e quindi non è necessario contrassegnarlo come abstract
più):
Dovresti notare che per ora non sembra diverso dalla prima immagine. Questo perché il virtual
metodo punta a un'implementazione " il modo standard ". Utilizzando virtual
, si può dire Persons
, che possono (non è necessario ) fornire un'implementazione diversa per ShowInfo
. Se fornisci un'implementazione diversa (usando override
), come ho fatto per quanto Teacher
sopra, l'immagine sembrerebbe la stessa di abstract
. Immagina, non abbiamo fornito un'implementazione personalizzata per Student
s:
public class Student : Person
{
}
Il codice si chiamerebbe così:
Person person = new Teacher();
person.ShowInfo(); // Shows 'I am a teacher!'
person = new Student();
person.ShowInfo(); // Shows 'I am a person!'
E l'immagine per Student
sarebbe simile a questa:
3. La magica `nuova` parola chiave alias" Shadowing "
new
è più un trucco intorno a questo. È possibile fornire metodi in classi generalizzate, che hanno gli stessi nomi dei metodi nella classe / interfaccia di base. Entrambi indicano la propria implementazione personalizzata:
L'implementazione è simile a quella fornita. Il comportamento differisce, in base al modo in cui accedi al metodo:
Teacher teacher = new Teacher();
Person person = (Person)teacher;
teacher.ShowInfo(); // Prints 'I am a teacher!'
person.ShowInfo(); // Prints 'I am a person!'
Questo comportamento può essere voluto, ma nel tuo caso è fuorviante.
Spero che questo renda le cose più chiare da capire per te!