Vícenásobná dědičnost v C ++ je účinný, ale ošemetný nástroj, který často vede k problémům, pokud není používán opatrně - k problémům, jako je diamantový problém.
V tomto článku budeme diskutovat o diamantovém problému, o tom, jak vzniká z vícenásobné dědičnosti, a o tom, co můžete pro vyřešení problému udělat.
Vícenásobná dědičnost v C ++
Vícenásobná dědičnost je a funkce objektově orientovaného programování (OOP) kde podtřída může dědit z více než jedné nadtřídy. Jinými slovy, podřízená třída může mít více než jednoho rodiče.
Níže uvedený obrázek ukazuje obrazovou reprezentaci více dědičností.
Ve výše uvedeném diagramu třída C. má třída A a třída B jako jeho rodiče.
Pokud vezmeme v úvahu scénář ze skutečného života, dítě dědí po svém otci a matce. Dítě tedy může být reprezentováno jako odvozená třída s „otcem“ a „matkou“ jako rodiči. Podobně můžeme mít mnoho takových skutečných příkladů vícenásobné dědičnosti.
Při vícenásobné dědičnosti jsou konstruktory zděděné třídy provedeny v pořadí, v jakém jsou zděděny. Na druhé straně jsou destruktory prováděny v opačném pořadí než jejich dědičnost.
Pojďme si nyní ukázat vícenásobnou dědičnost a ověřit pořadí stavby a ničení předmětů.
Kódová ilustrace vícenásobné dědičnosti
Pro ilustraci vícenásobné dědičnosti jsme přesně naprogramovali výše uvedenou reprezentaci v C ++. Kód programu je uveden níže.
#zahrnout
pomocí oboru názvů std;
třída A // základní třída A s konstruktorem a destruktorem
{
veřejnost:
A () {cout << "třída A:: Constructor" << endl; }
~ A () {cout << "třída A:: Destructor" << endl; }
};
třída B // základní třída B s konstruktorem a destruktorem
{
veřejnost:
B () {cout << "třída B:: Constructor" << endl; }
~ B () {cout << "třída B:: Destructor" << endl; }
};
třída C: veřejná B, veřejná A // odvozená třída C dědí třídu A a poté třídu B (všimněte si pořadí)
{
veřejnost:
C () {cout << "třída C:: Constructor" << endl; }
~ C () {cout << "třída C:: Destructor" << endl; }
};
int main () {
C c;
návrat 0;
}
Výstup, který získáme z výše uvedeného programu, je následující:
třída B:: Konstruktor
třída A:: Konstruktor
třída C:: Constructor
třída C:: Ničitel
třída A:: Ničitel
třída B:: Ničitel
Pokud zkontrolujeme výstup, uvidíme, že konstruktory jsou volány v pořadí B, A a C, zatímco destruktory jsou v opačném pořadí. Nyní, když známe základy vícenásobné dědičnosti, přejdeme k diskusi o diamantovém problému.
Diamantový problém, vysvětleno
Problém s diamantem nastává, když podřízená třída dědí ze dvou rodičovských tříd, které oba sdílejí společnou třídu prarodičů. To je znázorněno na obrázku níže:
Tady máme třídu Dítě dědění ze tříd Otec a Matka. Tyto dvě třídy zase třídu dědí Osoba protože otec i matka jsou osoba.
Jak je znázorněno na obrázku, třídní dítě dědí vlastnosti třídního člověka dvakrát - jednou po otci a znovu po matce. To vede k nejednoznačnosti, protože kompilátor nerozumí, kudy jít.
Tento scénář dává vzniknout grafu dědičnosti ve tvaru kosočtverce a skvěle se mu říká „diamantový problém“.
Kódová ukázka diamantového problému
Níže jsme programově reprezentovali výše uvedený příklad dědičnosti ve tvaru kosočtverce. Kód je uveden níže:
#zahrnout
pomocí oboru názvů std;
třída Osoba {// třída Osoba
veřejnost:
Osoba (int x) {cout << "Osoba:: Osoba (int) s názvem" << endl; }
};
class Father: public Person {// class Father inherits Person
veřejnost:
Otec (int x): Osoba (x) {
cout << "Otec:: Otec (int) volal" << endl;
}
};
třída Matka: veřejná osoba {// třída Matka dědí osobu
veřejnost:
Matka (int x): Osoba (x) {
cout << "Matka:: Matka (int) zvaná" << endl;
}
};
třída Dítě: veřejný otec, veřejná matka {// Dítě dědí otce a matku
veřejnost:
Dítě (int x): Matka (x), otec (x) {
cout << "Dítě:: Dítě (int) s názvem" << endl;
}
};
int main () {
Dítě dítě (30);
}
Následuje výstup tohoto programu:
Osoba:: Volaná osoba (int)
Otec:: Otec (int) zavolal
Osoba:: Volaná osoba (int)
Matka:: Volala matka (int)
Dítě:: Voláno dítě (int)
Nyní můžete vidět nejednoznačnost zde. Konstruktor třídy Person se nazývá dvakrát: jednou při vytvoření objektu třídy Father a dále při vytvoření objektu třídy Mother. Vlastnosti třídy Person se dědí dvakrát, což vede k nejednoznačnosti.
Protože se konstruktor třídy Person volá dvakrát, bude destruktor také vyvolán dvakrát, když je zničen objekt třídy Child.
Nyní, pokud jste správně pochopili problém, pojďme diskutovat o řešení diamantového problému.
Jak opravit diamantový problém v C ++
Řešením problému s diamanty je použití virtuální klíčové slovo. Uděláme ze dvou rodičovských tříd (kteří dědí ze stejné třídy prarodičů) do virtuálních tříd, abychom se vyhnuli dvěma kopiím třídy prarodičů v podřízené třídě.
Změníme výše uvedený obrázek a zkontrolujeme výstup:
Ilustrace kódu k opravě diamantového problému
#zahrnout
pomocí oboru názvů std;
třída Osoba {// třída Osoba
veřejnost:
Osoba () {cout << "Osoba:: Osoba () s názvem" << endl; } // Základní konstruktor
Osoba (int x) {cout << "Osoba:: Osoba (int) s názvem" << endl; }
};
class Father: virtuální veřejná osoba {// class Father inherits Person
veřejnost:
Otec (int x): Osoba (x) {
cout << "Otec:: Otec (int) volal" << endl;
}
};
třída matka: virtuální veřejná osoba {// třída matka dědí osobu
veřejnost:
Matka (int x): Osoba (x) {
cout << "Matka:: Matka (int) zvaná" << endl;
}
};
třída Dítě: veřejný otec, veřejná matka {// třída dítě dědí otce a matku
veřejnost:
Dítě (int x): Matka (x), otec (x) {
cout << "Dítě:: Dítě (int) s názvem" << endl;
}
};
int main () {
Dítě dítě (30);
}
Zde jsme použili virtuální klíčové slovo, když třídy Otec a Matka dědí třídu Osoba. Toto se obvykle nazývá „virtuální dědičnost“, což zaručuje, že je předána pouze jedna instance zděděné třídy (v tomto případě třídy Person).
Jinými slovy, třída Child bude mít jedinou instanci třídy Person, kterou budou sdílet třídy Otec a Matka. Tím, že máte jedinou instanci třídy Person, je nejednoznačnost vyřešena.
Výstup výše uvedeného kódu je uveden níže:
Volaná osoba: Osoba ()
Otec:: Otec (int) zavolal
Matka:: Volala matka (int)
Dítě:: Voláno dítě (int)
Zde vidíte, že konstruktor třídy Person je volán pouze jednou.
Jedna věc, kterou je třeba poznamenat o virtuální dědičnosti, je, že i když je parametrizovaný konstruktor souboru Třídu osob explicitně nazývají konstruktéři třídy Otec a Matka prostřednictvím inicializace seznamy, bude vyvolán pouze základní konstruktor třídy Person.
Důvodem je, že existuje pouze jedna instance virtuální základní třídy, kterou sdílí více tříd, které z ní dědí.
Aby se zabránilo tomu, aby se základní konstruktor nespustil několikrát, není konstruktor pro virtuální základní třídu volán třídou, která z něj dědí. Místo toho je konstruktor volán konstruktorem betonové třídy.
Ve výše uvedeném příkladu třída Child přímo volá základní konstruktor pro třídu Person.
Příbuzný: Průvodce pro začátečníky standardní knihovnou šablon v C ++
Co když potřebujete spustit parametrizovaný konstruktor základní třídy? Můžete to udělat tak, že to výslovně zavoláte do třídy Child, nikoli do tříd Otec nebo Matka.
Diamantový problém v C ++, vyřešen
Problém s diamantem je nejednoznačnost, která vzniká při vícenásobné dědičnosti, když dvě rodičovské třídy dědí ze stejné třídy prarodičů a obě nadřazené třídy dědí jedna podřízená třída. Bez použití virtuální dědičnosti by podřízená třída dědila vlastnosti prarodičovské třídy dvakrát, což by vedlo k nejednoznačnosti.
To se může v kódu reálného světa často objevovat, takže je důležité tuto nejednoznačnost řešit vždy, když je spatřen.
Problém s diamantem je vyřešen pomocí virtuální dědičnosti, ve které virtuální Klíčové slovo se používá, když nadřazené třídy dědí ze sdílené třídy prarodičů. Tím se vytvoří pouze jedna kopie třídy prarodičů a objektovou konstrukci třídy prarodičů provede podřízená třída.
Chcete se naučit programovat, ale nevíte, kde začít? Tyto začátečník programovací projekty a návody vás odstartují.
Číst dále
- Programování
- C Programování
Přihlaste se k odběru našeho zpravodaje
Připojte se k našemu zpravodaji a získejte technické tipy, recenze, bezplatné elektronické knihy a exkluzivní nabídky!
Kliknutím sem se přihlásíte k odběru