Universo DC - Aprenda POO com exemplos práticos
Entender o conceito de Herança em POO, criando classes derivadas (Herói e Vilão) a partir da classe base Personagem.
Personagem é um veículo genérico, Herói e Vilão são tipos específicos de veículos (carro, moto) que herdam características do veículo genérico.
Em C#, usamos : (dois pontos) para indicar herança:
public class Herói : Personagem
{
// Herói herda tudo de Personagem
}
Personagem (Classe Base/Pai)
├── Herói (Classe Derivada/Filha)
│ ├── Batman (Objeto)
│ ├── Superman (Objeto)
│ └── Flash (Objeto)
│
└── Vilão (Classe Derivada/Filha)
├── Coringa (Objeto)
├── Lex Luthor (Objeto)
└── Darkseid (Objeto)
// TÓPICO: Herança
// 'Herói' herda de 'Personagem' usando ':'
// Isso significa que Herói tem TUDO que Personagem tem, MAIS suas próprias características
public class Heroi : Personagem
{
// TÓPICO: Propriedades Específicas
// Propriedades que só os heróis têm
private string _equipe; // Equipe a que pertence (Liga da Justiça, etc.)
public string Equipe
{
get { return _equipe; }
set { _equipe = value; }
}
private int _vidasSalvas; // Quantas vidas o herói já salvou
public int VidasSalvas
{
get { return _vidasSalvas; }
set
{
// Validação: não pode ser negativo
_vidasSalvas = value >= 0 ? value : 0;
}
}
// TÓPICO: Construtor da Classe Derivada
// O construtor da classe filha DEVE chamar o construtor da classe pai
// Usamos 'base()' para chamar o construtor da classe base
public Heroi(string nome, int nivel, string equipe)
: base(nome, nivel) // Chama o construtor de Personagem
{
// Inicializa propriedades específicas de Herói
this.Equipe = equipe;
this.VidasSalvas = 0; // Começa com zero vidas salvas
}
// TÓPICO: Métodos Específicos
// Métodos que só heróis podem fazer
// Método para salvar vidas
public void SalvarVida()
{
VidasSalvas++;
Console.WriteLine($"{Nome} salvou uma vida! Total: {VidasSalvas} vidas salvas.");
}
// Método para se juntar à equipe
public void JuntarEquipe(string novaEquipe)
{
Equipe = novaEquipe;
Console.WriteLine($"{Nome} se juntou à {Equipe}!");
}
// TÓPICO: Sobrescrita de Métodos (Override)
// Podemos redefinir métodos da classe base
// Usamos 'override' para sobrescrever métodos virtuais da classe pai
public override void Apresentar()
{
// Chama o método da classe base e adiciona informações extras
base.Apresentar(); // Chama Apresentar() de Personagem
Console.WriteLine($"Sou um herói da {Equipe} e já salvei {VidasSalvas} vidas!");
}
}
// Versão mais concisa usando propriedades auto-implementadas
public class Heroi : Personagem
{
// Propriedades auto-implementadas (modo abreviado)
public string Equipe { get; set; }
public int VidasSalvas { get; set; }
// Construtor abreviado
public Heroi(string nome, int nivel, string equipe) : base(nome, nivel)
{
Equipe = equipe;
VidasSalvas = 0;
}
// Métodos abreviados com expressões lambda (quando possível)
public void SalvarVida() =>
Console.WriteLine($"{Nome} salvou uma vida! Total: {++VidasSalvas} vidas salvas.");
public void JuntarEquipe(string novaEquipe)
{
Equipe = novaEquipe;
Console.WriteLine($"{Nome} se juntou à {Equipe}!");
}
// Sobrescrita do método Apresentar
public override void Apresentar()
{
base.Apresentar();
Console.WriteLine($"Sou um herói da {Equipe} e já salvei {VidasSalvas} vidas!");
}
}
// TÓPICO: Herança - Classe Vilão
// Vilão também herda de Personagem
public class Vilao : Personagem
{
// Propriedades específicas de vilões
private string _organizacao; // Organização criminosa
public string Organizacao
{
get { return _organizacao; }
set { _organizacao = value; }
}
private int _planosExecutados; // Quantos planos maléficos foram executados
public int PlanosExecutados
{
get { return _planosExecutados; }
set { _planosExecutados = value >= 0 ? value : 0; }
}
// Construtor
public Vilao(string nome, int nivel, string organizacao)
: base(nome, nivel) // Chama construtor de Personagem
{
this.Organizacao = organizacao;
this.PlanosExecutados = 0;
}
// Métodos específicos de vilões
public void ExecutarPlano()
{
PlanosExecutados++;
Console.WriteLine($"{Nome} executou um plano maléfico! Total: {PlanosExecutados} planos.");
}
public void JuntarOrganizacao(string novaOrganizacao)
{
Organizacao = novaOrganizacao;
Console.WriteLine($"{Nome} se juntou à {Organizacao}!");
}
// Sobrescrita do método Apresentar
public override void Apresentar()
{
base.Apresentar();
Console.WriteLine($"Sou um vilão da {Organizacao} e já executei {PlanosExecutados} planos!");
}
}
public class Vilao : Personagem
{
public string Organizacao { get; set; }
public int PlanosExecutados { get; set; }
public Vilao(string nome, int nivel, string organizacao) : base(nome, nivel)
{
Organizacao = organizacao;
PlanosExecutados = 0;
}
public void ExecutarPlano() =>
Console.WriteLine($"{Nome} executou um plano! Total: {++PlanosExecutados} planos.");
public void JuntarOrganizacao(string novaOrganizacao)
{
Organizacao = novaOrganizacao;
Console.WriteLine($"{Nome} se juntou à {Organizacao}!");
}
public override void Apresentar()
{
base.Apresentar();
Console.WriteLine($"Sou um vilão da {Organizacao} e já executei {PlanosExecutados} planos!");
}
}
Para permitir sobrescrita de métodos, a classe base deve ter métodos virtual:
public class Personagem
{
public string Nome { get; set; }
public int Nivel { get; set; }
public Personagem(string nome, int nivel)
{
Nome = nome;
Nivel = nivel;
}
// TÓPICO: Método Virtual
// 'virtual' permite que classes filhas sobrescrevam este método
public virtual void Apresentar()
{
Console.WriteLine($"Olá! Eu sou {Nome}, nível {Nivel}!");
}
public void SubirNivel()
{
Nivel++;
Console.WriteLine($"{Nome} subiu para o nível {Nivel}!");
}
}
// TÓPICO: Polimorfismo
// Podemos tratar objetos de classes derivadas como se fossem da classe base
// Mas eles mantêm suas características específicas
// Criando heróis (objetos da classe Heroi)
Heroi batman = new Heroi("Batman", 85, "Liga da Justiça");
Heroi superman = new Heroi("Superman", 100, "Liga da Justiça");
Heroi flash = new Heroi("Flash", 90, "Liga da Justiça");
// Usando métodos específicos de heróis
batman.SalvarVida(); // Método só de heróis
batman.SalvarVida();
superman.SalvarVida();
// Usando métodos herdados
batman.SubirNivel(); // Método herdado de Personagem
batman.Apresentar(); // Método sobrescrito
// Criando vilões (objetos da classe Vilao)
Vilao coringa = new Vilao("Coringa", 80, "Legião do Mal");
Vilao lexLuthor = new Vilao("Lex Luthor", 75, "Legião do Mal");
Vilao darkseid = new Vilao("Darkseid", 95, "Apokolips");
// Usando métodos específicos de vilões
coringa.ExecutarPlano(); // Método só de vilões
lexLuthor.ExecutarPlano();
// Usando métodos herdados
darkseid.SubirNivel(); // Método herdado de Personagem
coringa.Apresentar(); // Método sobrescrito
// TÓPICO: Polimorfismo
// Podemos colocar objetos de classes derivadas em uma lista da classe base
List<Personagem> personagens = new List<Personagem>();
// Adicionando heróis e vilões na mesma lista
personagens.Add(new Heroi("Batman", 85, "Liga da Justiça"));
personagens.Add(new Heroi("Superman", 100, "Liga da Justiça"));
personagens.Add(new Vilao("Coringa", 80, "Legião do Mal"));
personagens.Add(new Vilao("Lex Luthor", 75, "Legião do Mal"));
// Iterando sobre a lista
foreach (Personagem personagem in personagens)
{
// Cada objeto chama sua própria versão do método Apresentar()
personagem.Apresentar(); // Polimorfismo em ação!
}
| Aspecto | Modo Completo | Modo Abreviado |
|---|---|---|
| Propriedades | Campos privados + get/set explícitos | Auto-implementadas { get; set; } |
| Construtor | this.Propriedade = valor | Propriedade = valor |
| Métodos | Blocos { } completos | Expressões lambda quando possível |
| Legibilidade | Mais verboso, mais explícito | Mais conciso, menos linhas |
: base(): Chama o construtor da classe basevirtual: Permite sobrescrita de métodosoverride: Sobrescreve método da classe baseNa próxima aula, veremos Classes Abstratas e como criar classes que não podem ser instanciadas diretamente.