Objektově orientované programování (OOP) je po strukturovaném programování

Podobné dokumenty
NMIN201 Objektově orientované programování 1 / :36:09

NPRG031 Programování II 1 / :25:46

7. OBJEKTOVĚ ORIENTOVANÉ PROGRAMOVÁNÍ

Anotace. Objekt self, Zapouzdření, polymorfismus,

1. D Y N A M I C K É DAT O V É STRUKTUR Y

Dědění, polymorfismus

Polymorfismus. Časová náročnost lekce: 3 hodiny Datum ukončení a splnění lekce: 30.března

type Obdelnik = array [1..3, 1..4] of integer; var M: Obdelnik;

dovolují dělení velkých úloh na menší = dekompozice

Unity a Objekty (NMIN102) RNDr. Michal Žemlička, Ph.D.

Programování II. Polymorfismus

Dynamicky vázané metody. Pozdní vazba, virtuální metody

Výčtový typ strana 67

Vyučovací hodina. 1vyučovací hodina: 2vyučovací hodiny: Opakování z minulé hodiny. Procvičení nové látky

Čtvrtek 8. prosince. Pascal - opakování základů. Struktura programu:

Delphi - objektově orientované

Pokročilé programování v jazyce C pro chemiky (C3220) Operátory new a delete, virtuální metody

Objektové programování

PB161 Programování v jazyce C++ Přednáška 7

PB161 Programování v jazyce C++ Přednáška 7

24. listopadu 2013, Brno Připravil: David Procházka

Anotace. Pointery. Martin Pergel,

Zpracování deklarací a přidělování paměti

Obsah přednášky 7. Základy programování (IZAPR) Přednáška 7. Parametry metod. Parametry, argumenty. Parametry metod.

1. Dědičnost a polymorfismus

Chování konstruktorů a destruktorů při dědění

Sada 1 - Základy programování

Kolekce ArrayList. Deklarace proměnných. Import. Vytvoření prázdné kolekce. napsal Pajclín

Využití OOP v praxi -- Knihovna PHP -- Interval.cz

Virtuální metody - polymorfizmus

NPRG030 Programování I, 2015/16 1 / :25:32

Sdílení dat mezi podprogramy

Programování v C++ VI

Anotace. Jednotky (tvorba a využití), struktury (typ record),

Vyřešené teoretické otázky do OOP ( )

7. přednáška - třídy, objekty třídy objekty atributy tříd metody tříd

typová konverze typová inference

Skripta ke školení. Základy VBA. vypracoval: Tomáš Herout. tel:

Třídy. Instance. Pokud tento program spustíme, vypíše následující. car1 má barvu Red. car2 má barvu Red. car1 má barvu Blue.

Programování v C++ 3, 3. cvičení

TŘÍDY POKRAČOVÁNÍ. Události pokračování. Příklad. public delegate void ZmenaSouradnicEventHandler (object sender, EventArgs e);

Maturitní otázky z předmětu PROGRAMOVÁNÍ

Programování v C++ 1, 6. cvičení

VÝUKOVÝ MATERIÁL. Bratislavská 2166, Varnsdorf, IČO: tel Číslo projektu

Abstraktní třída a rozhraní

2) Napište algoritmus pro vložení položky na konec dvousměrného seznamu. 3) Napište algoritmus pro vyhledání položky v binárním stromu.

Více o konstruktorech a destruktorech

Programovací jazyk. - norma PASCAL (1974) - implementace Turbo Pascal, Borland Pascal FreePascal Object Pascal (Delphi)

DUM 06 téma: Tvorba makra pomocí VBA

Programování II. Modularita 2017/18

Tento studijní blok má za cíl pokračovat v základních prvcích jazyka Java. Konkrétně bude věnována pozornost rozhraním a výjimkám.

Anotace. Pointery, dynamické proměnné

ALGORITMIZACE A PROGRAMOVÁNÍ

