CodeGym /Cursos /C# SELF /Métodos virtuais em C#: polimorfismo e sobrescrita

Métodos virtuais em C#: polimorfismo e sobrescrita

C# SELF
Nível 20, Lição 2
Disponível

1. Introdução

Imagina que você tem uma classe base Animal com um método Speak(). Por padrão, pra todos os animais ele escreve "Algum som". Você quer criar classes filhas, tipo Dog e Cat, pra que eles falem frases de verdade ("Au au!" e "Miau!"), não só "Algum som".

Você até poderia escrever um método Speak() em cada filho, mas se você trabalhar com um array do tipo Animal[], chamar animal.Speak() ainda vai chamar o método da classe Animal, não do cachorro ou do gato — porque o C# por padrão olha pro tipo da variável, não pro objeto real que tá ali.

Olha um exemplo bem simples:


Animal dog = new Dog();
dog.Speak(); // E aí, o que será que aparece?

Por padrão — "Algum som", não "Au au!", mesmo se Dog tiver seu próprio método Speak(). E agora? Tem que declarar o método como virtual (na base) e override (no filho).

O que é um método virtual?

virtual-método é um método declarado na classe base com o modificador virtual e serve pra que os filhos possam sobrescrever ele ( override).

Quando você chama esse método por uma referência da classe base, vai ser chamado o método do objeto "real" — tipo na vida real: se você adota um animal e ele é um gato, ele vai miar ("Miau!"), não só fazer "Algum som".

Métodos virtuais são a base do polimorfismo em C#.

2. Declarando métodos virtuais

Como declarar um método virtual

Na classe base, declara o método com a palavra-chave virtual:


public class Animal
{
    public virtual void Speak()
    {
        Console.WriteLine("Algum som");
    }
}
Declarando um método virtual na classe base

No filho, usa a palavra-chave override:


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

public class Cat : Animal
{
    public override void Speak()
    {
        Console.WriteLine("Miau!");
    }
}
Sobrescrevendo o método virtual nos filhos

Exemplo: mostrando polimorfismo


// Por exemplo, no arquivo Program.cs

// Classe base Animal com método virtual Speak
public class Animal
{
    public virtual void Speak()
    {
        Console.WriteLine("Algum som");
    }
}

// Classe Dog, sobrescreve o comportamento de Speak
public class Dog : Animal
{
    public override void Speak()
    {
        Console.WriteLine("Au au!");
    }
}

// Classe Cat, também sobrescreve Speak
public class Cat : Animal
{
    public override void Speak()
    {
        Console.WriteLine("Miau!");
    }
}

public static class Program
{
    public static void Main()
    {
        Animal[] animals = new Animal[]
        {
            new Animal(),
            new Dog(),
            new Cat()
        };

        foreach (Animal animal in animals)
        {
            animal.Speak(); // Vai mostrar: "Algum som", "Au au!", "Miau!"
        }
    }
}

Viu só a mágica do método virtual? Mesmo se a variável for do tipo Animal, vai ser chamada a versão do método da implementação concreta.

3. O que rola "por baixo dos panos": virtual table

Resumindo o esquema

Quando você declara um método como virtual, o compilador coloca ele numa "virtual table" especial de métodos pra cada tipo (tipo um cardápio diferente pra cada prato). Quando esse método é chamado, o C# não olha pro tipo da variável, mas sim pro que tá de verdade na referência — e "entrega" o método que corresponde ao tipo real do objeto.

Dá pra dizer que o C# troca a receita padrão pela personalizada, se a classe tiver sua própria versão.

Analogia: contrato com "cláusula extra em letras miúdas"

Imagina que você tem um contrato de aluguel (classe base), e nele tá escrito que o inquilino paga um valor fixo todo mês (método PayRent()). Mas você — espertinho — deixa colocar anexos com condições especiais (método virtual). Se algum inquilino (filho) usar esse direito, ele escreve seu próprio override, e agora o pagamento é diferente.

