Multiple arv i C ++ er kraftig, men et vanskelig verktøy, som ofte fører til problemer hvis det ikke brukes forsiktig - problemer som Diamond Problem.
I denne artikkelen vil vi diskutere diamantproblemet, hvordan det oppstår fra flere arv, og hva du kan gjøre for å løse problemet.
Flere arv i C ++
Flere arv er en funksjon av objektorientert programmering (OOP) hvor en underklasse kan arve fra mer enn én superklasse. Med andre ord kan en barneklasse ha mer enn én forelder.
Figuren nedenfor viser en billedlig fremstilling av flere arv.
I diagrammet ovenfor, klasse C har klasse A. og klasse B som foreldre.
Hvis vi vurderer et virkelighetsscenario, arver et barn fra sin far og mor. Så et barn kan representeres som en avledet klasse med "Far" og "Mor" som foreldre. På samme måte kan vi ha mange slike virkelige eksempler på flere arv.
I flere arv blir konstruktørene av en arvet klasse henrettet i den rekkefølgen de er arvet. På den annen side blir ødeleggerne henrettet i motsatt rekkefølge av arven.
La oss nå illustrere den multiple arven og verifisere rekkefølgen på konstruksjon og ødeleggelse av gjenstander.
Kode illustrasjon av flere arv
For illustrasjonen med flere arv har vi nøyaktig programmert representasjonen ovenfor i C ++. Koden for programmet er gitt nedenfor.
#inkludere
ved hjelp av navneområde std;
klasse A // basisklasse A med konstruktør og destruktor
{
offentlig:
A () {cout << "klasse A:: Constructor" << endl; }
~ A () {cout << "klasse A:: Destructor" << endl; }
};
klasse B // basisklasse B med konstruktør og destruktor
{
offentlig:
B () {cout << "klasse B:: Constructor" << endl; }
~ B () {cout << "klasse B:: Destructor" << endl; }
};
klasse C: offentlig B, offentlig A // avledet klasse C arver klasse A og deretter klasse B (merk ordren)
{
offentlig:
C () {cout << "klasse C:: Constructor" << endl; }
~ C () {cout << "klasse C:: Destructor" << endl; }
};
int main () {
C c;
retur 0;
}
Utgangen vi får fra programmet ovenfor er som følger:
klasse B:: Konstruktør
klasse A:: Konstruktør
klasse C:: Konstruktør
klasse C:: Destructor
klasse A:: Destructor
klasse B:: Destructor
Hvis vi sjekker utgangen, ser vi at konstruktørene kalles i rekkefølge B, A og C mens destruktorene er i motsatt rekkefølge. Nå som vi kjenner det grunnleggende om flere arv, fortsetter vi med å diskutere diamantproblemet.
Diamantproblemet, forklart
Diamantproblemet oppstår når en barneklasse arver fra to foreldreklasser som begge deler en felles besteforeldreklasse. Dette er illustrert i diagrammet nedenfor:
Her har vi en klasse Barn arver fra klasser Far og Mor. Disse to klassene arver på sin side klassen Person fordi både far og mor er person.
Som vist på figuren, arver klasse Child egenskapene til klasse Person to ganger - en gang fra far og igjen fra mor. Dette gir opphav til uklarhet siden kompilatoren ikke forstår hvilken vei han skal gå.
Dette scenariet gir opphav til en diamantformet arvediagram og kalles berømt "Diamantproblemet."
Kodeillustrasjon av diamantproblemet
Nedenfor har vi representert eksemplet ovenfor på diamantformet arv programmatisk. Koden er gitt nedenfor:
#inkludere
ved hjelp av navneområde std;
klasse Person {// klasse Person
offentlig:
Person (int x) {cout << "Person:: Person (int) kalt" << endl; }
};
klasse Far: offentlig person {// klasse Far arver Person
offentlig:
Far (int x): Person (x) {
cout << "Far:: Far (int) kalt" << endl;
}
};
klasse Mor: offentlig person {// klasse Mor arver Person
offentlig:
Mor (int x): Person (x) {
cout << "Mor:: Mor (int) kalt" << endl;
}
};
klasse Barn: offentlig far, offentlig mor {// Barn arver far og mor
offentlig:
Barn (int x): Mor (x), Far (x) {
cout << "Barn:: Barn (int) kalt" << endl;
}
};
int main () {
Barnbarn (30);
}
Følgende er resultatet av dette programmet:
Person:: Person (int) ringt
Far:: Far (int) ringte
Person:: Person (int) ringt
Mor:: Mor (int) ringte
Barn:: Barn (int) ringt
Nå kan du se tvetydigheten her. Personklasse -konstruktøren kalles to ganger: én gang når Fader -klasseobjektet opprettes og neste når moderklasseobjektet opprettes. Egenskapene til Person -klassen arves to ganger, noe som gir opphav til tvetydighet.
Siden Person -klasse -konstruktøren kalles to ganger, vil destruktoren også bli kalt to ganger når objektet i Child -klassen er ødelagt.
Hvis du har forstått problemet riktig, la oss diskutere løsningen på diamantproblemet.
Slik løser du diamantproblemet i C ++
Løsningen på diamantproblemet er å bruke virtuell søkeord. Vi gjør de to foreldreklassene (som arver fra den samme besteforeldreklassen) til virtuelle klasser for å unngå to kopier av besteforeldreklassen i barneklassen.
La oss endre illustrasjonen ovenfor og sjekke utgangen:
Kodeillustrasjon for å fikse diamantproblemet
#inkludere
ved hjelp av navneområde std;
klasse Person {// klasse Person
offentlig:
Person () {cout << "Person:: Person () kalt" << endl; } // Grunnkonstruktør
Person (int x) {cout << "Person:: Person (int) kalt" << endl; }
};
klasse Far: virtuell offentlig person {// klasse Far arver Person
offentlig:
Far (int x): Person (x) {
cout << "Far:: Far (int) kalt" << endl;
}
};
klasse mor: virtuell offentlig person {// klasse mor arver person
offentlig:
Mor (int x): Person (x) {
cout << "Mor:: Mor (int) kalt" << endl;
}
};
klasse Barn: offentlig far, offentlig mor {// klasse Barn arver far og mor
offentlig:
Barn (int x): Mor (x), Far (x) {
cout << "Barn:: Barn (int) kalt" << endl;
}
};
int main () {
Barnbarn (30);
}
Her har vi brukt virtuell søkeord når klasser Far og mor arver personklassen. Dette kalles vanligvis "virtuell arv", som garanterer at bare en enkelt forekomst av den arvede klassen (i dette tilfellet Person -klassen) blir videreført.
Med andre ord vil barneklassen ha en enkelt forekomst av personklassen, delt av både far- og morklassen. Ved å ha en enkelt forekomst av Person -klassen, løses uklarheten.
Utdataene fra koden ovenfor er gitt nedenfor:
Person:: Person () ringt
Far:: Far (int) ringte
Mor:: Mor (int) ringte
Barn:: Barn (int) ringt
Her kan du se at klassen Person -konstruktør bare kalles en gang.
En ting å merke seg om virtuell arv er at selv om den parameteriserte konstruktøren av Personklasse kalles eksplisitt av far og mor -klassekonstruktører gjennom initialisering lister, bare hovedkonstruktøren av Person -klassen vil bli kalt.
Dette er fordi det bare er en enkelt forekomst av en virtuell baseklasse som deles av flere klasser som arver fra den.
For å forhindre at grunnkonstruktøren kjører flere ganger, kalles ikke konstruktøren for en virtuell baseklasse av klassen som arver fra den. I stedet blir konstruktøren kalt av konstruktøren av betongklassen.
I eksemplet ovenfor ringer klassen Child direkte til grunnkonstruktøren for klassen Person.
I slekt: En nybegynnerguide til standardmalbiblioteket i C ++
Hva om du trenger å utføre den parameteriserte konstruktøren av basisklassen? Du kan gjøre det ved å eksplisitt kalle det i barneklassen i stedet for far- eller morklassen.
Diamantproblemet i C ++, løst
Diamantproblemet er en tvetydighet som oppstår i flere arv når to foreldreklasser arver fra samme besteforeldreklasse, og begge foreldreklassene arves av en enkelt barneklasse. Uten å bruke virtuell arv, ville barneklassen arve egenskapene til besteforeldreklassen to ganger, noe som førte til tvetydighet.
Dette kan dukke opp ofte i virkelige koder, så det er viktig å ta opp denne tvetydigheten når den oppdages.
Diamantproblemet løses ved hjelp av virtuell arv, der virtuell søkeord brukes når foreldreklasser arver fra en delt besteforeldreklasse. Ved å gjøre det, lages bare én kopi av besteforeldreklassen, og konstruksjonen til besteforeldreklassen utføres av barneklassen.
Vil du lære programmering, men vet ikke hvor du skal begynne? Disse nybegynnerprogrammeringsprosjektene og opplæringsprogrammene starter deg.
Les neste
- Programmering
- C Programmering
Abonner på vårt nyhetsbrev
Bli med i vårt nyhetsbrev for tekniske tips, anmeldelser, gratis ebøker og eksklusive tilbud!
Klikk her for å abonnere