Přetěžování operátorů ve Free Pascalu - 1. část - Builder.cz - Informacni server o programovani

Odběr fotomagazínu

Fotografický magazín "iZIN IDIF" každý týden ve Vašem e-mailu.
Co nového ve světě fotografie!

 

Zadejte Vaši e-mailovou adresu:

Kamarád fotí rád?

Přihlas ho k odběru fotomagazínu!

 

Zadejte e-mailovou adresu kamaráda:



Delphi

Přetěžování operátorů ve Free Pascalu - 1. část

8. ledna 2002, 00.00 | Ano, ve Free Pascalu není přetěžování operátorů problém. Vše si podrobně ukážeme na příkladu unity pro práci se zlomky - ale dnes se budeme věnovat především teorií.

Jednou z věcí, které mi na Pascalu vždycky chyběly oproti C++ bylo (hned po absenci šablon) přetěžování operátorů. Free Pascal tento nedostatek odstraňuje poměrně pěkným způsobem, a my si ve dvou článcích ukážeme, jak tuto vlastnost použít. Dnes si probereme teorii a připravíme několik pomocných funkcí, příště přetěžování poctivě implementujeme.

Co to je vlastně ono přetěžování? V Pascalu - stejně jako ve většině ostatních jazyků - jsou operátory definovány jen nad konečným počtem datových typů. Například operátorem + můžeme v podstatě sčítat pouze celá či reálná čísla nebo spojovat řetězce. Přetížení operátoru znamená, že definujeme tento operátor i pro jiné typy operandů (většinou i s jiným datovým typem výsledku). Pro názornost se vyplatí představovat si (binární) operátory jako funkce se dvěma parametry a nějakým výsledkem. My jen jakoby dopisujeme nové takové funkce.

V podstatě v každé učebnici C++ se v sekci o přetěžování operátorů obvykle uvádí jeden ze dvou příkladů: komplexní čísla nebo zlomková aritmetika (matematicky přesněji: aritmetika racionálních čísel). Jelikož komplexní čísla co do počtu příkladů v literatuře vedou, přikloním se ve článku tentokrát ke zlomkům. Úkol tedy zní: Napsat knihovnu (unitu) pro počítání s racionálními čísly ve Free Pascalu tak, aby byla co nejlépe použitelná a aby bylo co nejméně poznat, že počítáme se zlomy a ne s obyčejnými čísly - k tomu právě využijeme přetěžování. Podotkněme ještě, že přetěžování operátorů není zapnuto, pokud v kompilátoru nastavíme mód emulace Turbo/Borland Pascalu nebo Delphi, což je ovšem defaultně vypnuto.

Definujeme si tedy typ TZlomek reprezentující zlomek jako podíl dvou celých čísel:

type
  TZlomek = record
    C: Integer;
    J: Integer;
  end;

Zde je třeba se pozastavit u podstatného rozdílu proti C++, a totiž že operátory mohou být definovány i na typy, které nejsou třídami (jako náš TZlomek). Také nemohou být deklarovány jako součásti tříd, což je pro C++ asi nejčastější způsob.

Nejdříve zavedeme pomocnou funkci Zlomek, která vrátí zlomek sestavený ze dvou svých parametrů (čitatele a jmenovatele). V ní použijeme další pomocnou proceduru Zkrat, která zlomek předaný jí jako parametr převede na základní tvar, a v ní pro změnu používáme další pomocnou funkci NSD (největší společný dělitel), která pracuje na principu známého Euklidova algoritmu. Také přidáme proceduru VypisZlomek, která překvapivě vypíše zlomek na obrazovku. Být v céčku, většinu tyto funkcí/procedur by bylo vhodné implementovat jako makra, ale jelikož jsme v Pascalu, musíme se spokojit s procedurami (makra s parametry Free Pascal bohužel neovládá). Kód procedur tedy vypadá takto:

function NSD(A, B: Integer): Integer;
begin
  while A <> B do
    if A > B then Dec(A, B) else Dec(B, A);
  NSD := A;
end;

procedure Zkrat(var Z: TZlomek);
var
  D: Integer;
begin
  if Z.C = 0 then
    Z.J := 1
  else
  begin
    D := NSD(Abs(Z.C), Abs(Z.J));
    if D > 1 then
    begin
      Z.C := Z.C div D;
      Z.J := Z.J div D;
    end;
  end;
end;

function Zlomek(AC, AJ: Integer): TZlomek;
begin
  Zlomek.C := AC;
  Zlomek.J := AJ;
  Zkrat(Zlomek);
end;

procedure VypisZlomek(Z: TZlomek);
begin
  Writeln(Z.C, '/', Z.J);
end;

Povšimněte si, že funkce Zkrat ohlídá i případ, kdy čitatel je roven nule a v tom případě jmenovatele normalizuje na hodnotu 1. Také je v ní ošetřen případ záporných zlomků - největší společný dělitel se počítá z absolutních hodnot čitatele a jmenovatele.

Teď k vlastním operátorům. Co vlastně všechno budeme potřebovat přetížit? To shrnuje následující schématický výpis:

  • TZlomek := Integer
  • TZlomek <aritmetický_operátor> TZlomek
  • TZlomek <relační_operátor> TZlomek

Především tedy potřebujeme zlomku přiřadit celé číslo (reálné samozřejmě nemůžeme). Pak na zlomky potřebujeme aplikovat aritmetické operátory (+, -, *, /) a také je mezi sebou porovnávat, tj. přetížit relační operátory (=, <, >, <=, >=). Přetěžování typu TZlomek := TZlomek nepotřebujeme, protože přiřazování záznamů (record) umí Free Pascal "sám od sebe"; navíc stejně nedovoluje předefinovat operátor := pro stejné typy na obou stranách.

Všimněte si, že nepotřebujeme definovat operátory typu Integer <aritmetický_operátor> TZlomek a Integer <relační_operátor> TZlomek. To je proto, že kompilátor Pascalu automaticky Integer na jedné straně převede na typ TZlomek (definovali jsme mu pro to přiřazovací operátor, který lze využít i ke konverzím typů!) a tím pádem dostane na obou stranách operátoru typ TZlomek, což už je definovaný případ. Každopádně pokud bychom potřebovali někdy přetížit operátor tak, aby na každé jeho straně byl jiný typ, musíme si uvědomit, že kompilátor nepovažuje žádný operátor za komutativní! Musíme tedy definovat jak případ A <operátor> B, tak B <operátor> A. Díky této vlastnosti (nekomutativitě přetížených operátorů) lze například snadno přetížit operátor * pro násobení matic, ale to už jsme trochu jinde.

Také si povšimněte, že nebudeme přetěžovat operátor <> (nerovná se). Důvodem je, že kompilátor místo toho použije přetížený operátor = a výsledek porovnání zneguje. Přiznám se, že je mi trochu záhadnou, proč to nedělá i u ostatních relačních operátorů ("<" je opak ">=" a ">" je opak "<="), ale s tím se musíme smířit.

Tak, nyní jsme už po teoretické stránce vybaveni pro napsání definic přetížených operátorů. To už si ale (spolu s vysvětlením jejich syntaxe) necháme na příště.

Obsah seriálu (více o seriálu):

Tématické zařazení:

 » Rubriky  » Delphi  

 » Rubriky  » Windows  

 

 

 

Nejčtenější články
Nejlépe hodnocené články

 

Přihlášení k mému účtu

Uživatelské jméno:

Heslo: