Exercícios Resolvidos de Mais herança e mais polimorfismo

Ver Teoria

Enunciado

Crie classes H u m a n o , I n s e t o e S u p e r H e r o i . A classe H u m a n o possui atributos N o m e e I d a d e . A classe I n s e t o possui atributos N o m e , V e n e n o s o e A l a d o (os dois últimos são booleanos). A classe S u p e r H e r o i herda das duas classes anteriores, e adiciona os atributos C o d i n o m e e P o d e r e s . Todos os atributos possuem getters e setters. Crie a hierarquia de herança múltipla, um construtor e um método print na classe derivada. Crie um exemplo para testar sua hierarquia.

Passo 1

Vamos lá, pessoal

Essa é uma questão de herança dupla onde vamos criar duas classes base H u m a n o e I n s e t o e depois construir a classe derivada S u p e r H e r o i . O detalhe da questão está no atributo N o m e que existe dentro das duas classes base, e por consequência os métodos g e t N o m e e s e t N o m e também existem dentro das duas classes.

A primeira solução que você pode pensar é em simplesmente usar polimorfismo para dar prioridade a uma das classes. Mas acontece que o H u m a n o ∷ N o m e representa o nome da pessoa, enquanto I n s e t o ∷ N o m e representa o nome do inseto. Esses atributos tem o mesmo nome, mas representam coisas diferentes. Ou seja, precisamos fazer de um jeito em os dois atributos continuem existindo, mas que não gere ambiguidades

Mas pra começar, vamos escrever o cabeçalho do código.

Passo 2

Vamos começar escrevendo a classe base H u m a n o .

Essa classe possui dois atributos privados, N o m e que deve ser s t r i n g e I d a d e que deve ser inteiro.

Em seguida, vamos criar um construtor para a classe. Lembre-se que os construtores são quase sempre públicos. O construtor vai receber e inicializar os valores dos atributos N o m e e I d a d e :

Vamos definir setters e getters para os atributos privados.

Vamos começar pelo atributo N o m e . Como discutimos no passo anterior, esse atributo e seus setter e getter aparecem dentro das duas classes bases. Então, o primeiro passo para evitar ambiguidades é definir os métodos com nomes iguais como virtuais. Então vamos declarar s e t N o m e e g e t N o m e como métodos virtuais.

Show. Agora desenvolvemos os setter e getter para o atributo I d a d e . Aqui não tem segredo nem treta:

E assim finalizamos a classe H u m a n o

Passo 3

O passo seguinte é desenvolver a classe I n s e t o :

Aqui temos três atributos, o s t r i n g N o m e que representa o nome do inseto, e os atributos booleanos V e n e n o s o e A l a d o que determinam algumas características desse inseto. Vamos encapsular todos os atributos como privados.

Mudaremos agora para o encapsulamento público, e vamos desenvolver um construtor que recebe e inicializa os valores dos três atributos da classe:

E o passo seguinte é desenvolver os métodos setters e getters dessa classe.

Vamos começar pelo atributo N o m e , pois como já falamos, temos que lembrar esse atributo e seus setters e getters existem dentro das duas classes base, então para evitar ambiguidades, o primeiro passo é declarar os métodos como virtuais:

Belezinha. Agora, pra criar os setters e getters dos atributos V e n e n o s o e A l a d o não tem grilo:

E prontinho, a classe I n s e t o está prontinha.

Passo 4

Da hora! Agora é a parte mais importante da questão! Vamos criar a classe derivada S u p e r H e r o i usando duas classes como base: H u m a n o e I n s e t o . Lembre-se que pra efetuar uma herança múltipla a gente faz assim:

c l a s s   F i l h a   : p u b l i c   M a e 1 , p u b l i c   M a e 2 ,   … ,   p u b l i c   M a e N

No código fica assim:

Beleza. A classe S u p e r H e r o i possui dois atributos adicionais C o d i n o m e e P o d e r e s os dois do tipo s t r i n g . Então vamos declarar esses atributos com encapsulamento privado:

Mudando para o encapsulamento público, vamos definir um construtor para a classe S u p e r H e r o i . Mas pra agilizar esse processo, vamos executar os construtores das classes mãe.

A gente primeiro declara o construtor da classe filha recebendo todos os parâmetros, depois usamos o operador :   e executamos os construtores das classes mães, entregando pra elas os parâmetros necessários:

F i l h a   t i p o s   p a r a m s   : M a e 1 p a r a m s ,   M a e 2 p a r a m s , … ,   M a e N ( p a r a m s )

Isso vai garantir que as classes herdadas sejam inicializadas corretamente. E depois, é só a gente abrir as chaves, e dentro do método construtor inicializar os atributos exclusivos da classe filha.

No nosso código temos apenas duas classes mães, então fica assim:

Repare que dentro das chaves a gente inicializou os atributos C o d i n o m e e P o d e r e s que são exclusivos da classe derivada.

Belezinha, seguindo em frente, precisamos criar setters e getters para os atributos C o d i n o m e e P o d e r e s :

Os demais atributos herdados já possuem setters e getters que também foram herdados.

O problema são os métodos s e t N o m e e g e t N o m e , pois a gente possui duas cópias de cada um desses métodos, uma vinda de H u m a n o e outra vinda de I n s e t o . Normalmente, a gente simplesmente escolheria usar a versão de uma classe e ignoraríamos a versão da outra classe...

Acontece que o atributo H u m a n o ∷ N o m e e I n s e t o ∷ N o m e representam coisas diferente, o primeiro representa o nome humano e o segundo representa o tipo de inseto. Então não podemos ignorar nenhum dos dois, pois eles representam coisas diferentes.

Mas não criemos pânico! A solução é simples! Primeiro, vamos criar um polimorfismo para os métodos s e t N o m e e g e t N o m e e vamos fazer eles atuarem sobre o conteúdo de H u m a n o ∷ N o m e

E o que faremos a respeito do conteúdo existente em I n s e t o ∷ N o m e ? Simples! Vamos criar dois métodos novos: s e t N o m e I n s e t o ( ) que executa o método I n s e t o ∷ s e t N o m e ( ) e o método g e t N o m e I n s e t o ( ) que executa o I n s e t o ∷ g e t N o m e ( )

Viu! Foi facinho!

E pra terminar a classe, vamos desenvolver o método p r i n t H e r o i que simplesmente retorna um textinho engraçadinho com as características desse herói. O detalhe é que todos os atributos herdados são privados, e por isso devem ser acessados através dos métodos getters.

E prontinho! Classe S u p e r H e r o i concluída!

Passo 5

Beleza! Agora é só testar o nosso código.

Vou criar um objeto da classe S u p e r H e r o i e inicializa-lo com alguns valores aleatórios:

O resultado é:

E prontinho! Questão finalizada!

Resposta