Objektovo orientované programovanie umožňuje zadefinovať tzv. objekty - špeciálne premenné, ktoré uchovávajú svoj stav a komunikujú s ostatnými objektami. Pokúsim sa zhrnúť najdôležitejšie informácie na túto tému.
V TurboPascale 7 existuje kľúčové slovo object
, ale skutočnú podporu tried a objektov nájdeme až v Object Pascale a Free Pascale.
Ak sa vám vo Free Pascale nebude dariť skompilovať zdrojové kódy uvedené v tomto článku, je potrebné nastaviť ho: menu Options / Compiler, záložka Syntax, odstavec Compiler mode - vyberte možnosť Object Pascal extension on, prípadne Delphi compatible.
Veľmi zjednodušene možno povedať, že trieda je určitý typ premennej. Objekt je zas premenná typu trieda.
Pokúsime sa vytvoriť program, v ktorom vytvoríme triedu TSkola
. Bude v nej zadefinovaný atribút (niečo ako vlastnosť) - premenná Ziaci (typu integer
); ďalej tzv. metóda - procedúra PrijmiZiakov(pocet: integer)
, ktorá prijme určitý počet nových žiakov na školu a pripočíta ich k súčasnému počtu. Metóda VyhodZiaka
zmenší počet žiakov školy o 1. Funkcia (metóda) PocetLudi
vráti celkový počet ľudí na škole.
Konštruktor (constructor
) je špeciálnu metóda, ktorá sa zavolá pri vytvorení nového objektu typu TSkola
. Jeho úlohou bude nastaviť počiatočný počet žiakov na škole. Naopak, deštruktor (destructor
) sa vykoná pri zaniknutí objektu danej triedy. Ten však dnes nevyužijeme.
Zdrojový kód v dnešnom článku je trocha dlhší, preto som ho trošku rozkúskoval.
program objekty; const {pocet zamestnancov skoly je konstantny} Zamestnanci = 50; type TSkola = class {pocet ziakov na skole} Ziaci: integer; {prijatie dalsich ziakov} procedure PrijmiZiakov(pocet: integer); {vyhodenie ziaka zo skoly} procedure VyhodZiaka; {funkcia vrati celkovy pocet ludi na skole} function PocetLudi: integer; {konstruktor volany pri vytvoreni objektu} constructor Create; end;
To bola deklarácia. Kľúčovým slovom type
sme zadefinovali nový typ premennej - triedu (class
) TSkola
. Nasledoval akýsi výpis atribútov a metód.
Naprogramujme samotné „telá“ metód. Názvy sa tvoria spôsobom meno_triedy.Procedúra
.
procedure TSkola.PrijmiZiakov(pocet: integer); begin Ziaci := Ziaci+pocet; end; procedure TSkola.VyhodZiaka; begin {pascalovska procedura Dec zmensi pocet ziakov o 1} Dec(Ziaci); end; function TSkola.PocetLudi: integer; begin {vratime celkovy pocet ludi} PocetLudi := Zamestnanci+Ziaci; end;
Podobne napíšeme kód konštruktora Create
.
constructor TSkola.Create; begin {na zaciatku bude v kazdej skole 300 ziakov} Ziaci := 300; end;
To však nie je všetko - zdrojový kód nášho programu pokračuje ďalej.
Vytvoríme objekt typu TSkola
. Môže ich byť aj viacej. Každá škola má atribúty a metódy Ziaci
, VyhodZiaka
, atď. No jedna z nich bude mať po prijatí nových študentov 450 žiakov a druhá po ich vyhodení 280. To je jedna z výhod objektového programovania - môžeme vytvoriť viac inštancií jednej triedy.
Deklarujme premenné (objekty) ZSMala a VelkeGymnazium typu TSkola
:
var ZSMala, VelkeGymnazium: TSkola;
Konečne môžeme objekty vytvoriť, a to pomocou ich konštruktora.
begin ZSMala := TSkola.Create; VelkeGymnazium := TSkola.Create;
Nakoniec budeme s objektmi pracovať. Oddeľovačom medzi objektom a jeho atribútom, resp. metódou, je vždy bodka.
ZSMala.PrijmiZiakov(150); {300 ziakov + 50 zamestnancov + 150 prijatych = 500 ludi} writeln('ZSMala: ', ZSMala.PocetLudi, ' ludi'); VelkeGymnazium.VyhodZiaka; {300 + 50 - 1 = 349} writeln('Velky gympel: ', VelkeGymnazium.PocetLudi, ' ludi'); end.
Program môžeme spustiť a vyskúšať.
Dedičnosť je jednou z vlastností OOP. Predstavme si, že chceme navrhnúť novú triedu - TGymnazium
, ktorá by mala okrem vlastností triedy TSkola
navyše vlastnosť PocetRocnikov. Nemusíme programovať všetko odznova, stačí ju vytvoriť takto:
type TSkola = class ... (tu nič nemeníme) ... end; TGymnazium = class(TSkola) PocetRocnikov: byte; end;
Trieda TGymnazium
zdedila atribúty a metódy triedy TSkola
- je teda jej potomkom. Pribudol jej však PocetRocnikov.
Ešte zmeníme zvyšok kódu:
var ... VelkeGymnazium: TGymnazium; begin ... VelkeGymnazium: TGymnazium.Create;
Odteraz môžeme pracovať aj s premennou VelkeGymnazium.PocetRocnikov. Zápis ZSMala.PocetRocnikov je však nesprávny.
Ak chceme zamedziť prístupu k daným atribútom alebo metódam z určitých častí kódu, používame kľúčové slová private
(súkromné - neprístupné mimo triedy), public
(verejné - prístupné z akejkoľvek časti kódu), protected
(prístupné len pre danú triedu a jej potomkov) a published
(niečo podobné ako public
). Použitie je nasledovné:
type TSkola = class private Ziaci: integer; public procedure PrijmiZiakov(pocet: integer); ... end;
Bežný postup pri návrhu triedy je taký, že atribúty (členské premenné) by mali byť neprístupné pre ostatné triedy. Okolitý svet s nimi môže manipulovať prostredníctvom vhodných metód. Takéto spojenie stavu a správania sa nazýva zapúzdrenie. Význam spočíva v tom, že používateľ našej triedy nebude môcť zmeniť jej vnútorný stav, čím by mohol spôsobiť chyby.
Máme základnú triedu a niekoľko (napr. dve) z nej odvodených:
type TSkola = class function TypSkoly: string; virtual; abstract; end; TGymnazium = class(TSkola) function TypSkoly: string; override; end; TZakladnaSkola = class(TSkola) function TypSkoly: string; override; end;
Funkcie TGymnazium.TypSkoly
a TZakladnaSkola.TypSkoly
vrátia reťazec obsahujúci typ školy (implementáciu nechávam na Vás). Teraz vytvoríme funkciu, ktorá vypíše typ akejkoľvek konkrétnej školy, či už je to gymnázium, základná škola, alebo dokonca vysoká (keby sme takú v budúcnosti navrhli).
procedure VypisTypSkoly(skola: TSkola); begin writeln(skola.TypSkoly); end;
Hoci parameter je typu TSkola
, pri zavolaní tejto procedúry s parametrom typu TGymnazium
sa zavolá metóda TGymnazium.TypSkoly
a pri TZakladnaSkola
sa zavolá TZakladnaSkola.TypSkoly
. Tento zaujímavý jav sa nazýva polymorfizmus.