CodeGym /Cursos /C# SELF /Sobrescrita de métodos (override) em C#

Sobrescrita de métodos (override) em C#

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

1. Introdução

Imagina que a gente tem um app pra controlar os animais do zoológico (aquele exemplo que a gente já começou a desenvolver nas aulas passadas). Criamos uma classe base Animal com o método MakeSound, pra todos os bichos poderem "fazer" algum som.


public class Animal
{
    public virtual void MakeSound()
    {
        Console.WriteLine("Animal faz um som.");
    }
}
        
Classe base com método virtual

Mas aí a gente percebe que o som do leão e do papagaio são bem diferentes. O "Animal faz um som" genérico já não serve. É aí que entra a sobrescrita de métodos. Você precisa que cada filho tenha seu próprio som!

2. Sintaxe: como funciona o override

Regras principais

  • Pra sobrescrever um método, ele tem que estar marcado na classe base como virtual (ou abstract).
  • Na classe derivada, usa a palavra-chave override antes do método com a mesma assinatura.

Exemplo: leões e papagaios

public class Lion : Animal
{
    public override void MakeSound()
    {
        Console.WriteLine("Rrrrr!");
    }
}

public class Parrot : Animal
{
    public override void MakeSound()
    {
        Console.WriteLine("Papagaio bobo!");
    }
}

Agora, se você criar uma lista de animais e chamar MakeSound pra cada um, cada bicho vai "falar" do seu jeito:

Animal[] zoo = new Animal[]
{
    new Lion(),
    new Parrot(),
    new Animal()
};

foreach (var animal in zoo)
{
    animal.MakeSound();
}
// Saída:
// Rrrrr!
// Papagaio bobo!
// Animal faz um som.
Importante: O C# vai chamar exatamente a implementação do método que bate com o tipo real ( run-time) do objeto, mesmo que a variável seja do tipo Animal!

3. Tabela virtual de chamadas (v-table)

Quando você usa virtual e override, o compilador gera pra classe uma "tabela virtual de métodos" (v-table).
Quando chama o método por uma referência da classe base, o CLR olha na tabela: será que esse método foi sobrescrito no filho? Se sim — chama a versão do filho.
Essa é a "mágica" do late binding, ou polimorfismo dinâmico.

4. Juntando tudo: continuando nosso app

Bora adicionar mais uma classe:

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

E usar isso no nosso mini-app de controle de bichos:

Animal[] zoo = new Animal[]
{
    new Lion(),
    new Parrot(),
    new Dog()
};

foreach (var animal in zoo)
{
    animal.MakeSound();
}

Agora ficou muito mais fácil manter e expandir o código, e adicionar novos bichos é uma beleza!

5. Sobrescrevendo propriedades e override com valor de retorno

Métodos não são a única coisa que dá pra sobrescrever. Você também pode sobrescrever propriedades virtuais e indexadores.

public class Animal
{
    public virtual string Name { get; set; } = "Animal";
}

public class Lion : Animal
{
    public override string Name { get; set; } = "Leão";
}

Isso é muito útil quando você quer detalhar info pra um tipo específico.

6. Implementação base usando base

Às vezes você quer só expandir o comportamento do método base, não trocar tudo.
Pra isso, chama a implementação do método base com a palavra base dentro do sobrescrito.

public class Parrot : Animal
{
    public override void MakeSound()
    {
        base.MakeSound(); // "Animal faz um som."
        Console.WriteLine("Papagaio bobo!");
    }
}

Nesse caso, o papagaio primeiro faz o som "genérico" do zoológico, depois solta o clássico "Papagaio bobo!".

7. Onde isso é útil na prática

Entender como funciona o override é essencial em qualquer projeto C# mais sério que use OOP.

  • Modelos de animais no nosso zoológico? Já fizemos.
  • Criar controles customizados pra UI: Você sobrescreve métodos visuais padrão e mete sua lógica.
  • Lógica de negócio flexível: Dá pra montar o "esqueleto" do comportamento na base e implementar o detalhe nos filhos.
  • Testes e mocks: Fica fácil "trocar" métodos via herança pra testes unitários.
  • Plugins e extensões: Interface ou classe base abstrata, várias implementações — tudo funciona porque a sobrescrita tá certinha.

8. sealed override e métodos virtuais em cadeia

Se você não quiser que alguém mais embaixo na hierarquia sobrescreva seu método sobrescrito, pode usar sealed override:

public class Base
{
    public virtual void Foo() { }
}

public class Middle : Base
{
    public sealed override void Foo() { }
}

public class Last : Middle
{
    public override void Foo() {} // Erro — não pode sobrescrever!
}

Isso serve pra "fechar" a cadeia de sobrescritas onde for crítico pro sistema funcionar direito.

9. Novo método (palavra-chave new)

Às vezes você quer declarar no filho um método com a mesma assinatura, mas o da base não é virtual.
Nesse caso, pode usar a palavra new — mas isso não é polimorfismo, é mais tipo uma "camuflagem":

public class Animal
{
    public void MakeSound()
    {
        Console.WriteLine("Eu sou um animal!");
    }
}

public class Cat : Animal
{
    public new void MakeSound()
    {
        Console.WriteLine("Eu sou um gatinho!");
    }
}

Animal animal = new Cat();
animal.MakeSound(); // "Eu sou um animal!"
Cat cat = new Cat();
cat.MakeSound(); // "Eu sou um gatinho!"

Aqui, tudo depende do tipo da variável na hora da chamada! Então, pra polimorfismo dinâmico de verdade, sempre use virtual + override.

10. Erros comuns ao sobrescrever métodos

Erro nº1: tentar sobrescrever um método que não foi declarado como virtual, abstract ou override.
Em C#, não dá pra sobrescrever métodos normais. Se o método na base não tem um modificador especial (virtual, abstract ou override), tentar usar override na derivada vai dar erro de compilação.

Erro nº2: assinatura do método diferente.
Pra realmente sobrescrever, o nome, tipo de retorno e parâmetros do método têm que ser idênticos ao da base. Qualquer diferença (tipo, parâmetro diferente) vai criar um método novo, não sobrescrever.

Erro nº3: esqueceu o modificador override.
Se você define um método com a mesma assinatura da base, mas não coloca override, o compilador não considera sobrescrita. Isso se chama ocultação de método (vamos ver isso separado). Nesse caso, chamar o método por uma variável do tipo base vai dar um resultado inesperado — vai chamar o método da base, não o seu.

2
Tarefa
C# SELF, nível 20, lição 3
Bloqueado
Polimorfismo com sobrescrita de métodos
Polimorfismo com sobrescrita de métodos
2
Tarefa
C# SELF, nível 20, lição 3
Bloqueado
Uso da implementação base através de `base`
Uso da implementação base através de `base`
Comentários
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION