Ficha 02 · Herança, polimorfismo, composição
- Aplicar herança
- Usar polimorfismo
- Compor objectos
- Identificar quando usar cada técnica
Parte I · Herança
Exercício 1 · Herdar Pessoa (15 pts)
Cria Pessoa(nome, idade) com método saudar(). Cria Aluno(nome, idade, numero) que herda de Pessoa e adiciona método info() que devolve string com tudo.
class Pessoa:
def __init__(self, nome, idade):
self.nome = nome
self.idade = idade
def saudar(self):
return f"Olá, sou {self.nome}"
class Aluno(Pessoa):
def __init__(self, nome, idade, numero):
super().__init__(nome, idade)
self.numero = numero
def info(self):
return f"{self.nome}, {self.idade} anos, nº {self.numero}"
a = Aluno("Ana", 17, 42)
print(a.saudar()) # herdado
print(a.info()) # próprio
Exercício 2 · isinstance (10 pts)
Considera:
class A: pass
class B(A): pass
class C(B): pass
obj = C()
Indica True ou False:
a) isinstance(obj, C) ___
b) isinstance(obj, B) ___
c) isinstance(obj, A) ___
d) isinstance(obj, object) ___
e) type(obj) is C ___
f) type(obj) is A ___
a) True — é instância de C directamente.
b) True — C herda de B.
c) True — C herda transitivamente de A.
d) True — tudo em Python herda de object.
e) True — tipo exacto.
f) False — type() é exacto, não considera herança.
isinstance() respeita herança; type() is é estrito.
Parte II · Polimorfismo
Exercício 3 · Animais (20 pts)
Cria classe Animal com método som() que retorna "...". Cria 3 subclasses (Cão, Gato, Vaca) que redefinem som(). Escreve função coro(animais) que recebe lista e imprime som de cada.
class Animal:
def __init__(self, nome):
self.nome = nome
def som(self):
return "..."
def __repr__(self):
return f"{type(self).__name__}({self.nome})"
class Cao(Animal):
def som(self):
return "Au au!"
class Gato(Animal):
def som(self):
return "Miau!"
class Vaca(Animal):
def som(self):
return "Muuu!"
def coro(animais):
for a in animais:
print(f"{a.nome}: {a.som()}")
coro([
Cao("Rex"),
Gato("Mia"),
Vaca("Mimosa"),
])
Polimorfismo: coro() não precisa de saber o tipo concreto. Cada animal responde à sua maneira.
Exercício 4 · Figuras geométricas (15 pts)
Cria classe abstracta Figura com método abstracto area(). Cria Rectangulo, Circulo, Triangulo. Função area_total(figuras) devolve soma das áreas.
from abc import ABC, abstractmethod
import math
class Figura(ABC):
@abstractmethod
def area(self):
pass
class Rectangulo(Figura):
def __init__(self, l, a):
self.l, self.a = l, a
def area(self):
return self.l * self.a
class Circulo(Figura):
def __init__(self, r):
self.r = r
def area(self):
return math.pi * self.r ** 2
class Triangulo(Figura):
def __init__(self, base, altura):
self.base = base
self.altura = altura
def area(self):
return self.base * self.altura / 2
def area_total(figuras):
return sum(f.area() for f in figuras)
figs = [Rectangulo(3, 4), Circulo(5), Triangulo(6, 8)]
print(f"Total: {area_total(figs):.2f}")
Parte III · Composição
Exercício 5 · Carro (15 pts)
Cria classe Motor(cilindrada) com método ligar(). Cria classe Carro(marca, modelo, cilindrada) que contém um Motor. Carro.arrancar() chama motor.ligar().
class Motor:
def __init__(self, cilindrada):
self.cilindrada = cilindrada
self.ligado = False
def ligar(self):
self.ligado = True
return f"Motor {self.cilindrada}cc ligado"
class Carro:
def __init__(self, marca, modelo, cilindrada):
self.marca = marca
self.modelo = modelo
self.motor = Motor(cilindrada) # composição: Carro TEM Motor
def arrancar(self):
return self.motor.ligar()
c = Carro("Toyota", "Corolla", 1800)
print(c.arrancar())
print(c.motor.ligado)
Exercício 6 · Herança vs composição (15 pts)
Para cada caso, decide se modelarias com herança ou composição e justifica em 1 frase:
a) Aluno e Pessoa. ___
b) Carro e Motor. ___
c) Lobo e Animal. ___
d) Equipa e Jogador. ___
e) Livro e Editora. ___
f) Quadrado e Rectangulo (matematicamente). ___
a) Herança — Aluno é uma Pessoa.
b) Composição — Carro tem um Motor (não é um motor).
c) Herança — Lobo é um Animal.
d) Composição — Equipa tem jogadores (lista de Jogador).
e) Composição — Livro tem uma editora; livro não é editora.
f) Cuidado. Matematicamente Quadrado é Rectangulo, mas em código viola LSP — mudar largura de Quadrado teria de mudar altura. Melhor: ambos herdam de Figura, sem herança entre si. Composição (Quadrado tem propriedade lado) também válida.
Parte IV · Cenário
Exercício 7 · Sistema de empréstimo (10 pts)
Modela uma biblioteca:
- ItemBiblioteca (abstracta) com método info() abstracto.
- Livro(titulo, autor) herda.
- Revista(titulo, edicao) herda.
- Biblioteca que tem lista de itens (composição) e métodos adicionar(item), listar().
from abc import ABC, abstractmethod
class ItemBiblioteca(ABC):
@abstractmethod
def info(self):
pass
class Livro(ItemBiblioteca):
def __init__(self, titulo, autor):
self.titulo = titulo
self.autor = autor
def info(self):
return f"Livro: '{self.titulo}' por {self.autor}"
class Revista(ItemBiblioteca):
def __init__(self, titulo, edicao):
self.titulo = titulo
self.edicao = edicao
def info(self):
return f"Revista: '{self.titulo}' edição {self.edicao}"
class Biblioteca:
def __init__(self, nome):
self.nome = nome
self.itens = [] # composição
def adicionar(self, item):
if not isinstance(item, ItemBiblioteca):
raise TypeError("Tem de ser ItemBiblioteca")
self.itens.append(item)
def listar(self):
print(f"Biblioteca {self.nome}:")
for item in self.itens:
print(f" - {item.info()}")
# Teste
b = Biblioteca("Municipal")
b.adicionar(Livro("Saramago", "Ensaio sobre a cegueira"))
b.adicionar(Livro("Camões", "Lusíadas"))
b.adicionar(Revista("Visão", 1542))
b.listar()
Note como listar() chama item.info() sem se importar do tipo — polimorfismo.