Umíte pascalsky - 32.lekce ...

Umíte pascalsky?
32.lekce
Vytisknout  

Objektově orientované programování II.

Procedury a funkce můžou používat parametrů typu objekt.

Chceme používat proceduru Proved, která provede metodu Podil objektu určeného parametrem.

Deklarace procedury je následující:

procedure Proved (var ktery_objekt:TKalkulacka);
  begin
      ktery_objekt.Podil;
  end;

Volání procedury Proved má tvar

   Proved(kalkulacka);    nebo   Proved(new_kalkulacka);

V této souvislosti se musíme zmínit o kompatibilitě objektů a parametrů.

Pravidla kompatibility
- objektu lze přiřadit objekt téhož typu nebo potomka
- formální parametry je možno nahradit skutečnými téhož typu nebo potomka
Objekt typu potomka je zároveň typu rodiče (ne naopak).


3.Mnohotvárnost (polymorfismus)

Polymorfismus umožňuje, aby měl každý objekt metodu se stejným jménem ale jinak definovanou a při volání této metody odezvu každý jinou, pro daný objek správnou.

Například volání metody Proved(kalkulacka) by měla realizovat celočíselné dělení zadaných čísel a volání metody Proved(new_kalkulacka) by mělo provést reálné dělení. Vyzkoušíme si to v dalším programu.

Příklad 5:
Sestavte program Pocitej_static, který vznikne z předchozího programu Pocitej_vic rozšířením o volbu volání procedury Proved s parametrem kalkulacka a new_kalkulacka.

Doplníme tedy předchozí program o deklaraci procedury Proved:

 procedure Proved(var ktery_objekt:TKalkulacka);
   begin
       ktery_objekt.Podil;
   end;

{měla by volat metodu Podil}
{u objektu daného parametrem}

Hlavní program o volby 6 a 7 - volání Proved.

        6:Proved(kalkulacka);
        7:Proved(new_kalkulacka);
{Proved pro kalkulacku}
{Proved pro new_kalkulacku}


Jistě jste zjistili, že program Pocite_static ještě nesplňuje naše předpoklady. Nedokáže voláním jedné metody pro různé objekty realizovat správnou, různou odezvu. Procedura Proved vyvolá pro objekt kalkulacka i new_kalkulacka stejnou metodu (kalkulacka.Podil) pro celočíselné dělení. To je způsobením tím, že všechny dosud poznané metody jsou statické.


Statické metody

Metody, u nichž se všechna jejich volání již v době překladu nahrazují odpovídajícím kódem a řeší všechny vztahy mezi metodami a objekty. Těmto vztahům říkáme brzká vazba (early binding). Volá se vždy "nejstarší" - hierarchicky nejnižší (směrem k předkům) - statická metoda stejného jména.

Příklad:
Ve volbě 6 a 7 v našem programu Pocitej_vic by procedura Proved(ktery_objekt) měla volat metodu Podil pro objekt kalkulacka (vypočítat celočíselný podíl) nebo new_kalkulacka (vypočítat reálný podíl), podle hodnoty parametru ktery_objekt. Která z nich to bude se u takto deklarované metody Podil musí rozhodnou již při překladu programu. A podle výše uvedeného je tedy výsledkem volání procedury Proved (nezávisle na parametru) volání metody Podil "nejstaršího" objektu - tedy Podil pro kalkulacka a to je celočíselné dělení. (volba 6 i 7 poskytuje celočíselný podíl).


Statické metody neumožňují realizovat polymorfismus OOP. Na druhé straně jsou velmi rychlé a efektivní při jejich realizaci.
Vazby mezi statickými metodami a daty jsou vytvářeny již během překladu a během programu se nemění.


Virtuální metody (dynamické metody)

Umožňující rozhodnout, která z metod uložených pod stejným jménem se vyvolá až za běhu programu - pozdní vazba (late binding). Protože virtuální metody nabízejí možnost vytváření vazby mezi objekty a jejich metodami až v době výpočtu, jsou tyto metody pomalejší při vykonávání než metody statické.
Virtuální metody umožňují polymorfismus. Stejná zpráva (metoda se stejným jménem) může vyvolat u různých objektů různé reakce.

Deklarace objektu s virtuálními metodami.

Implementace metod se nemění, mění se jen hlavičky. Za hlavičkou metody uvedeme klíčové slovo virtual.
Je-li metoda deklarována jako virtuální, musí být virtuální i všechny její následovnice.

Každý objekt, který používá virtuální metody musí mít constructor - statická metoda, která inicializuje mechanismus volání virtuálních metod (procedure nahradíme slovem constructor). Musí být vyvolána před prvním voláním libovolné virtuální metody.

Každá proměnná obsahující virtuální metodu spolupracuje s tabulkou VMT (Virtual method table) - obsahuje adresy metod. Voláním konstruktoru se vytváří a naplňuje tabulka VMT a při volání metody je její adresa v ní nalezena.


type <název> = object {popis}
<dat.položka1> : <typ1>;

<dat.položkan> : <typn>;
{deklarace datových položek}
constructor <název_constr>;
procedure <metoda1>; virtual;
function <metoda2>: <typ>;virtual;
{komstruktor}

{virtální metody}
end;
constructor <název>.<metoda1>;
     begin
         <příkazy>
     end;
procedure <název>.<metoda1>;
     begin
         <příkazy>
     end;
function <název>.<metoda2>:<typ>;
     begin
         <příkazy>
     end;
{implementace metod}



{deklarace těl procedur a funkcí}





Příklad 6:
Upravte program Pocitej_static tak, aby používal virtuálních metodu Podil v objektové proměnné typu TKalkulacka a TNewKalkulacka - tedy fungovala i volba 6 a 7 z předchozího programu.

Musíme statickou metodu Podil změnit na virtuální. Toho dosáhneme změnou hlavičky přidáním klíčového slova virtual.
Dále je třeba objekt s virtuální metodou (TKalkulacka i TNewKalkulacka) doplnit konstruktorem (stačí pouze TKalkulacka, protože TNewKalkulacka ho zdědí).
Tím vznikne program Pocitej_virtualne. Změněné části proti progarmu Pocitej_static uvádíme červeně.

Program Pocitej_virtualne může vypadat takto:

program Pocitej_virtualne;

  uses Crt;

{připojení jednotky Crt}
  type TKalkulacka = object  
cislo1, cislo2, vysledek: integer; {cislo1, cislo2 - operandy, vysledek je výsledek}
constructor Init (ZadX, ZadY: integer);
function Soucin: integer;
procedure Podil; virtual;
{zadání operandů}

{výpočet součinu}
{výpočet celočísel.podílu}
end;      
  constructor TKalkulacka.Init(ZadX,ZadY:integer);
     begin
         cislo1:=ZadX;
         cislo2:=ZadY;
     end;
  function TKalkulacka.Soucin: integer;
     begin
         Soucin:=cislo1*cislo2;;
     end;
  procedure TKalkulacka.Podil;
     begin
         vysledek:=cislo1 div cislo2;
         writeln('Celociselnz podik cisel ',cislo1,'/',cislo2,'=',vysledek);
     end;
{popis konstruktoru Init}

{operandy budou vstupní parametry ZadX, ZadY}


{popis metody Soucin}

{vypočte součin operandů}

{popis metody Podil}

{vypočte celočís.podíl operandů}
{vytiskne výsledk}


  type TNewKalkulacka = object(TKalkulacka)  
vysl_podil:real; {nová datová položka}
procedure Podil; virtual;
function Mocnina: real;
{modifikace metody Podil}
{nová metoda Mocnina}
end;                           
procedure TNewKalkulacka.Podil;
     begin
         if cislo2<>0 then
            begin
             vysl_podil:=cislo1/cislo2;
             writeln('Podil cisel ',cislo1,'/',cislo2,'=',vysl_podil:5:2);
            end
          else
             writeln('Podil neni definovan');
     end;
function TNewKalkulacka.Mocnina:real;
     begin
         Mocnina:=exp(cislo2*ln(cislo1));
     end;
{modifikace metody Podil}

{počítá podíl jako real.číslo}






{popis metody Mocnina}

{vypočte mocniu cislo1 na cislo2}


 procedure Proved(var ktery_objekt:TKalkulacka);
   begin
       ktery_objekt.Podil;
   end;

{volá metodu Podil}
{u objektu daného parametrem}

var  kalkulacka:TKalkulacka;
        new_kalkulacka:TNewKalkulacka;
        volba,prvni_cislo,druhe_cislo:integer;

{globální objektová proměnná }
{potomek proměnné}
{další globální proměnné}

