Herança
A herança é um dos pilares da programação orientada a objetos (POO) e está presente de forma robusta em C#. Ela permite criar novas classes (derivadas ou subclasses) baseando-se em classes já existentes (bases ou superclasses), promovendo reutilização de código, organização e extensibilidade.
O que é Herança?
Herança é o mecanismo pelo qual uma subclasse herda atributos e métodos de uma super classe, podendo ainda estender ou modificar esse comportamento. Em C#, a herança é única: uma classe só pode herdar de uma única classe base, mas pode implementar múltiplas interfaces.
Como Funciona a Herança em C#
1. Definindo Classes Base e Derivada
// Classe base ou super classe
public class Animal
{
public string Nome { get; set; }
public void EmitirSom()
{
Console.WriteLine("Som de animal genérico");
}
}
// Classe derivada ou subclasse
public class Cao : Animal
{
public void Latir()
{
Console.WriteLine("Au au!");
}
}
No exemplo acima, Cao
herda as propriedades e métodos públicos de Animal
, podendo usar Nome
e EmitirSom()
diretamente.
2. Modificadores de Acesso
- public: Membros visíveis em qualquer lugar.
- protected: Visíveis apenas na própria classe e em classes derivadas.
- private: Visíveis apenas na própria classe.
Para que membros sejam acessíveis nas classes filhas, use protected
ou public
.
public class Conta
{
public int Numero { get; set; }
protected double Saldo { get; set; }
}
3. Sobrescrita de Métodos (Polimorfismo)
Para permitir que um método seja redefinido na subclasse, use virtual
na superclasse e override
na subclasse.
public class Animal
{
public virtual void EmitirSom()
{
Console.WriteLine("Som de animal genérico");
}
}
public class Gato : Animal
{
public override void EmitirSom()
{
Console.WriteLine("Miau!");
}
}
Assim, ao chamar EmitirSom()
em um objeto Gato
, será exibido “Miau!”.
4. Construtores e Herança
Construtores não são herdados. Se a classe base possui um construtor com parâmetros, a classe derivada deve explicitamente chamar esse construtor:
public class Conta
{
public int Numero { get; set; }
public Conta(int numero)
{
Numero = numero;
}
}
public class ContaPoupanca : Conta
{
public ContaPoupanca(int numero) : base(numero)
{
// Código adicional, se necessário
}
}
A palavra-chave base
chama o construtor da classe pai.
5. Tipos de Herança em C#
- Simples: Uma classe base, uma derivada.
- Hierárquica: Uma base, várias derivadas.
- Multinível: Uma derivada de outra derivada.
- Múltipla (via interfaces): C# não suporta herança múltipla de classes, mas permite implementar múltiplas interfaces.
Exemplo Completo
class Animal
{
public string Nome { get; set; }
public virtual void EmitirSom()
{
Console.WriteLine("Som de animal genérico");
}
}
class Cao : Animal
{
public override void EmitirSom()
{
Console.WriteLine("Au au!");
}
}
class Program
{
static void Main()
{
Animal a = new Cao();
a.Nome = "Rex";
a.EmitirSom(); // Saída: Au au!
}
}
No exemplo, mesmo usando uma referência do tipo Animal
, o método sobrescrito de Cao
é chamado, demonstrando polimorfismo.
6. Herança multipla com interfaces
Podemos simular herança múltipla em C# usando interfaces, pois uma classe pode implementar quantas interfaces desejar, agregando funcionalidades de diversas “fontes” mesmo que só possa herdar de uma única classe base.
Como Usar Interfaces para Simular Herança Múltipla
1. Defina as Interfaces
Cada interface representa um conjunto de comportamentos que você deseja “herdar”.
public interface IVoar
{
void Voar();
}
public interface INadar
{
void Nadar();
}
2. Implemente as Interfaces numa Classe
A classe pode implementar várias interfaces e fornecer sua própria implementação para cada método.
public class Pato : IVoar, INadar
{
public void Voar()
{
Console.WriteLine("O pato está voando!");
}
public void Nadar()
{
Console.WriteLine("O pato está nadando!");
}
}
Neste exemplo, Pato
“herda” o comportamento de voar e nadar, mesmo que C# não permita herança múltipla de classes.
3. Uso Prático
Podemos tratar o objeto como qualquer uma das interfaces que ele implementa:
Pato pato = new Pato();
pato.Voar(); // Saída: O pato está voando!
pato.Nadar(); // Saída: O pato está nadando!
IVoar voador = pato;
voador.Voar();
INadar nadador = pato;
nadador.Nadar();
4. Resolver Conflitos de Métodos
Se duas interfaces tiverem métodos com o mesmo nome, você pode implementar explicitamente cada um:
public interface IPorta
{
void Abrir();
}
public interface IJanela
{
void Abrir();
}
public class Casa : IPorta, IJanela
{
void IPorta.Abrir() => Console.WriteLine("Abrindo a porta");
void IJanela.Abrir() => Console.WriteLine("Abrindo a janela");
}
Uso:
Casa casa = new Casa();
((IPorta)casa).Abrir(); // Abrindo a porta
((IJanela)casa).Abrir(); // Abrindo a janela
Assim, evitamos ambiguidade e controla o comportamento de cada interface.
Pontos Importantes
- Herança única: Uma classe só pode herdar de uma base.
- Construtores não são herdados: Devem ser chamados explicitamente.
- Membros privados não são herdados: Use
protected
para acesso em classes derivadas. - Interfaces: Para herança múltipla de comportamentos, use interfaces.