Više nasljeđivanja u C ++ moćno je, ali lukav alat, koji često dovodi do problema ako se ne koristi pažljivo - problema poput problema dijamanta.
U ovom ćemo članku raspravljati o dijamantnom problemu, o tome kako on proizlazi iz više nasljeđivanja i što možete učiniti kako biste riješili problem.
Više nasljeđivanja u C ++
Više nasljeđivanja je a značajka objektno orijentiranog programiranja (OOP) gdje podrazred može naslijediti od više od jedne superklase. Drugim riječima, podređena klasa može imati više od jednog roditelja.
Donja slika prikazuje slikovni prikaz više nasljedstva.
Na gornjem dijagramu, razred C ima razred A i razred B kao njegovi roditelji.
Ako uzmemo u obzir scenarij iz stvarnog života, dijete nasljeđuje od oca i majke. Tako se Dijete može predstaviti kao izvedena klasa s “ocem” i “majkom” kao roditeljima. Slično, možemo imati mnogo takvih primjera iz stvarnog života o višestrukom nasljeđivanju.
Pri višestrukom nasljeđivanju konstruktori naslijeđene klase izvršavaju se redoslijedom kojim su naslijeđeni. S druge strane, destruktori se izvode obrnutim redoslijedom njihovog nasljeđivanja.
Ilustrirajmo višestruko nasljeđivanje i provjerimo redoslijed izgradnje i uništavanja objekata.
Šifra Ilustracija više nasljeđivanja
Za ilustraciju više nasljeđivanja, točno smo programirali gornji prikaz u C ++. Kôd programa dat je u nastavku.
#uključi
pomoću prostora imena std;
klasa A // osnovna klasa A s konstruktorom i destruktorom
{
javnost:
A () {cout << "klasa A:: Konstruktor" << endl; }
~ A () {cout << "klasa A:: Destruktor" << endl; }
};
klasa B // osnovna klasa B s konstruktorom i destruktorom
{
javnost:
B () {cout << "klasa B:: Konstruktor" << endl; }
~ B () {cout << "klasa B:: Destruktor" << endl; }
};
klasa C: javna B, javna A // izvedena klasa C nasljeđuje klasu A, a zatim klasu B (obratite pažnju na redoslijed)
{
javnost:
C () {cout << "klasa C:: Konstruktor" << endl; }
~ C () {cout << "klasa C:: Destructor" << endl; }
};
int main () {
C c;
return 0;
}
Izlaz koji dobivamo iz gornjeg programa je sljedeći:
klasa B:: Konstruktor
klasa A:: Konstruktor
klasa C:: Konstruktor
klasa C:: Destructor
klasa A:: Destruktor
klasa B:: Destruktor
Sada, ako provjerimo izlaz, vidimo da su konstruktori pozvani po redoslijedu B, A i C, dok su destruktori obrnutim redoslijedom. Sada kada znamo osnove višestrukog nasljeđivanja, prelazimo na raspravu o dijamantnom problemu.
Objašnjenje problema dijamanta
Dijamantni problem nastaje kada podređena klasa naslijedi od dvije roditeljske klase koje obje dijele zajedničku klasu baka i djed. To je ilustrirano donjim dijagramom:
Evo, imamo razred Dijete nasljeđujući od klasa Otac i Majka. Ove dvije klase, pak, nasljeđuju klasu Osoba jer su i Otac i Majka Osoba.
Kao što je prikazano na slici, klasa Dijete nasljeđuje osobine klase Osoba dva puta - jednom od Oca i opet od Majke. To izaziva nejasnoće jer prevoditelj ne razumije kojim smjerom krenuti.
Ovaj scenarij dovodi do dijagrama nasljeđivanja u obliku dijamanta i slavno se naziva "Dijamantni problem".
Kodna ilustracija problema dijamanta
Dolje smo programski predstavili gornji primjer nasljeđivanja u obliku dijamanta. Kôd je dat u nastavku:
#uključi
pomoću prostora imena std;
razredna osoba {// razredna osoba
javnost:
Osoba (int x) {cout << "Osoba:: Osoba (int) zvana" << endl; }
};
razred Otac: javna osoba {// razred Otac nasljeđuje Osobu
javnost:
Otac (int x): Osoba (x) {
cout << "Otac:: Otac (int) zvan" << endl;
}
};
razred Majka: javna Osoba {// razred Majka nasljeđuje Osobu
javnost:
Majka (int x): Osoba (x) {
cout << "Majka:: Majka (int) zvana" << endl;
}
};
razred Dijete: javni Otac, javna Majka {// Dijete nasljeđuje Oca i Majku
javnost:
Dijete (int x): Majka (x), Otac (x) {
cout << "Dijete:: Dijete (int) zvano" << endl;
}
};
int main () {
Dijete dijete (30);
}
Slijedi ispis ovog programa:
Osoba:: Osoba (int) pozvana
Otac:: Otac (int) zvan
Osoba:: Osoba (int) pozvana
Majka:: Majka (int) zvana
Dijete:: Pozvano dijete (int)
Sada možete vidjeti nejasnoće ovdje. Konstruktor klase Osoba poziva se dva puta: jednom kada se stvori objekt klase Otac i sljedeći kada se stvara objekt klase Majka. Svojstva klase Osoba nasljeđuju se dva puta, što dovodi do nejasnoća.
Budući da se konstruktor klase Person poziva dva puta, destruktor će se također pozvati dvaput kada se objekt klase Child uništi.
Ako ste dobro razumjeli problem, razgovarajmo o rješenju dijamantnog problema.
Kako riješiti problem dijamanta u C ++
Rješenje problema dijamanta je korištenje virtualan ključna riječ. Dvije roditeljske klase (koje nasljeđuju iz iste klase baka i djedova) pretvaramo u virtualne klase kako bismo izbjegli dvije kopije klase baka i djed u podređenoj klasi.
Promijenimo gornju ilustraciju i provjerimo izlaz:
Ilustracija koda za rješavanje problema s dijamantom
#uključi
pomoću prostora imena std;
razredna osoba {// razredna osoba
javnost:
Osoba () {cout << "Osoba:: Osoba () zvana" << endl; } // Konstruktor baze
Osoba (int x) {cout << "Osoba:: Osoba (int) zvana" << endl; }
};
razred Otac: virtualna javna Osoba {// razred Otac nasljeđuje Osobu
javnost:
Otac (int x): Osoba (x) {
cout << "Otac:: Otac (int) zvan" << endl;
}
};
razred Majka: virtualna javna Osoba {// razred Majka nasljeđuje Osobu
javnost:
Majka (int x): Osoba (x) {
cout << "Majka:: Majka (int) zvana" << endl;
}
};
razred Dijete: javni Otac, javna Majka {// razred Dijete nasljeđuje Oca i Majku
javnost:
Dijete (int x): Majka (x), Otac (x) {
cout << "Dijete:: Dijete (int) zvano" << endl;
}
};
int main () {
Dijete dijete (30);
}
Ovdje smo koristili virtualan ključna riječ kada klase Otac i Majka nasljeđuju klasu Osoba. To se obično naziva "virtualno nasljeđivanje", što jamči da se prenosi samo jedna instanca naslijeđene klase (u ovom slučaju klase Osoba).
Drugim riječima, klasa Dijete imat će jednu instancu klase Osoba koju dijele i klase Otac i Majka. Imajući jednu instancu klase Osoba, nejasnoće se rješavaju.
Izlaz gornjeg koda dat je u nastavku:
Osoba:: Osoba () pozvana
Otac:: Otac (int) zvan
Majka:: Majka (int) zvana
Dijete:: Pozvano dijete (int)
Ovdje možete vidjeti da se konstruktor klase Osoba poziva samo jednom.
Jedna stvar koju treba primijetiti kod virtualnog nasljeđivanja je da čak i ako je parametrizirani konstruktor datoteke Konstruktori klase Otac i Majka putem inicijalizacije izričito pozivaju klasu osobe popisi, pozvat će se samo osnovni konstruktor klase Osoba.
To je zato što postoji samo jedna instanca virtualne osnovne klase koju dijeli više klasa koje je nasljeđuju.
Kako bi se spriječilo da se osnovni konstruktor izvodi više puta, konstruktor za virtualnu baznu klasu ne poziva klasa koja ga nasljeđuje. Umjesto toga, konstruktor poziva konstruktor betonske klase.
U gornjem primjeru klasa Child izravno poziva osnovni konstruktor za klasu Osoba.
Povezano: Vodič za početnike u knjižnici standardnih predložaka u C ++
Što ako trebate izvršiti parametrizirani konstruktor osnovne klase? To možete učiniti tako da to izričito pozovete u razredu Dijete, a ne u razredima Otac ili Majka.
Dijamantni problem u C ++, riješen
Dijamantni problem je nejasnoća koja nastaje pri višestrukom nasljeđivanju kada dvije roditeljske klase nasljeđuju od iste klase baka i djedova, a obje roditeljske klase nasljeđuje jedna podređena klasa. Bez korištenja virtualnog nasljeđivanja, podređena klasa dva puta bi naslijedila svojstva klase baka i djed, što bi dovelo do nejasnoća.
To se često može pojaviti u kodu u stvarnom svijetu, pa je važno riješiti tu nejasnoću kad god se uoči.
Dijamantni problem riješen je virtualnim nasljeđivanjem u kojem se virtualan ključna riječ se koristi kada roditeljske klase nasljeđuju od zajedničke klase djeda i bake. Time se izrađuje samo jedna kopija klase baka i djed, a konstrukciju objekta klase baka i djed vrši klasa dijete.
Želite naučiti programiranje, ali ne znate odakle započeti? Ovi projekti i vodiči za programiranje početnika će vas započeti.
Pročitajte Dalje
- Programiranje
- C Programiranje
Pretplatite se na naše obavijesti
Pridružite se našem biltenu za tehničke savjete, recenzije, besplatne e -knjige i ekskluzivne ponude!
Kliknite ovdje za pretplatu