Menu
Coddy logo textTech

Palavras-chave Virtual e Override

Parte da seção Programação Orientada a Objetos do Journey de C# da Coddy — lição 21 de 70.

Quando uma classe derivada herda um método, às vezes você deseja alterar completamente como esse método se comporta. As palavras-chave virtual e override trabalham juntas para tornar isso possível de forma controlada.

Marque um método como virtual na classe base para sinalizar que as classes derivadas têm permissão para substituir sua implementação:

public class Animal
{
    public virtual void Speak()
    {
        Console.WriteLine("Some sound");
    }
}

public class Dog : Animal
{
    public override void Speak()
    {
        Console.WriteLine("Woof!");
    }
}

A palavra-chave override na classe derivada informa ao compilador que você está substituindo intencionalmente o método base. Sem virtual no método base, você não pode usar override.

O verdadeiro poder aparece quando você usa uma referência de classe base para conter um objeto derivado:

Animal myPet = new Dog();
myPet.Speak();  // Saída: Woof!

Embora myPet seja declarado como Animal, o C# chama a versão Dog de Speak(). Isso é chamado de polimorfismo de tempo de execução - o método real chamado depende do tipo verdadeiro do objeto, não do tipo declarado da variável.

Você ainda pode acessar a implementação base usando base.Speak() dentro da sua sobrescrita se desejar estender em vez de substituir completamente o comportamento.

challenge icon

Desafio

Fácil

Vamos construir um sistema de notificação que demonstra como classes derivadas podem sobrescrever completamente o comportamento da classe base usando as palavras-chave virtual e override, enquanto também mostramos o poder do polimorfismo em tempo de execução.

Você criará três arquivos para organizar seu código:

  • Notification.cs: Defina uma classe Notification no namespace Alerts. Esta classe base representa uma notificação genérica com uma propriedade Message (string) e um construtor que a define. Inclua um método virtual chamado Send() que retorna "Sending notification: " + Message.
  • EmailNotification.cs: Defina uma classe EmailNotification no namespace Alerts que herda de Notification. Adicione uma propriedade Recipient (string) e um construtor que aceita tanto a mensagem quanto o destinatário (use base para passar a mensagem). Sobrescreva o método Send() para retornar "Emailing " + Recipient + ": " + Message.
  • SmsNotification.cs: Defina uma classe SmsNotification no namespace Alerts que também herda de Notification. Adicione uma propriedade PhoneNumber (string) e um construtor que aceita tanto a mensagem quanto o número de telefone. Sobrescreva Send() para retornar "SMS to " + PhoneNumber + ": " + Message.
  • Program.cs: No seu arquivo principal, crie instâncias de todos os três tipos de notificação usando os valores de entrada. Em seguida, demonstre o polimorfismo em tempo de execução armazenando todos os três em variáveis do tipo Notification e chamando Send() em cada uma.

Você receberá três entradas:

  • A mensagem da notificação
  • O endereço de e-mail do destinatário
  • O número de telefone para SMS

Imprima o resultado da chamada de Send() em cada notificação, armazenadas como referências da classe base:

{base notification Send() result}
{email notification Send() result}
{sms notification Send() result}

Por exemplo, se as entradas forem Meeting at 3pm, alice@email.com, e 555-1234, a saída deve ser:

Sending notification: Meeting at 3pm
Emailing alice@email.com: Meeting at 3pm
SMS to 555-1234: Meeting at 3pm

Observe como, embora todos os três estejam armazenados como variáveis Notification, cada um chama sua própria versão sobrescrita de Send(). Isso é o polimorfismo em tempo de execução em ação!

Folha de consulta

Use a palavra-chave virtual em uma classe base para marcar um método que as classes derivadas podem sobrescrever:

public class Animal
{
    public virtual void Speak()
    {
        Console.WriteLine("Some sound");
    }
}

Use a palavra-chave override em uma classe derivada para substituir a implementação do método da classe base:

public class Dog : Animal
{
    public override void Speak()
    {
        Console.WriteLine("Woof!");
    }
}

O polimorfismo de tempo de execução ocorre quando uma referência de classe base contém um objeto derivado - o método real chamado depende do tipo real do objeto, não do tipo declarado da variável:

Animal myPet = new Dog();
myPet.Speak();  // Saída: Woof!

Você pode acessar a implementação base dentro de uma sobrescrita usando base:

public override void Speak()
{
    base.Speak();  // Chama a versão da classe base
    Console.WriteLine("Woof!");
}

Experimente você mesmo

using System;
using Alerts;

class Program
{
    public static void Main(string[] args)
    {
        // Lê as entradas
        string message = Console.ReadLine();
        string email = Console.ReadLine();
        string phone = Console.ReadLine();

        // TODO: Criar instâncias de todos os três tipos de notificação
        // Armazene-as em variáveis Notification para demonstrar polimorfismo
        
        // TODO: Criar uma Notification base
        Notification baseNotification;
        
        // TODO: Criar uma EmailNotification (armazenada como tipo Notification)
        Notification emailNotification;
        
        // TODO: Criar uma SmsNotification (armazenada como tipo Notification)
        Notification smsNotification;
        
        // TODO: Chamar Send() em cada uma e imprimir os resultados
        // Os métodos sobrescritos serão chamados devido ao polimorfismo de tempo de execução
    }
}
quiz iconTeste seus conhecimentos

Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.

Todas as lições de Programação Orientada a Objetos