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

Podobné dokumenty
Stromy. Strom: souvislý graf bez kružnic využití: počítačová grafika seznam objektů efektivní vyhledávání výpočetní stromy rozhodovací stromy

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

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

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

Více o konstruktorech a destruktorech

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

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

Algoritmy a datové struktury

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

Konstruktory a destruktory

Virtuální metody - polymorfizmus

Dědění, polymorfismus

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

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

Binární vyhledávací strom pomocí směrníků Miroslav Hostaša L06620

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

Programování II. Polymorfismus

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.

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

Dynamické datové struktury III.

1 Nejkratší cesta grafem

Abstraktní třídy, polymorfní struktury

1. Dědičnost a polymorfismus

5 Rekurze a zásobník. Rekurzivní volání metody

Bridge. Známý jako. Účel. Použitelnost. Handle/Body

Základní datové struktury III: Stromy, haldy

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

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

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

1. Programování proti rozhraní

Základy algoritmizace c2005, 2007 Michal Krátký, Jiří Dvorský1/39

Výčtový typ strana 67

Úvod do programovacích jazyků (Java)

Dynamické datové struktury IV.

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

Volné stromy. Úvod do programování. Kořenové stromy a seřazené stromy. Volné stromy

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

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

Stromy, haldy, prioritní fronty

Dynamické datové struktury I.

typová konverze typová inference

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

Programování 3. hodina. RNDr. Jan Lánský, Ph.D. Katedra informatiky a matematiky Fakulta ekonomických studií Vysoká škola finanční a správní 2015

Jazyk C# (seminář 3)

Jazyk C++ I. Polymorfismus

PREPROCESOR POKRAČOVÁNÍ

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

Struktura třídy, operátory, jednoduché algoritmy, junit. Programování II 2. cvičení Alena Buchalcevová

Objektově orientované programování. Úvod

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

Definice třídy. úplná definice. public veřejná třída abstract nesmí být vytvářeny instance final nelze vytvářet potomky

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

State. Známý jako. Účel. Použitelnost. Stav, Object for States. umožňuje objektu měnit svoje chování v závislosti na stavu objekt mění svou třídu

Abstraktní třída a rozhraní

Amortizovaná složitost. Prioritní fronty, haldy (binární, d- regulární, binomiální, Fibonacciho), operace nad nimi a jejich složitost

AVL stromy. pro každý uzel u stromu platí, že rozdíl mezi výškou jeho levého a pravého podstromu je nejvýše 1 stromy jsou samovyvažující

Binární vyhledávací stromy

Stromy. Jan Hnilica Počítačové modelování 14

Generické programování

Programování v Javě I. Leden 2008

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

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

Základy objektové orientace I. Únor 2010

Rekurzivní algoritmy

Dynamické datové struktury II.

Programování v C++ VI

Programování v Javě I. Únor 2009

Pokročilé programování v jazyce C pro chemiky (C3220) Třídy v C++

Definice třídy. úplná definice. public veřejná třída abstract nesmí být vytvářeny instance final nelze vytvářet potomky

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

Fronta (Queue) Úvod do programování. Fronta implementace. Fronta implementace pomocí pole 1/4. Fronta implementace pomocí pole 3/4

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

Stromy. Příklady. Rekurzivní datové struktury. Základní pojmy

Spojová implementace lineárních datových struktur

Binární Vyhledávací Stromy, u kterých je. složitost operací v nejhorším. rovná O(log n)

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

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

Základní datové struktury

Seznamy a iterátory. Kolekce obecně. Rozhraní kolekce. Procházení kolekcí

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

20. Projekt Domácí mediotéka

bin arn ı vyhled av an ı a bst Karel Hor ak, Petr Ryˇsav y 23. bˇrezna 2016 Katedra poˇ c ıtaˇ c u, FEL, ˇ CVUT

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

Problém, jehož různé instance je třeba často řešit Tyto instance lze vyjádřit větami v jednoduchém jazyce

PŘETĚŽOVÁNÍ OPERÁTORŮ

ALGORITMIZACE 2010/03 STROMY, BINÁRNÍ STROMY VZTAH STROMŮ A REKURZE ZÁSOBNÍK IMPLEMENTUJE REKURZI PROHLEDÁVÁNÍ S NÁVRATEM (BACKTRACK)

Algoritmizace a programování

Úvod do programovacích jazyků (Java)

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

Algoritmy výpočetní geometrie

Funkční objekty v C++.

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.

ADT STROM Lukáš Foldýna

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

Dědičnost (inheritance)

Jazyk C++ 1. Blok 3 Objektové typy jazyka C++ Třída. Studijní cíl. Doba nutná k nastudování. Průvodce studiem

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

Jazyk C++, některá rozšíření oproti C

Stromy. Karel Richta a kol. Katedra počítačů Fakulta elektrotechnická České vysoké učení technické v Praze Karel Richta a kol.

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

Transkript:

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

Motivace... class TBod protected: float x,y; public: int vrat_pocet_bodu() return 1; ;

od třídy TBod odvodíme: class TUsecka: public TBod protected: float x2,y2; public: int vrat_pocet_bodu() return 2; ;

