3. Základy OOP III
  1. 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).

  2. 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";
  3. 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.

  4. 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.
  5. 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.

  6. 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í.
  7. Následující program ukazuje jak lze použít všechny tři třídy v jednom programu (je to nový obsah funkce main).

  8. 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.
  9. 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.
  10. 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.
  11. 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:

  12. 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?
  13. 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.
  14. 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.

  15. 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:

3. Základy OOP III