Uživatel:Jkl~cswikiversity/Studuji cpp/dědičnost
Úvodní kecy
editovatDědičnost je klíčovou vlastností jazyka C++, který se koneckonců původně jmenoval C with classes, čili C s třídami.
Základní pojmy
editovatPro další pochopení je potřeba pochopit základní vztahy mezi objekty (viz [1])jsou to
- agregace - instance třídy B obsahuje jednu nebo více instancí třídy A
- asociace - association - je to obecnější než agregace, neboť B neobsahuje A
- dědičnost - specializace -inheritance - podtřída obsahuje upravenou nadtřídu
Implementace třídy
editovatclass NázevTřídy [: předchůdci třídy]
{ Položky třídy };
Třída může obsahovat proměnné nebo funkce, které se pak budou označovat jako metoda nebo member function. Tyto položky mohou být soukromé (private), chráněné (protected) nebo veřejné (public). Chráněné jsou něco mezi veřejnými a soukromým - chovají se totíiž jako veřejné vůči přáítelským funkcím a instancím přáítelských tříd. Lze to trochu přirovnat k systému Linuxového souborového systému s jeho právy pro majitele (=private), skupinu uživatelů (friend, protected) a celému světu (public).
Při dědění je výsledek tento:
- předek private -> potomek nemá do položky přístup
- předek protected -> při dědění public=protected, nebo lze změnit na private (čili nelze "zveřejnit)
- předek public -> potomek jí může mít jakkoliv
Sekce daných vlastností se vždy nadefinuje zhruba takto:
class Trida
{
private:
int soukrome_cislo;
public:
int verejne_cislo;
void nastavcislo(int c);
}
void trida::nastavcislo(int c){ //máme deklarováno se čtyřtečkou, píšeme tělo funkce ..
this->soukrome_cislo=c; //ono by to šlo i bez toho, ale takhle je to čistší a elegantnější
}
void funkce()
{
Trida t; //nebo podobně Trida *t = new Trida;
t.verejne_cislo=5;
t.soukrome_cislo=6; // sorry vole, error !
t.nastavcislo(6); // OK
std::cout<<t.verejne_cislo<<std::endl;
}
Navíc máme vždy k dispozici "implicitní parametr" this, který ukazuje na instanci třídi, jejíž položkou je daná metoda (funkce).
Za názvem funkce může být klíčové slovo const, které značí, že daná funkce nemění hodnotu proměnných instance.
Konstruktory, destruktory, kopírovací konstruktory
editovatTohle je mi celkem jasné, pokud vám ne, tak si přečtěte [2] a [3]. Jenom krátká opznámka - má se používat new a delete, protože volají konstruktoy na zozdíl od malloců.
- delete[] pole maže pole
Pokud chci z konstruktory volat "podkonstruktory" nebo konstruktory předků, dá se to udělat touto syntaxí:
LetajiciSlon():Slon():NastavLetani(1)
{
std::cout << "A máme tu létajícího slona !" << std::endl;
}
Virtuální metody
editovatVzhledem k postulátu OOP - kde je předek lze dosadit i potomka - je vhodné používt virtuální metody, které zajistí to, že pokud zavolám instanci potomka se zděděnou funkcí, tak to bude fungovat (i po přetypování ukazatele). Čili bavíme se o zprovoznění něčeho takového:
Rodic *x = new Potomek; /* Na místo předka dám potomka - to je OK */
x->funkce(); // a jsme v hnoji :-(
Abychom v hnoji neskončili, musíme místo takzvané časné vazby použít vazbu pozdní, t.j. říci překladači, ať si rovnou neodvozuje, kde se v paměti fláká funkce(). To se dělá klíčovým slovem virtual:
virtual void funkce()
virtual float dejObvod() = 0; //nebude mít tělo, snad v některém z potomků :-) Tímto se třída stává abstraktní
class potomek : public Predek1, public Predek2, public Predek3 {}; //A tohle je - jen tak prémiově - vícenásobná dědičnost
- Virtual se pak už v těle funkce dále neopakuje.
- Destruktor by měl být virtuální, konstruktor nesmí.
- Abstraktní třída nesmí mít instanci !
Vícenásobná dědičnost
editovatPokud je potomek více rodičů, tak je možné, že budou existovat dvě stejné proměnné ve více rodičích. Pak se musí samozřejmě volat NázevRodiče::proměnná.
- Pokud chceme, aby potomek neobsahoval dalsí instanci rodiče, tak použijeme class B : virtual public A
TODO
editovatNa místě, kde je očekáván předek, může být dosazen potomek.
Budu potřeba v praxi otestovat a ev. tady ukázat [4]