platí: objekt potomka je možné přiřadit do objektu předka, totéž platí i o ukazatelích void main(void) TBod b1, *b; TUsecka u; b = &b1; b->vrat_pocet_bodu(); b = &u; b->vrat_pocet_bodu(); Otázka: Jaká se zde vyvolá metoda? Od třídy TBod nebo TUsecka?

Odpověď: v obou případech se vyvolá metoda třídy TBod, protože b je ukazatel na TBod; rozhodnutí, jaká metoda se volá, se provádí staticky při překladu podle typu proměnné, resp. typu ukazatele určitě by bylo výhodné mít mechanismus, který rozhodne o volání metody dynamicky, za běhu programu, podle toho, na jakou instanci ukazatel právě ukazuje

tento mechanismus objektové jazyky většinou poskytují nazývá se mechanismus tzv. pozdní vazby (late binding); příslušné metody se označují jako dynamicky vázané metody implementace v C++ se provádí pomocí tzv. virtuálních metod metody, které chceme vázat dynamicky, označíme klíčovým slovem virtual

pravidlo: jednou virtuální, vždy virtuální chceme-li mít funkci virtuální, musíme ji označit jako virtuální ve všech třídách (základní i odvozených) klíčové slovo virtual píšeme pouze při deklaraci třídy, ne při implementaci metod! lze je naprogramovat jako inline, ale nemá to smysl (Proč?)

class TBod protected: float x,y; public: virtual int vrat_pocet_bodu(); ; class TUsecka: public TBod protected: float x2,y2; public: virtual int vrat_pocet_bodu(); ;

int TBod::vrat_pocet_bodu() return 1; Při implementaci se již klíčové slovo virtual nepíše int TUsecka:: vrat_pocet_bodu() return 2;

void main(void) TBod b1, *b; TUsecka u; b = &b1; Zde se vyvolá metoda ze třídy TBod b->vrat_pocet_bodu(); b = &u; Zde se vyvolá metoda ze třídy TUsecka b->vrat_pocet_bodu();

funguje to samozřejmě i u objektů vytvořených dynamicky void main(void) TBod *b; b = new TBod; b->vrat_pocet_bodu(); delete b; b = new TUsecka; b->vrat_pocet_bodu(); delete b;

POZOR: volání virtuálních metod funguje "dynamicky" jen přes ukazatele void main(void) TBod b1, b; TUsecka u; b = b1; b.vrat_pocet_bodu(); b = u; Vždy se vyvolá metoda ze třídy TBod b.vrat_pocet_bodu();

Jak je to implementováno uvnitř? adresy virtuálních metod jsou za běhu programu uloženy v tabulce virtuálních metod (VMT virtual method table) při běhu programu se před voláním virtuální metody zjistí, na instanci které třídy ukazatel ukazuje a adresa metody se vyhledá v tabulce režie způsobí zpomalení běhu programu

Poznámka: příklad je pouze ilustrativní, ale ve skutečnosti by jej asi nikdo takto neřešil lepšířešení: ve společném předkovi zavedeme atribut pocet_rid_bodu jeho hodnotu nastavíme v konstruktoru každého potomka na správnou hodnotu metoda vrat_pocet_bodu() nebude virtuální a bude implementována již v předkovi

Čisté virtuální metody Abstraktní třídy velmi často se v OOP definuje jedna třída, která je obecným a společným předkem několika potomků některé virtuální metody v této třídě nemají žádný kód, protože jej nemá smysl implementovat nebo se implementovat ve společném předkovi ani nedá kód se implementuje až v jednotlivých potomcích

metody bez kódu ve společném předkovi se označují jako čisté virtuální metody; v hlavičce třídy se deklarují takto: virtual int metoda()=0; třída, která má alespoň jednu čistou virtuální metodu, se nazývá abstraktní třída abstraktní třída nemůže mít žádnou instanci v programu se proměnné od abstraktní třídy používají pouze jako ukazatelé; ukazují pak na instanci nějakého potomka; virtuální metody se volají dle toho, na jakou instanci ukazují

Příklad - konečný automat abstraktní třída TAutomat (předek) čistá virtuální metoda: odezva(int *vst, int *vyst, int n) počítá výstupní posloupnost na vstupní posloupnost délky n potomci TMoore a TMealy virtuální metody, které vypočítají pro každý typ automatu ze zadané vstupní posloupnosti výstupní posloupnost stejné délky metodu odezva nelze napsat v předkovi, protože každý z automatů počítá posloupnost jinek

main () TAutomat *a; int typ; cout << "Jaky automat (1=Moore, 2=Mealy)"; cin >> typ; if (typ==1) a=new TMoore(); else a=new TMealy(); a -> nastav_prechod( ); a -> nastav_vystup( ); a -> odezva( ); delete a;

Kdybychom neměli dynamicky vázané metody main () TAutomat *a; int typ; cout << "Jaky automat (1=Moore, 2=Mealy)"; cin >> typ; if (typ==1) a=new TMoore(); else a=new TMealy(); if (typ==1) (TMoore)a->nastav_prechod( ); else (TMealy)a->nastav_prechod(); atd. delete a;

