2. Zßklady OOP II
  1. Ve t°φd∞ m∙╛e b²t definovßno n∞kolik konstruktor∙ (li╣φ se poΦtem a typy parametr∙). V²jimeΦnΘ postavenφ majφ bezparametrick² konstruktor a kopφrovacφ konstruktor. Bezparametrick² konstruktor je konstruktor bez parametr∙ (nebo konstruktor jeho╛ v╣echny parametry majφ definovanΘ implicitnφ hodnoty). Implicitnφ verze bezparametrickΘho konstruktoru (konstruktoru vytvo°enΘho p°ekladaΦem), pouze vyhradφ mφsto pro definovanou instanci. Kopφrovacφ konstruktor je konstruktor, jeho╛ jedin²m parametrem je odkaz na prom∞nnou tΘho╛ typu, jakΘho je tento konstruktor. TakΘ kopφrovacφ konstruktor umφ v p°φpad∞ pot°eby vytvo°it p°ekladaΦ. Tato implicitnφ verze kopφrovacφho konstruktoru, vyhradφ pot°ebnou pam∞╗ pro nov² objekt a zkopφruje obsah svΘho parametru do vytvß°enΘho objektu.

  2. Nßsledujφ zßsady pou╛φvßnφ konstruktor∙: Konstruktory se volajφ ve chvφli, kdy jsou objekty vytvß°eny. Definujeme-li globßlnφ nebo statick² objekt, provede se konstruktor je╣t∞ p°ed inicializaΦnφmi funkcemi (p°ed funkcemi uveden²mi v direktivßch #pragma startup, a tφm samoz°ejm∞ i p°ed funkcφ main; inicializaΦnφ funkce mohou poΦφtat s tφm, ╛e v╣echny statickΘ objekty jsou ji╛ p°ipraveny k pou╛itφ). AutomatickΘ objekty (objekty, kterΘ nejsou globßlnφ ani statickΘ) jsou vytvß°eny p°i ka╛dΘm vstupu do programu a stejn∞ tak jsou volßny i jejich konstruktory.
    Toto si nynφ ukß╛eme na p°φklad∞. Mßme nßsledujφcφ t°φdy:
    class A {
    public:
      int a1;
      int a2;
      void metoda() {};
    };
    class B {
    public:
      int bi;
      A bA;
      static int pocet;             // poΦet vytvo°en²ch instancφ
      B(A& a, int i = 0){           // definice konstruktoru
        bA = a;
        bi = i;
        pocet++;
      };// Je-li definovßn libovoln² konstruktor, pak p°ekladaΦ negeneruje bezparametrick² konstruktor
        // (v p°φpad∞ pot°eby jej musφme definovat sami, nap°. jako B() {}; nebo jako nßsledujφcφ konstruktor)
      B(int = 0, int = 0, int =0);
      B(B& b);   // kopφrovacφ konstruktor
    };
    int B::pocet = 0;
    inline B::B(int i1, int i2, int i3){
      bi = i1;
      bA.a1 = i2;
      bA.a2 = i3;
      pocet++;
    }
    B::B(B& b){
      bi = b.bi;
      bA.a1 = b.bA.a1;
      bA.a2 = b.bA.a2;
      pocet++;
    }
    Pro tyto t°φdy lze pou╛φvat konstruktory takto:
    A as1;             // pou╛ije se implicitnφ bezparametrick² konstruktor
    A as2 = {0, 2};// zp∙sob pou╛φvan² p°i inicializaci strukturovan²ch datov²ch typ∙
    const A as3 = as2; // pou╛ije se implicitnφ kopφrovacφ konstruktor
    B bs1;             // pou╛ije se B(0, 0, 0)
    B bs2 = 22;        // pou╛ije se B(int, 0, 0)
    const B bs3 = bs2.bi;      // pou╛ije se B(int, 0, 0)
    B bs4 = bs2;       // pou╛ije se kopφrovacφ konstruktor B(B&)
    B bs5 = as2;       // pou╛ije se B(A&, 0)
    B bs6(22);         // pou╛ije se B(int, 0, 0)
    B bs7(bs2.bA.a1);  // pou╛ije se B(int, 0, 0)
    B bs8(bs2);        // pou╛ije se kopφrovacφ konstruktor B(B&)
    const B bs9(as2);  // pou╛ije se B(A&, 0)
    B bs10(as2, 3);    // pou╛ije se B(A&, 3)
    B bs11(10, 20, 30);// pou╛ije se B(int, int, int)
    B bs12[3];         // pou╛ije se 3x B(0, 0, 0)
    Pokuste se pochopit, jak tyto konstruktory pracujφ a kdy se kter² z mo╛n²ch konstruktor∙ pou╛ije.
  3. T°φda typu union nesmφ obsahovat slo╛ky, kterß majφ konstruktory, ale sama tato t°φda konstruktory mφt m∙╛e. Vyzkou╣ejte (pokuste se deklarovat t°φdu typu union a jako polo╛ky v nφ pou╛ijte t°φdy A a B z p°edchozφho zadßnφ).
  4. Dal╣φm typem implicitn∞ volan²ch konstruktor∙ jsou konverznφ konstruktory. Jsou to konstruktory, kterΘ lze volat pouze s jednφm parametrem. Pou╛ijφ se, kdy╛ pot°ebujeme inicializovat instanci danΘho objektovΘho typu a mßme k dispozici instanci typu, pro n∞j╛ je definovßn pot°ebn² konverznφ konstruktor. Typick²m p°φkladem je nap°. p°edßvßnφ parametr∙ funkcφm. Jednß se o ekvivalent implicitnφho p°etypovßnφ. Uve∩me si p°φklad (p°edpoklßdßme platnost p°edchozφch definic):

  5. class C{
    public:
      B b;
      C(int i=0, int j=0, int k=0){b = B(i, j, k);};
      void c(B& bb){b = bb;};            // toto nenφ konstruktor
    };
    B Pokus(B b) {                       // obyΦejnß funkce
      return b;         // p°i p°edßvßnφ parametr∙ hodnotou a p°i p°edßvßnφ
    }                                                                         // vrßcenΘ hodnoty se volß kopφrovacφ konstruktor
    void main(void){
      C c1(10, 20, 30);
      c1.c(B(as2));        // volßnφ B::B(A&) pro p°etypovßnφ parametru
      for (int i=0; ++i <=3;) bs12[i] = B(i, i*i);
      bs1 = Pokus(bs12[2]);// proto╛e se parametr p°edßvß hodnotou, musφ se
      // vytvo°it novß instance - automaticky se volß kopφrovacφ konstruktor
      bs2 = Pokus(123);// automaticky se volß konverznφ konstruktor B::B(int, 0, 0)
    }
    Pokuste se pochopit, kdy je volßn kter² konstruktor.
  6. ObjektovΘ slo╛ky slo╛en²ch t°φd m∙╛eme inicializovat p°φmo. V hlaviΦce konstruktoru slo╛enΘ t°φdy lze urΦit konstruktor, kter² chceme pou╛φt pro vytvo°enφ danΘ slo╛ky. Provedeme to tak, ╛e za seznamem parametr∙ konstruktoru slo╛enΘ t°φdy napφ╣eme dvojteΦku a za nφ uvedeme seznam identifikßtor∙ slo╛ek, kterΘ chceme vytvß°et nestandardn∞. P°i vytvß°enφ instance se jejφ jednotlivΘ slo╛ky vytvß°ejφ v tom po°adφ, v jakΘm byly deklarovßny v definici t°φdy. Po°adφ uvedenφ inicializßtor∙ slo╛ek v hlaviΦce konstruktoru nemß na po°adφ jejich inicializace ╛ßdn² vliv (v dal╣φ ukßzce jsou schvßln∞ p°ehßzeny). Slo╛ky, jejich╛ inicializßtory nebudou uvedeny v hlaviΦce konstruktoru, budou vytvo°eny bezparametrick²m konstruktorem. Slo╛ky, kterΘ ji╛ byly inicializovßny, je mo╛nΘ pou╛φt jako parametry v inicializßtorech dal╣φch slo╛ek.

  7. class D{
    public:
      int i;
      A a;
      B b1;
      B b2;
      C c;
      D(B bb, A aa, int id2, int id3) : i(842), c(i/2, id2, id3), a(aa), b1(bb) {};
    };//slo╛ka b2 nenφ v seznamu a bude tedy inicializovßna bezparametrick²m konstruktorem
    D d(bs5, as2, 246, 987);
    Pole objektov²ch typ∙ m∙╛eme inicializovat stejn∞ jako pole instancφ neobjektov²ch typ∙. Jedin² rozdφl je v tom, ╛e kdy╛ nenφ typ inicializaΦnφ hodnoty mezi typy, pro n∞╛ je definovßn konverznφ konstruktor nebo kdy╛ pot°ebujeme p°i°adit danΘmu prvku pole hodnotu, pro jejφ╛ vytvo°enφ je pot°ebn² konstruktor s vφce parametry, uvedeme mφsto danΘ hodnoty p°φmo tento konstruktor (viz t°etφ a╛ ╣est² prvek pole v nßsledujφcφ ukßzce). Stejn∞ jako u klasick²ch polφ platφ, ╛e inicializaΦnφch hodnot nesmφ b²t vφce ne╛ je prvk∙ pole a stejn∞ jako u klasick²ch polφ nemusφme inicializovat v╣echny prvky danΘho pole (prvky na ne╛ se inicializaΦnφ hodnoty nedostanou budou inicializovßny bezparametrick²m konstruktorem).
    B bpole[9] = {as2, 124, bs2, B(321, 765), B(as2, 654), B(bs7), B(1, 2, 3)};
    Pokuste se pochopit jak inicializace objektov²ch typ∙ probφhß.
  8. M∙╛eme mφt takΘ datovou slo╛ku t°φdy, kterß je odkazem. V tomto p°φpad∞ odkaz m∙╛e b²t inicializovßn pouze v inicializaΦnφm seznamu t°φdy a nikde jinde:

  9. class mojeTrida {
      jinaTrida& jina;        // odkaz na jinou t°φdu
      // ...
    public:
      mojeTrida();
      // ...
    };
    mojeTrida::mojeTrida() :
      jina(*new jinaTrida)    // musφ b²t umφst∞no zde
    {
    }
  10. Slo╛ky, kterΘ jsou deklarovßny se specifikßtorem const, jsou konstantnφ slo╛ky. Konstantnφ slo╛ky uchovßvajφ hodnoty, kterΘ se nastavφ p°i vzniku instance a v pr∙b∞hu jejφho ╛ivota se ji╛ nem∞nφ. M∙╛e to b²t nap°. Φas vzniku danΘ instance, jejφ po°adovΘ Φφslo nebo jin² ·daj, kter² nebude pot°eba m∞nit. Vytvo°te jednoduchou t°φdu s konstantnφ slo╛kou por_cis (po°adovΘ Φφslo instance) a vyzkou╣ejte jak pracuje (v konstruktoru toto po°adovΘ Φφslo vypisujte, vytvo°te n∞kolik objekt∙ a u n∞kterΘho z nich se pokuste tuto slo╛ku zm∞nit).
  11. Napi╣te deklaraci a implementaci t°φdy datum se soukrom²mi polo╛kami den, mesic a rok, konstruktorem s implicitnφmi parametry (s nulovou hodnotou) a metodami nastav (nastavenφ v╣ech polo╛ek), nastavDen, nastavMesic, nastavRok, Den (zji╣t∞nφ dne), Mesic a Rok. U konstruktoru a v╣ech nastavovacφch metod zajist∞te, v p°φpad∞ nevhodnΘ hodnoty n∞kterΘho parametru, pou╛itφ hodnoty ze systΘmovΘho datumu (nap°. pomocφ standardnφ funkce getdate). Toto lze vyu╛φt v p°φpad∞, kdy pou╛ijete bezparametrick² konstruktor, pak hodnoty budou nastaveny na systΘmov² datum. Tuto t°φdu je╣t∞ dopl≥te p°etφ╛enφm operßtoru << (v²stup datumu do datovΘho proudu). V nßsledujφcφ implementaci tohoto operßtoru je uvedeno mnoho komentß°∙, aby jste se nauΦili definovat takovΘto operßtory i pro svΘ vlastnφ datovΘ typy.

  12. ostream& operator<< (ostream& o, datum& D){
      //Zapamatuj si p∙vodnφ nastavenφ formßtovacφch p°φznak∙ a nastav v²pis v des.
      //soustav∞ zarovnßvan² doprava. Hodnota ostatnφch p°φznak∙ nenφ v²znamnß.
      long flags = o.flags(ios::right + ios::dec);
      //zjisti rozdφl mezi po╛adovanou a pot°ebnou velikostφ v²pisovΘ oblasti
      int width = o.width() - 8;
      //zapamatuj si nastaven² v²pl≥ov² znak, my pou╛ijeme nulu, nap°. 01.03.99
      char fill = o.fill('0');
      //pokud je po╛adovanß oblast v∞t╣φ a pokud nebylo nastaveno zarovnßvßnφ vlevo
      //zapl≥ ·vodnφ p°ebytek p∙vodnφmi v²pl≥ov²mi znaky
      if ((width > 0) && !(flags & ios::left)){
      //prom∞nnß i z nßsledujφcφho cyklu je v tomto bloku lokßlnφ
        for (int i = 0; i < width; i++, o << fill);
      }
      //v²pis datumu
      o << setw(2) << D.Den() << "." << setw(2) << D.Mesic() << "."
        << setw(2) << (D.Rok()%100);
      //obnova p∙vodnφho nastavenφ zapln∞nφ zßv∞reΦnΘho p°ebytku v²pl≥ov²mi znaky
      o.fill(fill);
      o.flags(flags);
      if ((width > 0) && (flags & ios::left)){
        for (int i = 0; i < width; i++, o << fill);
      }
      return o;
    }
    Vytvo°enou t°φdu vyzkou╣ejte v n∞jakΘm programu.
  13. Stejn∞ jako datovΘ slo╛ky t°φdy mohou b²t se specifikßtorem static, mohou b²t s tφmto specifikßtorem i metody t°φdy. Definujφ se stejn∞ jako b∞╛nΘ metody, pouze musφme mφt na pam∞ti, ╛e nejsou svßzßny s ╛ßdnou instancφ (jednß se vlastn∞ o funkci) a nelze v nich tedy pou╛φvat klφΦovΘ slovo this. Tyto metody m∙╛eme kvalifikovat stejn∞ jako slo╛ky t°φdy se specifikßtorem static, bu∩ prost°ednictvφm identifikßtoru n∞jakΘ instance (ten odd∞lujeme teΦkou) nebo prost°ednictvφm identifikßtoru t°φdy (odd∞lujeme jej dv∞ma dvojteΦkami). Metody se specifikßtorem static se pou╛φvajφ kdy╛ pot°ebujeme pracovat pouze se slo╛kami static, kdy╛ chceme omezit p°φstupovß prßva k danΘ funkci na metody danΘ t°φdy nebo kdy╛ pot°ebujeme n∞jakou funkci, kterß nem∙╛e b²t b∞╛nou metodou, aby p°istupovala k soukrom²m slo╛kßm t°φdy. Pokuste se vytvo°it n∞jakou t°φdu, ve kterΘ pou╛ijete metodu se specifikßtorem static a tuto metodu vyzkou╣ejte.
  14. P°ßteli se mohou stßvat jak jednotlivΘ funkce, tak i celΘ t°φdy. Pokud je p°φtelem deklarovanΘ t°φdy celß t°φda, vztahuje se mo╛nost p°φstupu ke v╣em slo╛kßm deklarovanΘ t°φdy na v╣echny metody sp°ßtelenΘ t°φdy. Nositelem sd∞lenφ o p°ßtelstvφ m∙╛e b²t jedin∞ t°φda o jejich╛ soukrom²ch polo╛kßch se jednß. P°ßtelΘ se oznaΦujφ pomocφ klφΦovΘho slova friend, kterΘ je nßsledovßno bu∩ prototypem funkce nebo identifikßtorem t°φdy, kterou prßv∞ deklarovanß t°φda oznaΦuje za svΘho p°φtele. Pokud chceme zd∙raznit, ╛e deklarovan²m p°φtelem je t°φda, m∙╛eme p°ed identifikßtor sp°ßtelenΘ t°φdy uvΘst klφΦovΘ slovo class, struct nebo union. Nap°.

  15. class tajna_schranka{
      char *obsah;
      tajna_schranka(char *o = "") {obsah = o;};
      friend class agent;
    };
    V tomto p°φpad∞ jsou datovß polo╛ka a konstruktor soukromΘ a lze k nim p°istupovat pouze ze samotnΘ t°φdy tajna_schranka a ze sp°ßtelenΘ t°φdy agent. Vyzkou╣ejte.
  16. M∙╛eme definovat i konstanty objektov²ch datov²ch typ∙. Mß to ale jeden hßΦek: p°ekladaΦ neumφ v obecnΘm p°φpad∞ posoudit, zda n∞jakß metoda ovlivnφ hodnotu svΘ instance Φi nikoliv a tudφ╛ nßm pro jistotu nedovolφ pro konstantu pou╛φt ╛ßdnou metodu. JedinΘ, co s nφ m∙╛eme d∞lat, je p°edßvat ji jako parametr funkcφm, kterΘ majφ ve svΘm prototypu u p°φslu╣nΘho parametru specifikßtor const. Aby bylo mo╛no aplikovat na konstantnφ objekty metody, m∙╛eme oznaΦit metody, kterΘ nem∞nφ hodnoty instance, pro kterou je volßme, tak╛e je lze bezpeΦn∞ pou╛φt i na konstanty. Tyto metody se v deklaraci (v definici i v prototypu) oznaΦujφ klφΦov²m slovem const, kterΘ se uvede za zßvorkou, ukonΦujφcφ seznam parametr∙. Nap°.

  17. class datum {
      int den;
      int mesic;
      int rok;
    public:
      int Den() const {return den;};
      int Mesic() const {return mesic;};
      int Rok() const;
    };
    int datum::Rok() const{return rok;}
    Vytvo°te n∞jakΘ konstantnφ instance a vyzkou╣ejte.
2. Zßklady OOP II