Conteúdo do Curso
C++ Poo
C++ Poo
Herança Diamante
A herança múltipla pode levar a uma situação conhecida como problema do diamante ou herança em diamante, que é um desafio significativo em linguagens de programação orientadas a objetos que suportam herança múltipla.
Isso ocorre quando uma subclasse herda de duas ou mais classes
, que por sua vez herdam de uma superclasse comum. O termo diamante é utilizado porque o esquema de herança se assemelha ao formato de um diamante.
main.cpp
class Base {}; class Derived1 : public Base {}; class Derived2 : public Base {}; class Diamond : public Derived1, public Derived2 {};
O principal problema da herança em diamante é a ambiguidade que ela cria. Como Diamond
herda tanto de Derived1
quanto de Derived2
, que por sua vez herdam de Base
, existem duas cópias de Base
dentro de um objeto de Diamond
. Isso pode gerar ambiguidade.
main.cpp
#include <iostream> class Base { public: void display() { std::cout << "Base display()" << std::endl; } }; class Derived1 : public Base { }; class Derived2 : public Base { }; class Diamond : public Derived1, public Derived2 { }; int main() { Diamond obj; obj.display(); // Ambiguity: Which display() method should be called? }
Solução para o problema
A palavra-chave virtual
ajuda a evitar esse problema. É possível resolver essa ambiguidade por meio de herança virtual utilizando a palavra-chave virtual
. Quando Diamond
herda virtualmente, o C++ garante que apenas uma cópia da superclasse esteja presente, mesmo que seja herdada várias vezes por caminhos diferentes.
main.cpp
class Base {}; class Derived1 : virtual public Base {}; class Derived2 : virtual public Base {}; class Diamond : public Derived1, public Derived2 {};
Tente resolver o problema de ambiguidade no exemplo anterior utilizando herança virtual.
Implementação da Herança Diamante
Para implementar a herança diamante de forma eficaz, utilize a palavra-chave virtual na declaração da superclasse dentro das classes
intermediárias. Garanta o uso consistente da herança virtual em todos os caminhos da hierarquia de herança e atente-se à ordem de chamadas dos construtores e destrutores.
Resolução de Ambiguidades
Um dos desafios da herança múltipla é também lidar com possíveis ambiguidades quando há membros com os mesmos nomes.
main.cpp
#include <iostream> class Base {}; class Derived1 : public Base { public: void display() { std::cout << "Derived1 display()" << std::endl; } }; class Derived2 : public Base { public: void display() { std::cout << "Derived2 display()" << std::endl; } }; class Diamond : public Derived1, public Derived2 { }; int main() { Diamond obj; obj.display(); // Ambiguity: Which display() method should be called? }
Se ambas as superclasses possuírem membros com o mesmo nome, a subclasse pode não saber qual deles utilizar. Para resolver essas ambiguidades, é possível utilizar o operador de resolução de escopo (::
) para especificar qual membro da classe base deve ser acessado. Por exemplo:
main.cpp
#include <iostream> class Base {}; class Derived1 : public Base { public: void display() { std::cout << "Derived1 display()" << std::endl; } }; class Derived2 : public Base { public: void display() { std::cout << "Derived2 display()" << std::endl; } }; class Diamond : public Derived1, public Derived2 { }; int main() { Diamond obj; obj.Derived1::display(); obj.Derived2::display(); }
Obrigado pelo seu feedback!