Aula 9: O Pilar da Herança

Construindo classes a partir de outras, de forma eficiente.

O Que Você Vai Aprender

Nesta aula, você explorará o Pilar da Herança em Programação Orientada a Objetos. Entenderá como as classes podem compartilhar comportamentos e características, promovendo a reutilização de código e a organização de hierarquias de objetos. Você aprenderá o conceito de superclasses e subclasses e o significado do relacionamento "é um".

🌳 Conceito de Herança

Compreender como uma classe pode herdar atributos e métodos de outra.

🔗 Relacionamento "é um"

Entender a relação hierárquica entre superclasses e subclasses.

Conceito: O Pilar da Herança

A Herança é um dos pilares mais poderosos da Programação Orientada a Objetos. Ela permite que uma nova classe (chamada subclasse, ou classe filha) assuma as características e comportamentos de uma classe existente (chamada superclasse, ou classe pai). Isso promove a reutilização de código e a criação de hierarquias lógicas de classes.

Sintaxe Básica da Herança em Python

Para que uma classe herde de outra, você coloca o nome da superclasse entre parênteses após o nome da subclasse na definição da classe.

class Superclasse:
    def metodo_pai(self):
        print("Método da superclasse.")

class Subclasse(Superclasse): # Subclasse herda de Superclasse
    def metodo_filho(self):
        print("Método da subclasse.")

# Exemplo de uso:
# obj_filho = Subclasse()
# obj_filho.metodo_pai()   # Pode chamar método da superclasse
# obj_filho.metodo_filho() # Pode chamar método da própria subclasse

Por que usar Herança?

  • **Reutilização de Código:** Evita a duplicação de código. Se várias classes compartilham comportamentos, eles podem ser definidos uma vez na superclasse e herdados.
  • **Extensibilidade:** Você pode adicionar novas funcionalidades em subclasses sem modificar a superclasse existente.
  • **Organização:** Ajuda a organizar o código em uma estrutura hierárquica lógica, refletindo relações do mundo real.

Relacionamento "é um"

O relacionamento "é um" é a forma de pensar sobre a herança. Ele descreve uma hierarquia onde um objeto da subclasse é um tipo de objeto da superclasse.

Exemplos Práticos

Um Cachorro é um Animal.

A classe `Cachorro` herda da classe `Animal`. Um cachorro tem todas as características e comportamentos de um animal (como ter um nome, idade, comer), mas também pode ter comportamentos específicos de cachorro (como latir).

class Animal:
    def __init__(self, nome):
        self.nome = nome
    def comer(self):
        print(f"{self.nome} está comendo.")

class Cachorro(Animal): # Cachorro herda de Animal
    def latir(self):
        print(f"{self.nome} está latindo: Au Au!")

# meu_cachorro = Cachorro("Rex")
# meu_cachorro.comer()  # Método herdado
# meu_cachorro.latir()  # Método específico

Outros Exemplos

Um Gerente é um Funcionário.

A classe `Gerente` herda da classe `Funcionario`. Um gerente é um funcionário e, portanto, possui nome, salário, etc., mas também tem responsabilidades e métodos específicos de gerente (como gerenciar equipe).

class Funcionario:
    def __init__(self, nome, salario):
        self.nome = nome
        self.salario = salario
    def exibir_info(self):
        print(f"Nome: {self.nome}, Salário: {self.salario}")

class Gerente(Funcionario): # Gerente herda de Funcionário
    def gerenciar_equipe(self):
        print(f"{self.nome} está gerenciando a equipe.")

# gerente = Gerente("Maria", 5000)
# gerente.exibir_info() # Método herdado
# gerente.gerenciar_equipe() # Método específico

Simulador: Herança de `Animal` para `Cachorro`

Crie um objeto `Cachorro` (subclasse de `Animal`) e veja como ele herda atributos e métodos, além de ter os seus próprios. Abaixo, você encontra o código Python para as classes e, em seguida, um simulador interativo em JavaScript que mimetiza esse comportamento.

Classes `Animal` e `Cachorro` em Python

class Animal:
    def __init__(self, nome):
        self.nome = nome
    def comer(self):
        return f"{self.nome} está comendo."

class Cachorro(Animal): # Cachorro herda de Animal
    def __init__(self, nome, raca):
        super().__init__(nome) # Chama o construtor da superclasse
        self.raca = raca
    def latir(self):
        return f"{self.nome} ({self.raca}) está latindo: Au Au!"

# Exemplo de uso em Python:
# meu_cachorro = Cachorro("Rex", "Labrador")
# print(meu_cachorro.comer())
# print(meu_cachorro.latir())
# Saída esperada:
# Rex está comendo.
# Rex (Labrador) está latindo: Au Au!

Interagir com o Cachorro (Simulado)

Esta simulação abaixo reflete o comportamento do código Python acima. Crie um cachorro e veja como ele pode comer (método herdado) e latir (método próprio).

Desafios para Continuar

Aplique o que aprendeu sobre herança para resolver estes desafios no seu ambiente de desenvolvimento Python.

  • 1. Crie uma Hierarquia de Animais

    Defina uma superclasse `Animal` com um construtor que aceita `nome` e `idade`, e um método `fazer_som()` que imprime "Som genérico de animal".

    Crie uma subclasse `Cachorro` que herde de `Animal`. Adicione um método `latir()` específico do cachorro. Crie um objeto `Cachorro` e chame `fazer_som()` (herdado) e `latir()`.

  • 2. Classe `FormaGeometrica` e `Circulo`

    Crie uma superclasse `FormaGeometrica` com um método `calcular_area()` (que pode retornar 0 ou levantar um `NotImplementedError`).

    Crie uma subclasse `Circulo` que herde de `FormaGeometrica`. O construtor de `Circulo` deve aceitar um `raio`. Sobrescreva o método `calcular_area()` para calcular a área de um círculo ($$\pi \cdot \text{raio}^2$$). Crie um objeto `Circulo` e imprima sua área (use `3.14159` para $$\pi$$).