22. Seznßmenφ s OOP II
  1. Nßsledujφ program zavßdφ pou╛itφ konstruktor∙ a destruktor∙.

  2. class obdelnik {                  // jednoduchß t°φda
      int vyska;
      int sirka;
    public:
      obdelnik(void);                  // s konstruktorem,
      int plocha(void);                // s dv∞mi metodami
      void inicializace(int, int);
      ~obdelnik(void);                // a s destruktorem
    };
    obdelnik::obdelnik(void){     // konstruktor
      vyska = 6;
      sirka = 6;
    }
    int obdelnik::plocha(void){   // plocha obdΘlnφku
      return vyska * sirka;
    }
    void obdelnik::inicializace(int nova_vyska, int nova_sirka){
      vyska = nova_vyska;
      sirka = nova_sirka;
    }
    obdelnik::~obdelnik(void){ // destruktor
      vyska = 0;
      sirka = 0;
    }
    int main(int argc, char **argv)
    {
      obdelnik okno, ctverec;
      cout << "Plocha okna je " << okno.plocha() << endl;
      cout << "Plocha ctverce je " << ctverec.plocha() << endl;
      okno.inicializace(12,10);
      ctverec.inicializace(8,8);
      cout << "Plocha okna je " << okno.plocha() << endl;
      cout << "Plocha ctverce je " << ctverec.plocha() << endl;
      return 0;
    }
    Tento program je identick² s programem uveden²m na konci p°edchozφ kapitoly (do t°φdy je p°idßn konstruktor a destruktor a je vynechßna struktura). Konstruktor je v C++ volßn automaticky p°i deklaraci objektu a je tedy velkou pomocφ k zabrßn∞nφ pou╛itφ neinicializovan²ch prom∞nn²ch. Kdy╛ deklarujeme objekt okno, konstruktor je volßn automaticky systΘmem a nastavφ hodnoty jeho polo╛ek (v na╣em p°φpad∞ na hodnoty 6). Obdobn∞ to platφ i pro objekt ctverec. Konstruktor mß stejnΘ jmΘno jako t°φda (oboje se v na╣em p°φpad∞ jmenuje obdelnik). U konstruktoru nedefinujeme nßvratov² typ. I kdy╛ polo╛ky objektu jsou ji╛ inicializovßny konstruktorem, m∙╛eme jim p°i°adit jinΘ hodnoty. Destruktor je velmi podobn² konstruktoru, s tφm rozdφlem, ╛e je volßn automaticky, kdy╛ se objekt dostane mimo rozsah. Destruktor mß stejnΘ jmΘno jako t°φda, p°edchßzφ mu ale znak ~. Destruktor nemß ╛ßdn² nßvratov² typ. V na╣em p°φpad∞ destruktor provßdφ pouze vynulovßnφ obou polo╛ek. Destruktor je zde pouze pou╛it pro ilustraci jeho pou╛itφ. Jestli╛e objekt alokoval n∞jakou pam∞╗, pak destruktor by ji m∞l uvolnit.
  3. Do konstruktoru a destruktoru p°idejte p°φkaz vypisujφcφ informaci o volßnφ, aby jste se p°esv∞dΦili, ╛e jsou opravdu volßny systΘmem automaticky.
  4. Podφvejte se na nßsledujφcφ program. Tento program se velmi podobß p°edchozφmu. T°φda se nynφ jmenuje okno.  Program by vßm m∞l b²t srozumiteln² a╛ na jednu v∞c. Metoda oznaΦenß Φerven∞ obsahuje implementaci metody jako Φßst deklarace. Je to obdoba vno°enΘ funkce. Program vyzkou╣ejte.

  5. class okno {                                                          // jednoduchß t°φda
      int vyska;
      int sirka;
    public:
      okno(void);                                                          // s konstruktorem,
      int ziskej_plochu(void){ return vyska * sirka; }; // s dv∞mi metodami
      void nastav(int, int);
      ~okno(void);                                                        // a s destruktorem
    };
    okno::okno(void){                                                  // konstruktor
      vyska = 6;
      sirka = 6;
    }
    void okno::nastav(int nova_vyska, int nova_sirka){
      vyska = nova_vyska;
      sirka = nova_sirka;
    }
    okno::~okno(void){                                                 // destruktor
      vyska = 0;
      sirka = 0;
    }
    int main(int argc, char **argv)
    {
      okno male, stredni, velke;
      male.nastav(5, 7);                                     // stredni okno pou╛ije hodnoty nastavenΘ konstruktorem
      velke.nastav(15, 20);
      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;
      return 0;
    }
    Namφsto termφnu ?volßnφ funkce pou╛φvßme ?zasφlßnφ zprßv. V t∞chto dvou operacφch je rozdφl. Jeliko╛ data objektu jsou pevn∞ v objektu obsa╛ena, neexistuje mimo metod zp∙sob jak tato data zφskat. Za╣leme tedy objektu zprßvu, aby provedl n∞jakou operaci na sv²ch vnit°nφch datech. P°i volßnφ funkcφ pou╛φvßme pro p°φstup k dat∙e? pou╛φvßme
  6. Nßsledujφcφ program ukazuje pou╛itφ pole objekt∙.

  7. class okno {
      int delka;
      int sirka;
    public:
      okno(void);                                                               // konstruktor
      void nastav(int nova_delka, int nova_sirka);
      int ziskej_plochu(void) {return(delka * sirka);}
    };
    okno::okno(void){                                                        // konstruktor
      delka = 8;
      sirka = 8;
    }
    void okno::nastav(int nova_delka, int nova_sirka){
      delka = nova_delka;
      sirka = nova_sirka;
    }
    int main(int argc, char **argv)
    {
      okno male, stredni, velke, skupina[4];                      // sedm oken
      male.nastav(5, 7);
      for (int index = 1; index < 4; index++)                      // skupina[0] je implicitnφ
        skupina[index].nastav(index + 10, 10);
      cout << "Plocha malΘho okna je " << male.ziskej_plochu() << endl;
      cout << "Plocha st°ednφho okna je " << stredni.ziskej_plochu() << endl;
      for (int index = 0; index < 4; index++)
        cout << "Plocha pole okna je " <<
          skupina[index].ziskej_plochu() << endl;
      return 0;
    }
    V tomto programu je p°idßna deklarace pole 4 objekt∙ t°φdy okno. Ka╛d² z t∞chto objekt∙ je inicializovßn na hodnoty uvedenΘ v konstruktoru, nebo╗ konstruktor je proveden pro v╣echny deklarovanΘ objekty. Pole objekt∙ je v programu dßle pou╛φvßno. Pov╣imn∞te si jak se zasφlajφ zprßvy jednomu objektu v poli objekt∙. Pokuste se pochopit tento program a vyzkou╣ejte jej.
  8. Dal╣φ program pou╛φvß jako slo╛ku t°φdy °et∞zec znak∙. Ve skuteΦnosti v objektu nenφ vlo╛en² °et∞zec znak∙, ale je zde ukazatel na °et∞zec znak∙.

  9. class okno {
      int delka;
      int sirka;
      char *radek_textu;
    public:
      okno(char *radek);
      void nastav(int nova_delka, int nova_sirka);
      int ziskej_plochu(void);
    };
    okno::okno(char *radek){
      delka = 8;
      sirka = 8;
      radek_textu = radek;
    }
    void okno::nastav(int nova_delka, int nova_sirka){
      delka = nova_delka;
      sirka = nova_sirka;
    }
    okno::ziskej_plochu(void){
      cout << radek_textu << " = ";
      return (delka * sirka);
    }
    int main(int argc, char **argv)
    {
      okno male("malΘ okno "), stredni("st°ednφ okno "), velke("velkΘ okno ");
      male.nastav(5, 7);                 // stredni okno pou╛ije hodnoty nastavenΘ konstruktorem
      velke.nastav(15, 20);
      cout << "Plocha ";
      cout << male.ziskej_plochu() << endl;
      cout << "Plocha ";
      cout << stredni.ziskej_plochu() << endl;
      cout << "Plocha ";
      cout << velke.ziskej_plochu() << endl;
      return 0;
    }
    V deklaraci t°φdy je nynφ pou╛it ukazatel na char pojmenovan² radek_textu. Konstruktor obsahuje vstupnφ parametr, kter²m je ukazatel na °et∞zec a tento ukazatel bude v konstruktoru p°i°azen slo╛ce radek_textu. Mohli bychom definovat prom∞nnou radek_textu jako pole znak∙ ve t°φd∞ a potom pou╛φt funkci strcpy k p°ekopφrovßnφ °et∞zce do objektu. Tφm se budeme zab²vat v nßsledujφcφm zadßnφ.
    Nß╣ konstruktor mß nynφ jeden parametr, kter² slou╛φ k p°edßnφ informacφ do objektu. Mohli bychom jich pou╛φt i vφce. Kdy╛ nynφ deklarujeme objekty, p°edßvßme ka╛dΘ instanci jako aktußlnφ parametr °et∞zcovou konstantu, kterß je potom pou╛ita konstruktorem k p°i°azenφ ukazatele na nφ, slo╛ce radek_textu. V metod∞ ziskej_plochu tento text vypisujeme. V²pis textu sice s v²poΦtem plochy nesouvisφ, ale zde je to pou╛ito pro ilustraci toho, ╛e objekt obsahuje skuteΦn∞ ukazatel na text pou╛it² p°i deklaraci. Vhodn∞j╣φ by bylo vytvo°it dal╣φ metodu pro zji╣t∞nφ tohoto °et∞zce (a p°φpadn∞ dal╣φ pro jeho nastavenφ).
  10. Zm∞≥te p°edchozφ program tak, aby t°φda pou╛φvala pole znak∙ namφsto ukazatele na znak a do pole p°ekopφrujte °et∞zec znak∙ parametru konstruktoru. P°idejte dal╣φ metodu umo╛≥ujφcφ zm∞nit ulo╛enou hodnotu °et∞zce zaslßnφm zprßvy z hlavnφho programu a pou╛ijte novou metodu ke zm∞n∞ hodnot ulo╛en²ch ve v╣ech t°ech objektech. V²pisem se p°esv∞dΦte o provedenΘ zm∞n∞.
  11. Ve t°φd∞ m∙╛e b²t takΘ obsa╛en ukazatel na n∞jakß dynamicky alokovanß data. To ukazuje nßsledujφcφ program.

  12. class okno {
      int delka;
      int sirka;
      int *ukazatel;
    public:
      okno(void);
      void nastav(int nova_delka, int nova_sirka, int ulozena_hodnota);
      int ziskej_plochu(void) {return(delka * sirka);}
      int ziskej_hodnotu(void) {return *ukazatel;}
      ~okno(void);
    };
    okno::okno(void){
      delka = 8;
      sirka = 8;
      ukazatel = new int;
      *ukazatel = 122;
    }
    void okno::nastav(int nova_delka, int nova_sirka, int ulozena_hodnota){
      delka = nova_delka;
      sirka = nova_sirka;
      *ukazatel = ulozena_hodnota;
    }
    okno::~okno(void){
      delka = 0;
      sirka = 0;
      delete ukazatel;
    }
    int main(int argc, char **argv)
    {
      okno male, stredni, velke;
      male.nastav(5, 7, 177);
      velke.nastav(15, 20, 999);
      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;
      cout << "Ulo╛enß hodnota malΘho okna je "<<male.ziskej_hodnotu()<<endl;
      cout << "Ulo╛enß hodnota st°ednφho okna je "<<stredni.ziskej_hodnotu()<<endl;
      cout << "Ulo╛enß hodnota velkΘho okna je "<<velke.ziskej_hodnotu()<<endl;
      return 0;
    }
    V na╣em p°φpad∞ jsme do t°φdy p°idali ukazatel na int (je to pouze ukazatel a alokaci mφsta v hromad∞ musφme provΘst v konstruktoru). V na╣em programu jsou deklarovßny t°i objekty a ka╛d² z nich obsahuje ukazatel, kter² ukazuje do hromady na t°i r∙znß mφsta. Ka╛d² objekt mß svou vlastnφ dynamicky alokovanou datovou slo╛ku pro svΘ vlastnφ soukromΘ pou╛itφ. V tomto malΘm programu se nedostaneme do situace, kdy bude nedostatek pam∞ti v hromad∞. Ve skuteΦn²ch programech, je ale vhodnΘ testovat hodnotu vrßcenΘho ukazatele na NULL a zjistit tak, zda prom∞nnß byla skuteΦn∞ alokovßna.
    Metoda nastav mß nynφ t°i parametry a poslednφ z nich se pou╛φvß k nastavenφ hodnoty novΘ dynamicky alokovanΘ prom∞nnΘ. V programu dßle zasφlßme dv∞ zprßvy, jednu malΘmu oknu a druhou velkΘmu oknu k nastavenφ jejich polo╛ek. St°ednφ okno mß stßle implicitnφ hodnoty. Alokovanou dynamickou pam∞╗ musφme v destruktoru t°φdy op∞t uvolnit. K zji╣t∞nφ hodnoty dynamickΘ prom∞nnΘ je pou╛ita metoda ziskej_hodnotu. Ulo╛enΘ hodnoty v dynamick²ch prom∞nn²ch jsou vypsßny na konci programu. Prostudujte si tento program a vyzkou╣ejte jak pracuje.
  13. V nßsledujφcφm programu je pou╛it dynamicky alokovan² objekt. Vidφme, ╛e pou╛φvßnφ dynamick²ch objekt∙ se neli╣φ od jin²ch dynamick²ch prom∞nn²ch. Program si prostudujte.

  14. class okno {
      int delka;
      int sirka;
    public:
      okno(void);
      void nastav(int nova_delka, int nova_sirka);
      int ziskej_plochu(void);
    };
    okno::okno(void){
      delka = 8;
      sirka = 8;
    }
    void okno::nastav(int nova_delka, int nova_sirka){
      delka = nova_delka;
      sirka = nova_sirka;
    }
    okno::ziskej_plochu(void){
      return (delka * sirka);
    }
    int main(int argc, char **argv)
    {
      okno male, stredni, velke;
      okno *ukazatel;
      male.nastav(5, 7);
      velke.nastav(15, 20);
      ukazatel = new okno;                                            // pou╛itφ imlicitnφch hodnot
      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;
      cout << "Plocha novΘho okna je " << ukazatel->ziskej_plochu() << endl;
      ukazatel->nastav(12,12);
      cout << "Plocha novΘho okna je " << ukazatel->ziskej_plochu() << endl;
      delete ukazatel;
      return 0;
    }
    Na konci programu je pou╛it p°φkaz ukazatel->nastav(12,12). Zd∙vodn∞te, zda tento p°φkaz by bylo mo╛no nahradit p°φkazem (*ukazatel).nastav(12, 12). Poslednφm p°φkazem programu je dynamicky alokovan² objekt zru╣en. Zm∞≥te tento program tak, aby takΘ objekty male a stredni byly alokovßny dynamicky.
  15. Nßsledujφcφ program pou╛φvß objekt s vnit°nφm odkazem na jin² objekt svΘ vlastnφ t°φdy. Je to standardnφ struktura pou╛φvanß pro jednosm∞rn∞ z°et∞zen² seznam. V na╣em programu je pou╛ita velmi jednoduch²m zp∙sobem.

  16. 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 male, stredni, velke;
      okno *ukazatel;
      male.nastav(5, 7);
      velke.nastav(15, 20);
      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;
      male.nastav_ukazatel(&stredni);
      stredni.nastav_ukazatel(&velke);
      ukazatel = &male;
      ukazatel = ukazatel->ziskej_dalsi();
      cout << "Plocha okna je " << ukazatel->ziskej_plochu() << endl;
      return 0;
    }
    V konstruktoru je inicializovßn ukazatel na NULL. Takto je vhodnΘ inicializovat v╣echny ukazatele, kterΘ zatφm na nic neukazujφ. P°i°azenφ ukazatele v konstruktoru zajistφ, ╛e v╣echny objekty tΘto t°φdy budou mφt sv∙j ukazatel inicializovan². Do t°φdy byly p°idßny dal╣φ dv∞ metody. Pokuste se zjistit, co d∞lajφ a co d∞lß cel² program.
  17. V C++ je dal╣φ klφΦovΘ slovo a to this. Toto this je definovßno v ka╛dΘm objektu a oznaΦuje ukazatel na objekt, ve kterΘm je obsa╛eno. Je implicitn∞ deklarovßno jako

  18. jmeno_t°idy *this;
    a je inicializovßno k ukazovßnφ na objekt jeho╛ metoda je volßna. Ukazatel this nesmφme nikdy modifikovat. Tento ukazatel je velmi u╛iteΦn² pro prßci s ukazateli a obzvlß╣t∞ se z°et∞zen²mi seznamy, kterΘ pot°ebujφ ukazatel na objekt p°i vklßdßnφ do seznamu. Ukßzka pou╛itφ bude uvedena pozd∞ji.
  19. Ukazatel this se takΘ Φasto pou╛φvß v aplikacφch GUI. Kdy╛ v aplikaci GUI vklßdßme komponenty na formulß°, pak je v∞t╣ina prßce ud∞lßna za nßs. Komponentu lze ale takΘ vytvo°it za b∞hu aplikace. Nap°. p°i stisku tlaΦφtka m∙╛eme chtφt vytvo°it na formulß°i jinΘ tlaΦφtko. Obsluha stisku tlaΦφtka v tomto p°φpad∞ bude:

  20. void __fastcall TForm1::Button1Click(TObject *Sender)
    {
      TButton *tlacitko = new TButton(this);
      tlacitko->Parent = this;
      tlacitko->Caption = "NovΘ tlaΦφtko";
      tlacitko->Left = 100;
      tlacitko->Top = 50;
      tlacitko->Show();
      // dal╣φ k≤d
    }
    V tomto k≤du vidφme pou╛itφ ukazatele this (parametr konstruktoru tlaΦφtka a vlastnost Parent vytvo°enΘho tlaΦφtka). Vyzkou╣ejte.

NovΘ pojmy:

22. Seznßmenφ s OOP II