Kursusindhold
C++ OOP
C++ OOP
Diamantarv
Multipel arv kan føre til en situation kendt som diamantproblemet eller diamantarv, hvilket er en væsentlig udfordring i objektorienterede programmeringssprog, der understøtter multipel arv.
Dette opstår, når en subklasse arver fra to eller flere classes
, som selv arver fra en fælles superklasse. Udtrykket diamant bruges, fordi arvestrukturen ligner formen af en diamant.
main.cpp
class Base {}; class Derived1 : public Base {}; class Derived2 : public Base {}; class Diamond : public Derived1, public Derived2 {};
Det primære problem med diamantarv er den tvetydighed, det skaber. Da Diamond
arver fra både Derived1
og Derived2
, som hver især arver fra Base
, findes der to kopier af Base
i et objekt af typen Diamond
. Dette kan føre til tvetydighed.
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? }
Løsning på problemet
Nøgleordet virtual
hjælper med at undgå dette problem. Du kan løse denne tvetydighed gennem virtuel arv ved at bruge nøgleordet virtual
. Når Diamond
arver virtuelt, sikrer C++, at kun én kopi af superklassen er til stede, selvom den arves flere gange gennem forskellige stier.
main.cpp
class Base {}; class Derived1 : virtual public Base {}; class Derived2 : virtual public Base {}; class Diamond : public Derived1, public Derived2 {};
Prøv at løse tvetydighedsproblemet i det forrige eksempel ved at anvende virtuel arv.
Implementering af diamantarv
For at implementere diamantarv effektivt, anvend virtual-nøgleordet i superklassens deklaration inden for de mellemliggende classes
. Sørg for konsekvent brug af virtuel arv i alle veje i arvshierarkiet, og vær opmærksom på rækkefølgen af kald til konstruktører og destruktører.
Løsning af tvetydigheder
En af udfordringerne ved multipel arv er også håndtering af potentielle tvetydigheder, når det gælder medlemmer med samme navne.
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? }
Hvis begge superklasser har medlemmer med samme navn, kan subklassen være usikker på, hvilken der skal bruges. For at løse sådanne tvetydigheder kan du bruge scope resolution operatoren (::
) til at specificere, hvilket basisklasses medlem du vil tilgå. For eksempel:
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(); }
Tak for dine kommentarer!