Herança em C++: Conceitos e Implementações Práticas

Herança e Derivação

01 Conceitos de Herança e Derivação

Herança:

  • Ao criar uma classe B que se assemelha a uma classe A existente (ou seja, B incorpora todas as características de A), A é denominada classe base e B classe derivada (ou subclasse).

Classe Derivada:

  • A classe derivada é construída a partir da classe base, com modificações e extensões. É possível adicionar novas variáveis e funções membro.
  • Uma classe derivada herda todas as funções e variáveis da classe base, independentemente de seu modificador de acesso (private, protected, public). Entretanto, funções da classe derivada não podem acessar membros private da classe base.

02 Exemplo de Aplicação da Herança

Considere o desenvolvimento de software por diferentes especialidades. Vamos modelar uma classe base para profissionais de programação:

Atributos comuns (variáveis membro):

  1. Nome
  2. Gênero
  3. Cargo

Métodos comuns (funções membro):

  1. Verificar se há trabaloh extra
  2. Verificar se há bônus

Cada especialização possui atributos e métodos adicionais:

  • Programador C++: experiência em sistemas de baixo nível
  • Programador Java: conhecimento em ambientes corporativos
  • Programador Python: domínio em scripts e automação

03 Sintaxe da Classe Derivada

A herança é definida com a seguinte estrutura:

class NomeClasseDerivada : public NomeClasseBase
{
    
};

Classe base Desenvolvedor:

class Desenvolvedor
{
public:
    bool temHorasExtras(){}        // Verifica trabalho extra
    bool temBonus(){}              // Verifica bônus
    
    void configurarNome(const string & nome)
    {
        nome_ = nome;
    }
    
private:
    string nome_;   // Nome
    string cargo_;  // Cargo
    int genero_;    // Gênero
};

Classe derivada DesenvolvedorPython:

class DesenvolvedorPython : public Desenvolvedor
{
public:
    bool atuaIA(){}      // Verifica área de inteligência artificial
    bool atuaBigData(){} // Verifica área de big data
};

04 Espaço de Memória de Objetos Derivados

O tamanho de um objeto derivado é a soma do tamanho da classe base e das novas variáveis membro. O objeto da classe base é armazenado no início do objeto derivado.

class Base
{
    int x1;
    int x2;
};

class Derivada : public Base
{
    int x3;    
};

Relações de Herança e Composição

01 Tipos de Relações entre Classes

A relação de herança é uma relação "é-um":

  • Se B deriva de A, então um objeto B "é um" objeto A.

A relação de composição é uma relação "tem-um":

  • Se C contém uma variável i do tipo D, então C "tem" um D.

02 Uso Adequado da Herança

Suponha que exista uma classe Homem e uma classe Mulher. Herdar Mulher de Homem seria incorreto, pois implica que uma mulher é um homem. O correto é abstrair características comuns em uma classe Humano, da qual ambas derivam.

03 Exemplo de Composição

Em um sistema de gerenciamento de animais de estimação, com classes Tutor e Animal, onde um tutor pode ter vários animais, mas cada animal tem um único tutor.

Solução Correta:

class Animal;
class Tutor
{
    Animal * animais[10]; // Vetor de ponteiros para animais
};

class Animal
{
    Tutor * dono; // Ponteiro para tutor
};

Essa abordagem permite relações flexíveis sem dependências circulares.

04 Objetos vs. Ponteiros

Ponteiros economizam memória e permitem polimorfismo. Exemplo com uma classe Veiculo:

class Veiculo
{
    Motor motor;       // Composição direta
    Asa * asa;         // Ponteiro para componente opcional
};

Vantagens: espaço reduzido, reutilização de objetos, e suporte a polimorfismo via ponteiros de classe base.

Sobrescrita de Membros

01 Sobrescrita na Classe Derivada

A classe derivada pode definir membros com o mesmo nome da classe base. Para acesar o membro da base, utiliza-se o operador de escopo ::.

class Pai
{
public:
    int saldo;
    void exibir();
};

class Filho : public Pai
{
public:
    int saldo;   // Sobrescrita da variável
    void exibir(); // Sobrescrita da função
    
    void usarMembros()
    {
        saldo = 200;         // Acessa saldo da classe derivada
        Pai::saldo = 200;    // Acessa saldo da classe base
        
        exibir();            // Chama exibir da derivada
        Pai::exibir();       // Chama exibir da base
    }
};

Membros Protegidos

Membros protected da classe base são acessíveis em funções da classe dreivada, mas não externamente. Membros private não são acessíveis na derivada.

class Base
{
public:
    int publico;
protected:
    int protegido;
private:
    int privado;
};

class Derivada : public Base
{
    void acessar()
    {
        publico = 1;     // OK
        protegido = 1;   // OK
        privado = 1;     // Erro de compilação
    }
};

Construtores em Classes Derivadas

O construtor da classe derivada deve inicializar a classe base. Usa-se a lista de inicialização.

class Inseto
{
private:
    int patas; 
    int cor;
public:
    int tipo;
    Inseto(int p, int c);
};

class InsetoVoador : public Inseto
{
    int asas;
public:
    InsetoVoador(int p, int c, int a);
};

Inseto::Inseto(int p, int c)
{
    patas = p;
    cor = c;
}

// Correto: chamando construtor da base
InsetoVoador::InsetoVoador(int p, int c, int a) : Inseto(p, c)
{
    asas = a;
}

Ordem de destruição: o destrutor da derivada é chamado primeiro, seguido pelo da base.

Regras de Atribuição

01 Herança Pública

Com herança pública, objetos derivados podem ser atribuídos a referências e ponteiros da classe base.

class Base {};
class Derivada : public Base {};

Base b;
Derivada d;

b = d;               // Atribuição
Base & ref = d;       // Referência
Base * ptr = &d;      // Ponteiro

02 Herança Protegida e Privada

Essas formas de herança alteram os níveis de acesso, mas não permitem conversões diretas como na herança pública.

03 Conversão de Ponteiros

Em herança pública, ponteiros de classe derivada podem ser convertidos para ponteiros de classe base. A conversão inversa requer casting explícito.

Base * ptrBase = &objDerivada;
Derivada * ptrDerivada = static_cast<Derivada*>(ptrBase);

Tags: C++ Herança programacao-orientada-a-objetos classes Polimorfismo

Publicado em 6-9 19:57 por Thomas