Bez společného předka main () TMoore *a1, TMealy *a2; int typ; cout << "Jaky automat (1=Moore, 2=Mealy)"; cin >> typ; if (typ==1) a1=new TMoore(); else a2=new TMealy(); if (typ==1) a1->nastav_prechod( ); else a2->nastav_prechod(); atd. if (typ==1) delete a1; else delete a2;

Další výhoda (společného) předka pravidlo z minulé přednášky: do předka lze přiřadit potomka uplatnění: pokud je formálním parametrem nějaké metody ukazatel na předka, můžeme jako skutečný parametr uvést libovolného potomka

Úkol Implementujte abstraktní třídu TUtvar jako společného předka 2D-útvarům. Od třídy odvoďte 2 potomky - třídu TKruh a TObdelnik. Naimplementujte čistou virtuální metodu obsah, která vypočítá obsah útvaru. Uchovávejte počet řídicích bodů ve společném předkovi a název útvaru. Vyzkoušejte v hlavním programu ve stylu ukázky s konečným automatem.

Stromy Strom: souvislý graf bez kružnic využití: počítačová grafika seznam objektů efektivní vyhledávání výpočetní stromy (rozhodování, )

otec (rodič, předchůdce) vnitřní uzel kořen potomek (syn) list

Binární strom každý uzel má maximálně dva potomky uspořádaný binární strom uzly jsou ohodnoceny prvky (čísly, ) potomek na levé straně má vždy menší hodnotu nebo rovnu než rodič potomek na pravé straně má vždy větší hodnotu uspořádané binární stromy se využívají zejména jako vyhledávací stromy; složitost hledání je v průměrném případě log 2 n

Uspořádaný binární strom 10 5 12 2 7 11

binární strom je nejčastěji reprezentován ukazatelem na kořen (obecně na uzel) operace nad stromem jsou rekurzivní

class TStrom class TUzel public: int hodnota; TUzel *levy; TUzel *pravy; TUzel(int x, TUzel *l, TUzel *p); ; TUzel *strom; int najdi(tuzel *u, int x); void pridej(tuzel **u, int x); void zrus(tuzel *u); public: void vloz_prvek(int prvek); int hledej(int prvek); TStrom(); ~TStrom(); ;

TStrom::TUzel::TUzel(int x, TUzel *l, TUzel *p) hodnota = x; levy = l; pravy = p; int TStrom::najdi(TUzel *u, int x) if (u==null) return 0; if (u->hodnota==x) return 1; if (x < u->hodnota) return najdi(u->levy,x); else return najdi(u->pravy,x);

int TStrom::hledej(int prvek) return najdi(strom,prvek); void TStrom::pridej(TUzel **u, int x) if (*u == NULL) *u = new TUzel(x,NULL,NULL); else if (x <= (*u)->hodnota) pridej(&((*u)->levy),x); else pridej(&((*u)->pravy),x);

void TStrom::vloz_prvek(int prvek) pridej(&strom,prvek); void TStrom::zrus(TUzel *u) if (u==null) return; zrus(u->l); zrus(u->p); delete u;

TStrom::TStrom() strom = NULL; TStrom::~TStrom() zrus(strom);

Metodu přidej lze napsat i lépe TStrom::TUzel* TStrom::pridej(TUzel *u, int x) if (u == NULL) return new TUzel(x,NULL,NULL); else if (x <= u->hodnota) u->levy = pridej(u->levy,x); else u->pravy = pridej(u->pravy,x); return u;

Nová metoda vložení prvku do stromu void TStrom::vloz_prvek(int prvek) strom = pridej(strom,prvek);

void main(void) TStrom s; s.vloz_prvek(10); s.vloz_prvek(5); s.vloz_prvek(7); s.vloz_prvek(2); s.vloz_prvek(12); s.vloz_prvek(11); s.hledej(5);

Jaký vznikne strom nyní? void main(void) TStrom s; s.vloz_prvek(10); s.vloz_prvek(5); s.vloz_prvek(7); s.vloz_prvek(2); s.vloz_prvek(11); s.vloz_prvek(12);

A nyní? void main(void) TStrom s; s.vloz_prvek(12); s.vloz_prvek(11); s.vloz_prvek(10); s.vloz_prvek(7); s.vloz_prvek(5); s.vloz_prvek(2);

12 11 10 7 5 2

Snaha je vytvořit strom, kde výška levé a pravé větve se liší maximálně o 1. To musí platit pro libovolný podstrom. Pokud tomu tak není, strom se vyvažuje.

10 5 12 2 7 11

Jak využít dědičnost a virtuální metody u binárního stromu? binární strom má tři typy uzlů: uzel se dvěma potomky uzel s levým potomkem uzel s pravým potomkem list vytvoříme abstraktní třídu TUzel, od ní odvodíme čtyři třídy pro každý typ uzlu; metoda hledej pak bude virtuální

takto implementovat jednoduchý binární strom je spíše přístup s kanónem na vrabce ale poměrně přehledně demonstruje abstraktní třídy a virtuální metody příklad: strom2 náročnější je přidání prvků do stromu zkuste přijít na to, jak to funguje