|
|
|
Zapúzdrenie |
|
Dedičnosť |
|
Polymorfizmus |
|
|
|
|
|
|
|
|
|
|
var
g:TCanvas; |
|
type
TKruh = class |
|
private |
|
x,y,r:integer; f:TColor; vid:boolean; |
|
public |
|
constructor Create(xx,yy,rr:integer); |
|
procedure ukaz; |
|
procedure skry; |
|
procedure ZmenFarbu(ff:TColor); |
|
procedure posun(dx,dy:integer); |
|
end; |
|
|
|
|
|
|
Constructor TKruh.Create(xx,yy,rr:integer); |
|
begin |
|
x:=xx; y:=yy; r:=rr;
vid:=false; f:=clBlack; |
|
end; |
|
procedure TKruh.ukaz; |
|
begin |
|
g.Pen.Color:=f;
g.Brush.Style:=bsClear; g.Ellipse(x-r,y-r,x+r,y+r); vid:=true; |
|
end; |
|
|
|
|
|
|
procedure TKruh.skry; |
|
begin |
|
g.Pen.Color:=clWhite; |
|
g.Brush.Style:=bsClear; |
|
g.Ellipse(x-r,y-r,x+r,y+r);
vid:=false; |
|
end; |
|
|
|
procedure TKruh.ZmenFarbu(ff:TColor); |
|
begin |
|
f:=ff; if vid then ukaz; |
|
end; |
|
|
|
|
procedure TKruh.posun(dx,dy:integer); |
|
var b:boolean; |
|
begin |
|
b:=vid; if vid then skry; |
|
inc(x,dx); inc(y,dy); |
|
if b
then ukaz; |
|
end; |
|
|
|
|
|
|
var a,b,c:TKruh; |
|
poc:integer; |
|
|
|
procedure TForm1.FormCreate(Sender:TObject); |
|
begin |
|
g:=Image1.Canvas; |
|
end; |
|
|
|
|
|
|
procedure TForm1.Button1Click(Sender:TObject); |
|
begin |
|
a:=TKruh.Create(100,100,50); |
|
with a do |
|
begin ZmenFarbu(clGreen); |
|
ukaz; |
|
end; |
|
end; |
|
|
|
|
|
|
procedure TForm1.Button2Click(Sender:TObject); |
|
begin b:=TKruh.Create(300,200,100); |
|
b.ZmenFarbu(clRed); b.ukaz; |
|
end; |
|
|
|
procedure TForm1.Button3Click(Sender:TObject); |
|
begin |
|
c:=TKruh.Create(200,250,70); c.ukaz; |
|
end; |
|
|
|
|
|
|
procedure TForm1.Button4Click(Sender:TObject); |
|
begin |
|
poc:=100; Timer1.Enabled:=true; |
|
end; |
|
procedure TForm1.Timer1Timer(Sender:TObject); |
|
begin if a<>nil then a.posun(3,2); |
|
if b<>nil then b.posun(-5,-1); |
|
if c<>nil then c.posun(2,-3); dec(poc); |
|
if poc<=0 then Timer1.Enabled:=false; |
|
end; |
|
|
|
|
|
|
procedure TForm1.Button5Click(Sender:TObject); |
|
begin if a<>nil then with a do |
|
begin if vid then skry;
Free; a:=nil; end; |
|
if b<>nil then with b do |
|
begin if vid then skry;
Free; b:=nil; end; |
|
if c<>nil then with c do |
|
begin if vid then skry; Free; c:=nil; end; |
|
end; |
|
|
|
|
|
|
type TStvorec = class(TKruh) |
|
public |
|
procedure ukaz; |
|
procedure skry; |
|
procedure ZmenFarbu(ff:TColor); |
|
procedure posun(dx,dy:integer); |
|
end; |
|
|
|
|
|
|
procedure TStvorec.ukaz; |
|
begin |
|
g.Pen.Color:=f; |
|
g.Brush.Style:=bsClear; |
|
g.Rectangle(x-r,y-r,x+r,y+r);
vid:=true; |
|
end; |
|
|
|
procedure TStvorec.skry; |
|
begin |
|
g.Pen.Color:=clWhite; |
|
g.Brush.Style:=bsClear; |
|
g.Rectangle(x-r,y-r,x+r,y+r);
vid:=false; |
|
end; |
|
|
|
|
procedure TStvorec.ZmenFarbu(ff:TColor); |
|
begin |
|
f:=ff; if vid then ukaz; |
|
end; |
|
procedure TStvorec.posun(dx,dy:integer); |
|
var b:boolean; |
|
begin b:=vid; if vid then skry; |
|
inc(x,dx); inc(y,dy); |
|
if b then ukaz; |
|
end; |
|
|
|
|
|
|
|
|
|
|
|
ak porovnáme metódy ZmenFarbu a posun v oboch
triedach, zistíme, že sú úplne identické, takže sa ich pokúsime v triede TStvorec
vyhodiť: kompilátoru to nevadí - pochopí, že sa majú zdediť, |
|
ale projekt už nefunguje správne ... |
|
|
|
|
|
|
|
|
Virtuálne metódy |
|
|
|
potrebovali by sme, aby TKruh.posun "pochopil", že bol
zavolaný z potomka a teda nebude volať svoj TKruh.skry ale potomkovu metódu
skry: |
|
TKruh.posun -- TKruh.skry
// skry je virtuálna
^ \
| \
TStvorec.posun --> TStvorec.skry // skry je virtuálna |
|
|
|
|
|
|
zrejme sa to nedá urobiť počas kompilácie, lebo
TKruh.posun nemôže "tušiť", že niekedy v budúcnosti si niekto
niekde inde naprogramuje veľa potomkov, ktoré budú volať TKruh.posun |
|
|
|
|
|
|
|
|
Polymorfizmus |
|
|
|
metóda sa zdieľa v rôznych stupňoch objektovej
hierarchie -> |
|
napr. vtedy, ak rôzne triedy zdedia
"spoločnú" metódu (napr. metódu posun), ale detaily pre rôzne
objekty zodpovedajú ich zvláštnostiam (napr. metóda skry) |
|
|
|
|
|
|
kompilátor - okamžité rozhodnutie pri statických
metódach odložené rozhodnutie pri virtuálnych metódach |
|
zatiaľ nevieš, ktorú metódu
(ktorého objektu), keď príde čas volania, opýtaj sa inštancie (premennej
typu objekt) |
|
pri statických metódach kompilátor hľadá
zodpovedajúce meno v hierarchii smerom k predkom od danej úrovne (kde je
definovaná metóda) |
|
|
|
|
pri virtuálnych metódach nie kompilátor, ale
počas behu sa hľadá zodpovedajúce meno v hierarchii smerom k predkom, ale
od úrovne inštancie |
|
včasná väzba = early binding - pri statických |
|
neskorá väzba = late binding - pri virtuálnych |
|
|
|
|
|
|
|
|
Virtuálne metódy |
|
|
|
v deklarácii objektu virtual |
|
ak je v nejakej triede virtuálna metóda =>
všetci potomkovia, ak majú metódu tohoto mena, mali by mať override
(prekryje virtuálnu metódu) a s rovnakou hlavičkou - bez override sa táto
definícia bude chápať ako "predefinovanie" virtuálnej na statickú |
|
|
|
|
každý objekt obsahuje VMT (Virtual Method Table): |
|
konštruktor objektu inicializuje napojenie na
túto tabuľku |
|
každá inštancia obsahuje len referenciu na túto
(jedinú pre danú triedu) tabuľku - je to prvá položka v zázname |
|
|
|
|
|
|
|
|
hovoríme, že konštruktor môže byť použitý aj na
inicializovanie stavových premenných - jeho "hlavná" funkcia je
vyhradiť pamäť pre objekt a inicializovať VMT !!! |
|
|
|
|
|
|
|
|
Kompatibilita tried (objektových typov) |
|
|
|
kompatibilita je jednosmerná => odvodený typ
dedí kompatibilitu so svojimi predkami (kompatibilita s predkami nie
potomkami) |
|
medzi inštanciami |
|
medzi formálnymi a skutočnými parametrami |
|
|
|
|
|
|
máme deklarácie: |
|
var a,c:TKruh; |
|
b:TStvorec; |
|
|
|
potom je povolené: |
|
a:=TKruh.Create(...); |
|
b:=TStvorec.Create(...); |
|
c:=b; // c
referencuje tú istú inštanciu ako b |
|
c:=TStvorec.Create(...); |
|
|
|
procedure zmen(k:TKruh); |
|
begin |
|
k.ZmenFarbu(clBlue); |
|
k.posun(1,1); |
|
end; |
|
|
|
|
|
|
|
a tiež môže byť volané: |
|
|
|
zmen(b); |
|
===> formálny parameter k je polymorfný
objekt (rôznorodý) |
|
|
|
===> potomok môže kdekoľvek nahradiť predka
(predok môže zastupovať potomka) |
|
|
|