int21h

Pseudopole v pascalu

Co je pole, je jasné. Pascal ale zná i tzv. pseudopole. Z klasického Turbo pascalu určitě znáte pseudopole Port a PortW. Zde je na místě otázka, co je to vlastně zač. Není to blok paměti, ale jakýsi virtualizovaný přístup ke skrytým procedurám. To může být užitečné i v mnoha jiných případech, ale bohužel, Turbo pascal neumožňuje tvořit si vlastní pseudopole. To je rys, pro který bývá pascal vysmívaný programátory jiných jazyků, tedy, že programátor nemůže vytvořit analogie některých zabudovaných konstrukcí. A z toho odvozují, že pascal není plnohodnotný programovací jazyk. To je samozřejmě nesmysl a navíc pro Freepascal neplatí ani první část námitky. Ve Freepascalu totiž je možné tvořit vlastní pseudopole a umí to obě generace: 1.x.x i 2.x.x.>

Pseudoproměnné

Než se pustíme do pseudopolí, začneme trochu jednoduššími pseudoproměnnými. Pozadí této syntaxe je dosti složité a v tomto článku se nebudu pouštět do rozsáhlého výkladu a omezím se jen na minimum. Teorii a systematický výklad syntaxe si můžete přečíst z manuálu k Freepascalu nebo z jakékoliv lepší knihy o Delphi.
Pseudoproměnné jsou odvozeny od jedné vlastnosti tříd z objektového programování. Přípomeňme si, že TP i BP znají tzv. objekty, což je seskupení procedur, funkcí a proměnných, ve kterých procedury a funkce objektu společně sdílí proměnné objektu. Freepascal (a Delphi) kromě objektů znají i třídy (class), které koncept objektů v různých aspektech rozšířují. Jedním z rozšíření jsou tzv. properties, což se do češtiny překládá jako vlastnosti.
Ukažme si prográmek:
{$MODE OBJFPC}         {Nutno zapnout budto takto nebo pomoci nastaveni v menu}
type TTrida = class
     public
        Procedure PriradCislo(i:longint);
        Function ZjistiCislo:longint;
        property cislo:longint read ZjistiCislo write PriradCislo;

     protected
        vnitrnicislo:shortint;
     end;

Procedure TTrida.PriradCislo(i:longint);
begin
if i<(-128) then i:=-128;
if i>127 then i:=127;
vnitrnicislo:=i;
end;

Function TTrida.ZjistiCislo:longint;
begin
ZjistiCislo:=vnitrnicislo;
end;

var trida:TTrida;
begin
trida:=TTrida.Create;
trida.cislo:=4543;
writeln(trida.cislo);
readln;
end.
Před sebou máme ne zcela triviální kód, který přiřadí proměnné vnitrnicislo hodnotu. Možná se ptáte, proč to dělat tak složitě, když by prostě stačilo ponechat vnitrnicislo v režimu public a provést přiřazení:
trida.vnitrnicislo:=HODNOTA
No jo, jenže všimněte si, že vnitrnicislo je jenom shortint a lehko bychom mohli přiřadit hodnotu mimo rozsah, což by vedlo k neočekávanému chování programu. Oklika přes pseudoproměnnou cislo umožňuje provést kontrolu rozsahu a podobným věcem zamezit. A nejen to. Obsah obslužných funkcí PriradCislo a ZjistiCislo může být libovolný a zdaleka se nemusí jen omezovat na kontroly rozsahů. Jako dobrý způsob použití mě napadá ukládání přiřazovaných hodnot do logovacího souboru, což by umožňovalo snadnější analýzu chyb.

Pseudopole

Pseudopole jsou dalším drobným rozšířením vymoženosti property, potažmo pseudoproměnných. Bez dlouhých řečí si ukažme kód, který se podobá standardní pascalovské definici pseudopole Port
{$MODE OBJFPC}
{$CALLING OLDFPCCALL}
type TBrana = class
     public
        Procedure DoPortu(p:word;b:byte);
        Function ZPortu(p:word):byte;
        property B[p:word]:byte read ZPortu write Doportu;
     end;

