Úvod do objektově orientovaného programování

Slides:



Advertisements
Podobné prezentace
A1PRG - Programování – Seminář Ing. Michal Typová konverze, oblast platnosti, paměťové třídy 9 Verze
Advertisements

Standardní knihovní funkce pro práci s textovými řetězci
(instance konkrétní třídy)
Seminář C++ 5. cvičení Dědičnost Ing. Jan Mikulka.
Programovací jazyk C++
Programování 2 Cvičení 5.
Pole, ukazatele a odkazy
ÚVOD DO CPP 7 Dědičnost - pokračování
BLIŽŠÍ POHLED NA TŘÍDY, DĚDIČNOST - úvod
C++ Přednáška 3 Konstantní a statické členy tříd, ukazatel this, konstantní instance třídy Ing. Jiří Kulhánek , kat. 352, VŠB TU Ostrava 2004.
Programování v C++ Cvičení.
Principy překladačů Běhová podpora Jakub Yaghob. Běhová podpora Statická podpora jazyka Překladač Interface na knihovny Hlavičkové soubory Dynamická podpora.
Programování 02 OOP.
Čtvrté cvičení Objektové programování Objektový model v Javě
Programování v Pascalu Přednáška 7
Materiály k přednášce Úvod do programování Ondřej Čepek.
J a v a Začínáme programovat Lucie Žoltá metody, objekty, konstruktor.
State. State – kontext a problém Kontext  chování objektu má záviset na jeho stavu, který se typicky mění za běhu Neflexibilní řešení  metody obsahují.
Páté cvičení Dědičnost Interface Abstarktní třídy a metody
Seminář C++ 9. cvičení Šablony Ing. Jan Mikulka. Šablony ► template – vzory, podle kterých může překladač tvořit skupiny podobných tříd nebo funkcí, které.
Vyučovací hodina 1 vyučovací hodina: Opakování z minulé hodiny 5 min Nová látka 20 min Procvičení nové látky 15 min Shrnutí 5 min 2 vyučovací hodiny: Opakování.
PB161 Jmenné prostory, I/O proudy PB161 | Jmenné prostory, IO proudy PB161 – Programování v jazyce C++ Objektově Orientované Programování.
Seminář C cvičení STL, Trolltech Ing. Jan Mikulka.
PB161 – Programování v jazyce C++ Objektově Orientované Programování
Objektové programování
Dynamická alokace, polymorfismus
Seminář C cvičení Obsluha výjimek Ing. Jan Mikulka.
Současný svět Projekt č. CZ /3. 1
Strategy. Strategy – „All-in-1“ na začátek class AStrategy { public: virtual void Algorithm()=0; protected: AStrategy(); }; class SpecificStrategy: public.
Seminář C++ 4. cvičení Objekty Ing. Jan Mikulka. Co je objekt ► obraz třídy i instance ► třída – definovaná za pomocí klíčového slova class ► instance.
6. cvičení Polymorfismus
A1PRG - Programování – Seminář Ing. Michal Ukazatele a pole 10 Verze
Počítače a programování 1
PB161 Právo friend, přetěžování operátorů, přetypování PB161 | Friend, operátory PB161 – Programování v jazyce C++ Objektově Orientované Programování.
KIV/PPA1 cvičení 8 Cvičící: Pavel Bžoch. Osnova cvičení Objekty v Javě Třída Konstruktor Metody Metody a proměnné třídy x instance Program sestávající.
OSNOVA: a) Úvod do OOPb) Třídy bez metod c) Třídy s metodamid) Konstruktory a destruktory e) Metody constf) Knihovní třídy g) Třídy ve tříděh) Přetížení.
Algoritmizace a programování Objektově orientované programování - 16 Mgr. Josef Nožička IKT Algoritmizace a programování
PB161 Principy OOP - rozhraní, dědičnost PB161 | Principy OOP - Dědičnost, rozhraní
C# - předávání parametrů Centrum pro virtuální a moderní metody a formy vzdělávání na Obchodní akademii T.G. Masaryka, Kostelec nad Orlicí.
IB111 Programování a algoritmizace
Návrh a tvorba WWW Přednáška 5 Úvod do jazyka PHP.
Dědičnost - inheritance dědičnost je jednou z forem znovupoužitelnosti dědičnost je jednou z forem znovupoužitelnosti B A Třída A je předkem třídy B Třída.
7. Typ soubor Souborem dat běžně rozumíme uspořádanou množinu dat, uloženou mimo operační paměť počítače (na disku). Pascalský soubor je abstrakcí skutečného.
OSNOVA: a)Funkce – úvod b) Hlavičky funkcí c) Rekurze funkcí d)Knihovny funkcí e)Příklady Jiří Šebesta Ústav radioelektroniky, FEKT VUT v Brně Počítače.
13/04/20151 Datový typ třída – class (1) Datový typ definovaný uživatelem Poskytuje mechanismus pro modelování entit, s nimiž manipulují aplikace Charakterizuje.
Principy OOP Objektově orientované programování vychá-zí ze třech základních principů (rysů): zapouzdření (encapsulation) dědičnost (inheritance) polymorfismus.
Ukazatele BI-PA1 Programování a algoritmizace 1, ZS Katedra teoretické informatiky © Miroslav Balík Fakulta informačních technologií České vysoké.
Objektově orientované programování
STRING A UKAZATELE. Co to je řetězec? Řetězec v Javě je samostatný objekt. Je konstantní, co znamená, že jednou vytvořený řetězec nelze změnit. Chceme-li.
Počítače a programování 1 7.přednáška. Základy Pole ve třídách a metodách Pole Arrays.
Pokročilé programování v C++ (část B)
Ukazatele, řetězce Přednáška č. 3. Ukazatele  Ukazatel (pointer) – typ o velikosti 4 bajty (v 32bit. systémech) pro uložení adresy objektu na který ukazuje.
Soubory BI-PA1 Programování a algoritmizace 1, ZS Katedra teoretické informatiky © Miroslav Balík Fakulta informačních technologií České vysoké.
Jazyk C A0B36PRI - PROGRAMOVÁNÍ Část II.
C – procedury Mgr. Lenka Švancarová.
Práce se soubory a řetězci Přednáška č. 9. Práce se soubory v C (1)  Knihovna #include  Knihovna #include  Ukazatel FILE *stream;  Otevření souboru.
Strategy. Motivace Různé algoritmy pro stejnou akci Hromada kódu v mnoha podmínkách Důsledky  Komplexnost  Špatná čitelnost  Těžká správa kódu  Těžka.
Programování v jazyce C++ Dědičnost a polymorfismus.
Programování OPERÁTOR SIZEOF, FUNKCE, POLE JAKO PARAMETRY FUNKCÍ ERIK KRÁL.
Programování v jazyce C++ Speciality jazyka C++, úvod do OOP.
Počítače a programování 2
Y36PJC Programování v jazyce C/C++
Úvod do C# - OOP Jaroslav BURDYS 4IT.
Programování ENUM, SWITCH,pole jednorozměrná a vícerozměrná, deklarace, inicializace, kopírování, porovnání Erik Král.
Programovací jazyk C++
Y36PJC Programování v jazyce C/C++
Programování v jazyce C++
Bridge.
C# přehled vlastností.
NÁZEV ŠKOLY: S0Š Net Office, spol. s r.o., Orlová-Lutyně
Transkript prezentace:

