Objektově Orientované Programování - V BORLAND PASCALU

   V minulém  čísle vyšel  článek o  OOP. Jako  dodatek k  němu připojuji
toto stručné zasvěcení do syntaxe OOP v Borland Pascalu.

   Sám  jsem začínal  hezky pomaloučku.  Krůček po  krůčku. První  krůček
už  máš  určitě za  sebou,  takže  se  při  čtění příštího  odstavce  nic
nového nedozvíš.  Ale postupně  bys měl  v článku dojít  až k  místu, kde
narazíš  na  nějaké  nové  informace (kdybys  syntaxi  ovládal,  asi  bys
tohle nečet... leda že bys hledal bugy :-).. zdravím cpoce, hi dood!).

                          _____ Object _____

   Věděl jsem,  že existují  nějaké objekty, vypadá  to jeko  record, ale
místo record  se píše  object. Tak  jsem to zkusil  a všechno  se chovalo
jako record. Fajn.

                          _____ Dědění _____

   Pak  bylo  potřeba,   aby  jeden  record  zdědil   položky  jiného.  V
nějakém  zdrojáku jsem  viděl vazbu  object(předek), tak  jsem ji  zkusil
použít...

  Type
    typ1=object
           nějaká_proměnná : byte;
           jiná_proměnná : word;
          end;
    typ2=object(typ1)
           další_proměnná : string;
          end;

   A  ono  to  funguje,  v  typu2  jsou  obsaženy  i  všechny  položky  z
typu1. To je teda ta dědičnost, príma.

                          _____ Metody _____

   Další,  co asi  tak uhodí  do oka  při prohlížení  OOP zdrojáků,  jsou
hlavičky procedur a funkcí v definici typu. To jsou metody.

  Type
    typ1=object
           abc : integer;
           procedure xyz;
          end;

  Procedure typ1.xyz;
  begin
   write(abc);
  end.

   Třída  typ1 má  atribut abc  a metodu  xyz. Všimni  si, čím  se metoda
xyz  liší od  obyčejné procedury.  Za prvé,  před názvem  má "typ1.".  Za
druhé, uvnitř metody se dá normálně pracovat s atributy, zde abc.

               _____ Constructor a destructor? _____

   Konstruktor  a  destruktor  jsou  skoro  úplně  obyčejné  metody.  Jen
místo  procedure se  u  nich píše  constructor,  resp. destructor.  Třída
může  mít víc  konstruktorů i  destruktorů. Většinou  ale mívá  po jednom
a obvykle  se pojmenovávají Init a  Done. Jejich náplní by  mělo být něco
jako inicializace  a zrušení jedné  instance. Obvykle to jsou  také první
a  poslední věc,  které ta  instance  zažije. Všechno  píšu tak  neurčitě
proto,   že   máme  v   použití   konstruktorů   a  destruktorů   spoustu
volnosti (na  rozdíl od C++,  kde se  samy zavolají automaticky  IHNED po
vzniku  instance  a AŽ  při  destrukci  instance).  V pascalu  je  můžeme
volat podle  libosti třeba osmkrát za  sebou nebo ani jednou,  ale jak už
jsem psal,  obvykle se  volají jen  jednou a  to na  začátku a  na konci.
Navíc platí,  že pokud má  třída virtuální  metody, nelze je  volat dříve
než konstruktor.

                           _____ Fail _____

   Další  zvláštností  je příkaz  Fail,  který  lze použít  pouze  uvnitř
konstruktoru.  Tenhle odstaveček  by  měl  být až  někde  u dna  stránky,
protože Fail  není tak důležitý,  ale kvůli New a  Dispose bys o  něm měl
vědět.
   Konstruktor  se zvenčí  tváří  jako funkce,  vrací  true pokud  uspěl,
false   pokud  neuspěl.   Ale  zevnitř   vypadá  jako   procedura,  nelze
nastavit result.  Jediným způsobem jak  ohlásit neúspěch je  příkaz Fail,
který   konstruktor   zároveň    ukončí   (exitne).   Pokud   konstruktor
proběhne bez failu, skončí úspěchem.

                      _____ New a Dispose _____

   Dosud  to  vypadalo  tak,  že  konstruktor  a  destruktor  jsou  úplně
obyčejné  metody.  Jedna z  jejich  odlišností  se  ale může  projevit  u
příkazů New a Dispose. Mějme třídu a její instance

  Type
    typ1=object
           abc : integer;
           constructor init;
           procedure xyz;
           destructor done;
          end;
  Var
     a:typ1;
     p:^typ1;

   Po   spuštění   programu   je   a   neinicializovaná   instance  a   p
neinicializovaný pointer  na instanci.  a můžeme  jednoduše inicializovat
příkazem  a.init;.  Pro inicializaci  p  existuje několik  ekvivalentních
variant:

    1) new(p); if p<>nil then if not p.init then dispose(p);
    2) new(p,init);                - new se chová jako procedura
    3) p:=new(^typ1,init);         - new se chová jako funkce : ^typ1

   Máme  tedy  rozšířený příkaz  new.  Jeho  druhým parametrem  ale  musí
být  konstruktor,  žádná  jiná   metoda.  Analogicky  existuje  rozšířený
dispose, ve kterém lze zadat pouze destruktor.

    1) p.done; dispose(p);
    2) dispose(p,done);

                      _____ Inherited, Self _____

   Občas  se někde  objeví slůvka  jako self  nebo inherited.  Vyskytovat
se  mohou   pouze  v  metodách.   Self  je  instance  se   kterou  metoda
pracuje.
   Předek   a  potomek   mohou  mít   stejně  nazvanou   metodu,  to   je
korektní. Když  potomek provede  příkaz xyz;, volá  se jeho  xyz. Zavolat
xyz předka lze příkazem inherited xyz;.

                          _____ Virtual _____

   Pro  jistotu lehce  zopáknu něco  z  minulého článku.  Máme p  pointer
na  instanci typu  xxx, ale  ten ukazuje  na instanci  typu yyy  (kde yyy
je  potomek  xxx).  Když  zavoláme  nějakou  metodu,  provede  se  metoda
třídy xxx  nebo yyy? U  statických metod  xxx, u virtuálních  yyy. Neboli
u statických rozhoduje typ pointeru, u virtuálních typ instance.
   A  teď  už  syntaxe:  pokud  za  deklarací  metody  uvedeme  virtual;,
bude  virtuální, v  opačném případě  zůstane statická.  Pokud má  potomek
stejně  nazvanou  metodu  jako  předek, musí  zachovat  její  statičnost,
resp. virtuálnost.

                      _____ Private, public _____

   Zapouzdření  znamená,  že  všechno   potřebné  pro  práci  třídy  bude
zahrnuto v  ní. Na  povrchu bude  vidět jen  to co  nás zajímá  z pohledu
uživatele  objektu   (metody  udělej_tohle,  udělej_tamto).   Uvnitř  asi
budou další  důležité metody a  atributy, ale ty už  uživatele nezajímají
a  ani  by  o nich  neměl  vědět.  Proto  lze  každému atributu  a  každé
metodě  říct jestli  je privátní  nebo veřejná.  Nejjednodušší vysvětlení
bude příklad:

  Type
    typ1=object
           abc : integer;
          private:
           efg : string;
           hij : byte;
          public:
           constructor init;
           procedure xyz;
          private:
           destructor done;
          end;

   To co  je za private: je  privátní, to za public: je  veřejné. Položky
před prvním private nebo public jsou public.
   Co  přesně  ta  veřejnost  znamená?  Že  k  položce  může  přistupovat
kdokoliv  a kdekoliv.  Naproti  tomu k  private  položce lze  přistupovat
pouze  uvnitř metod  dané třídy  a uvnitř  metod jejích  potomků v  témže
modulu  (unitě). Na  jiných místech  "není vidět",  její použití  znamená
syntax error (neznámý identifikátor).

   Pozor    na    private.    Inherited   xyz    nevrací    metodu    xyz
bezprostředního  předka,  ale  nejbližší   public  xyz.  Když  má  předek
private xyz a prapředek public xyz, inherited vrací prapředka.

                          _____ Chyby _____

   Našel  jsem jednu.  Pokud má  třída dva  konstruktory a  z jednoho  se
volá  druhý, a  pokud má  potomka, ten  se nesprávně  inicializuje. Uvedu
příklad.

  Type
    typ1=object
           constructor init1;   {inicializace...}
           constructor init2;   {obsahuje volání init1}
          end;

  Type
    typ2=object(typ1)
           constructor init1;   {obsahuje volání inherited init1}
           constructor init2;   {obsahuje volání inherited init2}
          end;

   New(typ2,init1) vrací  správně objekt  typu typ2,  ale new(typ2,init2)
vrací  hybrid tvaru  a velikosti  typ2 ale  s tabulkou  virtuálních metod
třídy typ1.

                   _____ TCollection, TStream _____

   K  čemu  všechna  ta  teorie..  hrr  do  praxe.  Ohromně  (giganticky,
kolosálně)  užitečnými se  ukazují třídy  TCollection a  TStream dodávané
s  Borland  Pascalem  (jsou  v unitě  objects).  TCollection  představuje
kolekci  "objektů"  stejného  typu  (třeba bajtů,  třeba  stringů,  třeba
buttonů..).  Do kolekce  lze  přidávat,  odmazávat, vyhledávat,  provádět
libovolné akce  na všechny prvky... K  prvkům je přímý přístup  přes pole
pointerů.  TStream  představuje proud  dat,  ze  kterého lze  číst,  psát
do něj, seekovat v něm.

                           _____ C++ _____

   Vážně se nechceš naučit radši C++? :)

Dee