Procedure TBrana.DoPortu(p:word;b:byte);assembler;
asm
mov dx,p
mov al,b
out dx,al
end;

Function TBrana.ZPortu(p:word):byte;assembler;
asm
mov dx,p
in al,dx
end;

var brana:TBrana;
    i:longint;
    a:byte;
begin
brana:=TBrana.Create; {ve skutecnosti neni nutne, nebot nepristupujeme k zadnym datum tridy}

writeln('Po zmacknuti Enteru program pocka 700 snimkovych behu, tedy 10 sekund');
readln;
writeln('Start!');
for i:=1 to 700 do
    begin
    while Brana.B[$3da] and 8 <> 0 do;
    while Brana.B[$3da] and 8 = 0 do;
    end;
writeln('Cas uplynul!');
readln;
end.
Docela se to už podobá pascalovskému pseudopoli Port, že? Ale jak odstranit ono ohyzné "Brana.B" a nahradit to prostým "Brana"? Jde to? Ano, jde.
Do deklarace property jde totiž vsunout kouzelný modifikátor default, který umožní vynechat část ".B"
Takže do třetice krátký prográmek, který připraví pseudopole přesně tak, jak jsme zvyklí. Opakovat příklad z porty by ale bylo nudné, takže si ukážeme, jak virtualizovat obrazovku do dvourozměrného pseudopole, a připomeneme si, jak ve Freepascalu provést přímý zápis do videopaměti.
{$MODE OBJFPC}
const SIRKAOBRAZOVKY:longint = 80;
      VYSKAOBRAZOVKY:longint = 25;

type
     TObr = class
     private
        Function RozsahOK(x,y:byte):boolean;
        Procedure ZapisZnak(x,y:byte;c:char);
        Function PrectiZnak(x,y:byte):char;
     public
        property ZZ[x,y:byte]:char read PrectiZnak write ZapisZnak;default;
        end;

Function TObr.RozsahOK(x,y:byte):boolean;
begin
RozsahOK:=(x>0) and (y>0) and (x<=SIRKAOBRAZOVKY) and (y<=VYSKAOBRAZOVKY);
end;

Procedure TObr.ZapisZnak(x,y:byte;c:char);
begin
if RozsahOK(x,y) then
   asm
   movzx ebx,y
   movzx eax,x
   dec ebx
   dec eax
   imul ebx,SIRKAOBRAZOVKY
   add ebx,eax
   shl ebx,1
   add ebx,0B8000h
   mov al,c
   mov fs:[ebx],al
   end;
end;

Function TObr.PrectiZnak(x,y:byte):char;
begin
if RozsahOK(x,y) then
   asm
   movzx ebx,y
   movzx eax,x
   dec ebx
   dec eax
   imul ebx,SIRKAOBRAZOVKY
   add ebx,eax
   shl ebx,1
   add ebx,0B8000h
   mov al,fs:[ebx]
   end;
end;

var Obr:TObr;
    x,y:byte;
    
begin
{Obr:=TObr.Create}   {neni treba, protoze neprisupuji k promennym tridy}
for y:=10 to 20 do
    for x:=20 to 60 do
        Obr[x,y]:='*';  {Mozno i Obr.ZZ[x,y]:='*'  (ale proc tak osklive?)}
readln;
end.
Properties mají pochopitelně mnohem širší použití než jen tvorba psedopolí. Velice užiteční jsou například v tvorbě užívatelských rozhraní (GUI), kdy je jejich pomocí možné dosáhnout toho aby se při změně parametrů grafického prvku změna okamžitě projevila na obrazovce. Například zavoláním...
Tlacitko.text:='zmeneny text';
...patřičně obaleným v properties dosáhneme toho, aby měnící procedura rovnou zavolala Tlacitko.Draw a změna se tak ihned projevila na obrazovce.

A to je vše.
2009-07-12 | Laaca
Reklamy:
Trávicí enzymy pro podporu zažívání trávení