Objektově orientované programování v jazyce Python

Programování II. Abstraktní třída Vícenásobná dědičnost 2018/19

Objektově orientované programování v jazyce Python

Implementace LL(1) překladů

Cílem kapitoly je seznámit studenta se seznamem a stromem. Jejich konstrukci, užití a základní vlastnosti.

Úvod Třídy Rozhraní Pole Konec. Programování v C# Hodnotové datové typy, řídící struktury. Petr Vaněček 1 / 39

Generické programování

Základy objektové orientace I. Únor 2010

1.1 Struktura programu v Pascalu Vstup a výstup Operátory a některé matematické funkce 5

Programujeme v softwaru Statistica

MATURITNÍ OTÁZKY ELEKTROTECHNIKA - POČÍTAČOVÉ SYSTÉMY 2003/2004 PROGRAMOVÉ VYBAVENÍ POČÍTAČŮ

Úvod do programování

IB111 Programování a algoritmizace. Objektově orientované programování (OOP)

Programovací jazyk Pascal

Assembler - 5.část. poslední změna této stránky: Zpět

IRAE 07/08 Přednáška č. 1

PODPROGRAMY PROCEDURY A FUNKCE

8 Třídy, objekty, metody, předávání argumentů metod

DUM 07 téma: Proměnné, konstanty a pohyb po buňkách ve VBA

Implementace seznamů do prostředí DELPHI pomocí lineárního seznamu

Pascal. Katedra aplikované kybernetiky. Ing. Miroslav Vavroušek. Verze 7

Čtvrtek 3. listopadu. Makra v Excelu. Obecná definice makra: Spouštění makra: Druhy maker, způsoby tvorby a jejich ukládání

Programování II. Dědičnost změna chování 2018/19

Statické proměnné a metody. Tomáš Pitner, upravil Marek Šabo

Programování v C++ 2, 4. cvičení

Lineární spojový seznam (úvod do dynamických datových struktur)

Funkční objekty v C++.

Vzorce. StatSoft. Vzorce. Kde všude se dá zadat vzorec

Konstruktory a destruktory

3. Je defenzivní programování technikou skrývání implementace? Vyberte jednu z nabízených možností: Pravda Nepravda

Sada 1 - Základy programování

Střední škola pedagogická, hotelnictví a služeb, Litoměříce, příspěvková organizace

Jazyk C# (seminář 3)

C++ přetěžování funkcí a operátorů. Jan Hnilica Počítačové modelování 19

Michal Krátký. Úvod do programovacích jazyků (Java), 2006/2007

Programování 2 (NMIN102) Soubory. RNDr. Michal Žemlička, Ph.D.

PB161 programování v C++ Výjimky Bezpečné programování

Programování II. Třídy a objekty (objektová orientovanost) 2018/19

PREPROCESOR POKRAČOVÁNÍ

III/2 Inovace a zkvalitnění výuky prostřednictvím ICT

Je n O(n 2 )? Je n 2 O(n)? Je 3n 5 +2n Θ(n 5 )? Je n 1000 O(2 n )? Je 2 n O(n 2000 )? Cvičení s kartami aneb jak rychle roste exponenciála.

for (int i = 0; i < sizeof(hodnoty) / sizeof(int); i++) { cout<<hodonoty[i]<< endl; } cin.get(); return 0; }

Projekt Obrázek strana 135

3. Třídy. Základní pojmy objektového programování. Třídy

Úvod do programovacích jazyků (Java)

7 Formátovaný výstup, třídy, objekty, pole, chyby v programech

Datové struktury. alg12 1

Transkript:

