1. Základy OOP I
  1. Následující příklad ukazuje použití zřetězeného seznamu vytvořeného objektově orientovaným způsobem.

  2. class okno {
      int delka;
      int sirka;
      okno *dalsi_okno;
    public:
      okno(void);
      void nastav(int nova_delka, int nova_sirka);
      int ziskej_plochu(void);
      void nastav_ukazatel(okno *ktere_okno);
      okno *ziskej_dalsi(void);
    };
    okno::okno(void){
      delka = 8;
      sirka = 8;
      dalsi_okno = NULL;
    }
    void okno::nastav(int nova_delka, int nova_sirka){
      delka = nova_delka;
      sirka = nova_sirka;
    }
    int okno::ziskej_plochu(void){
      return (delka * sirka);
    }
    void okno::nastav_ukazatel(okno *ktere_okno){
      dalsi_okno = ktere_okno;
    }
    okno *okno::ziskej_dalsi(void){
      return dalsi_okno;
    }
    int main(int argc, char **argv)
    {
      okno *start = NULL;                                        // Vždy ukazuje na počátek seznamu
      okno *temp;                                                    // Pracovní ukazatel
      okno *ukazatel_na_okno;                               // Použito pro vytváření okna
      for (int index = 0; index < 10; index++){         // Generování seznamu
        ukazatel_na_okno = new okno;
        ukazatel_na_okno->nastav(index + 1, index + 3);
        if (start == NULL)
          start = ukazatel_na_okno;                         // První prvek v seznamu
        else
          temp->nastav_ukazatel(ukazatel_na_okno);         // další prvek
        temp = ukazatel_na_okno;
      }
      temp = start;                                                   // Výpis seznamu
      do {
        cout << "Plocha okna je " << temp->ziskej_plochu() << endl;
        temp = temp->ziskej_dalsi();
      } while (temp != NULL);
      temp = start;                                                   // Zrušení seznamu
      do {
        temp = temp->ziskej_dalsi();
        delete start;
        start = temp;
      } while (temp != NULL);
      return 0;
    }
    Tento program vytváří zřetězený seznam 10 objektů, vypíše plochy těchto objektů a seznam zruší. Zjistěte jak tento program pracuje.
  3. Změňte předchozí program tak, aby zřetězený seznam obsahoval 1000000 prvků. Přidejte také test k zjištění, zda každá dynamická alokace byla provedena. Zajistěte, aby výstup obsahoval správné hodnoty.
  4. Další program používá třídu vnořenou do třídy. Jedná se o velmi jednoduchý příklad. Program obsahuje třídu okno, která byla značně zjednodušena a jako jedna složka je do ní vložena třída, kterou jsme nazvali podtrida. Tento objekt je pro použití přístupný pouze v implementaci třídy okno, protože je zde také definován a žádná jeho definice se nevyskytuje v hlavím programu.

  5. class podtrida {
      int hodnota1;
      int hodnota2;
    public:
      void nastav(int h1, int h2){ hodnota1 = h1; hodnota2 = h2;}
      int ziskej_h2(void) {return hodnota2;}
    };
    class okno {
      int delka;
      int sirka;
      podtrida vn_trida;
    public:
      void nastav(int d, int s, int h1, int h2){
        delka = d;
        sirka = s;
        vn_trida.nastav(h1, h2);
      }
      int ziskej_plochu(void) {return(delka * sirka);}
    };
    int main(int argc, char **argv)
    {
      okno male, stredni, velke;
      male.nastav(2, 4, 1, 35);
      stredni. nastav(5, 6, 2, 72);
      velke.nastav(8, 10, 4, 98);
      cout << "Plocha malého okna je " << male.ziskej_plochu() << endl;
      cout << "Plocha středního okna je " << stredni.ziskej_plochu() << endl;
      cout << "Plocha velkého okna je " << velke.ziskej_plochu() << endl;
    }
    Prostudujte si tento program a přidejte do něj příkazy, které vypíší i hodnoty uložené ve vnořené třídě (bude-li potřeba, vytvořte i nové metody).
  6. Následující program ukazuje překrývání operátorů. To umožňuje definovat objekty třídy a redefinovat normální operátory. Výsledkem je, že objekty nové třídy mohou být používány přirozeně jako předdefinované typy.

  7. class okno {
      int delka;
      int sirka;
    public:
      void nastav(int nova_delka, int nova_sirka);
      int ziskej_plochu(void) {return(delka * sirka);}
      friend okno operator+(okno a, okno b); // Součet dvou oken vedle sebe
      friend okno operator+(int a, okno b);  // Přičtení konstanty k šířce okna
      friend okno operator*(int a, okno b);  // Vynásobení okna konstantou
    };
    void okno::nastav(int nova_delka, int nova_sirka){
      delka = nova_delka;
      sirka = nova_sirka;
    }
    okno operator+(okno a, okno b){
      okno pomocne;
      pomocne.delka = a.delka;
      pomocne.sirka = a.sirka + b.sirka;
      return pomocne;
    }
    okno operator+(int a, okno b){
      okno pomocne;
      pomocne.delka = b.delka;
      pomocne.sirka = a + b.sirka;
      return pomocne;
    }
    okno operator*(int a, okno b){
      okno pomocne;
      pomocne.delka = a * b.delka;
      pomocne.sirka = a * b.sirka;
      return pomocne;
    }
    int main(int argc, char **argv)
    {
      okno male, stredni, velke;
      okno pomocne;
      male.nastav(2, 4);
      stredni.nastav(5, 6);
      velke.nastav(8, 10);
      cout << "Plocha malého okna je " << male.ziskej_plochu() << endl;
      cout << "Plocha středního okna je " << stredni.ziskej_plochu() << endl;
      cout << "Plocha velkého okna je " << velke.ziskej_plochu() << endl;
      pomocne = male + stredni;
      cout << "Plocha nového okna je " << pomocne.ziskej_plochu() << endl;
      pomocne = 10 + male;
      cout << "Plocha nového okna je " << pomocne.ziskej_plochu() << endl;
      pomocne = 4 * velke;
      cout << "Plocha nového okna je " << pomocne.ziskej_plochu() << endl;
      return 0;
    }
    V našem programu jsou překryty operátory + a *. Jejich implementační metody jsou deklarovány jako spřátelené funkce (pomocí klíčového slova friend). Jestliže nepoužijeme ?přátelskou konstrukci, pak funkce musí být částí jednoho objektu a tomuto objektu budeme zasílat zprávy. Použití ?přátelské konstrukce umožňuje oddělit tyto metody od objektu a volat je pomocí infixového zápisu. Pomocí této techniky, můžou? konstrukci, objekt1 + objekt2 namísto objekt1.operator+(objekt2). Bez přátelské konstrukce bychom také nemohli překrýt operátory, které mají jako první parametr (operand) typ int, neboť nelze zaslat zprávu celočíselné proměnné. Dva ze tří překrytých operátorů používají int pro první parametr a je tedy nutno je deklarovat jako spřátelené funkce.
    Červený řádek ukazuje první překrytí, kdy je překrýván operátor +. Zapisujeme návratový typ následovaný klíčovým slovem operator s operátorem, který překrýváme. V závorkách jsou uvedeny dva formální parametry a jejich typy a na následujících řádcích pokračuje implementace funkce. První parametr určuje levý operand překrývaného operátoru a druhý pravý operand. Na modrém řádku našeho programu je tato metoda volána pomocí infixového zápisu namísto obvyklého formátu zasílání zpráv. Jelikož proměnné male a strední jsou objekty třídy okno, systém hledá operátor + pro dva objekty třídy okno a nalezne náš první překrytý operátor. Další překryté operátory používají jako levý operand hodnotu typu int. Jinak pracují obdobně. Vyzkoušejte tento program. Změňte třetí řádek od konce na
    pomocne = velke * 4;
    a zjistěte reakci na tuto změnu.
  8. Další program ukazuje překrývání funkcí ve třídě. V tomto programu je pro ilustraci překrýván konstruktor a jedna metoda.

  9. class mnoho_jmen {
      int delka;
      int sirka;
    public:
      mnoho_jmen(void);
      mnoho_jmen(int del);
      mnoho_jmen(int del, int sir);
      void zobraz(void);
      void zobraz(int jeden);
      void zobraz(int jeden, int dva);
      void zobraz(float cislo);
    };
    mnoho_jmen::mnoho_jmen(void) {
      delka = 8;
      sirka = 8;
    }
    mnoho_jmen::mnoho_jmen(int del) {
      delka = del;
      sirka = 8;
    }
    mnoho_jmen::mnoho_jmen(int del, int sir) {
      delka = del;
      sirka = sir;
    }
    void mnoho_jmen::zobraz(void) {
      cout << "Z funkce bez parametrů, plocha = " << delka * sirka << endl;
    }
    void mnoho_jmen::zobraz(int jeden) {
      cout << "Z funkce s jedním parametrem, plocha = "<<delka * sirka<<endl;
    }
    void mnoho_jmen::zobraz(int jeden, int dva) {
      cout << "Z funkce se dvěmi parametry, plocha = "<<delka * sirka<<endl;
    }
    void mnoho_jmen::zobraz(float cislo) {
      cout <<"Z funkce s reálným parametrem, plocha = "<<delka * sirka<<endl;
    }
    int main(int argc, char **argv)
    {
      mnoho_jmen male, stredni(10), velke(12, 15);
      int cele = 144;
      float pi = 3.1415;
      male.zobraz();
      male.zobraz(100);
      male.zobraz(cele, 100);
      male.zobraz(pi);
      stredni.zobraz();
      velke.zobraz(pi);
      return 0;
    }
    Tento program ukazuje překrytí metod. Zopakujme si, že funkce je vybrána na základě počtu a typů parametrů. V našem případě jsou tři konstruktory. Použitý konstruktor je určen počtem parametrů. V programu vytvoříme tři objekty, každý pomocí jiného konstruktoru. Třída obsahuje dále čtyři metody zobraz. Zjistěte jak tento program pracuje.
  10. V hlavičkovém souboru COMPLEX.H je deklarace standardní třídy complex umožňující provádět výpočty s komplexními čísly. Podívejte se do tohoto souboru, jak je třída deklarována. V nápovědě zjistěte, jaké operace, konstruktory a spřátelené funkce zde můžeme používat.
  11. Vytvořte program, který vypočítá hodnotu výrazu (A + B) / A pro z klávesnice zadané komplexní hodnoty.
  12. Vytvořte program, který bude pracovat jako jednoduchá kalkulačka v oblasti komplexních čísel (sčítání, odečítání, násobení, dělení, a případně některé funkce).
  13. Deklarace typu třídy může začínat mimo klíčového slova class i struct nebo union. Typ třídy mimo jiné ovlivňuje přístupová práva ke složkám. Složky tříd typu class jsou implicitně soukromé (můžeme to změnit specifikátory přístupu public nebo protected). Složky tříd typu struct jsou implicitně veřejné (můžeme to změnit specifikátory přístupu private nebo protected). Složky tříd typu union jsou implicitně veřejné a toto nastavení nelze změnit. Vyzkoušejte (pokuste se změnit typ některé existující třídy typu class na struct).
  14. Uvažujte následující část programu:

  15. class trida {
      int x;
      int y;
      static int pocet;
    public:
      void nastavx(int novex) {x = novex; };
      void nastavy(int);
      void nastav(int x, int y);
      void nacti(trida bod);
      trida &predej();
    };
    int trida::pocet = 0;
    inline void trida::nastavy(int novey){y = novey;}
    void trida::nastav(int x, int y){
      this->x = x;
      this->y = y;
    }
    void trida::nacti(trida b){
      x = 5 * b.x;
      y = 5 * b.y;
      this->x = 2*x;
      this->y = 2*y;
      this->x = 10 * b.x;
      this->y = 10 * b.y;
    }
    V této ukázce si povšimněte několika věcí. Na identifikátoru parametru v deklaraci nezáleží (viz metoda nacti) a tento identifikátor nemusí být uveden (metoda nastavy). Metoda predej není implementována a jestliže ji nikde nepoužijeme pak překladač nesignalizuje chybu. Metody nastavx a nastavy ukazují použití vložené funkce. V metodě nastav jsou použita stejná jména parametrů jako jména složek třídy. Je zde ukázáno jak pomocí ukazatele this můžeme v tomto případě přistupovat ke složkám třídy. Složka pocet ukazuje použití globální složky (všechny instance této třídy budou mít tuto složku společnou). Takovouto složku je možno např. použít k počítání existujících instancí této třídy (v každém konstruktoru této třídy položku inkrementujeme a v destruktoru dekrementujeme). Tuto položku je nutno také definovat (dříve než vytvoříme první instanci této třídy) a inicializovat. Tato třída neobsahuje žádný konstruktor ani destruktor a jsou tedy vytvořeny překladačem automaticky.
    Zjistěte, kdy v metodě nacti je použito které x a y. Přidejte do této třídy konstruktor, destruktor a metodu zjišťující hodnotu složky pocet a vyzkoušejte, že složku pocet je možno použít k počítání instancí této třídy.

Základní pravidla pro metody:


 
1. Základy OOP I