Begin
   clrscr;
   writeln('Program Pocitej_vic umoznuje podle volby uzivatele:');
   repeat
     writeln;
     writeln('1 - zadat dve cela cisla');;
     writeln('2 - vypocitat jejich soucin');
     writeln('3 - vypocitat jejich celočiselný podil');
     writeln('4 - vypocitat jejich podil');
     writeln('5 - vypocitat jejich mocninu');
     writeln('6 - vola Proved pro objekt kalkulacka');
     writeln('7 - vola Proved pro objekt new_kalkulacka');;
     writeln('0 - ukoncit cinnost');writeln;;
     write('Zadejte svoji volbu:');readln(volba);writeln;
     case volba of
        1:begin
            write('Zadej dve cela cisla:');
            readln(prvni_cislo,druhe_cislo);
            kalkulacka.Init(prvni_cislo,druhe_cislo);
            new_kalkulacka.Init(prvni_cislo,druhe_cislo);
           end;
        2:writeln('Soucin ',prvni_cislo,'*', druhe_cislo ,'=', kalkulacka. Soucin);
        3:kalkulacka.Podil;
        4:new_kalkulacka.Podil;
        5:writeln('Mocnina ',prvni_cislo,' na ',druhe_cislo,'=', new_kalkulacka.Mocnina:5:2);
        6:Proved(kalkulacka);
        7:Proved(new_kalkulacka);
        0:;
      end;
   until volba=0


{opakuje}





{nabídka programu}



{zadáni volby}



{zadání čísel}


{součin čísel}
{celočíselný podíl čísel}
{reálný podíl čísel}
{mocnina čísel}
{Proved pro kalkulacku}

{Proved pro new_kalkulacku}

{program končí nulou}

End.


Jednou z velkých předností OOP je možnost pozdější modifikace již odladěného a zkompilovaného programu. Nejprve napíšeme a zkompilujeme modul (.TPU) s objekty.

Například modul Kalku s objektem TKalkulacka vypadá takto:

unit Kalku;

 interface

{veřejná část}
  type TKalkulacka = object  
cislo1, cislo2, vysledek: integer; {cislo1, cislo2 - operandy, vysledek je výsledek}
constructor Init (ZadX, ZadY: integer);
function Soucin: integer;
procedure Podil; virtual;
{zadání operandů}

{výpočet součinu}
{výpočet celočísel.podílu}
end;      

 implementation

{soukoromá část}
  constructor TKalkulacka.Init(ZadX,ZadY:integer);
     begin
         cislo1:=ZadX;
         cislo2:=ZadY;
     end;
  function TKalkulacka.Soucin: integer;
     begin
         Soucin:=cislo1*cislo2;;
     end;
  procedure TKalkulacka.Podil;
     begin
         vysledek:=cislo1 div cislo2;
         writeln('Celociselnz podik cisel ',cislo1,'/',cislo2,'=',vysledek);
     end;
{popis konstruktoru Init}

{operandy budou vstupní parametry ZadX, ZadY}


{popis metody Soucin}

{vypočte součin operandů}

{popis metody Podil}

{vypočte celočís.podíl operandů}
{vytiskne výsledk}


 BEGIN
 END.


{výkonná část}


Potom můžeme v novém programu připojit tento modul a deklarovat potomka (rodič v modulu) s modifikovanými a novými metodami.
Vytvořte program Pocitej_virtualne_modul, který vznikne z programu Pocitej_virtualne aplikací ukázaného modulu Kalku.


Domácí úkol:

Objekty TKalkulacka a TNewKalkulacka zkompilujte do modulu Kalk. V programu Pocitej_super připojte modul Kalk a deklarujte potomka TSuperKalkulacka, který má modifikovanou metodu Podil (počítá podíl čísel v procentech) a novou metodu Odmocnina (počítá cislo2-tou odmocninu z císla1). Hlavní program umožňuje podle volby uživatele provést všechny operace s celými čísly (tři druhy podílu procedurou Proved).

On-line účast na řešení úkolu

Řešit úkol Prohlídka hodnocení úkolu Dotazy,připomínky

Pomocí volby Řešit můžete (po přihlášení) odeslat vaše řešení domácího úkolu (každý úkol smíte řešit jen jednou). Volbou Hodnocení si přečtete hodnocení a komentář od vyučujícího. Dotaz nebo připomínku můžete opakovaně zasílat pomocí tlačítka Dotazy, Komunikace (na levém okraji) zobrazuje příklad možné komunikace s vyučujícím.