Tomáš Holan, oop.txt, Verse: 15. března 2006. Objektově orientované programování Objektově orientované programování (OOP) je po strukturovaném programování a modulárním programování další pokus, jak se vypořádat se složitostí programů tak, že dovolíme program rozdělit na části, u nichž nám stačí vědět, CO dělají, aniž bychom se museli starat o to, JAK to dělají. U strukturovaného programování je takovou částí příkaz nebo podprogram, u modulárního programování modul a u objektově orientovaného programování objekt. Objekt... Pokud píšeme nebo někdy potom spouštíme program, obvykle to není proto, že by nás zajímalo právě jen to, jaký výsledek dá program (alespoň většinu z nás a alespoň většina programů). Spíš to bývá tak, že řešíme nějaký problém ve skutečném světě a řešíme ho tak, že vytvoříme jeho model v počítači (pozor, tím modelem může být třeba jen několik čísel, například u modelování růstu ekonomiky nemusíme sledovat všechny nákupy), programem ho vyřešíme a výsledek modelu se pokusíme nějak přenést zase zpátky do skutečného světa. Takže objekt... - no, pokud modelujeme, řekněme, pohyb automobilu, tak takovým objektem může být automobil. Ale objekty mohou být jednodušší (třeba komplexní číslo) nebo také složitější (třeba komplexní továrna na výrobu automobilů). 1 Historie Mohlo by to vypadat, že objekty jsou vynález jazyků jako je C++ nebo Java, ale objekty se objevily už v jazyku Simula 67 v roce 1967, což byl programovací jazyk s knihovnou na vytváření simulačních modelů. Potom se nějakou dobu nedělo nic, když nepočítáme akademické jazyky jako byl Smalltalk, až zhruba do konce osmdesátých a začátku devadesátých let, kdy se objektově orientované programování stalo stejně módním heslem jako o pár let později multimédia, fuzzy logika nebo Internet. 2 V Pascalu V normě jazyka Pascal objekty nebyly. V Turbo Pascalu se objekty objevily poprvé ve versi 5.5. 3 Co to teda je a jak se to používá OOP je... No, je to několik syntaktických možností jazyka a potom způsob uvažování. Pokud jde o syntaxi, je to pár možností a změn, které jsou příjemné, ale bez kterých bychom se, kdyby to bylo potřeba, také obešli. Důležitější je způsob uvažování o částech programu jako o objektech a organizace programu. Ale pojd me už být konkrétní a ukažme si nějaký příklad.

TKomplexniCislo = record Re, Im: real Takhle by vypadal typ pro ukládání komplexních čísel a takhle: function AbsolutniHodnota( x: TKomplexniCislo ): real; with x do AbsolutniHodnota := sqrt( Re*Re + Im*Im )...a takhle funkce vypočítávající absolutní hodnotu. V programu bychom tento typ potom použili takto: var x: TKomplexniCislo; x.re := 1.00; x.im := 2.54; writeln( AbsolutniHodnota( x ) ) end. Zkusme ted upravit deklaraci typu a program tak, aby používal objekty. Předtím ovšem ještě zaved me pojmy: Objektovému typu budeme říkat třída. Proměnné tohoto typu, neboli instanci třídy budeme říkat objekt. Takže ted pojd me definovat třídu TKomplexni (a nenechte se zmýlit tím, že k definici třídy se v Turbo/Borland/Free Pascalu používá klíčové slovo object): TKomplexni = object Re, Im: real; function AbsolutniHodnota: real; function TKomplexni.AbsolutniHodnota: real; AbsolutniHodnota := sqrt( Re*Re + Im*Im ) var x: TKomplexni; x.re := 1.00;

