Contenuti del Corso
OOP in C++
OOP in C++
Ereditarietà a Diamante
L'ereditarietà multipla può portare a una situazione nota come problema del diamante o ereditarietà a diamante, che rappresenta una sfida significativa nei linguaggi di programmazione orientati agli oggetti che supportano l'ereditarietà multipla.
Questo si verifica quando una sottoclasse eredita da due o più classes
, le quali a loro volta ereditano da una superclasse comune. Il termine diamante viene utilizzato perché lo schema di ereditarietà ricorda la forma di un diamante.
main.cpp
class Base {}; class Derived1 : public Base {}; class Derived2 : public Base {}; class Diamond : public Derived1, public Derived2 {};
Il problema principale dell'ereditarietà a diamante è l'ambiguità che crea. Poiché Diamond
eredita sia da Derived1
che da Derived2
, che a loro volta ereditano da Base
, esistono due copie di Base
all'interno di un oggetto di tipo Diamond
. Questo può portare a ambiguità.
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? }
Soluzione al problema
La parola chiave virtual
aiuta a evitare questo problema. È possibile risolvere questa ambiguità tramite l'ereditarietà virtuale utilizzando la parola chiave virtual
. Quando Diamond
eredita virtualmente, C++ garantisce che sia presente una sola copia della superclasse, anche se viene ereditata più volte attraverso percorsi diversi.
main.cpp
class Base {}; class Derived1 : virtual public Base {}; class Derived2 : virtual public Base {}; class Diamond : public Derived1, public Derived2 {};
Cerca di risolvere il problema di ambiguità nell'esempio precedente utilizzando l'ereditarietà virtuale.
Implementazione dell'Ereditarietà a Diamante
Per implementare efficacemente l'ereditarietà a diamante, utilizzare la parola chiave virtual nella dichiarazione della superclasse all'interno delle classes
intermedie. Garantire un uso coerente dell'ereditarietà virtuale in tutti i percorsi della gerarchia di ereditarietà e prestare attenzione all'ordine di chiamata di costruttori e distruttori.
Risoluzione delle Ambiguità
Una delle sfide dell'ereditarietà multipla è anche la gestione delle potenziali ambiguità quando si hanno membri con lo stesso nome.
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 entrambe le superclassi possiedono membri con lo stesso nome, la sottoclasse potrebbe non sapere quale utilizzare. Per risolvere tali ambiguità, è possibile utilizzare l'operatore di risoluzione dello scope (::
) per specificare a quale membro della classe base si desidera accedere. Ad esempio:
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(); }
Grazie per i tuoi commenti!