-
V této kapitole se začneme zabývat dědičností. Zaměříme se na mechanismus
dědění a jak jej zabudovat do programu. Začneme jednoduchou třídou, kterou
budeme používat během seznamování s dědičností. Nejprve uvedeme deklaraci
této třídy a implementaci této třídy (zapíšeme ji do našeho programu před
funkci main).
class vozidlo {
int kola;
float vaha;
public:
void inicializace(int
nova_kola, float nova_vaha);
int ziskej_kola(void);
float ziskej_vahu(void);
float vaha_na_kolo(void);
};
void vozidlo::inicializace(int
nova_kola, float nova_vaha){
kola = nova_kola;
vaha = nova_vaha;
}
int vozidlo:: ziskej_kola(){
return kola;
}
float vozidlo::ziskej_vahu(){
return vaha;
}
float vozidlo::vaha_na_kolo(){
return vaha/kola;
}
Třída je jednoduchá a nepotřebuje žádné vysvětlení. Tato třída je použita
v následujícím programu (je zde uveden pouze obsah funkce main).
Zjistěte, jak tento program pracuje.
vozidlo automobil,
motocykl, nakladni, sedan;
automobil.inicializace(4,
1300.0);
motocykl.inicializace(2,
400.0);
nakladni.inicializace(10,
22000.0);
sedan.inicializace(4,
1500.0);
cout << "Automobil
má " << automobil.ziskej_kola() << " kola.\n";
cout <<"Nákladní
má zátěž "<<nakladni.vaha_na_kolo()<<" kg na kolo.\n";
cout << "Motocykl
má váhu " << motocykl.ziskej_vahu() << " kg.\n";
cout << "Sedan
váží " << sedan.ziskej_vahu() << " kg a má " <<
sedan.ziskej_kola()
<< " kola.\n";
-
V toto příkladu se poprvé seznámíme s dědičností. Třída automobil
je odvozena od třídy vozidlo (prostřednictvím zápisu ":
public vozidlo" na prvním řádku
definice třídy automobil). Třída automobil obsahuje vše,
co obsahuje třída vozidlo a všechny své vlastní přidané informace.
V programu budeme moci nadále používat obě tyto třídy. Pro označení třídy,
od které odvozujeme, budeme používat název předek a odvozenou třídu budeme
nazývat potomek. Předek je obecnější třída, může popisovat všechny možné
typy vozidel, přesněji řečeno to, co všechny typy vozidel mají společné.
Potomek je specializovaná třída, popisuje již konkrétní typ vozidla. V
našem případě předek vozidlo může být použit k deklarování objektů
reprezentujících nákladní auta, motocykly, kola a mnoho jiných typů vozidel,
zatím co třída automobil pouze pro objekty osobních automobilů.
Třída automobil je více specifikovaná než třída vozidlo.
V případě potřeby bychom od třídy automobil mohli odvodit další
specifičtější třídu, např. třídu popisují sportovní automobily.
Následuje deklarace a implementace třídy automobil. Třída
automobil
obsahuje dvě datové složky zděděné od třídy vozidlo a jednu novou.
Pokud se týče metod, od vozidlo byly zděděny čtyři metody a zde
byly přidány dvě nové metody. Metoda inicializace ze třídy vozidlo
není zde ale použitelná, neboť ve třídě automobil je skryta lokální verzí
této metody (obě metody mají stejné jméno). Tuto deklaraci a implementaci
zapíšeme za deklaraci a implementaci třídy vozidlo.
class automobil :
public vozidlo {
int osob;
public:
void inicializace(int
nova_kola, float nova_vaha, int lidi = 4);
int pasazeru(void);
};
void automobil::inicializace(int
nova_kola, float nova_vaha, int lidi){
osob = lidi;
vozidlo::inicializace(nova_kola,
nova_vaha);
}
int automobil::pasazeru(void){
return osob;
}
Povšimněte si, že v implementaci třídy již není žádná informace o tom,
že tato třída byla odvozena od nějaké jiné třídy. Na červeně označeném
řádku je použita nová konstrukce. Při inicializaci musíme provést také
inicializaci složek obsažených již ve třídě předka, tzn. zaslat zprávu
třídě předka. Metoda inicializace provádí inicializaci nové složky (osob)
a vyvolává zděděnou metodu inicializace k inicializování původních položek.
Prostudujte si tuto novou třídu.
-
Od třídy vozidlo můžeme odvodit další třídy. Vytvoříme ještě třídu
nakladni.
Třída nakladni je opět odvozena od třídy vozidlo a jsou zde
přidány dvě složky a tři metody. Vše co nějak spojuje třídy
automobil
a nakladni je to, co je obsaženo v jejich společném předkovi. Obě
tyto třídy mají sice metody pasazeru, ale to nepůsobí žádné problémy.
class nakladni :
public vozidlo {
int osob;
float naklad;
public:
void inic_nakl(int
kolik = 2, float max_naklad = 12000.0);
float vykonost(void);
int pasazeru(void);
};
void nakladni::inic_nakl(int
kolik, float max_naklad){
osob = kolik;
naklad = max_naklad;
}
float nakladni::vykonost(void){
return naklad
/ (naklad + ziskej_vahu());
}
int nakladni::pasazeru(void)
{
return osob;
}
Zjistěte, co tato třída provádí.
-
Následující program ukazuje jak lze použít všechny tři třídy v jednom programu
(je to nový obsah funkce main).
vozidlo unicykl;
unicykl.inicializace(1,
7.5);
cout << "Unicykl
má " << unicykl.ziskej_kola() << " kol.\n";
cout << "Zátěž
na kolo unicyklu je " << unicykl.vaha_na_kolo() << endl;
cout << "Váha
unicyklu je " << unicykl.ziskej_vahu() << " kg.\n";
automobil sedan;
sedan.inicializace(4,
1500.0, 5);
cout << "Sedan
má " << sedan.pasazeru() << " osob.\n";
cout << "Sedan
má zátěž " << sedan.vaha_na_kolo() << " kg na kolo.\n";
cout << "Sedan
váží " << sedan.ziskej_vahu() << " kg.\n";
nakladni tatra;
tatra.inicializace(2,
7500.0);
tatra.inic_nakl(1,
7000.0);
cout << "Váha
tatry je " << tatra.ziskej_vahu() << " kg.\n";
cout << "Výkonnost
tatry je "<<100.0 * tatra.vykonost()<<" procent.\n";
Prostudujte si tento program a zjistěte co provádí. Do programu přidejte
další objekt třídy vozidlo a proveďte s ním stejné operace jako
s unicyklem.
-
Do třídy nakladni přidejte novou metodu vracející celkovou váhu
(včetně nákladu) a do programu přidejte příkaz vypisující tuto hodnotu
na monitor.
-
Mimo tříd typu class mohou v dědické hierarchii vystupovat i třídy
typu struct. Pokuste se změnit vozidlo na deklaraci třídy
typu struct (pozor na implicitní přístupová práva k položkám) a
předchozí program s touto změnou vyzkoušejte. Svazy nesmějí v dědické hierarchii
vystupovat, tj. nesmějí být předkem ani potomkem. Vyzkoušejte.
-
Přestože metoda inicializace definovaná ve třídě automobil
skrývá metodu stejného jména ve třídě svého předka, může se stát, že někdy
potřebujeme použít tuto skrytou metodu. Lze to provést takto:
sedan.vozidlo::inicializace(4,
1500.0);
Vyzkoušejte v našem programu. Změní se po použití tohoto příkazu hodnota
složky osob?
-
Povšimněte si dále, že inicializaci objektu nakladni je nutno provést
pomocí zaslání dvou zpráv tomuto objektu. Které příkazy to jsou? Změňte
metodu inic_nakl, aby prováděla inicializaci najednou (předávejte
ji všechny čtyři parametry a u posledních dvou např. uveďte implicitní
hodnoty). Potřebnou změnu proveďte i v hlavním programu. Program vyzkoušejte.
-
Předchozí program změňte takto: v prvním řádku definice obou odvozených
tříd vynechejte klíčové slovo public. Použití tohoto klíčového slova
zajišťuje, že všechny složky definované ve třídě předka jsou použitelné
(dostupné) v odvozené třídě a to stejně jako by zde byly definovány. V
předchozím programu jsme tedy mohli volat metody definované v třídě vozidlo
z hlavního programu i když jsme pracovali s některým objektem některé odvozené
třídy. Např. mohli jsme zaslat zprávu objektu sedan, aby zjistil svou váhu.
Vynechejte tato klíčová slova a zjistěte jaké chyby bude překladač signalizovat.
Chybné řádky označte jako komentář a program vyzkoušejte.
Když nyní deklarujeme objekt typu automobil, obsahuje tři datové
složky. Jedna je nově definovaná a ostatní dvě jsou zděděny od svého předka.
Pro přímé použití ve svých metodách je dostupná pouze nově definovaná a
ostatní dvě (zděděné) jsou skryty. Neexistuje tedy v tomto programu žádný
způsob jak použít položky kola a vaha.
Základní pravidla pro datové složky:
-
Nepoužívejte veřejné datové složky.
-
Používejte metody pro nastavení a čtení hodnot soukromých datových složek,
když k nim potřebujete přistupovat.
-
V nastavovacích metodách datových složek ověřujte správnost dat.
-
V konstruktorech inicializujte všechny datové složky.
-
Nezapomeňte dealokovat všechny datové složky, které byly alokovány dynamicky.