x.im := 2.54; writeln( x.absolutnihodnota ) end. Funkce AbsolutniHodnota nemá žádné parametry, protože je součástí třídy a tedy má přístup ke všem datovým složkám objektu. Říkali jsme, že objekty slouží k tomu, abychom oddělili CO od JAK. Kdybychom to v našem příkladu chtěli udělat pořádně, vypadal by výsledek nějak takhle: TKomplexni = object procedure Dosad( are, aim: real ); function RealnaSlozka: real; function ImaginarniSlozka: real; function AbsolutniHodnota: real; private Re, Im: real; procedure TKomplexni.Dosad( are, aim: real ); Re := are; Im := aim function RealnaSlozka: real; RealnaSlozka := Re function ImaginarniSlozka: real; ImaginarniSlozka := Im function TKomplexni.AbsolutniHodnota: real; AbsolutniHodnota := sqrt( Re*Re + Im*Im ) var x: TKomplexni; x.dosad( 1.00, 2.54 ); writeln( x.absolutnihodnota )

end. Ted už žádný uživatel objektu x nemůže sahat na jeho vnitřní proměnné (o to se stará direktiva private) a smí používat jen to, co třída TKomplexní deklaruje jako vnější rozhraní - tedy proceduru Dosad a funkce RealnaSlozka, ImaginarniSlozka a AbsolutniHodnota. Všechny deklarace uvedené za příznakem (specifikátorem přístupu) private jsou viditelné pouze v rámci unity, kde je deklarovaná třída TKomplexni. V jiných jazycích nebo překladačích je možné přístup k částem deklarace specifikovat jemněji a přesněji, ale to zásadní zůstává poskytovat ostatním předem definované rozhraní a nepovolit přístup k tomu, jak je to uděláno uvnitř. To má svůj význam při psaní programu v týmu domluvené rozhraní je to jediné, co musíte dodržet a i kdybyste se rozhodli datové složky ukládat třeba do souboru, funkčnost zbytku programu (ne jeho rychlost!) to neovlivní. Této vlastnosti objektů, sdružovat data i metody (souhrnné označení pro procedury a funkce) a zároveň zveřejnit jenom to, co zveřejnit chceme, říkáme zapouzdření (encapsulation). Pojd me se podívat na další vlastnosti objektů. Mějme například třídu TPes (to, že jména tříd začínají písmenem T není předpis, jen zvyklost usnadňující čtení programů): TPes = object procedure Dosad( ajmeno: string; vyska: integer ); procedure Stekni; procedure Zastekej; private jmeno: string; vyska: integer procedure TPes.Dosad( ajmeno: string; vyska: integer ); jmeno := ajmeno; vyska := avyska procedure TPes.Stekni; writeln( haf! (,jmeno, ) ) procedure TPes.Zastekej; Stekni; Stekni

Když si vytvoříme objekt typu TPes... var pes: TPes; pes.dosad( Fousek, 20 ); pes.stekni end. objeví se na výstupu haf! (Fousek) Potud nic zvláštního. A ted si představme, že bychom potřebovali ještě jeden typ pro velké psy. Velký pes má stejné datové složky i stejné metody jako pes, ale liší se tím, jak štěká. Mohli bychom tedy popsat typ TVelkyPes stejně jako jsme popsali typ TPes a jenom změnit tělo metody Stekni. OOP nám však nabízí lepší způsob - můžeme velkého psa odvodit od třídy TPes: TVelkyPes = object( TPes ) procedure Stekni; procedure TVelkyPes.Stekni; writeln( HAF! (,jmeno, ) ) Tím, že jsme do závorky za klíčové slovo object napsali jméno jiného objektového typu, říkáme, že třída TVelkyPes je odvozená neboli že dědí od typu TPes. Odvozená třída - převezme všechny datové složky - převezme hlavičky všech metod (ale může změnit jejich tělo) - může přidat nové datové složky i nové metody. Takže třída TVelkyPes má všechny datové složky i všechny metody, jaké má třída TPes a tedy ji můžeme také stejně používat: var VelkyPes: TVelkyPes; VelkyPes.Dosad( Fous, 60 ); VelkyPes.Stekni end. V tomto případě se na výstupu objeví HAF! (Fous)

