Há uma diferença entre new
e virtual
/ override
.
Você pode imaginar que uma classe, quando instanciada, nada mais é do que uma tabela de ponteiros, apontando para a implementação real de seus métodos. A imagem a seguir deve visualizar isso muito bem:
Agora, existem diferentes maneiras de definir um método. Cada um se comporta diferente quando é usado com herança. A maneira padrão sempre funciona como a imagem acima ilustra. Se você deseja alterar esse comportamento, pode anexar palavras-chave diferentes ao seu método.
1. Classes abstratas
O primeiro é abstract
. abstract
Os métodos simplesmente apontam para lugar nenhum:
Se sua classe contiver membros abstratos, ela também precisará ser marcada como abstract
, caso contrário, o compilador não compilará seu aplicativo. Você não pode criar instâncias de abstract
classes, mas pode herdar delas e criar instâncias de suas classes herdadas e acessá-las usando a definição de classe base. No seu exemplo, isso seria semelhante a:
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 chamado, o comportamento de ShowInfo
varia, com base na implementação:
Person person = new Teacher();
person.ShowInfo(); // Shows 'I am a teacher!'
person = new Student();
person.ShowInfo(); // Shows 'I am a student!'
Ambos, Student
s e Teacher
s são Person
s, mas se comportam de maneira diferente quando solicitados a solicitar informações sobre si mesmos. No entanto, a maneira de solicitar que eles solicitem suas informações é a mesma: usando a Person
interface da classe.
Então, o que acontece nos bastidores, quando você herda Person
? Ao implementar ShowInfo
, o ponteiro não está mais apontando para lugar nenhum, agora aponta para a implementação real! Ao criar uma Student
instância, ele aponta para Student
s ShowInfo
:
2. Métodos virtuais
A segunda maneira é usar virtual
métodos. O comportamento é o mesmo, exceto que você está fornecendo uma implementação padrão opcional em sua classe base. Classes com virtual
membros podem ser instanciadas, no entanto, classes herdadas podem fornecer implementações diferentes. Aqui está como seu código deve realmente funcionar:
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!");
}
}
A principal diferença é que o membro base Person.ShowInfo
não está mais apontando para lugar nenhum. Esse também é o motivo pelo qual você pode criar instâncias de Person
(e, portanto, não precisa mais ser marcado como abstract
):
Você deve notar que isso não parece diferente da primeira imagem no momento. Isso ocorre porque o virtual
método está apontando para uma implementação " da maneira padrão ". Usando virtual
, você pode dizer Persons
, que eles podem (não devem ) fornecer uma implementação diferente para ShowInfo
. Se você fornecer uma implementação diferente (usando override
), como eu fiz para o Teacher
acima, a imagem terá a mesma aparência de abstract
. Imagine, não fornecemos uma implementação personalizada para Student
s:
public class Student : Person
{
}
O código seria chamado assim:
Person person = new Teacher();
person.ShowInfo(); // Shows 'I am a teacher!'
person = new Student();
person.ShowInfo(); // Shows 'I am a person!'
E a imagem para Student
ficaria assim:
3. A palavra-chave mágica `new`, conhecida como" Shadowing "
new
é mais um truque em torno disso. Você pode fornecer métodos em classes generalizadas, com os mesmos nomes que os métodos na classe / interface base. Ambos apontam para sua própria implementação personalizada:
A implementação se parece com a que você forneceu. O comportamento é diferente, com base na maneira como você acessa o método:
Teacher teacher = new Teacher();
Person person = (Person)teacher;
teacher.ShowInfo(); // Prints 'I am a teacher!'
person.ShowInfo(); // Prints 'I am a person!'
Esse comportamento pode ser desejado, mas no seu caso, é enganoso.
Espero que isso torne as coisas mais claras para você entender!