Image
17.6.2016 0 Comments

Stretnutie s Pascalom II. /5.časť

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

Minule sme si vytvorili knižnicu MyPoints, kde sme definovali objekt Figure a jeho priameho potomka Point. Vieme, že Point zdedil všetky vlastnosti objektu Figure a tie, ktoré mu nevyhovujú, sme predefinovali podľa svojich potrieb. Hierarchiu objektových typov obvykle budujeme tak, že k skôr definovaným typom (Figure, Point) pridávame ďaľšie ako ich potomkov. Predstavme si teda, že chceme pridať bezprostredného potomka objektu Figure - objektový typ Circle:

type
   Circle = object(Figure)
     Radius: integer;
     procedure Init(InitX,InitY,InitRadius : integer);
     procedure Draw;
     procedure Show;
     procedure Hide;
     proedure MoveTo(NewX, NewY);
   end;

            Aj tento objektový typ zdedí všetky datové položky a metódy od svojho predka. Je však bohatší o ďaľšiu vlastnosť - polomer (radius), takže mu niektoré zdedené metódy nevyhovujú. Môžeme to riešiť klasicky, teda predefinovaním metódy, napr.:

procedure Circle.Draw;
begin
   Graph.Circle(X,Y,radius);
end;

            Na rozdiel od typu Point musíme predefinovať aj metódu Init:

procedure Circle.Init(InitX, InitY, InitRadius);
begin
   Figure.Init(InitX, InitY);
   Radius:= InitRadius;
end;

            Všimnime si, že predefinovaním metódy jej pôvodný význam nestrácame, naopak, môžeme ho s výhodou použiť. Musíme ale rozlišovať príslušnosť identifikátorov jednotke (Graph.Circle) a objektovému typu (Figure.Init).
            Metódy, ktoré sme dosiaľ používali, sa nazývajú statické. Ich väzby sme si už povedali v predchádzajúcich častiach. Ale pri dedení statických metód môže dôjsť k problémom. Pozrime sa na unit MyPoints ešte raz. Všimnime si, že metódy Show, Hide a MoveTo objektový typ Point nezdedí od typu Figure napriek tomu, že sú formálne úplne rovnaké! Líšia sa iba v tom, že metódy typu Figure volajú Figure.Draw a metódy typu Point volajú Point.Draw. Práve kôli tomu ich musíme vždy predefinovať.

            Predstavme si, že v definícii objektového typu Point tieto metódy neuvedieme, a teda sa zdedia v pôvodnom tvare. Ak teraz budeme volať pre nejakú inštanciu (napr.Bod) typu Point napr. metódu Show, bude toto volanie realizované ako Figure.Show, ktoré volá Figure.Draw. Tá nám rozhodne bod nenakreslí. Overte si zapoznámkovaním metód v jednotke MyPoints a krokujte! Je to skutočne tak. (Ak teraz nechápete, čo som vlastne povedal, prečítajte si to niekoľkokrát a snažte sa tomu porozumieť a overte si to na príkladoch, aj mne to trvalo pekne dlho! Jednoduchšie to už v časopise vysvetliť neviem.).
            Nedalo by sa to urobiť jednoduchšie a efektnejšie? Ale áno, použijeme už dávnejšie spomínané virtuálne metódy. Aj ich princíp sme si už hovorili.
            Ak by sme chceli obohatiť jednotku MyPoints o virtuálne metódy, vyzerala by časť INTERFACE takto:

type
  Figure = object
     x,y : integer;
     visible: boolean;
     constructor Init(InitX,InitY : integer);
     function GetX: integer;
     function GetY: integer;
     function IsVisible : boolean;
     procedure Draw; virtual;
     procedure Show;
     procedure Hide;
     procedure MoveTo(NewX, NewY: integer);
  end;
 
  Point = object(Figure);
     procedure Draw; virtual;
 
     (všimnite si, že tu už nič nie je!}
 
  end;

            Vidíte, ako sa zjednoduší zápis objektových potomkov, ak sa používajú virtuálne metódy. Všetky časti objektu sme si už spomínali, ale teraz ich začneme používať v praxi.

            Už nie je potrebné deklarovať totožné metódy Show, Hide a MoveTo u objektu Point, aj keď volajú metódu Draw. Na základe virtuality program vždy použije tú správnu metódu Draw, ktorá prislúcha patričnému objektu.
            Aby naša knižnica MyPoints nebola taká chudobná, deklarujeme ďaľších potomkov - kružnicu (Circle) ako potomka Figure, a oblúk (Arc) a elipsu (Ellipse) ako potomkov Circle. (Čisto teoreticky sú to už vnuci objektového typu Figure). Postavíme ju na základe virtuálnej metódy Draw. Jej výpis je na listingu č.1.
            Aby sme ju otestovali, použijeme demonštračný program MYFIGDEM.PAS na listingu č.2.