4 Zádrhel a virtuální metody Zkusme ted místo metody Stekni volat metodu Zastekej: var Pes: TPes; VelkyPes: TVelkyPes; Pes.Dosad( Fousek, 20 ); Pes.Zastekej; VelkyPes.Dosad( Fous, 60 ); VelkyPes.Zastekej end. Výsledek bude možná trochu překvapivý: haf! (Fousek) haf! (Fousek) haf! (Fous) haf! (Fous) Metoda Zastekej zavolá dvakrát po sobě metodu Stekni. A podivný výsledek našeho programu je dán tím, že metoda Zastekej patřící velkému psovi Fousovi zavolá dvakrát metodu Stekni ale protože třída TVelkyPes nemá vlastní metodu Zastekej, volá se metoda Zastekej zděděná od třídy TPes a ta volá dvakrát metodu Stekni - také třídy TPes, protože v době, kdy se překládalo tělo metody Zastekej, vůbec nebylo jasné, že někdy později vznikne nová třída TVelkyPes a že bude existovat nějaká jiná metoda Stekni. 4.1 Co s tím? Vidíme, že problém je v tom, že když se překládají příkazy tvořící tělo procedury Zastekej, konkrétně volání procedury Stekni, přeloží se toto volání tak, jak to jde ted, tedy tak, že volá ted známou metodu Stekni. Říkáme, že procedura Stekni je statická. Alternativní způsob je oznámit, že chceme, aby se volání procedury Stekni nepřekládalo takto, ale aby se před voláním program podíval, jaká je ted platná procedura Stekni a tu zavolal! Takové proceduře říkáme virtuální procedura a svůj požadavek ohlásíme tak, že v deklaraci třídy za hlavičku metody připíšeme klíčové slovo virtual: TPes = object procedure Dosad( ajmeno: string; vyska: integer ); procedure Stekni; virtual; procedure Zastekej; private jmeno: string; vyska: integer

Všimněme si, že to je vlastnost té procedury, která je volaná, ne toho, kdo ji volá. Také poznamenejme, že tatáž metoda může být statická nebo virtuální, ale u všech předchůdců a potomků stejná, není možné, aby u třídy TPes byla metoda statická a u třídy TVelkyPes virtuální nebo naopak, pokud je mezi těmito třídami vztah dědičnosti. Přesnější popis najdete kousek dál v kapitole nazvané,,slíbené upřesnění, které můžete přeskočit. 4.2 Jak se volají virtuální metody? Pokud chceme, aby metoda Zastekej, která se ve výsledném programu vyskytuje pouze v jednom exempláři, volala jednou proceduru Stekni patřící třídě TPes a jednou proceduru Stekni patřící třídě TVelkyPes, může se rozhodovat jedině podle dat aktuálního objektu. Mohlo by to být třeba tak, že by objekt, instance třídy TPes nebo TVelkyPes, obsahoval adresu procedury Stekni. Pokud nechceme mluvit o adresách, stačí proměnná typu procedura (bez parametrů). Volání takové metody Stekni by potom znamenalo zavolat proceduru uloženou v této proměnné, něco, co v Pascalu jde a šlo dávno před objekty. A tak se to skoro dělá, až na dvě drobnosti. První drobnost se týká toho, že je zbytečné, aby si, třeba v programu modelujícím psí útulek, každý objekt typu TPes pamatoval adresu své procedury Stekni a případně adresy všech svých virtuálních procedur. Stačí, když si tyto adresy budeme pamatovat jednou pro každou třídu, v jakési tabulce a každý objekt si potom bude pamatovat jenom adresu této tabulky. Tak to je a té tabulce se říká tabulka virtuálních metod (virtual method table, VMT). Ta druhá zmíněná drobnost se týká toho, jak se v objektu nastaví ukazatel na tabulku virtuálních metod. Když si deklarujeme globální proměnnou, možná bude na začátku vynulovaná, záleží na překladači. Vynulovaná znamená vyplněná nulovými bajty. Pokud si proměnnou deklarujeme uvnitř procedury (tj. na zásobníku) nebo ji vytvoříme dynamicky (tj. na haldě), nebude ani vynulovaná, bude mít jakýsi nahodilý obsah podle toho, k čemu její pamět ové buňky sloužily před chvílí. Tak či tak, případný ukazatel na tabulku virtuálních metod zřejmě nebude ukazovat tam, kam bychom potřebovali. Jak ho tedy nastavíme? 4.3 Konstruktor Konstruktor je procedura, která se od ostatních metod objektu liší tím, že místo klíčového slova procedure její hlavička začíná klíčovým slovem constructor. A potom tím, že dříve než provede svůj první příkaz, nastaví objektu ukazatel na tabulku virtuálních metod! Takže dříve než zavoláme virtuální metodu nějakého objektu, musíme zavolat jeho konstruktor. viz Nová syntaxe procedury New. 5 Slíbené upřesnění, které můžete přeskočit Vrat me se ještě k tvrzení, že tatáž metoda může být statická nebo virtuální, ale u všech předchůdců a potomků stejná.