4. Quando usar métodos virtuais?

  • Se o método na classe base deve funcionar pra maioria dos filhos, mas alguns podem precisar de um comportamento diferente.
  • Quando você monta uma hierarquia de classes que pode ser expandida ou ter parte da lógica alterada.
  • Quando tá criando uma arquitetura flexível, tipo pra lógica de negócio, onde tipos diferentes de operações podem precisar de comportamentos próprios.

Em projetos reais, métodos virtuais são a base dos padrões Template Method, Strategy, e de metade da OOP.

Comparando com métodos normais

Método normal Método virtual
Dá pra sobrescrever Não Sim (override)
Como é chamado Pelo tipo da variável Pelo tipo "real" do objeto
Polimorfismo Não Sim

Perguntas frequentes

  • Dá pra fazer construtor virtual?
    Não! Construtores nunca são virtuais — eles sempre funcionam pelo tipo do objeto.
  • Métodos virtuais podem ser estáticos?
    Não, só métodos de instância podem ser virtuais. Métodos estáticos não participam do polimorfismo, porque não tem objeto — quem ia sobrescrever?
  • Campos podem ser virtuais?
    Não, só métodos, propriedades e eventos.

5. Prática: evoluindo o app "Mundo Animal"

No nosso app de estudo você já fez uma hierarquia simples de animais. Bora adicionar novos métodos virtuais pros bichos comerem de jeitos diferentes!

Exemplo de código com comentários


// Na classe base, criamos o método virtual Eat
public class Animal
{
    public virtual void Speak()
    {
        Console.WriteLine("Algum som");
    }

    public virtual void Eat()
    {
        Console.WriteLine("Come comida genérica.");
    }
}

// Em Dog, sobrescrevemos Eat
public class Dog : Animal
{
    public override void Speak() => Console.WriteLine("Au au!");
    public override void Eat() => Console.WriteLine("Come ração de cachorro.");
}

// Em Cat, também tem comportamento próprio
public class Cat : Animal
{
    public override void Speak() => Console.WriteLine("Miau!");
    public override void Eat() => Console.WriteLine("Come peixe.");
}

public static class Program
{
    public static void Main()
    {
        Animal[] animals = new Animal[]
        {
            new Animal(),
            new Dog(),
            new Cat()
        };
        foreach (var animal in animals)
        {
            animal.Speak();
            animal.Eat();
            Console.WriteLine("---");
        }
    }
}

Pronto, agora cada gatinho e cachorrinho come do seu jeito! E o Animal base continua comendo algo estranho, como um funcionalzão com "default".

6. Erros comuns e pegadinhas

  • Dá pra esquecer o override no filho — aí o método da base continua valendo.
  • Ou, ao contrário, esquecer o virtual na base, aí não dá pra usar override no filho.

Não dá pra escrever override sem virtual

O compilador C# não deixa sobrescrever um método que não foi declarado como virtual (ou abstrato) na base.

Pra que serve o override

override deixa claro pro compilador e pra quem lê o código: "Não tô só criando um método novo — tô mudando de propósito o que veio da base". Isso evita erro quando você quer "sobrescrever", mas sem querer só cria um método novo com assinatura parecida.

Se esquecer o override e escrever um método novo

public class Dog : Animal
{
    public void Speak()
    {
        Console.WriteLine("Au au!");
    }
}
Isso NÃO é sobrescrita! Polimorfismo não funciona.

Mas isso não é sobrescrita! Se você acessar Dog por uma variável do tipo Animal, vai chamar o método do animal ("Algum som"), não do cachorro. Essas surpresas de tipos são fogo!

2
Tarefa
C# SELF, nível 20, lição 2
Bloqueado
Criação de uma classe com método virtual
Criação de uma classe com método virtual
2
Tarefa
C# SELF, nível 20, lição 2
Bloqueado
Método virtual com lógica adicional
Método virtual com lógica adicional
Comentários
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION