Image
8.6.2016 0 Comments

Stretnutie s Pascalom II. /2. časť

Späť na úvod >> Späť na programovanie >> Späť na seriál

Prišli sme na to, že OOP je skutočne niečo nové a zložité. Preto sa budeme k mnohým veciam vracať a vysvetľovať si ich z iného ohľadu tak, aby sme si ich zautomatizovali a hlavne aby sme ich pochopili. Ak ste sa pozerali na výpis programu OOP.PAS, ste si istotne niektoré nové pravidlá pri písaní zdrojového zápisu. Možnopovažujete tento program za bezúčelný a, samozrejme, vedeli by ste ho napísať inak a jednoduchšie klasickými technikami.
            Bohužiaľ, v začiatkoch je to bežné, lebo krása OOP sa prejaví pri podstatne zložitejších a rozsiahlejších programoch. Ale na to musíte prísť sami... (Ja som sa bránil OOP niekoľko rokov, až Friendly Pascal a Delphi ma k nim priviedli. Škoda strateného času.) Preto nezúfajte, ak niečo nep ochopíte hneď. Neskôr v súvislosti s inými princípmi OOP sa vám všeličo objasní a zistíte, že bez OOP by to ani nešlo!
Ale poďme k dalšej teórii o OOP.

Definícia objektu, vytvorenie inštancie objektu

Objekt je v podstate nový dátový typ, jeho definícia sa teda uskutoční rovnako ako definícia iného používateľského dátového typu.
            Je preň zavedené kľúčové slovo object , ktorého použitie je veľmi podobné použitiu kľúčového slova record na definíciu záznamu. Medzi kľúčové slová record a end sa uvedú deklarácie d átových položiek a hlavičiek procedúr a funkcií, ktoré v OOP predstavujú metódy objektov definovanej triedy. Vráťme sa k nášmu príkladua definujme objekt pocitac:

pocitac = object
     sirka_zbernice  :  tbity;
     velkost_pamate  :  string;
     constructor Init(abity  :  tbity;

            pamat  :  string);
     procedure Pipni;
     procedure Urci_Typ_procesora;

            virtual;
     procedure Pocitaj;
end;


            Takto sme nadefinovali objekt, ktorý má d ve dátové položky - sirka_zbernice a velkost_pamate - a štyri metódy - Init, Pipni, Urci_Typ_procesora, Pocitaj . Význam použitých slov constructor a virtual si vysvetlíme neskôr. Ak chceme definovať objekt, ktorý je potomkom iného objektu, uvedieme meno pr edka do okrúhlych zátvoriek za slovo object:
 

atecko = object(pocitac)
   Urci_Typ_procesora; virtual;
end;


Takto nadefinovaný objekt atecko je potomkom objektu pocitac. My už vieme, že zdedil všetky vlastnosti (dáta) a sc hopnosti (metódy) objetku pocitac. Kód jednotlivých metód sa uvedie až za deklaráciou objektu. Pri definovaní metódy sa uvedie meno objektu oddelené bodkou:

procedure Pocitac.Pocitaj;
      begin
      .
      .
      .
end;


Inštanciu objektu vytvoríme tak, že deklarujeme premennú, ktorej typom bude meno definovaného objektu:

var pc1  :  pocitac;

Teraz je premenná pc1 inštanciou objektu pocitac.
 

Prístup k položkám obj ektu, rozsahy platnosti
Všetky dátové položky a metódy niektorej inštancie sú z ľubovoľného miesta programu, kde je táto inštancia platnou premennou, prístupné pomocou bodkového zápisu rovnako ako v zázname record. Ak teda použijeme v hlavnom programe zápis


pc1.Pocitaj;

vyvoláme tým metódu Pocitaj príslušnej inštancie pc1 objektu pocitac. Rovnakým spôsobom je možné pristupovať k dátovým položkám objektu, teda
 

pamat := pc1.velkost_pamate;

je platný zápis, pokiaľ je premenná pamat typu string. Vnútri objektu sú dáta a metódy prístupné jednoduchým zápisom bez bodky:

procedure Pocitac.Pocitaj;
      begin
      .
      .
      Urci_Typ_Procesora;
      .
      .
end;


            Pre rozsahy platnosti jednotlivých objektov platia bežné pravidlá iných dátových typov a premenných. Zvláštnosťou je, že všetky dátové položky definované v predkovi sú platné aj v potomkovi a netreba ich v potomkovi znova deklarovať. Dátovú položku nie je možné v potomkovi predefinovať! Ak teda v potomkovi uvedieme rovnaké meno dátovej položky ako v predkovi, dôjde ku kolízii a prekladač vyhlási chybu!
            Pre metódy platí rovnaké pravidlo o rozsahu platnosti ako pre dátové položky. Rozdiel je však v tom, že metódy definované v predkovi je možné v potomkovi predefinovať! Ak v potomkovi použijeme meno metódy, ktorá je deklarovaná v predkovi, prekladač to akceptuje a metóda je predefinovaná. Počínajúc týmto objektom, v hierarchii objektov je platná novo nadefinovaná metóda. Táto možnosť sa v OOP veľmi využíva. Pre statické, teda nie virtuálne metódy platí, že metóda, ktorá predefinováva (prekrýva metódu predka), sa môže líšiť počtom a typom parametrov. Toto neplatí pre virtuálne metódy.

Prístup k metódam predka

Veľmi často potrebujeme v programe zavolať metódu predka, teda nie tú, ktorá ju predefinovala. Môžeme použiť dva spôsoby:
a) zápis plného mena metódy, teda

meno_predka.meno_metody;
tento spôsob je platný vo všetkých verziách Turbo Pascalu,
b) p oužitie kľúčového slova inherited, ktoré bolo doplnené vo verzii TP 7.0, teda takto:

inherited meno_metody;

            Pokiaľ sa tento zápis objaví v definícii potomka, vyvolá vykonanie metódy definovanej v jeho predkovi.

Virtuálne metódy, konštruktory

Virtuálne metódy sú prostriedkom na využitie polyformizmu - mnohotvarosti objektov. Čiastočne sme si to naznačili v predchádzajúcej časti. Teraz si vysvetlíme pravidlá prekrývania virtuálnych metód. Ak je už raz metóda definovaná ako virtuálna, musí byť ak o virtuálna definovaná v každom ďalšom potomkovi. Pri virtuálnej metóde nie je možné zmeniť počet ani typ parametrov. Záhlavie virtuálnych metód musí byť úplne rovnaké po celej hierarchii dedičnosti.
            Ak je v danom objekte definovaná aspoň jedna virtuálna metóda, musí byť v objekte nevyhnutne definovaná metóda s kľúčovým slovom constructor . Konštruktor je zvláštna metóda, pri ktorej vyvolaní sa vytvorí spojenie medzi tabuľkou virtuálnych metód a aktuálnou inštanciou objektu. Toto spojenie sa potom využíva pri volaní niektorej z virtuálnych metód daného objektu. Ak zabudneme v objekte aspoň s jednou virtuálnou metódou zadeklarovať konšruktor, prekladač vyhlási chybu. Konštruktor musí byť vyvolaný pred prvým volaním niektorej virtuálnej metódy objektu. Opomenutie toho spôsobí chybu za behu programu, ktorá nie je hlásená a jej prejavy bývajú rôzne.

Dynamické alokácie objektov, deštruktory

Pretože objekty a ich inštancie (premenné) sú rovnocenné bežným dátovým typom a premenným, môžeme s nimi rovnako aj zaobchádzať. Teda je možné získavať ukazovatele na objekty, dynamicky ich alokovať a rušiť.
            Dynamická alokácia objektov sa v technike OOP veľmi často používa a okrem iného zrýchľuje beh programu. Pre alokáciu objektov bola rozšírená syntax príkazov New a Dispose. Príkaz New má dve formy:

procedurálnu
New( ukazateľ [, konštruktor])
 

a funkčnú
ukazateľ = New(typ_ukazateľa [,konštruktor]).

            Druhým parametrom je v oboch príkladoch konštruktor alokovaného objektu s prípadnými parametrami. Tento konštruktor sa po vykonaní alokácie automaticky vykoná. Samozrejme, ak objekt nepoužíva virtuálne metódy, konštruktor ako parameter sa neuvádza.
            Prvý parameter v prípade procedurálnej verzie je premenná typu ukazovateľ, do ktorej sa priradí adresa alokovaného objektu. Tento parameter sa teda musí odovzdávať odkazom.
            V prípade funkcionálneho volania má prvý parameter význam typu vytváraného objektu. Vlastná adresa je vrátená ako funkčná hodnota.
            Uvoľnenie dynamicky alokovaného objektu z pamäte sa vykonáva pr íkazom Dispose :

Dispose( ukazateľ [, deštruktor]).

            Prvý parameter je ukazovateľ na rušený objekt, druhý je tzv. deštruktor. Deštruktor je zvláštna metóda, ktorá sa definuje pomocou kľučového slova destructor:

Destructor Done;

            Deštruktor vykonáva uvoľnenie dynamicky alokovaného objektu, pričom zabezpečí, že aj v prípade využitia mechanizmu polyformizmu bude vždy uvoľnené presne správne množstvo byteov pamäte. Robí sa to, samozrejme, pomocou tabuľky virtuálnych metód. Deštruktor musíme použiť vždy, ak máme objekt obsahujúci virtuálne metódy a chceme s ním zaobchádzať dynamicky. Telo deštruktora môže zostať v niektorých prípadoch prázdne.
            Pozrime sa teraz podrobnejšie na náš prvý objektovo orientovaný program OOP.PAS:
 Pre OOP je typic ké, že všetky možné funkcie programu sú nadefinované v deklaračnej časti a samotné telo programu, teda jeho výkonná časť obsahuje iba niekoľko riadkov. Pri práci s knižnicou Turbo Vision sa stretnete s hlavným telom programu, ktoré bude obsahovať iba tri ( !) riadky. Všetko ostatné sa nachádza v deklaračnej časti. Aj náš program má veľmi bohatú deklaračnú časť. Po definícii využívania unitu Crt nadeklarujeme nový výčtový typ tbity , v ktorom je päť položiek. Skutočné objekty sa začínajú nadeklarovaním objektu pocitac. Jeho
dátové položky a metódy už poznáme. Všimnime si ešte raz, že v definovaní objektu sú uvedené iba hlavičky procedúr, ktoré priberajú úlohu metódy. Ich deklarácie sú na inom mieste programu.
            Za definíciou objektu pocitac následuje deklarovanie nových objektov: Sinclair, Atecko, Styri86, Pentium . Každý z týchto objektov je potomkom objektu pocitac, lebo jeho meno je uvedené v zátvorkách. Čo sa nachádza v telách jednotlivých objektov? No predsa iba meno metódy Urci_Typ_procesora, ktorú chceme
pre definovať pre každého potomka zvlášť. Všimnime si, že už nemusíme uvádzať v potomkoch dátové položky a ostatné metódy. Tie sa automaticky zdedia od predka pocitac . Čo to konkrétne znamená? No to, že aj objekt Atecko, aj jeho "bratia" majú dáta sirka_zbernice, velkost_pamate a metódy Init, Pípni a Pocitaj, hoci nie sú definované v ich telách!
Všimnime si zápis

patecko = ^atecko;

            Ide o deklaráciu typu patecko , čo nie je nič iné ako ukazovateľ na typ atecko. Toto som uviedol ako príklad na spomínanú dynamickú alokáciu objektu atecko. Po deklarácii potomkov nasledujú vlastné definície metód jednotlivých objektov.
            Začneme pekne po poriadku - všeobecným objektom pocitac a konštruktorom Init . Vidíme, že Init nastaví dátové položky. Spravidla sa v konštruktoroch zadáva naplnenie dátových položiek, aby sme s nimi mohli ďalej pracovať. Metóda Pocitac.Pipni je zrejmá. Metóda Pocitac.Urci_Typ_procesora je tá, ktorú zadefinujeme ako virtuálnu, a preto ju budeme v každom potomkovi predefinovávať. V tomto prípade ide o všeobecný počítač, a tak deklarujeme, aby táto metóda tohto objektu vypísala "rôzny". Najmohutnejšia metóda je Pocitac.Pocitaj.
            Obsahuje procedúru Vypis, ktorá volá vo svojom tele všeobecnú virtuálnu metódu Urci_Typ_procesora. Príkazy na výpis pomocných textov sú jasné. V tele metódy Pocitaj je zavolaná procedúra Vypis a metóda Pipni. Takto sme nadeklarovali všetko o objekte pocitac.
            Pristúpme teraz k deklarácii metód ostatných objektov - potomkov. Už vieme, že nemusíme deklarovať tie metódy, ktoré sú nadeklarované v predkovi. Na správnu funkciu programu stačí, ak predefinujeme metódu, ktorá opisuje typ procesora. Preto v jednotlivých potomkoch - v objektoch Sinclair, Atecko, Styri86
