Viacnásobná dedičnosť v C ++ je účinný, ale náročný nástroj, ktorý často vedie k problémom, ak sa nepoužíva opatrne - k problémom, ako je diamantový problém.
V tomto článku budeme diskutovať o diamantovom probléme, o tom, ako vzniká z viacnásobnej dedičnosti, a o tom, čo môžete urobiť na vyriešenie problému.
Viacnásobná dedičnosť v C ++
Viacnásobné dedičstvo je a funkcia objektovo orientovaného programovania (OOP) kde podtrieda môže dediť z viac ako jednej nadtriedy. Inými slovami, detská trieda môže mať viac ako jedného rodiča.
Nasledujúci obrázok zobrazuje obrazové znázornenie viacerých dedičstiev.
Vo vyššie uvedenom diagrame trieda C. má trieda A a trieda B ako jeho rodičia.
Ak vezmeme do úvahy skutočný scenár, dieťa dedí po otcovi a matke. Dieťa teda môže byť reprezentované ako odvodená trieda s „otcom“ a „matkou“ ako rodičmi. Podobne môžeme mať mnoho takýchto skutočných príkladov viacnásobnej dedičnosti.
Pri viacnásobnej dedičnosti sa konštruktory zdedenej triedy vykonávajú v poradí, v akom sú zdedené. Na druhej strane sú deštruktory vykonávané v opačnom poradí ako ich dedičnosť.
Teraz si ukážeme viacnásobnú dedičnosť a overíme poradie stavby a ničenia predmetov.
Kódová ilustrácia viacnásobného dedičstva
Na ilustráciu viacnásobnej dedičnosti sme presne naprogramovali vyššie uvedenú reprezentáciu v C ++. Kód programu je uvedený nižšie.
#include
pomocou priestoru názvov std;
trieda A // základná trieda A s konštruktorom a deštruktorom
{
verejné:
A () {cout << "trieda A:: Constructor" << endl; }
~ A () {cout << "trieda A:: Destructor" << endl; }
};
trieda B // základná trieda B s konštruktorom a deštruktorom
{
verejné:
B () {cout << "trieda B:: Constructor" << endl; }
~ B () {cout << "trieda B:: Destructor" << endl; }
};
trieda C: verejná B, verejná A // odvodená trieda C zdedí triedu A a potom triedu B (všimnite si poradie)
{
verejné:
C () {cout << "trieda C:: Constructor" << endl; }
~ C () {cout << "trieda C:: Destructor" << endl; }
};
int main () {
C c;
návrat 0;
}
Výstup, ktorý získame z vyššie uvedeného programu, je nasledujúci:
trieda B:: Konštruktér
trieda A:: Konštruktér
trieda C:: Konštruktér
trieda C:: Ničiteľ
trieda A:: Ničiteľ
trieda B:: Ničiteľ
Ak teraz skontrolujeme výstup, uvidíme, že konštruktéry sa volajú v poradí B, A a C, zatiaľ čo deštruktory sú v opačnom poradí. Teraz, keď poznáme základy viacnásobnej dedičnosti, prejdeme k diskusii o diamantovom probléme.
Vysvetlený diamantový problém
Diamantový problém nastáva, keď detská trieda dedí po dvoch rodičovských triedach, ktoré zdieľajú spoločnú triedu starých rodičov. Ilustruje to nasledujúci diagram:
Tu máme triedu Dieťa dedenie z tried Otec a Matka. Tieto dve triedy naopak triedu dedia Osoba pretože otec aj matka sú osobou.
Ako je znázornené na obrázku, triedna dieťa zdedí vlastnosti triednej osoby dvakrát - raz od otca a znova od matky. To spôsobuje nejednoznačnosť, pretože kompilátor nerozumie, ktorou cestou má ísť.
Tento scenár vedie k vzniku grafu dedičnosti v tvare diamantu a je skvele nazývaný „Problém s diamantom“.
Kódová ilustrácia diamantového problému
Nižšie sme programovo reprezentovali vyššie uvedený príklad dedičnosti v tvare diamantu. Kód je uvedený nižšie:
#include
pomocou priestoru názvov std;
triedna osoba {// triedna osoba
verejné:
Osoba (int x) {cout << "Osoba:: Osoba (int) nazývaná" << endl; }
};
triedny otec: verejná osoba {// triedny otec dedí osobu
verejné:
Otec (int x): Osoba (x) {
cout << "Otec:: Otec (int) volal" << endl;
}
};
triedna matka: verejná osoba {// triedna matka dedí osobu
verejné:
Matka (int x): Osoba (x) {
cout << "Matka:: Matka (int) volala" << endl;
}
};
trieda Dieťa: verejný otec, verejný matka {// dieťa zdedí otca a matku
verejné:
Dieťa (int x): Matka (x), otec (x) {
cout << "Dieťa:: Dieťa (int) nazývané" << endl;
}
};
int main () {
Dieťa dieťa (30);
}
Nasleduje výstup z tohto programu:
Osoba:: Volaná osoba (int)
Otec:: Otec (int) zavolal
Osoba:: Volaná osoba (int)
Matka:: Volala matka (int)
Dieťa:: Volané dieťa (int)
Teraz tu môžete vidieť nejednoznačnosť. Konštruktor triedy Person sa volá dvakrát: raz pri vytváraní objektu triedy Father a potom pri vytváraní objektu triedy Mother. Vlastnosti triedy Person sa dedia dvakrát, čo spôsobuje nejednoznačnosť.
Pretože sa konstruktor triedy Person volá dvakrát, deštruktor sa vyvolá aj dvakrát, keď sa zničí objekt triedy Child.
Ak ste teraz správne pochopili problém, poďme diskutovať o riešení diamantového problému.
Ako opraviť problém s diamantom v C ++
Riešením problému s diamantmi je použitie virtuálne kľúčové slovo. Z dvoch rodičovských tried (ktorí dedia z rovnakej triedy starých rodičov) robíme virtuálne triedy, aby sme sa vyhli dvom kópiám triedy starých rodičov v detskej triede.
Zmeňme vyššie uvedený obrázok a skontrolujte výstup:
Ilustrácia kódu na opravu diamantového problému
#include
pomocou priestoru názvov std;
triedna osoba {// triedna osoba
verejné:
Osoba () {cout << "Osoba:: Osoba () s názvom" << endl; } // Základný konštruktor
Osoba (int x) {cout << "Osoba:: Osoba (int) nazývaná" << endl; }
};
triedny otec: virtuálna verejná osoba {// triedny otec dedí osobu
verejné:
Otec (int x): Osoba (x) {
cout << "Otec:: Otec (int) volal" << endl;
}
};
triedna matka: virtuálna verejná osoba {// triedna matka dedí osobu
verejné:
Matka (int x): Osoba (x) {
cout << "Matka:: Matka (int) volala" << endl;
}
};
trieda Dieťa: verejnosť Otec, verejnosť Matka {// trieda Dieťa zdedí otca a matku
verejné:
Dieťa (int x): Matka (x), otec (x) {
cout << "Dieťa:: Dieťa (int) nazývané" << endl;
}
};
int main () {
Dieťa dieťa (30);
}
Tu sme použili virtuálne kľúčové slovo, keď triedy Otec a Matka zdedia triedu Osoba. Toto sa zvyčajne nazýva „virtuálna dedičnosť“, čo zaručuje, že je odovzdaná iba jedna inštancia zdedenej triedy (v tomto prípade trieda Person).
Inými slovami, trieda Child bude mať jednu inštanciu triedy Person, ktorú budú zdieľať triedy Otec a Matka. Tým, že máte jednu inštanciu triedy Person, je nejednoznačnosť vyriešená.
Výstup z vyššie uvedeného kódu je uvedený nižšie:
Volaná osoba: Osoba ()
Otec:: Otec (int) zavolal
Matka:: Volala matka (int)
Dieťa:: Volané dieťa (int)
Tu môžete vidieť, že konštruktor triedy Osoba sa volá iba raz.
Jedna vec, ktorú je potrebné poznamenať o virtuálnej dedičnosti, je, že aj keď je parametrizovaný konštruktor súboru Osobnú triedu konštruktéri triedy Otec a Matka výslovne nazývajú inicializáciou zoznamy, bude vyvolaný iba základný konštruktor triedy Person.
Dôvodom je, že existuje iba jedna inštancia virtuálnej základnej triedy, ktorú zdieľajú viaceré triedy, ktoré z nej dedia.
Aby sa zabránilo spusteniu základného konštruktora viackrát, konštruktér virtuálnej základnej triedy nie je volaný triedou, ktorá z neho dedí. Namiesto toho je konštruktor zavolaný konštruktorom betónovej triedy.
Vo vyššie uvedenom príklade trieda Child priamo volá základný konštruktor triedy Person.
Súvisiace: Príručka pre začiatočníkov k štandardnej knižnici šablón v C ++
Čo keď potrebujete vykonať parametrizovaný konštruktor základnej triedy? Môžete to urobiť tak, že ho výslovne zavoláte do triedy Dieťa, a nie do tried Otec alebo Matka.
Diamantový problém v C ++, vyriešený
Diamantový problém je nejednoznačnosť, ktorá vzniká pri viacnásobnej dedičnosti, keď dve rodičovské triedy dedia z rovnakej triedy prarodičov a obe rodičovské triedy dedí jedna podradená trieda. Bez použitia virtuálnej dedičnosti by podriadená trieda zdedila vlastnosti triedy prarodičov dvakrát, čo by viedlo k nejednoznačnosti.
V kóde reálneho sveta sa to môže často objaviť, takže je dôležité túto nejednoznačnosť riešiť vždy, keď sa objaví.
Problém s diamantom je vyriešený pomocou virtuálnej dedičnosti, v ktorej virtuálne kľúčové slovo sa používa, ak rodičovské triedy dedia zo zdieľanej triedy starých rodičov. Pritom sa vytvorí iba jedna kópia triedy prarodičov a objektovú konštrukciu triedy prarodičov vykoná detská trieda.
Chcete sa naučiť programovať, ale neviete, kde začať? Tieto projekty a návody pre začiatočníkov v oblasti programovania vás začnú.
Čítajte ďalej
- Programovanie
- C Programovanie
prihlásiť sa ku odberu noviniek
Pripojte sa k nášmu bulletinu a získajte technické tipy, recenzie, bezplatné elektronické knihy a exkluzívne ponuky!
Kliknutím sem sa prihlásite na odber