Pokud v předchůdci deklarujeme metodu jako virtuální a u potomka jako statickou, (Turbo) Pascal hlásí chybu ERROR 149: VIRTUAL expected a program nepřeloží. Když naopak u předchůdce deklarujeme metodu jako statickou a u potomka jako virtuální, potom se chování programu liší podle toho, jak metodu zavoláme: Když ji voláme prostřednictvím ukazatele na předka, volá se statická metoda předka a to i případě, že odvodíme dalšího potomka (3.generace) od potomka, který již měl metodu deklarovánu jako virtuální. Když ji voláme prostřednictvím ukazatele na potomka, volá se metoda potomka, ale pokud do tohoto ukazatele dosadíme ukazatel na již zmíněného potomka třetí generace, volá se opět metoda daná m ukazatele. Metoda deklarovaná jednou jako statická se tedy překládá stále jako statická, i když ji v potomcích deklarujeme jako virtuální. Zdrojový kód na vysvětlenou a na pokusy: PStatic = ^TStatic; TStatic = object constructor C; procedure P; PVirtual = ^TVirtual; TVirtual = object constructor C; procedure P; virtual; constructor TStatic.C; writeln( constructor TStatic ) procedure TStatic.P; writeln( Static ) procedure TVirtual.P; writeln( Virtual )

constructor TVirtual.C; writeln( constructor TVirtual ) {--------- potomci: -----------------} PStaticV = ^TStaticV; TStaticV = object( TStatic ) constructor C; procedure P; virtual; PVirtualS = ^TVirtualS; TVirtualS = object( TVirtual ) procedure P; virtual; { bez toho hlasi ERROR 149: VIRTUAL expected } constructor TStaticV.C; writeln( constructor TStaticV ) procedure TStaticV.P; writeln( StaticV ) procedure TVirtualS.P; writeln( VirtualS ) {-------- 3.generace: ---------------------} PStaticVV = ^TStaticVV; TStaticVV = object( TStaticV ) constructor C; procedure P; virtual; constructor TStaticVV.C; writeln( constructor TStaticVV )

procedure TStaticVV.P; writeln( StaticVV ) var ps: PStatic; pv: PVirtual; psv: PStaticV; writeln( ----------------- ); ps := new( PStatic ); ps^.c; {} ps^.p; end. ps := new( PStaticV ); ps^.c; {} ps^.p; ps := new( PStaticVV ); ps^.c; {} ps^.p; psv := new( PStaticV ); psv^.c; {} psv^.p; psv := new( PStaticVV ); psv^.c; {} psv^.p; 6 Kompatibilita objektových typů Velký pes je také pes. Proto: 1. ukazatelem na třídu TPes můžeme ukazovat i na objekty odvozených typů; k dispozici budeme mít pouze data a metody příslušející typu ukazatele, ale virtuální metody se budou volat podle tabulky virtuálních metod, takže podle skutečného typu objektu. 2. do proměnné typu TPes... Dosadit do proměnné typu TPes proměnou typu TVelkyPes by mohlo mít určitý smysl, s tím, že se dosadí hodnota jen do těch datových složek, které má objekt, do kterého dosazujeme a že se nedosazuje do ukazatele na VMT, ten zůstane beze změny.