Úvod do objektově orientovaného programování RNDr. Filip Zavoral, Ph.D. Katedra softwarového inženýrství MFF UK Malostranské nám. 25, Praha 1 Filip.Zavoral@mff.cuni.cz http://ulita.ms.mff.cuni.cz/~zavoral/VSFS

Studijní povinnosti Přednáška 1.5 hod (od 9:00) Cvičení 1.5 hod (do 11:30) Následné osobní konzultace (45 min ve studovně) Klasifikovaný zápočet Příklady na cvičeních, 'domácí úkoly' Závěrečný test Odladit krátký program v omezeném čase Podmínka účasti – úspěšně absolvovaný test z PJC (ZS) Zápočtový program Libovolný prográmek, zůstává ze ZS, stačí C, nemusí být OOP Samostatně vypracovat během semestru

Literatura Bjarne Stroustrup: The C++ Programming Language Bruce Eckel: Myslíme v jazyku C++ James O. Coplien: Advanced C++ Programming Styles and Idioms Herb Sutter: Exceptional C++ Miroslav Virius: Pasti a propasti jazyka C++ Miroslav Virius: Programování v C++ http://kmdec.fjfi.cvut.cz/~virius/liter/litCpp.htm Stroustrup 3rd ed

Obsah předmětu ZS (PJC) LS (OOP) C++ C++ C C

Obsah předmětu Paradigmata programování, OOP Objekty, zapouzdření, dědičnost Konstruktory a destruktory, new a delete Pozdní vazba, virtuální funkce Přetěžování funkcí, předefinování operátorů Abstraktní datové typy OO styly a idiomy Výjimky, šablony, knihovny, streams, STL, RTTI, ...

Paradigmata programování Procedurální programování jakou akci mám provést vstup – výpočet (algoritmus) – výstup black box: procedura / funkce !! side effects, údržba Modulární programování rozdělení problému na komponenty procedury pracují nad daty - rozhraní black box: modul

Paradigmata programování Datová abstrakce vytvoření vlastního datového typu (abstract/user defined d.t.) kompletní množina operací nad tímto typem black box: datový typ !! nelze rozumně rozšiřovat Objektové programování dědičnost – obecné / konkrétní vlastnosti polymorfismus možnost pozdějších rozšíření

Třídy a objekty Koncepční pohled Technický pohled objekt: entita reagující na vnější podněty třída: monžina stejně reagujících entit Technický pohled objekt: struktura obsahující data a funkce, instance třídy datové položky, metody; angl. members třída: typ objektu Rozhraní – veřejné informace pro uživatele Implementace – (neveřejná) interní data a metody

Zvíře v C++ - rozhraní definice třídy zvire.h vnitřní stav (privátní) class zvire { private: int zaludek; public: zvire() { zaludek = 1; }; int zije() { return zaludek>0; }; int jez( int jidlo); int vymesuj( int objem); }; datová položka inline tělo funkce inline tělo funkce rozhraní (veřejné) konstruktor (inicializace) deklarace metody metody

Zvíře - implementace :: operátor kvalifikace zvire.cpp int zvire::jez( int jidlo) { if( ! zije()) return 0; return zaludek += jidlo; } int zvire::vymesuj( int objem) if( (zaludek -= objem) <= 0) zaludek = 0; return zaludek; implementace (tělo) metody třída metody přístup k datům třídy

Zvíře - použití mujprogram.cpp #include ”zvire.h” ..... { zvire pytlik; pytlik.jez(5); pytlik.vymesuj(3); if( ! pytlik.zije()) return –1; pytlik.vymesuj(4); if( ! pytlik.jez(1)) return –2; } import rozhraní instance třídy = objekt zaludek = 1 automaticky konstruktor zaludek = 3 -2  0

Objekt - instance třídy Metoda třídy - ke kterému objektu má přistupovat? int zvire::jez( int jidlo) { if( ! zije()) return 0; return zaludek += jidlo; } ..... zvire pytlik, beruska; pytlik.jez( 5); beruska.jez( 1); ? pytlik: zaludek 6 beruska: zaludek 2 dvě instance třídy

Každá metoda dostane tajný parametr this - ukazatel na objekt C-style řešení int jez( zvire* this, int jidlo) { if( ! zije( this)) return 0; return this->zaludek += jidlo; } ..... zvire pytlik, beruska; jez( &pytlik, 5); jez( &beruska, 1); this pytlik: zaludek 6 beruska: zaludek 2

Reference x: 3 :px y: 4 :ry int x = 1, y = 2; int *px; px = &x; int &ry = y; ry = 4; return *px + ry; y: 4 :ry reference i ukazatele jsou reprezentovány adresou reference - pouze inicializace nelze měnit

Reference jako parametry skutečné parametry odkazy na proměnné swap( int& a, int& b) { int c = a; a = b; b = c; } int x = 1, y = 2; swap( x, y); x: 1 :a y: 2 :b význam: zpřehlednění kódu přetěžování operátorů !

Přetěžování funkcí Funkce je definována svým identifikátorem a počtem a typem parametrů Funkce se stejným identifikátorem ale různým počtem parametrů Funkce se stejným identifikátorem ale různým počtem parametrů int pocitej( int x) { return x+1; } int pocitej( int a, int b) return 2*a + b; pocitej( 1); // int pocitej( int) pocitej( 1, 2); // int pocitej( int, int) Správná funkce podle počtu a typů skutečných parametrů

Konstruktory class zvire { private: int zaludek; public: zvire() { zaludek = 1; }; zvire( int zal) { zaludek = zal; }; zvire( zvire& vzor) { zaludek = vzor.zaludek; }; }; zvire beruska; zvire pytlik( 20); zvire beberuska( beruska); zvire tlustoch = pytlik; implicitní konstruktor copy (kopírovací) konstruktor X(X&) různé zápisy copy konstruktoru

Přetěžování operátorů - deklarace class bod { private: int x, y; public: bod( int xx=0, int yy=0) { x=xx; y=yy; }; bod operator+( bod&); bod operator=( bod&); }; bod a(1,2), b, c; c = a + b; implicitní parametry  implicitní konstruktor přetížení operátoru + a + b  a.operator+(b) a = b  a.operator=(b) bod::bod(0,0); c.operator=(a.operator+(b)); c.assign( a.add( b));

Přetěžování operátorů – těla metod bod bod::operator=( bod& b) { x = b.x; y = b.y; return *this; } bod bod::operator+( bod& b) return bod( x+b.x, y+b.y); reference x  this->x aktualizace stavu kopie objektu (hodnotou přiřazení je přiřazovaná hodnota) co to je ??? vytvoření dočasného objektu konstruktor bod::bod(int, int)

Přetěžování operátorů – ekvivalence Pozor!   Pro předefinované operátory nemusí platit identity definované pro základní typy: a=a+b  a+=b a[b]  *(a+b) bod bod::operator+=( bod& b) { x += b.x; y += b.y; return *this; } bod bod::operator+=( bod& b) { return *this = *this + b; } this->operator=( this->operator+( b))

copy konstruktor a operator= class bod { private: int x, y; public: bod( bod& b) { x=b.x; y=b.y; }; bod operator=( bod& b) { x=b.x; y=b.y; return *this; }; }; bod a(1,2); bod k, m(a), n = a; k = m; není-li copy konstruktor nebo operator= definován, automaticky se vygeneruje copy konstruktor resp. operator= všech složek copy konstruktor deklarace nového objektu operator= přiřazení do existujícího obj.

Operátory new a delete bod a(1,2); bod *pb = new bod; *pb = a + a; a = *pb; delete pb; pb = new bod( a); bod *pc = new bod( 3, 5); a = *pb + *pc; delete pc; dynamická alokace, implicitní konstruktor náhrada za malloc() uvolnění paměti další alokace, explicitní konstruktory