A teraz si predstavte situáciu, že vám niekto dal knižnicu MyFigure len v tvare .TPU, teda bez zdrojového textu, a vy chcete pridať nového potomka - úsečku Line. Ako na to? V klasickom použití Turbo Pascalu je to nemožné, ba dokonca ani pri použití objektovo orientovaného programovania so statickými metódami by to nešlo. Ale pri použití virtuálnych metód to nie je nič jednoduchšie. Ukážeme si to!
            Vytvoríme si jednotku NewFigs, kde použijeme jednotku MyFigure. V interfejsovej časti deklarujeme nový objekt Line ako potomka Figure (listing č.3). Na jeho deklaráciu stačí konštruktor Init, datové položky dX a dY typu integer, virtuálna metóda Draw a dve funkcie - GetdX a GetdY. To ostatné, čo je v zložených zátvorkách tento objekt zdedí od svojho predka, ale ja som to schválne napísal pre vašu ilustráciu, čoho nás objekty ušetrujú. V implementačnej časti unitu deklarujeme jednotlivé metódy. Vzhľadom na virtualitu metódy Draw ani tu nie je nutné opakovať identické a zdeditelné metódy Show, Hide a MoveTo.
            Použitie tejto knižnice NewFigs demonštruje program NewFigsDemo (NFIGSDEM.PAS - listing č.4). Je skoro rovnaký ako predchádzajúci príklad MYFIGDEM.PAS z listingu č.2, len má pridané tri riadky, týkajúce sa úsečky Line.
            Ak správne opíšete tento program, pohráte sa s jeho parametrami a budete sledovať jeho činnosť na obrazovke, isto vás napadne, že by sa to akosi dalo urobiť tak, aby sa tie objekty pohybovali plynule. Ale, ale, moji zlatí, to už sú začiatky animácie! A to je ďaľší bod pre objekty. O tom nabudúce.

LISTING č. l

unit MyFigure;

{ Upraven verzia jednotky MyPoints}

INTERFACE

uses Graph, Crt;

const FigColor = White;

{ Figure Color - farba objektu }

type

Figure = object
X,Y: Integer;
Visible: Boolean;
constructor Init(InitX, InitY:
Integer);
function GetX: Integer;
function GetY: Integer;
function IsVisible: Boolean;
procedure Draw; virtual;
procedure Show;
procedure Hide;
procedure MoveTo(NewX, NewY:
Integer);
  end;
Point = object (Figure)  
procedure Draw; virtual;
end;
Circle = object (Figure)
Radius: Integer;
constructor Init(InitX, InitY,
InitRadius: Integer);
procedure Draw; virtual;
end;
Arc = object (Circle)
 StartAngle, EndAngle: Integer;
 constructor Init(InitX, InitY,
InitRadius: Integer;
InitStartAngle,
InitEndAngle: Integer);
procedure Draw; virtual;
end;
Ellipse = object (Circle)
Radius2: Integer;
constructor Init(InitX, InitY,
InitRadius, InitRadius2: Integer);
procedure Draw; virtual;
end;
IMPLEMENTATION
{-------------------}
{ Implementacia metod Figure:
}
{-------------------}
constructor Figure.InitflnitX, InitY:
Integer);
begin
X := InitX;
Y := InitY;
Visible := False;
end;
 
function Figure.GetX: Integer;
begin
GetX := X;
end;
 
function Figure.GetY: Integer;
begin
GetY := Y;
end;
function Figure.IsVisible:  Boolean;
 
begin
IsVisible := Visible;
end;
procedure Figure. Draw;
begin
end;
 
procedure Figure.Show;
begin
Visible := True;
SetColor(FigColor);
Draw;
end;
 
procedure Figure.Hide;
begin
Visible := False;
SetColor(GetBkColor);
Draw;
end;
procedure Figure.MoveTo(NewX, NewY:
Integer);
begin
Hide;
X := NewX;
T := HewY;
Show;
end;
{-----------------------------}
{ Implementacia metod Point:
}
{-----------------------------}
procedure Point.Draw; begin
PutPixel(X, Y, GetColor);
end;
{-----------------------------}
{ Implementacia metod Circle:
}
{-----------------------------}
constructor Circle.Init(InitX, InitY,
InitRadius: Integer);
begin
Figure.Init(InitX, InitY);
Radius := InitRadius;
end;
 
procedure Circle.Draw;
begin
Graph.Circle(X, Y, Radius);
end;
{-----------------------------}
{ Implementacia metod Arc:
}
{-----------------------------}
 
constructor Arc.Init(InitX, InitY,
InitRadius: Integer;
InitStartAngle,
InitEndAngle: Integer);
begin
Circle.Init(InitX, InitY, InitRadius);
StartAngle := InitStartAngle;
EndAngle  := InitEndAngle;
end;
 
