Aula 10: Implementando a Herança

Herança em ação: sintaxe e `super()`.

O Que Você Vai Aprender

Nesta aula, você aprofundará seus conhecimentos sobre o Pilar da Herança em Programação Orientada a Objetos. Entenderá a sintaxe completa para implementar herança em Python e, crucialmente, aprenderá a utilizar a função `super()` para garantir que a inicialização e os comportamentos da superclasse sejam corretamente herdados e estendidos pelas subclasses.

✍️ Sintaxe da Herança

Revisar e entender a forma como as subclasses são definidas em relação às superclasses.

⬆️ Acesso à Superclasse (`super()`)

Dominar o uso de `super()` para chamar métodos (especialmente o construtor `__init__`) da classe pai.

Sintaxe: Definindo Subclasses

A sintaxe para criar uma subclasse (classe filha) que herda de uma superclasse (classe pai) em Python é bastante direta. Basta colocar o nome da superclasse entre parênteses após o nome da subclasse na sua definição.

Forma Geral

class Superclasse:
    # Atributos e métodos da superclasse
    pass

class Subclasse(Superclasse): # A Subclasse herda da Superclasse
    # Atributos e métodos específicos da subclasse
    pass

Isso significa que a `Subclasse` terá acesso a todos os atributos e métodos públicos e protegidos definidos na `Superclasse`.

Exemplo: `Animal` e `Cachorro`

class Animal:
    def __init__(self, nome):
        self.nome = nome

    def fazer_som(self):
        print(f"{self.nome} faz um som genérico.")

class Cachorro(Animal): # Cachorro herda de Animal
    def __init__(self, nome, raca):
        # ... inicialização específica do Cachorro
        self.raca = raca

    def latir(self):
        print(f"{self.nome} (${self.raca}) late: Au Au!")

Acesso à Superclasse (`super()`): O Vínculo Essencial

Um dos usos mais comuns da herança é quando a subclasse precisa estender (adicionar mais funcionalidades) o que a superclasse já faz, especialmente no método construtor (`__init__`). A função `super()` nos permite chamar métodos da superclasse de dentro da subclasse.

Chamando `__init__` da Superclasse

É fundamental que, ao definir o `__init__` de uma subclasse, você chame o `__init__` da superclasse usando `super().__init__(...)`. Isso garante que todos os atributos definidos na superclasse sejam corretamente inicializados.

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

class Gerente(Funcionario):
    def __init__(self, nome, salario, bonus):
        super().__init__(nome, salario) # Chama o construtor da classe pai
        self.bonus = bonus
    
    def exibir_bonus(self):
        return f"Bônus de Gerente: R$ {self.bonus:.2f}"

# Exemplo de uso:
# funcionario = Funcionario("João", 3000)
# print(funcionario.exibir_info())

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

Chamando Outros Métodos da Superclasse

`super()` também pode ser usado para chamar outros métodos da superclasse que foram sobrescritos ou para acessar funcionalidades que você quer reutilizar.

class Veiculo:
    def acelerar(self):
        print("Veículo acelerando.")

class Carro(Veiculo):
    def acelerar(self):
        super().acelerar() # Chama o método acelerar da superclasse
        print("Carro acelerando mais rápido.")

# meu_carro = Carro()
# meu_carro.acelerar()
# Saída:
# Veículo acelerando.
# Carro acelerando mais rápido.

Simulador: `Funcionario` e `Gerente`

Crie instâncias das classes `Funcionario` e `Gerente` (que herda de `Funcionario`) e veja como os atributos são inicializados e os métodos são chamados, incluindo o uso de `super()`.

Classes `Funcionario` e `Gerente` em Python

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

class Gerente(Funcionario):
    def __init__(self, nome, salario, bonus):
        super().__init__(nome, salario) # Chama o construtor da classe pai
        self.bonus = bonus
    
    def exibir_bonus(self):
        return f"Bônus de Gerente: R$ {self.bonus:.2f}"

# Exemplo de uso em Python:
# funcionario_base = Funcionario("Carlos", 3500)
# print(funcionario_base.exibir_info())

# gerente_novo = Gerente("Fernanda", 6000, 1500)
# print(gerente_novo.exibir_info()) # Método herdado
# print(gerente_novo.exibir_bonus()) # Método específico
# Saída esperada:
# Nome: Carlos, Salário: R$ 3500.00
# Nome: Fernanda, Salário: R$ 6000.00
# Bônus de Gerente: R$ 1500.00

Criar e Interagir com Funcionários/Gerentes (Simulado)

Esta simulação abaixo reflete o comportamento do código Python. Crie um funcionário ou gerente e interaja com seus dados.

Desafios para Continuar

Aplique o que aprendeu sobre a implementação da herança e o uso de `super()` para resolver estes desafios no seu ambiente de desenvolvimento Python.

  • 1. Classe `Pessoa` e `Estudante`

    Crie uma superclasse `Pessoa` com `__init__(self, nome, idade)`. Adicione um método `apresentar()` que imprima "Olá, meu nome é [nome] e tenho [idade] anos."

    Crie uma subclasse `Estudante` que herde de `Pessoa`. Seu `__init__` deve aceitar `nome`, `idade` e `curso`. Use `super().__init__` para os atributos de `Pessoa`. Adicione um método `estudar()` que imprima "Estou estudando [curso]."

    Crie uma instância de `Estudante` e chame `apresentar()` e `estudar()`.

  • 2. Sobrescrita de Método com `super()`

    Crie uma superclasse `Veiculo` com um método `ligar_motor()` que imprima "Motor do veículo ligado."

    Crie uma subclasse `CarroEsportivo` que herde de `Veiculo`. Sobrescreva o método `ligar_motor()` em `CarroEsportivo` para primeiro chamar `super().ligar_motor()` e, em seguida, imprimir "O motor ronca com potência!"

    Crie uma instância de `CarroEsportivo` e chame `ligar_motor()` para ver a sequência de mensagens.