1 / 76

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

Ú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)

lois
Télécharger la présentation

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

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Ú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

  2. 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

  3. 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

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

  5. Obsah předmětu • Paradigmataprogramová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, ...

  6. 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

  7. 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í

  8. Třídy a objekty • Koncepční 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

  9. 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

  10. 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

  11. 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

  12. 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: beruska: dvě instance třídy

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

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

  15. 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ů !

  16. 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 alerůzným počtem parametrů Funkce se stejným identifikátorem alerů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ů

  17. 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í) konstruktorX(X&) různé zápisy copy konstruktoru

  18. 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));

  19. 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)

  20. 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))

  21. 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 konstruktordeklarace nového objektu operator= přiřazení do existujícího obj.

  22. 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; delete pb; dynamická alokace, implicitní konstruktor náhrada za malloc() uvolnění paměti další alokace, explicitní konstruktory

  23. 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

  24. 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

  25. Chytré řetězce - třída operace s řetězci 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) další metody (délka řetězce)

  26. 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

  27. 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

  28. Ř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

  29. 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

  30. Implementace kopírování zkontrolovatprá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í

  31. Zřetězení str str::operator+( str& s) { 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

  32. 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*)

  33. 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

  34. později si ukážeme elegantnější řešení - streams Výstup 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

  35. ... 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(); };

  36. 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

  37. pes jako potomek zvířete - definice potomek zvířete 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; } };

  38. 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

  39. 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

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

  41. 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

  42. 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

  43. 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

  44. Polymorfismus – takto nelze z je ukazatel na zvíře volá se zvire::jez() zvire* z; z = new pes; z->jez(); // priroda(); z = new clovek; z->jez(); // priroda(); 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)

  45. 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

  46. 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á

  47. 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

  48. 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 };

  49. 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

  50. 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

More Related