Notice: This page requires JavaScript to function properly.
Please enable JavaScript in your browser settings or update your browser.
Oppiskele Timanttiperiytyminen | Perinnän Yleiskatsaus
C++ OOP

book
Timanttiperiytyminen

Moniperintä voi johtaa tilanteeseen, jota kutsutaan nimellä timanttiongelma tai timanttiperintä, mikä on merkittävä haaste olio-ohjelmointikielissä, jotka tukevat moniperintää.

Tämä tapahtuu, kun aliluokka perii kahdesta tai useammasta classes, jotka itse perivät yhteisestä yliluokasta. Termi timantti viittaa siihen, että perintärakenne muistuttaa timantin muotoa.

main.cpp

main.cpp

copy
class Base {};

class Derived1 : public Base {};

class Derived2 : public Base {};

class Diamond : public Derived1, public Derived2 {};
1234567
class Base {}; class Derived1 : public Base {}; class Derived2 : public Base {}; class Diamond : public Derived1, public Derived2 {};

Timanttiperinnän ensisijainen ongelma on sen aiheuttama epäselvyys. Koska Diamond perii sekä Derived1:stä että Derived2:sta, jotka puolestaan perivät Base:sta, Base-oliossa on kaksi kopiota Diamond:sta. Tämä voi johtaa epäselvyyteen.

main.cpp

main.cpp

copy
#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?
}
12345678910111213141516
#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? }

Ongelman ratkaisu

Avainsana virtual auttaa välttämään tämän ongelman. Voit ratkaista tämän epäselvyyden virtuaalisen perinnän avulla käyttämällä virtual-avainsanaa. Kun Diamond perii virtuaalisesti, C++ varmistaa, että yliluokasta on vain yksi kopio, vaikka se periytyisi useamman polun kautta.

main.cpp

main.cpp

copy
class Base {};

class Derived1 : virtual public Base {};

class Derived2 : virtual public Base {};

class Diamond : public Derived1, public Derived2 {};
1234567
class Base {}; class Derived1 : virtual public Base {}; class Derived2 : virtual public Base {}; class Diamond : public Derived1, public Derived2 {};
Note
Huomautus

Yritä ratkaista edellisen esimerkin epäselvyysongelma hyödyntämällä virtuaalista perintää.

Timanttiperinnän toteuttaminen

Timanttiperinnän tehokkaaseen toteuttamiseen käytä virtual-avainsanaa yliluokan määrittelyssä välikurssien classes. Varmista virtuaalisen perinnän johdonmukainen käyttö kaikissa perintäpoluissa ja huomioi rakentajien ja tuhoajien kutsujärjestys.

Epäselvyyksien ratkaiseminen

Yksi moniperinnän haasteista on myös mahdollisten epäselvyyksien käsittely, kun kyseessä ovat samannimiset jäsenet.

main.cpp

main.cpp

copy
#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?
}
12345678910111213141516171819
#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? }

Jos molemmilla yläluokilla on samannimisiä jäseniä, alaluokka ei välttämättä tiedä, kumpaa käyttää. Tällaiset epäselvyydet voidaan ratkaista käyttämällä alueen tarkennusoperaattoria (::), jolla määritetään, minkä kantaluokan jäsentä halutaan käyttää. Esimerkiksi:

main.cpp

main.cpp

copy
#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();
}
1234567891011121314151617181920
#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(); }
question mark

Mikä on timanttiperinnän aiheuttama ensisijainen ongelma?

Select the correct answer

Oliko kaikki selvää?

Miten voimme parantaa sitä?

Kiitos palautteestasi!

Osio 4. Luku 5

Kysy tekoälyä

expand

Kysy tekoälyä

ChatGPT

Kysy mitä tahansa tai kokeile jotakin ehdotetuista kysymyksistä aloittaaksesi keskustelumme

some-alt