C ++ daudzkārtēja mantošana ir spēcīgs, bet sarežģīts rīks, kas bieži rada problēmas, ja to neizmanto rūpīgi - tādas problēmas kā Dimanta problēma.
Šajā rakstā mēs apspriedīsim Dimanta problēmu, kā tā rodas no vairāku mantojumu un ko jūs varat darīt, lai atrisinātu šo problēmu.
Vairāki mantojumi C ++
Vairāku mantojumu a objektorientētas programmēšanas (OOP) iezīme kur apakšklase var mantot no vairākām superklasēm. Citiem vārdiem sakot, bērnu klasē var būt vairāki vecāki.
Zemāk redzamajā attēlā parādīts vairāku mantojumu attēlojums.
Iepriekš redzamajā diagrammā C klase ir A klase un B klase kā tās vecāki.
Ja mēs apsveram reālu dzīves scenāriju, bērns manto no sava tēva un mātes. Tātad bērnu var attēlot kā atvasinātu klasi, kuras vecāki ir “tēvs” un “māte”. Līdzīgi mums var būt daudz šādu reālās dzīves piemēru par vairāku mantojumu.
Vairāku mantojumu gadījumā mantotās klases konstruktori tiek izpildīti tādā secībā, kādā tie tiek mantoti. No otras puses, iznīcinātāji tiek izpildīti apgrieztā mantojuma secībā.
Tagad ilustrēsim daudzkārtējo mantojumu un pārbaudīsim objektu uzbūves un iznīcināšanas kārtību.
Vairāku mantojumu kodu ilustrācija
Vairāku mantojumu ilustrācijai mēs esam precīzi ieprogrammējuši iepriekš minēto attēlojumu C ++. Programmas kods ir norādīts zemāk.
#iekļaut
izmantojot nosaukumvietas std;
klase A // bāzes klase A ar konstruktoru un iznīcinātāju
{
publiski:
A () {cout << "A klase:: Konstruktors" << endl; }
~ A () {cout << "A klase:: Iznīcinātājs" << endl; }
};
klase B // B bāzes klase ar konstruktoru un iznīcinātāju
{
publiski:
B () {cout << "B klase:: Konstruktors" << endl; }
~ B () {cout << "B klase:: Iznīcinātājs" << endl; }
};
C klase: publiska B, publiska A // atvasināta C klase pārmanto A klasi un pēc tam B klasi (ņemiet vērā pasūtījumu)
{
publiski:
C () {cout << "C klase:: Konstruktors" << endl; }
~ C () {cout << "C klase:: Iznīcinātājs" << endl; }
};
int main () {
C c;
atgriezties 0;
}
Rezultāts, ko mēs iegūstam no iepriekš minētās programmas, ir šāds:
B klase:: Konstruktors
A klase:: Konstruktors
C klase:: Konstruktors
C klase:: Iznīcinātājs
A klase:: Iznīcinātājs
B klase:: Iznīcinātājs
Tagad, ja mēs pārbaudām izvadi, mēs redzam, ka konstruktori tiek izsaukti secībā B, A un C, kamēr iznīcinātāji ir apgrieztā secībā. Tagad, kad mēs zinām vairāku mantojumu pamatus, mēs pārrunājam Dimanta problēmu.
Dimanta problēma, izskaidrota
Dimanta problēma rodas, kad bērnu klase manto no divām vecāku klasēm, kurām abām ir kopīga vecvecāku klase. Tas ir parādīts zemāk redzamajā diagrammā:
Šeit mums ir klase Bērns manto no klasēm Tēvs un Māte. Šīs divas klases savukārt pārmanto klasi Persona jo gan tēvs, gan māte ir personība.
Kā parādīts attēlā, klases bērns divas reizes pārmanto klases Personas iezīmes - vienu reizi no tēva un vēlreiz no mātes. Tas rada neskaidrības, jo kompilators nesaprot, kuru ceļu iet.
Šis scenārijs rada dimanta formas mantojuma grafiku, un to sauc par “Dimanta problēmu”.
Dimanta problēmas koda ilustrācija
Zemāk mēs esam programmatiski attēlojuši iepriekš minēto dimanta formas mantojuma piemēru. Kods ir norādīts zemāk:
#iekļaut
izmantojot nosaukumvietas std;
klases Persona {// klases Persona
publiski:
Persona (int x) {cout << "Person:: Person (int) sauc" << endl; }
};
klases tēvs: publiska persona {// klases tēvs manto personu
publiski:
Tēvs (int x): persona (x) {
cout << "Tēvs:: Tēvs (int) sauc" << endl;
}
};
klase Māte: publiska persona {// klases māte manto Personu
publiski:
Māte (int x): persona (x) {
cout << "Māte:: Māte (int) sauc" << endl;
}
};
klase Bērns: publisks tēvs, publiska māte {// Bērns manto tēvu un māti
publiski:
Bērns (int x): māte (x), tēvs (x) {
cout << "Bērns:: Bērns (int) ar nosaukumu" << endl;
}
};
int main () {
Bērns bērns (30);
}
Šīs programmas iznākums ir šāds:
Persona:: Persona (int) izsaukta
Tēvs:: zvanīja tēvs (int)
Persona:: Persona (int) izsaukta
Māte:: Māte (int) zvanīja
Bērns:: Bērns (int) izsaukts
Tagad jūs varat redzēt neskaidrības šeit. Personas klases konstruktors tiek izsaukts divreiz: vienu reizi, kad tiek izveidots tēva klases objekts, un nākamo reizi, kad tiek izveidots objekts Māte. Personas klases īpašības tiek mantotas divas reizes, radot neskaidrības.
Tā kā Personas klases konstruktors tiek izsaukts divreiz, iznīcinātājs tiks izsaukts arī divreiz, kad tiks iznīcināts Child klases objekts.
Tagad, ja esat pareizi sapratis problēmu, apspriedīsim Dimanta problēmas risinājumu.
Kā novērst dimanta problēmu C ++
Dimanta problēmas risinājums ir izmantot virtuāls atslēgvārds. Mēs abas vecāku klases (kuras manto no vienas vecvecāku klases) pārvēršam virtuālās klasēs, lai izvairītos no diviem vecvecāku klases eksemplāriem bērnu klasē.
Maināsim iepriekš redzamo ilustrāciju un pārbaudīsim rezultātu:
Koda ilustrācija dimanta problēmas novēršanai
#iekļaut
izmantojot nosaukumvietas std;
klases Persona {// klases Persona
publiski:
Persona () {cout << "Person:: Person () sauc" << endl; } // Bāzes konstruktors
Persona (int x) {cout << "Person:: Person (int) sauc" << endl; }
};
klases tēvs: virtuāla publiska persona {// klases tēvs manto personu
publiski:
Tēvs (int x): persona (x) {
cout << "Tēvs:: Tēvs (int) sauc" << endl;
}
};
klases māte: virtuāla publiska persona {// klases māte manto personu
publiski:
Māte (int x): persona (x) {
cout << "Māte:: Māte (int) sauc" << endl;
}
};
klases bērns: publisks tēvs, publiska māte {// klases bērns manto tēvu un māti
publiski:
Bērns (int x): māte (x), tēvs (x) {
cout << "Bērns:: Bērns (int) ar nosaukumu" << endl;
}
};
int main () {
Bērns bērns (30);
}
Šeit mēs izmantojām virtuāls atslēgvārds, kad klases tēvs un māte manto klasi Persona. To parasti sauc par “virtuālo mantojumu”, kas garantē, ka tiek nodota tikai viena mantotās klases instance (šajā gadījumā Personu klase).
Citiem vārdiem sakot, klasei Bērns būs viens personības klases gadījums, kuru koplieto gan Tēva, gan Mātes klases. Izmantojot vienu Personas klases gadījumu, neskaidrības tiek atrisinātas.
Iepriekš minētā koda izvade ir parādīta zemāk:
Persona:: Persona () izsaukta
Tēvs:: zvanīja tēvs (int)
Māte:: Māte (int) zvanīja
Bērns:: Bērns (int) izsaukts
Šeit jūs varat redzēt, ka klases konstruktors Persona tiek izsaukts tikai vienu reizi.
Viena lieta, kas jāatzīmē par virtuālo mantojumu, ir tā, ka pat tad, ja parametrizēts konstruktors Tēva un mātes klases konstruktori, inicializējot, skaidri sauc personas klasi sarakstus, tiks izsaukts tikai Personas klases bāzes konstruktors.
Tas ir tāpēc, ka ir tikai viens virtuālās bāzes klases gadījums, kas ir kopīgs vairākām klasēm, kas no tā pārmanto.
Lai bāzes konstruktors netiktu darbināts vairākas reizes, virtuālās bāzes klases konstruktors netiek izsaukts no mantojuma klases. Tā vietā konstruktoru izsauc betona klases konstruktors.
Iepriekš minētajā piemērā klase Child tieši izsauc klases Personas bāzes konstruktoru.
Saistīts: Iesācēja rokasgrāmata standarta veidņu bibliotēkai C ++
Ko darīt, ja jums ir jāizpilda pamatklases parametrētais konstruktors? To var izdarīt, skaidri to nosaucot Bērnu klasē, nevis Tēva vai Mātes klasēs.
Dimanta problēma C ++, atrisināta
Dimanta problēma ir neskaidrība, kas rodas vairāku mantojumu gadījumā, kad divas vecāku klases manto no vienas vecvecāku klases un abas vecāku klases pārmanto viena bērnu klase. Neizmantojot virtuālo mantojumu, bērnu klase divas reizes manto vecvecāku klases īpašības, izraisot neskaidrības.
Tas var bieži parādīties reālās pasaules kodā, tāpēc ir svarīgi novērst šo neskaidrību ikreiz, kad tā tiek pamanīta.
Dimanta problēma tiek novērsta, izmantojot virtuālo mantojumu, kurā virtuāls atslēgvārds tiek izmantots, ja vecāku klases pārmanto no kopīgas vecvecāku klases. To darot, tiek izgatavots tikai viens vecvecāku klases eksemplārs, un vecvecāku klases objektu uzbūvi veic bērnu klase.
Vēlies iemācīties programmēt, bet nezini, ar ko sākt? Šie iesācēju programmēšanas projekti un apmācības sāks jūs.
Lasīt Tālāk
- Programmēšana
- C Programmēšana
Abonējiet mūsu biļetenu
Pievienojieties mūsu informatīvajam izdevumam, lai iegūtu tehniskus padomus, pārskatus, bezmaksas e -grāmatas un ekskluzīvus piedāvājumus!
Noklikšķiniet šeit, lai abonētu