Dědění, volání konstruktorů a destruktorů, virtuální a nevirtuální metody
Napište následující program. Odevzdejte pouze program, na otázky
si odpovězte pouze pro sebe.
Program bude obsahovat soubory
main.cpp, hlavičkové soubory Cbase.h, Cderiv1.h, Cderiv2.h.
Trida.cpp, trida.h
Na začátku každého souboru napište identifikaci
pro Doxygen (file, autor, ...)
1) Vytvořte bázovou třídu CBase, která bude mít metodu Print,
která vytiskne text „Print Cbase“.
Vytvořte ve třídě
CBase konstruktor implicitní a destruktor.
Konstruktor bude
tisknout text „Konstr_CBase“, destruktor vytiskne
„Destr_CBase“.
2) Vytvořte odvozenou třídu CDeriv1 od CBase pomocí public dědění,
která bude mít tytéž metody jako CBase.
Místo „CBase“
se bude v textech tisknout „CDeriv1“.
3) Vytvořte
odvozenou třídu CDeriv2 od CBase pomocí public dědění, která bude mít
tytéž metody jako CBase.
Místo „CBase“ se bude v
textech tisknout „CDeriv2“.
Tato třída bude obashovat
jeden prvek třídy Cderiv1 (v private sekci).
4) Vytvořte v main jeden objekt od každé třídy.
Pro každý
objekt zavolejte jeho metodu Print.
Program spusťte a podívejte se
co se tiskne - kudy prochází program.
Implementujte počítání
vzniklých a aktuálních objektů pomocí statických proměnných pro
každou třídu. Sledujte počet vytvořených proměnných na konci programu
(aktuálních by měla být nula). (V main uveďte kód do zvláštního
bloku, aby po jeho skončení bylo možné zjistit zda všechny objekty
zanikly).
5) Vytvořte v main pole pro tři ukazatele pb,pd1,pd2 na každou třídu (typ třídy) a nainicializujte je pomocí vytvořených prvků (všechny stejně => vzniknou všechny kombinace tříd ukazatelů a objektů).
CBase *pb[3] = {&b,&d1,&d2};
CDerived1 *pd1[3] =
{(CDerived1 *) &b,(CDerived1 *)&d1,(CDerived1 *)&d2
};
CDerived2 *pd2[3] = { (CDerived2 *)&b,(CDerived2
*)&d1,(CDerived2 *)&d2 };
6) Pro všechny ukazatele z minulého bodu zavolejte metodu Print.
Co očekáváte a co se stane.
Zavolejte metodu Print i pro základní
objekty.
7) Do všech tříd přidejte metodu PrintV tak, aby byla realizována
pozdní vazbou (polymorfizmus/virtual).
Realizujte stejný tisk jako
v minulém bodě, nyní pro metodu PrintV. Co očekáváte a co se stane.
Porovnejte tisk průběhu minulého tisku (časná vazba) a současného (
po přidání pozdní vazby, mechanizmus virtuálních metod).
Zavolejte
metodu PrintV i pro základní objekty.
Na jakých proměnných se
bude výsledek lišit – u objekt nebo při přístupu přes ukazatel?
Proč?
8) Vysvětlete, která/které kombinace ukazatelů pb,pd1,pd2 a jejich inicializací (bod 5 zadání) dávají smysl, a které jsou špatně a proč.
9) Je možné zjistit typ proměnné "programově" (všimněte
si, že plně "funguje" až po zavedení vlastnosti virtual,
kdy použije pozdní vazbu. Jinak je tato funkce "vyřešena"
při překladu).
Pomocí příkazu typeid je možné získat strukturu
type_info.
Pomocí metody name() můžeme například zjistit jméno
typu objektu. typeid( XXX ).name(); Doplňte tento tisk do metod Print
a PrintV – zhodnoťte, zda se název třídy získaný pomocí typeid
liší od tisků původních (body zadání 1-3).
10) vytvořte dynamickou proměnnou typu CDerived2 a ihned ji zrušte
pomocí delete.
Porovnejte počet vzniklých a zaniklých objektů.
Přidejte k destruktoru virtualitu a srovnejte s předchozím.
11) Doplňte třídu, na které jste během semestru pracovali o metody Print a PrintV tak, aby mohly být zařazeny jako další prvek do polí pb,pd1,pd2 a zařaďte je na poslední místo (takže budou mít pole čtyři prvky, poslední bude patřit k vaší třídě). Soubory pro vaši třídu budou mít jména Trida.cpp, trida.h.