Ve Free Pascalu to funguje, v Borland Pascalu dosazování objektů různého typu funguje, jen pokud jsou objekty alokovány dynamicky (na haldě), jinak se neprovede nic. A neplatí to jen o psech, ale obecně pro odvozené typy, at už bezprostředně nebo přes libovolný počet mezičlánků. 6.1 Nová syntaxe procedury New S tím souvisí nová syntaxe procedury new. Procedura new, jak ji známe, alokuje dynamické proměnné a do proměnné, která je parametrem volání, dosadí ukazatel na alokovanou proměnnou. Nová syntaxe procedury new dovoluje do volání procedury new jako druhý parametr zapsat volání konstruktoru, včetně parametrů (to je ještě jedna vlastnost, která odlišuje konstruktor od obyčejných procedur, obyčejnou proceduru zde zapsat nemůžeme). Navíc lze proceduru new volat jako funkci, která ukazatel na alokovanou proměnnou vrací jako výslednou hodnotu. V takovém případě není (prvním) parametrem volání proměnná, ale ukazatelový typ. Pokud při volání uvedeme i druhý parametr volání konstruktoru, musí se jednat o konstruktor objektového typu odpovídajícího uvedenému ukazateli. Kdyby v našem příkladu procedura Dosad byla deklarovaná jako konstruktor (jediná změna je v klíčovém slově constructor namísto procedure), mohli bychom psát: PPes = ^TPes; PVelkyPes = ^TVelkyPes; var Psi: array[1..10] of PPes; i: integer; Psi[1] := New( PPes, Dosad( Alik, 10 ) ); Psi[2] := New( PPes, Dosad( Brok, 10 ) ); Psi[3] := New( PVelkyPes, Dosad( Caesar,10 ) ); Psi[4] := New( PVelkyPes, Dosad( Don, 10 ) ); Psi[5] := New( PVelkyPes, Dosad( Edgar, 10 ) ); Psi[6] := New( PPes, Dosad( Fousek,10 ) ); Psi[7] := New( PVelkyPes, Dosad( Gregor,10 ) ); Psi[8] := New( PVelkyPes, Dosad( Hafan, 10 ) ); Psi[9] := New( PVelkyPes, Dosad( Igor, 10 ) ); Psi[10]:= New( PPes, Dosad( Jim, 10 ) ); for i:=1 to 10 do Psi[i]^.Stekni end....a výstup programu by byl:

