Herança

A herança é um conceito fundamental na programação orientada a objetos e torna-se crucial para criar aplicações robustas, reutilizáveis e de fácil manutenção. Neste capítulo, exploraremos o conceito de herança em Python, a forma como se define e utiliza classes base e derivadas, e veremos exemplos práticos para solidificar o nosso entendimento.

Introdução à Herança

Herança permite que uma classe (a classe derivada) herde atributos e métodos de outra classe (a classe base). Isto promove a reutilização de código e facilita a criação de novas funcionalidades sem necessidade de reescrever código já escrito. A sintaxe básica para a definição de uma classe derivada é:

class ClasseBase:
    def __init__(self):
        print("Inicialização ClasseBase")

    def metodo_base(self):
        print("Método da ClasseBase")
        
class ClasseDerivada(ClasseBase):
    def __init__(self):
        super().__init__()
        print("Inicialização ClasseDerivada")
        
    def metodo_derivado(self):
        print("Método da ClasseDerivada")

Ao usar super().__init__(), garantimos que o construtor da classe base é chamado, inicializando apropriadamente os componentes da classe base antes de executar qualquer código adicional na classe derivada.

Ao falamos em Herança temos que introduzir um novo conceito:

Protegido

  • Atributos e métodos protegidos são indicados com um underscore (_) no início do nome. Estes atributos não podem ser acedidos fora da classe e das suas subclasses.

Exemplo Prático: Sistema de Funcionários

Vamos criar um exemplo prático onde veremos como gerir diferentes tipos de funcionários numa organização, utilizando herança para evitar duplicação de código.

Passo 1: Definir a Classe Base Funcionario

class Funcionario:
    def __init__(self, nome, salario):
        self._nome = nome
        self._salario = salario

    def mostrar_detalhes(self):
        print(f"Nome: {self._nome}, Salário: {self._salario}")
				
func = Funcionario("Teste", 200)
func.mostrar_detalhes()
Nome: Teste, Salário: 200

A classe Funcionario contém atributos genéricos como nome e salario, e um método para mostrar esses detalhes.

Passo 2: Definir Classes Derivadas Gerente e Programador

class Gerente(Funcionario):
    def __init__(self, nome, salario, departamento):
        super().__init__(nome, salario)
        self._departamento = departamento

    def mostrar_detalhes(self):
        super().mostrar_detalhes()
        print(f"Departamento: {self._departamento}")

class Programador(Funcionario):
    def __init__(self, nome, salario, linguagens):
        super().__init__(nome, salario)
        self._linguagens = linguagens

    def mostrar_detalhes(self):
        super().mostrar_detalhes()
        print(f"Linguagens: {', '.join(self._linguagens)}")

Estas classes derivadas estendem Funcionario, adicionando atributos específicos e modificando o método mostrar_detalhes para incluir as novas informações.

Passo 3: Utilizar as Classes

gerente = Gerente("Ana", 4000, "Vendas")
programador = Programador("Carlos", 3000, ["Python", "Java"])

gerente.mostrar_detalhes()
programador.mostrar_detalhes()

Este código instanciará objetos das classes Gerente e Desenvolvedor e demonstrará como as classes derivadas utilizam e estendem a funcionalidade da classe base.

Herança Múltipla

Python também suporta herança múltipla, onde uma classe pode herdar de mais de uma classe base. Embora poderosa, a herança múltipla deve ser usada com cautela devido a possíveis ambiguidades no momento da resolução de métodos.

class ClasseA:
    def metodo(self):
        print("Método da ClasseA")

class ClasseB:
    def metodo(self):
        print("Método da ClasseB")

class ClasseC(ClasseA, ClasseB):
    pass

obj = ClasseC()
obj.metodo()

No exemplo acima, o método metodo da ClasseA será invocado ao invés do da ClasseB, pois ClasseA é listada primeiro na definição da ClasseC. Porém, podemos usar super() para invocar métodos específicos de uma cadeia de herança.

Resumo

Neste capítulo, aprendemos sobre a herança em Python e como reutilizar código existente para criar novas funcionalidades. Usamos herança para expandir a funcionalidade de uma classe base em classes derivadas e exploramos a herança múltipla.

Quiz

  1. Qual é o principal benefício de utilizar herança em programação orientada a objetos?

    • a) Melhorar a performance do programa
    • b) Facilitar a reutilização de código
    • c) Reduzir o tamanho do código fonte
    • d) Todas as anteriores
  2. O que faz a função super() numa classe derivada?

    • a) Chama o método inicial da própria classe derivada
    • b) Chama o construtor da classe base
    • c) Define a prioridade de métodos na herança múltipla
    • d) Nenhuma das anteriores
  3. O que ocorrerá se uma classe derivate não chamar explicitamente o construtor da classe base?

    • a) O Python irá gerar um erro de execução
    • b) Os atributos da classe base não serão inicializados
    • c) Será usado um construtor de classe base padrão automaticamente
    • d) Nada acontecerá, o programa correrá como esperado
  4. Na herança múltipla, qual critério o Python usa para decidir qual método chamar se o mesmo método existir em várias classes base?

    • a) A complexidade do método
    • b) A ordem de definição das classes base
    • c) A sintaxe do método
    • d) A primeira classe base definida no corpo da classe derivada
<< Encapsulamento Índice Polimorfismo >>