new a delete – pole a reference char* buf = new char[10]; strcpy( buf, “ahoj”); ... delete[] buf; alokace pole objektů uvolnění paměti - u alokovaných polí nutno [] bod& rb = *new bod( 1,2); rb = rb + rb; delete &rb; dynamická inicializace reference

‘obyčejné‘ zřetězení – nechci se starat o to, kde sebrat místo Chytré řetězce – nápad Práce s řetězci v C + efektivní – nepohodlá – chyby Chtěl bych: přiřazování, spojování, alokace místa s3 = malloc( strlen(s1) + strlen(s2) + 2); strcpy( s3, s1); s3[strlen(s1)] = ‘ ‘; strcpy( s3 + strlen(s1) + 1, s2); str s1 = “ahoj”; str s2 = “babi”; str s3; s3 = s1 + ‘ ‘ + s2; s3 += “.”; ‘obyčejné‘ zřetězení – nechci se starat o to, kde sebrat místo

Chytré řetězce - třída class str { private: char* buf; public: str() { buf = 0; }; str( str& s); str( char* s); ~str() { delete[] buf; }; str& operator=( str& s); str operator+( str& s); int len() { return buf ? strlen(buf) : 0; }; }; ukazatel na alokovaná data implicitní konstruktor – prázdný řetězec destruktor – objekt si musí po sobě uklidit ! (delete přežije i 0) operace s řetězci další metody (délka řetězce)

Destruktory ukazatel na alokovaná data class str { private: char* buf; public: str() { buf = 0; }; str( char* s) { buf = new char[ strlen( s) + 1]; strcpy( buf, s); }; ~str() { delete[] buf; }; }; alokace paměti pro řetězec destruktor – automaticky se volá při zrušení objektu nemá argumenty, nic nevrací objekt po sobě musí uklidit

Vyvolání destruktoru v kostruktoru s1 se alokuje paměť fce() { str s1 = “ahoj”; str* s2 = new str( “babi”); ..... delete s2; } dynamická alokace sp2 delete zavolá destruktor (a potom uvolní paměť) zde končí život s1, automaticky se vyvolá destruktor

