Fotografický magazín "iZIN IDIF" každý týden ve Vašem e-mailu.
Co nového ve světě fotografie!
Zadejte Vaši e-mailovou adresu:
Kamarád fotí rád?
Přihlas ho k odběru fotomagazínu!
Zadejte e-mailovou adresu kamaráda:
C/C++
Vícenásobná dědičnost v C++ - volání konstruktorů a destruktorů
20. března 2001, 00.00 | Dnes si dokončíme téma vícenásobné dědičnosti. Podíváme se jaké platí pravidla pro volání konstruktorů a destruktorů při vícenásobné dědičnosti.
V tomto článku si ukážeme jak to je s voláním konstruktorů a destruktorů při vytváření a rušení instancí tříd vzniklých vícenásobnou dědičností. Stejně jako při jednoduché dědičnosti se i u vícenásobné dědičnosti nedědí konstruktory a destruktory, ale lze je vyvolat implicitně (stejně jako při jednoduché dědičnosti).
KonstruktoryPři vytváření instance třídy odvozené jednoduchou dědičností jsem napsal, že kromě konstruktoru této třídy je implicitně vyvolán bezparametrický konstruktor "nejvyšší" nadtřídy, potom konstruktor její podtřídy a tak dále až je vyvolán konstruktor dané třídy. U vícenásobné dědičnosti je situace obdobná. Není-li použito virtuální dědění (Viz předchozí článek Vícenásobná dědičnost v C++ - opakovaná dědičnost) je situace jednoduchá. Nejprve je volán konstruktor nejvyšší nadtřídy prvního předka (uvedeného v seznamu předků nejvíce vlevo), poté jeho potomka a tak dále, až je zavolán konstruktor předka naší třídy. Poté jsou stejným způsobem volány konstruktory ostatních předků naší třídy. Po vyvolání konstruktorů všech předků je vyvolán konstruktor naší třídy. Vše objasní příklad:
|
Program vypíše:
A
B
A
C
D
Instance d je vytvořena
Stejně jako u jednoduché dědičnosti lze i při vícenásobné dědičnosti volání bezparametrických konstruktorů potlačit a volat konstruktory s parametry.
Trochu problematičtější je použití virtuální dědičnosti. S virtuální dědičností jsou bohužel jen problémy. Rozdíly jsou vlastně dva:
Pokud v mém předchozím příkladu upravíte třídy B a C tak, aby dědily virtuálně, program po spuštění vypíše:
A
B
C
D
Instance d je vytvořena
Tedy přesně podle pravidel, která jsem uvedl. Nyní můžeme trochu experimentovat a třídu deklarovat třeba takto: class D : public B, public E, public C { /* To co tu bylo */ } . Před tím ale třídu E deklarovat jako nevirtuálního potomka třídy A. Vznikne zajímavá situace. Třída D má nadtřídy B a C, které mají virtuální nadtřídu A. Tedy D bude mít po B a C zděděné atributy a metody jen jedenkrát. Ale dále ještě přímo dědí z E, kde A není virtuální předek, takže zde budou atributy a metody třídy A podruhé. Stejně tak volání konstruktoru třídy A bude dvakrát. Jednou se A::A() zavolá jako virtuální předek tříd B a C (Platí pravidlo, že konstruktor virtuálního předka je volán jen jednou.) a poté se zavolá znovu A::A() jako nevirtuální přímý předek třídy E. Doporučuji Vám takto opravit zdrojový text a program spustit. Jak vidíte, použití jedné třídy jako virtuálního i nevirtuálního předka nám sem vneslo trochu zmatku.
Destruktory se chovají podle stejných pravidel jako konstruktory. S tím rozdílem, že jejich volání probíhá v opačném pořadí než volání konstruktorů. Tedy jejich volání neprobíhá směrem od "nadpředka" k potomkům ale od potomků k "nadpředkovi". Situace je obdobná jako při jednoduché dědičnosti.
Závěrem o vícenásobné dědičnostiPoužívání vícenásobné dědičnosti (Hlavně použití virtuální dědičnosti při opakovaném dědění.) v C++ je složité a velmi nepřehledné. Představte si ne můj příklad, ale velký program, který má třeba desítky, nebo stovky tříd různě propojených jednoduchou a vícenásobnou dědičností. Bude asi radost orientovat se ve virtuálních a nevirtuálních nadtřídách a při volání konstruktorů a destruktorů virtuálních a nevirtuálních nadtříd. Některé programovací jazyky (Například Java) řeší tento problém velmi svérázným způsobem - vícenásobnou dědičnost vůbec nepodporují. O používání vícenásobné dědičnosti se vedou veliké spory. Vícenásobná dědičnost má své nadšence, kteří ji používají kde mohou, i velké odpůrce. Proti vícenásobné dědičnosti je silný argument. Není totiž znám způsob, kdy vícenásobnou dědičnost nelze korektně obejít. Další argumenty proti říkají, že vícenásobná dědičnost v C++ (hlavně virtuální dědění) je příliš složitá a nepřehledná. Ale podle mne je správné, že vícenásobná dědičnost v C++ je. Je-li tak špatná, jak tvrdí její odpůrci, nemusí ji programátor použít. Nedojde-li ke konfliktu jmen a opakovanému dědění, není vícenásobná dědičnost vlastně příliš složitá. S konfliktem jmen se při troše trpělivosti také dá pracovat. Jediné co Vám nedoporučuji, je pouštět se do opakovaného dědění a virtuální dědičnosti - to chce opravdu nervy :(
Tolik k vícenásobné dědičnosti. V příštím článku se podívám na přetěžování operátorů a poté v dalším článku na vstupní a výstupní operace v C++.
Obsah seriálu (více o seriálu):
- Základy OOP v C++: Od C k C++
- Základní pojmy objektově orientovaného programování
- Vytváření tříd, instance třídy, zasílání zpráv v C++
- Vytváření instancí - konstruktory, destruktory
- Kopírovací konstruktor v C++
- Jednoduchá dědičnost v C++
- Časná versus pozdní vazba - úvod do polymorfismu v C++
- Polymorfismus - dokončení
- Vícenásobná dědičnost v C++
- Vícenásobná dědičnost v C++ - opakovaná dědičnost
- Vícenásobná dědičnost v C++ - volání konstruktorů a destruktorů
- Přetěžování operátorů v C++ 1.díl
- Přetěžování operátorů v C++ 2. díl
- Vstupní a výstupní operace pomocí datových proudů v C++
- Přetěžování operátorů << a >> pro datové proudy v C++
- Neformátovaný vstup a výstup v C++
- Paměťové proudy v C++
- Prostory jmen v C++
- Řetězce v C++
- Výjimky v C++
- Výjimky v C++ - výjimky tvoří dědičnou hierarchii
- Výjimky v C++ - dokončení
- Dynamická identifikace typů v C++
- Přetypování v C++
- Problémy s typy při vícenásobné dědičnosti
- Šablony funkcí v C++
- Šablony datových typů v C++
- Vnitřní typy u parametrů šablon, vnořené šablony v C++
- Pole s libovolným intervalem indexování v C++
- Datové kontejnery v C++ - Úvod do STL
- Vector - datový kontejner v C++
- Iterátory v C++
- Šablona vector v C++ a iterátory
- Asociativní pole v C++
- Množina v C++
- Funkční objekty v C++
- Standardní funkční objekty v C++
- Úvod do standardních algoritmů v C++
- Kopírovací a přesouvací algoritmy v C++
- Vyhledávací algoritmy v C++
- Skenovací (prohlížecí) algoritmy v C++
- Transformační algoritmy v C++
- Řadící algoritmy v C++
- Halda v C++
- Standardní algoritmy v C++ - dokončení
- Automatické ukazatele v C++
- Inteligentní ukazatel - čítač referencí v C++
- Použití čítače referencí v C++
- Kopírování velkých objektů v C++
- Řízené kopírování prvků v poli v C++
- Dokončení seriálu objektově orientované programování v C++
-
25. listopadu 2012
-
30. srpna 2002
-
10. října 2002
-
4. listopadu 2002
-
12. září 2002
-
25. listopadu 2012
-
28. července 1998
-
31. července 1998
-
28. srpna 1998
-
6. prosince 2000
-
27. prosince 2007
-
4. května 2007