a Pentium -
predefinujeme metódu Urci_Typ_procesora. Ostatné metódy jednoducho zdedíme!
            Nesmieme zabudnúť na deklaráciu deštruktora Done, ktorý obsahuje objekt Atecko , aby sme zabezpečili správne uvoľnenie pamäte.
            Na záver deklaračnej časti programu definujeme premenné pc1pc5, ktoré sú takého typu, aký sme nadekl arovali, teda pc1 je typu pocitac, pc2 typu Sinclair, pc3 typu patecko atď. Hovoríme, že sme vytvorili inštancie jednotlivých objektov. Vlastné telo programu obsahuje výmaz obrazovky a po ňom volanie konštruktorov jednotlivých inštancií s konkrétnymi para metrami.
            Keďže chceme objekt Atecko alokovať dynamicky, musíme uviesť zápis s kľúčovým slovom New. Teraz si všimnime hlavnú myšlienku OOP. Vyvoláme metódu Pocitaj pre jednotlivé inštancie bez toho, aby sme ju definovali pre každú inštanciu zvlášť! A tu je ten objektovo orientovaný pes zakopaný! Už nemusíme
definovať metódu Pocitaj pre rôzne objekty, ktoré sú potomkom objektu pocitac . Stačí, ak sme ju nadefinovali raz v predkovi, a potomkovia ju iba zdedia! A toto je v štruktúrovanom programovaní nemožné! Jej správnu funkciu pri vyvolaní z rôznych inštancií zabezpečuje práve virtualita metódy Urci_Typ_procesora. Neveríte?
            Ak vám nie je niečo jasné, nezúfajte! Upravte zdrojový text tak, že zmažete slovo "virtual" pri metóde Urci_Typ_procesora , program preložte alebo krokujte! Čo sa stane? Na konci programu nesmieme zabudnúť na uvoľnenie alokovanej pamäte príkazom Dispose . Ak by sme tak neučinili, pamäť by ostala aj po skončení programu obsadená a až do resetu počítača by ju nemohol využiť iný program. A to by sme nechceli. Nabudúce si vysvetlíme ďašie zásady pri tvorbe objektových programov.

 


Nechajte si posielať prehľad najdôležitejších správ emailom

Mohlo by Vás zaujímať

Ako na to

Tipy a triky: Ako na snímku obrazovky na akomkoľvek počítači s Windows?

02.12.2016 00:13

Ak snímky obrazovky robíte často apotrebujete napríklad funkcie na posun stránok alebo snímanie zobrazenia pri vyššom rozlíšení displeja, zrejme používate nejakú špecializovanú aplikáciu. Väčšina použ ...

Ako na to 1

Tipy a triky: Ako aplikácii prednastaviť spúšťanie s administrátorskými právami?

30.11.2016 00:10

Väčšina aspoň trochu skúsenejších používateľov vie, že aj keď máte na operačnom systéme Windows vytvorený administrátorský účet, aplikácie pre bezpečnosť nefungujú vždy splnými administrátorskými práv ...

Ako na to 2

Tipy a triky: Ako vypnúť uzamykaciu obrazovku vo Windows 10?

29.11.2016 00:10

Rozčuľuje vás, že pred každým prihlásením doúčtu vášho počítača musíte prejsť uzamykacou obrazovkou? Windows 10 na tejto obrazovke ukazuje čas,dátum anejakú zaujímavú fotografiu zrôznych kútov sveta. ...

Žiadne komentáre

Vyhľadávanie

Kyocera - prve-zariadenia-formatu-a4-s-vykonom-a3

Najnovšie videá