haf! (Alik) haf! (Brok) HAF! (Caesar) HAF! (Don) HAF! (Edgar) haf! (Fousek) HAF! (Gregor) HAF! (Hafan) HAF! (Igor) haf! (Jim) Neboli - máme pole ukazatelů stejného obeceného typu, jehož hodnoty jsou ukazatelé na objekty různých typů a když voláme virtuální metody jednotlivých objektů, volá se vždy metoda odpovídající skutečnému typu objektu. Této schopnosti objektů se říká polymorfismus. 7 Abstraktní třídy Žádný pes neexistuje! Tedy neexistuje žádné zvíře, které by bylo právě jen pes. Existují jezevčíci a foxteriéři a dobrmani, ale neexistuje žádné zvíře, které by bylo jenom pes. Nakonec, vlastně... neexistuje ani žádný jezevčík a foxteriér a dobrman, existují jen konkrétní jedinci a jakékoliv označení rasy nebo živočišného druhu je jen jakási přihrádka, kategorie, která nám pomáhá sdružovat jedince se stejnými vlastnostmi. Se stejným interfacem. Když k nám přiběhne zvíře, které jsme nikdy nepotkali, nevíme, co od něj můžeme čekat. Když se nám ho podaří zařadit do přihrádky pes, potom víme, že mu můžeme dát kostku cukru, pohladit ho, nebo ho nakopnout - známe jeho interface, rozhraní. Nevíme, co je uvnitř, ale umíme s ním pracovat. Už jsme se setkali s algoritmy procházení do šířky a do hloubky. Víme, že procházení do hloubky se snadno naprogramuje pomocí rekurse, ale také víme, že oba algoritmy jsou zvláštní případy obecného algoritmu prohledávání a že se liší jen tím, zda pro ukládání rozpracovaných stavů použijeme frontu (do šířky), nebo zásobník (do hloubky). Protože už umíme používat objekty a víme, co je polymorfismus, mohli bychom naprogramovat proceduru prohledávání tak, že by parametrem byl ukazatel na objekt sloužící pro ukládání stavů, jednou zásobník, podruhé fronta. Víme ale, že polymorfismus dovoluje ukazatelem na objekty obecnější ukazovat na typy specifičtější, odvozené. Kdybychom tedy chtěli týmž m ukazatele ukazovat jednou na zásobník, podruhé na frontu, znamená to, že by musel a) zásobník být odvozen od fronty, nebo b) fronta odvozena od zásobníku nebo c) fronta i zásobník odvozeny od společného předka, což vypadá nejrozumněji, protože fronta není zvláštním druhem zásobníku ani zásobník není zvláštním druhem fronty.

Tento společný předek, seznam, musí mít všechny metody a vlastnosti, které budou mít fronta a zásobník, to proto, abychom pomocí ukazatele na tohoto předka mohli volat metody zásobníku a fronty: PSeznam = ^TSeznam; TSeznam = object procedute Pridej( x: TPrvek ); virtual; function JePrazdny: boolean; virtual; procedure Vyber( var x: TPrvek ); virtual; Všechny uvedené metody musí být virtuální, protože chceme pomocí ukazatele na obecný typ TSeznam volat metody odvozených tříd. Protože nikdy nebudeme vytvářet objekty tohoto typu, nemusíme uvádět žádné další údaje krom těch, na které se budeme odkazovat v odvozených třídách a ve volání metod. Třídě, jejíž instance nebudeme vytvářet, říkáme abstraktní třída. Jejím metodám, které nikdy nebudeme volat, říkáme abstraktní metody. V některých programovacích jazycích stačí v deklaraci objektu pouze u hlavičky metody poznamenat, že je abstraktní, v Pascalu musíme uvést i její tělo; obvykle do těla vkládáme výpis chybového hlášení, kdybychom omylem přece jen někdy zavolali abstraktní metodu, abychom se o své chybě dozvěděli: procedure Pridej( x: TPrvek ); RunError( 211 ) function JePrazdny: boolean; virtual; RunError( 211 ) procedure Vyber( var x: TPrvek ); virtual; RunError( 211 ) Procedura RunError vyvolá běhovou chybu. 211 je kód chyby Volání abstraktní metody. 8 Self Uvnitř metod je dostupný identifikátor Self. Tento identifikátor označuje tuto proměnnou, tu, s jejímiž daty budeme pracovat a například místo Vyska bychom mohli psát Self.Vyska. Ten slouží k tomu, když někde potřebujeme označit tuto proměnnou, tu, s jejímiž daty budeme pracovat, například když uvnitř metody nějaké třídy chceme tento objekt zadat jako parametr nějaké metody.

Pokud potřebujeme znát adresu tohoto objektu, například pro přidání objektu do spojového seznamu, použijeme (Turbo/Borland Pascal nebo Free Pacsal) operátor Addr nebo jeho kratší tvar @. Například takto: var p: PPes; procedure TPes.UlozSvouAdresu; p := @Self