procedure Arc.Draw;
begin
Graph.Arc(X, Y, StartAngle, EndAngle,
Radius);
end;
{-----------------------------}
{ Implementacia metod Ellipse:
 
}
{-----------------------------}
 
constructor Ellipse.Init(InitX, InitY,
InitRadius, InitRadius2: Integer);
begin
Circle.Init(InitX, InitY, InitRadius);
Radius2 := InitRadius2;
end;
 
procedure Ellipse.Draw;
begin
Graph.Ellipse(X, Y, O, 360, Radius,
Radius2) ;
end;
END.
 
LISTING č.2
 
program MyFigureDemo;
uses Crt, Graph, MyFigure;
 
var Kruznica: Circle;
    Obluk: Arc;
    Elipsa: Ellipse;
    gd, gm: integer;
    ErrCode  : Integer;
BEGIN
  gd := detect;
  InitGraph(gd,gm,'');
  Kruznica.Init(50,50,30);
{mente tieto parametre !!!)
  Obluk.Init(150,50,50,220,320);
{mente tieto parametre !!!}
  Elipsa,Init(250,50,20,50);
{mente tieto parametre !!!}
  Kruznica.Show;
  Obluk. Show;
  Elipsa.Show;
  while not keypressed do
   begin
Kruznica.MoveTo(random(GetMaxX),ran-
dom(GetMaxY));
Obluk.MoveTo(random(GetMaxX),ran-
dom(GetMaxY));
Elipsa.MoveTo(random(GetMaxX),ran-
dom(GetMaxY));
delay(15000);
 {ak chcete, tak aj tu}
end;
  Kruznica.Hide;
  Obluk. Hide;
  Elipsa.Hide;
  CloseGraph;
END.
LISTING č. 3
unit NewFigs;
INTERFACE
uses Crt, Graph, MyFigure;
type
Line = object (Figure)
{ X,Y: Integer; }
dX, dY : Integer;
{ Visible: Bbolean; }
constructor Init(InitX, InitY,
InitdX, InitdY: Integer);
procedure Draw; virtual;
{ procedure Show; }
{ procedure Hide; }
{ function GetX: Integer; }
{ function GetY: Integer; }
function GetdX: Integer;
 
   function GetdY: Integer;
 { function IsVisible: Boolean; }
 { procedure MoveTo(NewX, NewY:
Integer); }
  end;
IMPLEMENTATION
{------------------------ }
{ Implementacia metod Line: }
{------------------------ }
constructor Line.Init(InitX, InitY,
InitdX, InitdY: Integer);
begin
Figure.Init(InitX, InitY);
dX := InitdX;
dY := InitdY;
end;
 
procedure Line.Draw;
begin
Graph.Idne ( X, Y, X + dX, Y + dY );
end;
 
function Line.GetdX: Integer;
begin
GetdX:=dX;
end;
 
function Line.GetdY: Integer;
begin
GetdY:=dY;
end;
END.
LISTING č. 4
program NewFigsDemo;
uses Crt, Graph, NewFigs, MyFigure;
 
var Kruznica: Circle;
Obluk: Arc;
Elipsa: Ellipse;
Usecka: Line;
gd, gm: integer;
BEGIN
gd := detect;
InitGraph(gd,gm,'');
Kruznica.Init(50,50,30);
Obluk.Init(150,50,50,220,320);
Elipsa.Init(250,50,20,50);
Usecka.Init(350,50,50,0) ;
Kruznica.Show;
Obluk.Show;
Elipsa.Show;
Usecka.Show;
while not keypressed do
 begin
Kruznica.MoveTo(random(GetMaxX),ran-
dom(GetMaxY));
Obluk.MoveTo(random(GetMaxX),ran-
dom(GetMaxY)};
Elipsa.MoveTo(random(GetMaxX),ran-
dom (GetMaxY) );
Usecka.MoveTo(random(GetMaxX),ran-
dom (GetMaxY) );
delay(15000);
end;
  Kruznica.Hide;
  Obluk.Hide;
  Elipsa.Hide;
  Usecka.Hide;
  CloseGraph;
END.

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

Mohlo by Vás zaujímať

Ako na to

Čo robiť keď firme chýba IT expert?

08.12.2016 10:36

IT projekty majú z hľadiska nárokov na kapacity špecialistov premenlivý charakter a v určitých fázach často treba posilniť kapacity IT oddelení externými odborníkmi. Riešením je IT ousourcing, ako fo ...

Ako na to

Ako funguje sandbox?

08.12.2016 15:36

Každá aplikácia môže pre operačný systém počítača či mobilného zariadenia predstavovať potenciálnu hrozbu, a to aj v prípade, ak neobsahuje žiadne bloky škodlivého kódu. Murphyho zákony neúprosne defi ...

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ž ...

Žiadne komentáre

Vyhľadávanie

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

Najnovšie videá