Řetězce – implementace uklidit po předchozím řetězci str& str::operator=( str& s) { delete[] buf; if( ! s.len()) { buf = 0; } else { buf = new char[ s.len()+1]; if( buf) strcpy( buf, s.buf); } return *this; str::str( str& s) { .... prázdný řetězec alokace paměti okopírování znaků přiřazená hodnota – objekt sám reference kvůli efektivitě copy konstruktor – totéž bez delete a return

O něco lepší implementace později si ukážeme ještě lepší – counted pointers class str { private: char* buf; void copy( char* s); public: str() { buf = 0; }; str( str& s) { copy( s.buf); }; str( char* s) { copy( s); }; ~str() { clear(); }; str& operator=( str& s) { clear(); copy( s.buf); return *this; }; str& operator=( char* s) { clear(); copy( s); return *this; }; void clear() { delete[] buf; }; }; privátní metoda – provádí vlastní alokaci a kopírování často potřebujeme uklízet

Implementace kopírování zkontrolovat prázdný řetězec void str::copy( char* s) { if( !s || !*s) { buf = 0; } else { buf = new char[ strlen( s)+1]; if( buf) strcpy( buf, s); } předpokládáme prázdný buf zařídí volající metoda – copy je private alokace a kopírování

Zřetězení str str::operator+( str& s) nový prázdný řetězec { str newstr; newstr.buf = new char[ len() + s.len() + 1]; strcpy( newstr.buf, buf); strcat( newstr.buf, s.buf); return newstr; } str str::operator+( char* s) .... nový prázdný řetězec místo na znaky první operand druhý operand návratová hodnota

Připojení řetězce class str { .... public: str& operator=( str& s); str& operator=( char* s); str operator+( str& s); str operator+( char* s); str& operator+=( str& s) { *this = *this + s; return *this; }; str& operator+=( char* s) { *this = *this + s; return *this; }; }; když už umíme + a = proč si neudělat += operator+( str&) operator+( char*)

Spolupráce str a int (jednotlivé znaky) class str { ... public: str(); str( str&); str( char*); str( int c) { buf = new char[ 2]; buf[0] = c; buf[1] = '\0'; }; str& operator=( str&); str& operator=( char*); str& operator=( int); str operator+( int); str operator+=( int); }; dodefinovat konstruktor, přiřazení a operace pro další typ dodefinovat konstruktor, přiřazení a operace pro další typ

Výstup později si ukážeme elegantnější řešení - streams neprázdný obsah na stdout class str { ... public: int print() { return buf ? printf( "%s", buf) : 0; }; }; str s1 = "ahoj", s2("babi"), s3; s3 = s1 + ' ' + s2; s3.print(); str("\n").print(); (s3 += ".\n").print(); ‘normálně’ spojím řetězce s mezerou ... a vytisknu dočasný objekt reference na s3

... and together class str { private: char* buf; void copy( char* s); public: str() { buf = 0; }; str( str& s); str( char* s); str( int c); ~str(); str& operator=( str& s); str& operator=( char* s); str& operator=( int c); str operator+( str& s); str operator+( char* s); str operator+( int c); str& operator+=( str& s); str& operator+=( char* s); str& operator+=( int c); void clear(); int len(); int print(); };

Dědičnost Vztah tříd předek-potomek – hierarchie Vícenásobná dědičnost specializace (potomek má/umí něco navíc) reusabilita (jiné chování bez změny pův. třídy) protokoly - později zvíře pes pitbul jez, vyměšuj sedni, lehni trhej člověk uč_se

pes jako potomek zvířete - definice class zvire { private: int zaludek; public: zvire(); zvire( int jidlo); int zije(); int jez( int jidlo); int vymesuj( int objem); }; class pes : public zvire { private: enum t_stav { Stoji, Sedi, Lezi }; t_stav stav; public: pes() { stav = Stoji; }; int sedni() { stav = Sedi; }; t_stav codela() { return stav; } };

pes jako potomek – obsah objektu metody předka položky předka stav žaludek jez, vyměšuj metody potomka položky potomka sedni zvire pytlik; pes azor; pytlik.jez(); azor.jez(); azor.sedni(); potomek obsahuje všechny položky a metody předka

Konstruktor předka implicitní konstruktor předka (automaticky) class pes : public zvire { ... public: pes() { stav = Stoji; }; pes( int jidlo) : zvire( jidlo) { stav = Stoji; }; }; konstruktory předků a vložených tříd se volají před konstruktorem potomka explicitní konstruktor předka

Destruktor předka zabijim psa zabijim zvire class zvire { ... ~zvire() { printf( "zabijim zvire "); }; }; class pes : public zvire ~pes() { printf( "zabijim psa "); }; { pes azor; ... } destruktor předka se vyvolá automaticky po ukončení destruktoru potomka zabijim psa zabijim zvire

Kompatibilita předka a potomka Potomka lze přiřadit do předka (platí i pro ukazatele) Předka NELZE přiřadit do potomka (platí i pro uk.) pes umí jíst, brouk neumí štěkat azor zvire pytlik, *pz; pes azor, *pp; pytlik = azor; *pz = &azor; pytlik stav žaludek žaludek azor pytlik azor = pytlik; *pp = &pytlik; stav žaludek žaludek ??? nelze

Polymorfismus odlišné chování potomků – pozdní vazba (late binding) zvíře pes pitbul jez jez jez sní maso sní hodně masa najde něco v přírodě člověk jez jde do restaurace

Polymorfismus - motivace Tohle není polymorfismus ! class zvire { jez() { priroda(); }; }; class pes : public zvire { jez() { maso(1); }; class pitbul : public pes { jez() { maso(10); }; class clovek : public zvire { jez() { hospoda(); }; zvire pytlik; pes punta; pitbul zorro; clovek pepa; pytlik.jez(); // priroda(); punta.jez(); // maso(1); zorro.jez(); // maso(10); pepa.jez(); // hospoda(); 'normální' vlastnost tříd zakrývání metod Při překladu je známo ze které třídy se volá metoda

Polymorfismus – takto nelze z je ukazatel na zvíře volá se zvire::jez() zvire* z; z = new pes; z->jez(); // priroda(); z = new clovek; zvire* z; z = new pes; z->pes::jez(); // priroda(); z = new clovek; z->clovek::jez(); // priroda(); nelze (syntaktická chyba, pes není předkem zvířete)

Polymorfismus – takto bych to chtěl zvire* z; z = new pes; z->jez(); // maso(1); z = new clovek; z->jez(); // hospoda(); zvire* nase_rodina[3]; nase_rodina[0] = new clovek; nase_rodina[1] = new pes; nase_rodina[2] = new pitbul; for( int i = 0; i < 3; i++) z->jez(); Pokaždé se zavolá jiná metoda Rozlišení metody se děje za běhu Pokaždé se zavolá jiná metoda Rozlišení metody se děje za běhu

Virtuální funkce - deklarace magické klíčové slovo virtual class zvire { virtual jez() { priroda(); }; }; class pes : public zvire { virtual jez() { maso(1); }; class pitbul : public pes { virtual jez() { maso(10); }; class clovek : public zvire { virtual jez() { hospoda(); }; každý objekt si s sebou nese informaci kterou virtuální funkci používá

Virtuální funkce - implementace zvire * z; z = new zvire; z = new pes; pes zvire stav žaludek žaludek tabulka virtuálních funkcí tabulka virtuálních funkcí jez jez zvire::jez() { priroda(); }; pes::jez() { maso(1); }; z->jez(); zavolá se správná metoda

Virtuální funkce a konstruktory class A { public: virtual f(); A() { f(); }; // A::f ~A() { f(); }; // A::f g() { f(); }; // A/B::f }; class B : public A { public: virtual f(); B() { f(); }; // A::A B::f ~B() { f(); }; // B::f A::~A g() { f(); }; // B::f };

Volání virtuálních funkcí A a; // A::A B b; // B::B A * paa = &a; A * pab = &b; B * pbb = &b; a.f(); // A::f b.f(); // B::f paa->f(); // A::f pab->f(); // B::f pbb->f(); // B::f b.A::f(); // A::f b.B::f(); // B::f a.B::f(); // NE! paa->A::f(); // A::f pab->A::f(); // A::f pab->B::f(); // NE! pbb->A::f(); // A::f pbb->B::f(); // B::f pozdní vazba paa a A::f kvalifikované volání pab b B::f pbb

Abstraktní třída, čistě virtuální funkce int armada; class vojak { public: enum THod { vojin, desatnik, porucik, general }; private: THod hodnost; public: vojak( THod hod = vojin) { hodnost=hod; armada++; }; virtual void pal() = 0; ~vojak() { armada--; }; }; class samopal {}; class kalasnikov : public samopal {}; class pesak : public vojak { private: samopal* sam; public: pesak( THod hod=vojin) : vojak( hod) { sam = new kalasnikov; }; virtual void pal() { sam->pal(); }; ~pesak() { delete sam; }; }; pure virtual function abstraktní třída POZOR!!! Nutný virtuální destruktor

Abstraktní třídy, virtuální destruktory vojak v; // NELZE – abstraktní třída pesak p; // OK – pesak vojin pesak* pp = new pesak; // OK pp->pal(); // pesak::pal vojak* v = new pesak; // OK v->pal(); // pesak::pal delete pp; // OK, pesak::~pesak delete v; // !!! vojak::~vojak class vojak { virtual ~vojak() { armada--; }; }; class pesak : public vojak virtual ~pesak() { delete sam; }; POZOR!!! nejsou-li destruktory virtuální, nezruší se samopal Řešení: virtuální destruktor

Prostory jmen (namespaces) zapouzdření identifikátorů prevence kolizí (velké projekty, knihovny) stejné identifikátory v různých prostorech jmen definice prostoru jmen namespace aa { int p; int f1( int x) { return x + p; } int f2( int x, int y); } int aa::f2( int x, int y) { return p * (x + y); aa::f1( aa::f2( 5, 6)); přístup k identifikátoru ze stejného prostoru definice funkce mimo prostor jmen přístup k identifikátorům přes ::

Prostory jmen prostor jmen se může opakovaně otevírat a zavírat explicitní přístup ke globálnímu identifikátoru ::id standardní knihovny – namespace std rozbalení std using namespace std; namespace aa { int p; int q; } int g( int n) { cout << (n + aa::p); int f3( int x) { return 1 + ::g( x); přístup k identifikátorům std přístup do aa znovuotevření prostoru aa přístup ke globálnímu identifikátoru

Prostory jmen a standardní knihovny stará konvence: stdio.h, ctype.h, iostream.h identifikátory v globálním prostoru jmen nová konvence: cstdio, cctype, iostream identifikátory uzavřené do namespace std standardní knihovny C++ Základní knihovny z C přejmenované podle nové konvence Rozšířené C++ knihovny iostream: znakový formátovaný vstup a výstup STL: Standard Template Library

Vstup a výstup - proudy (streams) hierarchie tříd pro (formátovaný znakový) vstup a výstup jednotné rozhraní pro v/v do souborů a paměti, ... operátory << a >>, manipulátory, snadné rozšiřování #include <iostream> using namespace std; int main() { int n; cout << "Rekni cislo: "; cin >> n; cout << "Mam vic: " << (n+1) << ", hec!" << endl; } definice základních tříd a manipulátorů ostream cout  FILE* stdout istream cin  FILE* stdin ostream& ostream::operator<< ( )

Streams – hierarchie tříd

Hlavičkové soubory <iostream> – základní operace, standardní v/v, manip. bez parametrů cin, cout, <<, >>, endl, ws, ... <iomanip> – manipulátory s parametry setw, setfill, ... <fstream> – vstup a výstup do souborů fstream, ifstream, ofstream, ... <strstream> - vstup a výstup do paměti (chytré řetězce) strstream, istrstream, ostrstream, ...

Manipulátory do proudu lze vkládat manipulátory – změní stav proudu endl pošle buffer na výstup a odřádkuje left, right zarovnávej doleva / doprava dec, hex v desítkové / šestnáctkové soustavě ws přeskoč bílé znaky (na vstupu) setw(int) šířka výstupního pole (jen pro násl. číselnou položku) setfill(int) výplňkový znak ... a spousty dalších cout << "[" << setfill('.') << setw(5) << 17 << "]" << endl; [...17]

Výstup do souboru spojení proudu se souborem v konstruktoru způsob otevření ios::in, out, app, trunc, binary, ... #include <fstream> using namespace std; int main() { fstream f( "C:\\src\\pokus.txt", ios::out); if( ! f) error(); f << "bubu" << endl; } operator ! (ostream&) vrátí true když se operace nepodařila soubory není třeba zavírat, zavře je automaticky destruktor

Další metody vstupních proudů pro binární vstup a výstup nelze použít operátory << a >> Vstup get( kam, délka, koncový_znak) getline( kam, délka, koncový_znak) ignore( délka, koncový_znak) read( pole_znaků, délka) tellg() seekg( posun, odkud) unget() peek()

Další metody výstupních proudů get( kam, délka, koncový_znak) put( znak) write( pole_znaků, délka) tellp() seekp(posun, odkud) flush() ... a další int i = 17; ofstream f( "pokus.txt", ios::binary); if( ! f) error(); f.write( (char*)&i, sizeof( i)); pole bajtů a jejich počet

Spřátelené funkce – vlastní výstup class complx { private: int re, im; public: complx( int _re = 0, int _im = 0) { re = _re; im = _im; }; friend ostream& operator<<( ostream& s, complx& c) { return s << c.re << "+" << c.im << "i"; }; }; complx x(1,2); cout << x << endl; POZOR! Toto není metoda třídy! spřátelená (friend) funkce může přistupovat k privátním položkám

Šablony množina funkcí/objektů lišících se pouze typem parametrů/položek vzor, podle kterého překladač vytvoří funkci nebo třídu - instanci Typový parametr T nahrazuje skutečný typ Definice šablony funkce template <class T> T max( T a, T b) { return a > b ? a : b; }; int x = 10, y = 20; double m = 1.1, n = 2.2; cout << max(x,y) << max(m,n) << endl; int max( int a, int b) double max( double a, double b)

Šablony tříd - definice pole neznámého typu template<class T> class guma { private: int size; T* array; public: enum { default_size = 10 }; guma( int _size = default_size) { size = _size; array = new T[size]; }; ~guma() { delete array; } T& operator[] (int n); }; int main(int argc, char* argv[]) guma<int> ip(5); ip[3] = 999; size: 5 array: 1 2 3 4 ? instance šablony třídy definice proměnné přetížený operator[]

Šablony metod, instance šablon instance šablony třídy definice typu template<class T> class guma { private: int size; T* array; public: T& operator[] (int n); }; template<class T> T& guma<T>::operator[] (int n) { if( n >= size) { T* na = new T[ n + 1]; for( int i = 0; i < size; i++) na[i] = array[i]; delete array; array = na; size = n + 1; } return array[n]; struct krabice { int a, b; char jm[10]; }; typedef guma<krabice> polekrab; int main(int argc, char* argv[]) { guma<int> ip(5); polekrab pk; ip[3] = 999; pk[12].a = ip[3]; definice šablony metody pk[i] je typu krabice&

STL – Standard Template Library kontejnery – datové struktury pro ukládání dat a manipulaci s nimi iterátory – třídy pro přístup k datům kontejnerů algoritmy – základní algoritmy nad kontejnery (třídění, procházení, hledání) další pomocné třídy – alokátory, komparátory, funktory ... obousměrný seznam list<int> sez; sez.push_front( 1); sez.push_back( 2); sez.push_front( 3); list<int>::iterator i; for( i = sez.begin(); i != sez.end(); i++) cout << "[" << *i << "]"; přidání prvku zepředu ... zezadu ... zepředu iterátor seznamu průchod seznamem přístup k datům přes iterátor – operator*

STL – kontejnery deque – dvoustranná fronta (implementace: pomocí polí) stack, queue, priority_queue – fronta, zásobník vector – pole list – dvousměrný seznam (implementace: spojový seznam) map, multimap – zobrazení, asociativní pole, slovník, mapa (uspořádaná struktura indexovaná libovolným typem, pair: klíč, hodnota) set – množina (každý prvek nejvýše jednou) string – chytré řetězce (+, +=, mnoho dalších operací a metod)

STL – iterátory a metody kontejnerů kontejner<T>::iterator iterátor příslušného kontejneru T& iterator::operator* přístup k prvku přes iterátor begin(), end() iterátor na začátek / za(!) konec kontejneru push_front(T), push_back(T) přidání prvku na začátek / konec pop_front(), pop_back() odebrání prvku ze začátku / konce – nevrací! push(T), pop() přidání a odebrání z fronty / zásobníku front(), back(), top() prvek na začátku fr. / konci fr. / vrcholu zás. operator[], at() přímý přístup k prvku insert(iterator,T) vložení prvku na místo určené iterátorem size(), empty(), clear() velikost / neprázdost / smazání kontejneru

STL – použití asociativního pole map<string,string> ts; ts["Filip"] = "605123456"; ts["Petra"] = "721334455"; ts["David"] = "723654321"; ts["Kuba"] = "222333444"; cout << "Telefon Petry: " << ts["Petra"] << endl; map<string,string>::iterator ti; for( ti = ts.begin(); ti != ts.end(); ti++) cout << ti->first << ": " << ti->second << endl; ts: pair: string first string second pair<string,string> iterator::operator*

STL – generické algoritmy Algorithms initializing a sequence fill Fills a sequence with an initial value fill_n Fills n positions with an initial value copy Copies a sequence into another sequence copy_backward Copies a sequence into another sequence generate Initializes a sequence using a generator generate_n Initializes n positions using a generator swap_ranges Swaps values from two parallel sequences Searching algorithms find Finds an element matching the argument find_if Finds an element satisfying a condition adjacent_find Finds consecutive duplicate elements find_first_of Finds one member of a sequence in another seq. find_end Finds the last occurrence of a sub-seq. in a seq. search Matches a sub-sequence within a sequence max_element Finds the maximum value in a sequence min_element Finds the minimum value in a sequence mismatch Finds first mismatch in parallel sequences Removal algorithms remove Removes elements that match condition unique Removes all but first of duplicate values Algorithms for in-place transformations reverse Reverses the elements in a sequence replace Replaces specific values with new value replace_if Replaces elements matching predicate rotate Rotates elements in a sequence around a point partition Partitions elements into two groups stable_partition Partitions preserving original ordering next_permutation Generates permutations in sequence prev_permutation Generates permutations in reverse sequence inplace_merge Merges two adjacent sequences into one random_shuffle Randomly rearranges elements in a sequence Scalar generating algorithms count Counts number of elements matching value count_if Counts elements matching predicate accumulate Reduces sequence to a scalar value inner_product Gives inner product of two parallel sequences equal Checks two sequences for equality lexicographical_compare Compares two sequences Sequence generating algorithms transform Transforms each element partial_sum Generates sequence of partial sums adjacent_difference Generates sequence of adjacent differences Miscellaneous operations for_each Applies a function to each element of a collection

STL – chybová hlášení \SRC\templ\templ.cpp(101) : error C2664: 'class std::_Tree<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >,struct std::pair<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > const ,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > >,struct std::map<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >,struct std::less<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > >,class std::allocator<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > > >::_Kfn,struct std::less<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > >,class std::allocator<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > > >::iterator __thiscall std::map<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >,struct std::less<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > >,class std::allocator<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > > >::insert(class std::_Tree<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >,struct std::pair<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > const ,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > >,struct std::map<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >,struct std::less<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > >,class std::allocator<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > > >::_Kfn,struct std::less<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > >,class std::allocator<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > > >::iterator,const struct std::pair<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > const ,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > > &)' : cannot convert parameter 1 from 'char [6]' to 'class std::_Tree<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >,struct std::pair<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > const ,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > >,struct std::map<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >,struct std::less<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > >,class std::allocator<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > > >::_Kfn,struct std::less<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > >,class std::allocator<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > > >::iterator'

Výjimky Motivace: co dělat, když (knihovní) funkce zjistí chybu? nedostatek paměti, nelze otevřít soubor, nulový ukazatel, ... Vypsat zprávu na 'obrazovku' a skončit FUJ! Nikdy! Nastavit do globální funkce příznak chyby Vrátit 'divnou' hodnotu – takhle funguje většina knihovních funkcí C nepříliš praktické, testování každé funkce, vnořené testy, divná hodnota nemusí existovat, ... Co chceme: - oddělit detekci výjimečné situace od jejího zpracování - po výskytu 'chyby' (výjimečné situace) automaticky skočit na zpracování - kulturně po sobě uklidit (volání destruktorů) Řešení v C++: mechanismus výjimek

Výjimky - jednoduchý příklad vyvolání výjimky void mojefce( char* str) { if( ! str) throw runtime_error( "Nic!"); cout << str; } int main(int argc, char* argv[]) char* p = 0; try { mojefce( p); } catch( runtime_error& e) { cout << "Chyba: " << e.what() << endl; return 0; typ výjimky standardní třída potomek exception pokusný blok try block handler(y) typ výjimky standardní metoda třídy runtime_error řetězec z konstruktoru

Výjimky - pravidla k try bloku může být několik handlerů s různými typy try bloky mohou být vnořené výjimka může být vyvolána v libovolně zanořené funkci po vyvolání výjimky se řízení předá handleru s odpovídajícím typem před odchodem ze všech bloků se zavolají destruktory lokálních objektů předávaná hodnota nese informaci o výjimce typické použití: potomek standardní třídy exception i pro výjimky platí, že potomek může nahradit předka konstruktor runtime_error(string&), metoda string what() po ošetření výjimky pokračuje program za handlery try bloku při běhu bez výjimky se handlery ignorují (přeskočí) neošetřená výjimka – unhandled exception, konec programu

Specifikace výjimek funkcí Problém: jak programátor pozná které výjimky má ošetřovat? Řešení: funkce může specifikovat výjimky, které může vyvolat funkce může vyvolat výjimky těchto typů void mojefce( char* s) throw (runtime_error, mojechyba); int jinafce( void) throw(); char* tretifce( char* s); funkce nevyvolává žádnou výjimku funkce může vyvolat libovolnou výjimku

... co jsme neprobrali spoustu věcí Jazyk OOP const, protected, volatile, static, operátory .* a ->*, ukazatele na funkce, ... vícenásobná dědičnost, protokoly RTTI, typeid, type_info static_cast, dynamic_cast, reinterpret_cast podrobněji knihovny OOP counted pointers, mělké vs. hluboké kopie objektová paradigmata – zprávy, obálkové třídy, subtyping, forwarding hlouběji o objektovém návrhu, reusabilitě, efektivitě implementace funktory a jiné specialitky