C ++ mitmekordne pärimine on võimas, kuid keeruline tööriist, mis põhjustab sageli probleeme, kui seda ei kasutata hoolikalt - selliseid probleeme nagu teemandiprobleem.
Selles artiklis käsitleme teemandiprobleemi, seda, kuidas see tekib mitmest pärandist ja mida saate probleemi lahendamiseks teha.
Mitu pärandit C ++ keeles
Mitu pärandit on a objektorienteeritud programmeerimise (OOP) funktsioon kus alamklass võib pärida rohkem kui ühest superklassist. Teisisõnu, lasteklassis võib olla rohkem kui üks vanem.
Alloleval joonisel on kujutatud mitme pärandi piltlik esitus.
Ülaltoodud diagrammil klass C on klass A ja klass B kui tema vanemad.
Kui me vaatame reaalse stsenaariumi, pärib laps oma isalt ja emalt. Seega saab last kujutada tuletatud klassina, mille vanemad on „isa” ja „ema”. Samamoodi võib meil olla palju selliseid näiteid päriselust mitme pärimise kohta.
Mitme pärimise korral täidetakse päritud klassi konstruktorid nende pärimise järjekorras. Teisest küljest hukatakse hävitajad nende pärimise vastupidises järjekorras.
Nüüd illustreerime mitmekordset pärandit ja kontrollime objektide ehitamise ja hävitamise järjekorda.
Mitme pärandi koodi illustratsioon
Mitme pärimise illustratsiooni jaoks oleme täpselt programmeerinud ülaltoodud esituse C ++ -is. Programmi kood on toodud allpool.
#kaasake
kasutades nimeruumi std;
klass A // baasklass A koos konstruktori ja hävitajaga
{
avalik:
A () {cout << "class A:: Constructor" << endl; }
~ A () {cout << "class A:: Destructor" << endl; }
};
klass B // baasklass B koos konstruktori ja hävitajaga
{
avalik:
B () {cout << "class B:: Constructor" << endl; }
~ B () {cout << "klass B:: Hävitaja" << endl; }
};
klass C: avalik B, avalik A // tuletatud klass C pärib klassi A ja seejärel klassi B (pange tähele järjekorda)
{
avalik:
C () {cout << "klass C:: konstruktor" << endl; }
~ C () {cout << "klass C:: Hävitaja" << endl; }
};
int main () {
Cc;
tagasitulek 0;
}
Ülaltoodud programmist saadud väljund on järgmine:
klass B:: Konstruktor
klass A:: Konstruktor
klass C:: Konstruktor
klass C:: Hävitaja
klass A: Hävitaja
klass B: Hävitaja
Nüüd, kui kontrollime väljundit, näeme, et konstruktorid kutsutakse järjekorras B, A ja C, samal ajal kui hävitajad on vastupidises järjekorras. Nüüd, kui me teame mitme pärandi põhitõdesid, jätkame teemandiprobleemi arutamist.
Teemantide probleem, seletatud
Teemandiprobleem tekib siis, kui lasteklass pärib kahelt vanemaklassilt, kellel mõlemal on ühine vanavanemate klass. Seda illustreerib allolev diagramm:
Siin on meil klass Laps klassidelt pärimine Isa ja Ema. Need kaks klassi omakorda pärivad klassi Isik sest nii isa kui ema on isik.
Nagu jooniselt näha, pärib klassi Laps klassi Isiku tunnused kaks korda - kord isalt ja uuesti emalt. See tekitab ebaselgust, kuna kompilaator ei saa aru, millist teed minna.
See stsenaarium loob rombikujulise pärimisgraafiku ja seda nimetatakse kuulsalt teemandiprobleemiks.
Kood Illustratsioon teemandiprobleemist
Allpool oleme programmiliselt esindanud ülaltoodud näidet teemandikujulise pärandi kohta. Kood on toodud allpool:
#kaasake
kasutades nimeruumi std;
klassi inimene {// klassi inimene
avalik:
Isik (int x) {cout << "Isik:: Isik (int) nimega" << endl; }
};
klassi isa: avalik isik {// klassi isa pärib isiku
avalik:
Isa (int x): isik (x) {
cout << "Isa:: Isa (int) nimega" << endl;
}
};
klassi ema: avalik isik {// klassi ema pärib isiku
avalik:
Ema (int x): inimene (x) {
cout << "Ema:: Ema (int) nimega" << endl;
}
};
klass Laps: avalik isa, avalik ema {// Laps pärib isa ja ema
avalik:
Laps (int x): ema (x), isa (x) {
cout << "Laps:: Laps (int) nimega" << endl;
}
};
int main () {
Lapslaps (30);
}
Selle programmi väljund on järgmine:
Isik:: Isik (int) kutsutud
Isa:: isa (int) helistas
Isik:: Isik (int) kutsutud
Ema:: Ema (int) helistas
Laps:: Laps (int) kutsutud
Nüüd näete ebaselgust siin. Isikuklassi konstruktorit kutsutakse kaks korda: üks kord, kui luuakse Isa klassi objekt, ja järgmine kord, kui luuakse ema klassi objekt. Isikuklassi omadused päritakse kaks korda, tekitades ebaselgust.
Kuna isikukonstruktorit kutsutakse kaks korda, kutsutakse hävitavat ka kaks korda, kui alamklassi objekt on hävitatud.
Kui olete probleemist õigesti aru saanud, arutame teemandiprobleemi lahendust.
Kuidas parandada teemandiprobleemi C ++ -is
Teemandiprobleemi lahendus on kasutada virtuaalne märksõna. Teeme kaks vanemaklassi (kes pärivad samalt vanavanemate klassilt) virtuaalseteks klassideks, et vältida lasteklassi kahte vanavanemate klassi eksemplari.
Muutame ülaltoodud joonist ja kontrollime väljundit:
Kood illustratsioon teemandiprobleemi lahendamiseks
#kaasake
kasutades nimeruumi std;
klassi inimene {// klassi inimene
avalik:
Isik () {cout << "Isik:: Isik () nimega" << endl; } // Baaskonstruktor
Isik (int x) {cout << "Isik:: Isik (int) nimega" << endl; }
};
klassi isa: virtuaalne avalik isik {// klassi isa pärib isiku
avalik:
Isa (int x): isik (x) {
cout << "Isa:: Isa (int) nimega" << endl;
}
};
klassi ema: virtuaalne avalik isik {// klassi ema pärib isiku
avalik:
Ema (int x): inimene (x) {
cout << "Ema:: Ema (int) nimega" << endl;
}
};
klassi Laps: avalik Isa, avalik Ema {// klassi Laps pärib Isa ja Ema
avalik:
Laps (int x): ema (x), isa (x) {
cout << "Laps:: Laps (int) nimega" << endl;
}
};
int main () {
Lapslaps (30);
}
Siin oleme kasutanud virtuaalne märksõna, kui klassid Isa ja ema pärivad klassi Isik. Seda nimetatakse tavaliselt “virtuaalseks pärimiseks”, mis tagab, et päritud klassi (antud juhul isikuklassi) edastatakse ainult üks eksemplar.
Teisisõnu, klassis Laps on üks isikuklassi eksemplar, mida jagavad nii isa kui ka ema klass. Kui isikuklassis on üks eksemplar, lahendatakse ebaselgus.
Ülaltoodud koodi väljund on toodud allpool:
Isik:: Isik () helistas
Isa:: isa (int) helistas
Ema:: Ema (int) helistas
Laps:: Laps (int) kutsutud
Siin näete, et klassi isikukonstruktorit kutsutakse ainult üks kord.
Üks asi, mida virtuaalse pärandi kohta märkida, on see, et isegi kui parameetritega konstruktor Isaklassi kutsuvad isa ja ema klassi konstruktorid selgesõnaliselt lähtestamise kaudu nimekirjad, kutsutakse ainult isikuklassi baaskonstruktorit.
Seda seetõttu, et virtuaalsest põhiklassist on ainult üks eksemplar, mida jagavad mitmed klassid, mis pärivad sellest.
Selleks, et baaskonstruktor ei töötaks mitu korda, ei kutsuta virtuaalse baasklassi konstruktorit sellest päriv klass. Selle asemel kutsub konstruktorit betooniklassi konstruktor.
Ülaltoodud näites kutsub klass Child otse klassi Isik baaskonstruktorit.
Seotud: Algaja juhend standardse malliteegi jaoks C ++ -is
Mis siis, kui teil on vaja käivitada põhiklassi parameetriline konstruktor? Seda saate teha, nimetades seda selgesõnaliselt klassis Laps, mitte Isa või Ema klassis.
Teemandiprobleem C ++ -is, lahendatud
Teemandiprobleem on mitmetähenduslikkus, mis tekib mitme pärimise korral, kui kaks vanemaklassi pärivad ühest ja samast vanavanemate klassist ja mõlemad vanemaklassid pärib üks lasteklass. Virtuaalset pärandit kasutamata päriks alamklass vanavanemate klassi omadusi kaks korda, põhjustades ebaselgust.
See võib reaalajas koodis sageli esile kerkida, seega on oluline selle ebaselgusega tegeleda alati, kui seda märgatakse.
Teemandiprobleem lahendatakse virtuaalse pärimise abil, mille puhul virtuaalne märksõna kasutatakse siis, kui vanemaklassid pärivad jagatud vanavanemate klassist. Seda tehes tehakse vanavanemate klassist ainult üks koopia ja vanavanemate klassi objektide ehitamise teeb lasteklass.
Kas soovite õppida programmeerimist, kuid ei tea, kust alustada? Need algajad programmeerimisprojektid ja õpetused alustavad teid.
Loe edasi
- Programmeerimine
- C Programmeerimine
Telli meie uudiskiri
Liituge meie uudiskirjaga, et saada tehnilisi näpunäiteid, ülevaateid, tasuta e -raamatuid ja eksklusiivseid pakkumisi!
Tellimiseks klõpsake siin