Artigo original: https://www.freecodecamp.org/news/multiple-inheritance-in-c-and-the-diamond-problem-7c12a9ddbbec/

Escrito por: Onur Tuna

Ao contrário de muitas outras linguagens de programação orientada a objetos, o C++ permite várias heranças.

A herança múltipla permite que uma classe filho herde de mais de uma classe pai.

No início, parece um recurso muito útil. Um usuário, porém, precisa estar atento a algumas dificuldades ao implementar esse recurso.

Nos exemplos abaixo, abordaremos alguns cenários sobre os quais é preciso estar atento.

Começaremos com um exemplo simples para explicar esse conceito em C++.

#include <iostream>

class SerVivo {
protected:
    void respirar() {
        std::cout << "Respiro como um ser vivo." << std::endl;
    }
};

class Animal : protected SerVivo {
protected:
    void respirar() {
        std::cout << "Respiro como um animal." << std::endl;
    }
};

class Reptil : protected SerVivo {
protected:
    void rastejar() {
        std::cout << "Rastejo como um réptil." << std::endl;
    }
};

class Cobra : protected Animal, protected Reptil {
public:
    void respirar() {
        std::cout << "Respiro como uma cobra." << std::endl;
    }

    void rastejar() {
        std::cout << "Rastejo como uma cobra." << std::endl;
    }
};

int main() {
    Cobra cobra;

    cobra.respirar();
    cobra.rastejar();

    return 0;
}

A saída desse código é a seguinte:

Respiro como uma cobra.
Rastejo como uma cobra.

No exemplo acima, temos uma classe base chamada SerVivo. As classes Animal e Reptil herdam dela. Somente a classe Animal sobrescreve o método respirar(). A classe Cobra herda das classes Animal e Reptil. Ela sobrescreve seus métodos. Acima, não vemos problemas. O código funciona bem.

Agora, vamos deixar as coisas um pouco mais complexas.

O que ocorreria se a classe Reptil sobrescrevesse o método respirar()?

A classe Cobra não saberia qual método respirar() deve ser chamado. Esse é o "Problema do diamante".

1_cI0TQYv7yOgSsHhfES1Kaw

Problema do diamante

Veja o código abaixo. É como o código no exemplo acima, com a diferença que sobrescrevemos o método respirar() na classe Reptil.

#include <iostream>

class SerVivo {
protected:
    void respirar() {
        std::cout << "Respiro como um ser vivo." << std::endl;
    }
};

class Animal : protected SerVivo {
protected:
    void respirar() {
        std::cout << "Respiro como um animal." << std::endl;
    }
};

class Reptil : protected SerVivo {
public:
    void respirar() {
        std::cout << "Respiro como um réptil." << std::endl;
    }

    void rastejar() {
        std::cout << "Rastejo como um réptil." << std::endl;
    }
};

class Cobra : public Animal, public Reptil {

};

int main() {
    Cobra cobra;

    cobra.respirar();
    cobra.rastejar();

    return 0;
}

Se tentar compilar esse programa, ele não funcionará. Você verá uma mensagem de erro como a seguinte.

member ‘respirar’ found in multiple base classes of different types
Tradução: membro 'respirar' encontrado em várias classes de base de tipos diferentes

O erro tem a ver com o "Problema do diamante" da herança múltipla. A classe Cobra não sabe qual método respirar() deve ser chamado.

No primeiro exemplo, apenas a classe Animal sobrescrevia o método respirar(). A classe Reptil class não fazia isso. Assim, não era problema para a classe Cobra saber qual método respirar() deveria ser chamado. A classe Cobra acabaria chamando o método respirar() da classe Animal.

No segundo exemplo, a classe Cobra herda dois métodos respirar(): o método respirar() das classes Animal e Reptil. Como não sobrescrevemos o método respirar() na classe Cobra, acabamos com uma ambiguidade.

O C++ tem muitos recursos poderosos, como a herança múltipla. Porém, não é necessário usarmos todos os recursos que ele oferece.

Prefiro não usar herança múltipla e usar a herança virtual em vez dela.

A herança virtual resolve o clássico "Problema do diamante”. Ela garante que a classe filho receba apenas uma única instância da classe base comum.

Em outras palavras, a classe Cobra teria apenas uma instância da classe SerVivo. As classes Animal e Reptil compartilhariam essa instância.

Isso resolve o erro de tempo de compilação que recebemos anteriormente. As classes derivadas das classes abstratas devem sobrescrever as funções virtuais puras definidas na classe base.

Esperamos que tenha gostado dessa visão geral de heranças múltiplas e do "Problema do diamante".