1 / 385

Objektov ě-orientované p rogramování v C++

Objektov ě-orientované p rogramování v C++. David Bednárek ulita.ms.mff.cuni.cz. Pravidla studia. PRG0 32 2/2 Z,Zk. Zápis na cvičení. Elektronický zápis do jednotlivých skupin www.mff.cuni.cz/vnitro/is/sis Grupíček Skupiny budou naplněny podle příslušnosti ke studijním skupinám

larue
Télécharger la présentation

Objektov ě-orientované p rogramování v C++

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. Objektově-orientované programování v C++ David Bednárek ulita.ms.mff.cuni.cz

  2. Pravidla studia PRG032 2/2 Z,Zk

  3. Zápis na cvičení • Elektronický zápis do jednotlivých skupin • www.mff.cuni.cz/vnitro/is/sis • Grupíček • Skupiny budou naplněny podle příslušnosti ke studijním skupinám • Asi 30% studentů žije mimo studijní skupiny a nebyli takto zapsáni • Zapsáni musejí být všichni • Do 13.10. • Kdo se neobjeví na prvním ani druhém cvičení, bude vyškrtnut • Kapacita laboratoře je omezena, skupiny nelze přeplňovat • Udělit zápočet může jen cvičící,ke kterému je student zapsán • Kdo nebude do 13.10. zapsán, zápočet v tomto šk. roce nedostane

  4. Udělení zápočtu • Přesné podmínky udělení zápočtu určuje cvičící • Cvičící může podmínky individuálně upravit, pokud se s ním student na začátku semestru dohodne • Vzorové podmínky • Přiměřená účast na cvičeních • Úspěšné odevzdání domácího úkolu • Úspěšné složení zápočtového testu • 1. a 2. pokusy ve zkouškovém období ... 3. pokusy v dubnu • 2-3 hodiny v laboratoři, společně pro všechny skupiny • Vypracování zápočtového programu • Dohoda o tématu - do konce října • Předvedení cvičícímu do 15.3.2005 • Doladění do konce výuky v letním semestru

  5. Zkouška • Zkouška bude provedena formou abc-testu • Vlastnosti a pravidla jazyka C++ • Základy používání knihoven C++ (STL, iostream) • Typické konstrukce objektového programování • Exception-safe programming • Termíny • Ve zkouškovém období ZS • Během výuky v LS

  6. Pravidla pro budoucí neúspěšné • Zkouška • Pokud letos složíte obě zkoušky z PRG029 a PRG032 se známkou výborně nebo velmi dobřea nedostanete některý zápočet, budou vám příští rok obě automaticky uznány • Tento mechanismus je implementován zkoušejícími, nikoliv studijním oddělěním • Příští rok se bude měnit rozdělení syllabu mezi semestry, proto toto pravidlo neplatí pro jednotlivé předměty • Zápočet • Pokud nedostanete zápočet, budete příští rok opakovat ty části, které jste letos nesplnili • Podmínky splněné letos se automaticky uznávají • V příštím roce se musíte na začátku semestru přihlásit na některé cvičení a dohodnout se s jeho cvičícím na konkrétních podmínkách • Mohou být vypsána speciální cvičení pro repetenty

  7. Obsah

  8. Obsah cvičení • V laboratoři SW2 / v učebně • Microsoft Visual Studio .NET 2003 • Demonstrace konstruktorů, destruktorů a virtuálních funkcí • Příklady dědičnosti a virtuálních funkcí • Demonstrace operátorů a copy-constructoru • Příklady datových typů (Complex, String, Vector, Matrix) • Praktická implementace vlastního typu string • Šablony, implementace vlastních kontejnerů • STL: deque, vector, map • fstream, open etc. • iostream, manipulátory, implementace vlastního operatoru << (Complex) • Experimenty s výjimkami • Exception-safe programování • Debugging • Vlastní nástroje pro ladění

  9. Obsah přednášky

  10. Literatura

  11. Literatura • Pro začátečníky • Bruce Eckel:Thinking in C++ (2000)Myslíme v jazyku C++ (Grada 2000) • Miroslav Virius:Pasti a propasti jazyka C++Programování v C++ (ČVUT 2001) • Andrew Koenig, Barbara E. Moo:Accelerated C++ (2000) • Stanley B. Lippman:Essential C++ (2000)

  12. Literatura • Pro středně pokročilé • Andrei Alexandrescu, Herb Sutter:C++ Coding Standards (2005) • Scott Meyers:Effective C++ (1998)More Effective C++ (1996)Effective STL (2001) • Herb Sutter:Exceptional C++ (2000)More Exceptional C++ (2002)Exceptional C++ Style (2004) • Nicolai M. Josuttis:Object-Oriented Programming in C++ (2002)The C++ Standard Library (1999)

  13. Literatura • Až si budete myslet, že všechno umíte • Andrei Alexandrescu:Modern C++ Design (2001)Moderní programování v C++ (Computer Press 2004) • David Vandevoorde, Nicolai M. Josuttis:C++ Templates (2003)

  14. Normy • C++ • ISO/IEC JTC1/SC22/WG21:14882 - Programming languages - C++ (2003) • C++ 2003 TR1 (2005) • Nové rozšíření knihoven (částečně podporováno GCC 4.0) • Založeno na knihovně Boost • C++0x • Návrhy lze sledovat na http://www.open-std.org/jtc1/sc22/wg21/ • C: • ISO/IEC 9899:Programming languages - C (1999) • C99 • Významně není podmnožinou C++ • Řada překladačů jej nezvládá (včetně MSVC 2005)

  15. www • http://www.open-std.org/jtc1/sc22/wg21/ • ISO • http://www.gotw.ca/ • Herb Sutter: Guru of the Week • http://www.boost.org/ • Knihovna Boost • http://gcc.gnu.org/ • GCC

  16. C++

  17. Třída a objekt • Třída (class) • Zobecnění pojmu struktura (struct) • Rozdíl mezi class a struct v C++ je nepatrný • Užívání class místo struct je pouze konvence • Deklarace třídy obsahuje • Deklarace datových položek (stejně jako v C) • Funkce (metody), virtuální funkce a statické funkce • Definice výčtových konstant a typů (včetně vnořených tříd) • Objekt (instance třídy) • Běhová reprezentace jednoho exempláře třídy • Reprezentace objektu v paměti obsahuje • Datové položky • Skryté pomocné položky umožňující funkci • virtuálních metod, výjimek a RTTI • virtuální dědičnosti

  18. Třída a objekt • Instanciace třídy = vznik objektu tohoto typu • Jako globální proměnná • V rámci startu programu (před main) • Jako lokální proměnná • V okamžiku průchodu řízení deklarací • Jako parametr předávaný hodnotou • Těsně před voláním funkce • Jako pomocná proměnná při výpočtu výrazu • V okamžiku, kdy je vypočtena její hodnota • Dynamickou alokací • V okamžiku volání operátoru new • Jako položka jiné třídy nebo součást pole • V okamžiku vzniku celku • Jako předek jiné třídy • V okamžiku vzniku instance potomka

  19. Objekt a ukazatel na objekt • C++ důsledně odlišuje objekt a ukazatel na něj • Triviální důsledek: • class T { /*...*/ }; • T * p; // zde nevzniká objekt typu T

  20. Objekt a ukazatel na objekt • C++ důsledně odlišuje objekt a ukazatel na něj • Triviální důsledek: • class T { /*...*/ }; • T * p; // zde nevzniká objekt typu T • Netriviální důsledek: • Proměnná typu T je vždy objekt typu T a žádného jiného, přestože do ní lze přiřadit i objekt odvozeného typu • class U : public T { /*...*/ }; • U y; • T x = y;// toto je kopie části objektu y do vznikajícího objektu x

  21. Objekt a ukazatel na objekt • C++ důsledně odlišuje objekt a ukazatel na něj • Triviální důsledek: • class T { /*...*/ }; • T * p; // zde nevzniká objekt typu T • Netriviální důsledek: • Proměnná typu T je vždy objekt typu T a žádného jiného, přestože do ní lze přiřadit i objekt odvozeného typu • class U : public T { /*...*/ }; • U y; • T x = y;// toto je kopie části objektu y do vznikajícího objektu x • Poznámka pro znalce pravidel: • K tomuto přiřazení může dojít díky existenci automaticky vytvořeného copy-constructoru • T::T( const T &); • a díky možnosti konvertovat odkaz na potomka na odkaz na předka:U => U & => T & => const T &

  22. Objekt a ukazatel na objekt • C++ důsledně odlišuje objekt a ukazatel na něj • Triviální důsledek: • class T { /*...*/ }; • T * p; // zde nevzniká objekt typu T • Netriviální důsledek: • Proměnná typu T je vždy objekt typu T a žádného jiného, přestože do ní lze přiřadit i objekt odvozeného typu • class U : public T { /*...*/ }; • U y; • T x = y;// toto je kopie části objektu y do vznikajícího objektu x • Poznámka pro znalce implementace: • Zde (ani nikde jinde) se nekopírují odkazy na tabulky virtuálních funkcí • Proměnná typu T tedy zůstane typem T včetně přiřazení těl virtuálních funkcí • Jiné chování by nemělo smysl

  23. Objekt a ukazatel na objekt • C++ důsledně odlišuje objekt a ukazatel na něj • Triviální důsledek: • class T { /*...*/ }; • T * p; // zde nevzniká objekt typu T • Netriviální důsledek: • Proměnná typu T je vždy objekt typu T a žádného jiného, přestože do ní lze přiřadit i objekt odvozeného typu • class U : public T { /*...*/ }; • U y; • T x = y;// toto je kopie části objektu y do vznikajícího objektu x • V tomto odlišování se C++ liší od většiny jazyků s objekty (Java, JavaScript, PHP, VisualBasic, ...)

  24. Objekt a ukazatel na objekt • C++ důsledně odlišuje objekt a ukazatel na něj • Nefunguje naivní implementace polymorfního typu: • class Variant { enum { REAL, COMPLEX } t; }; • class Real : public Variant { public: double Re; }; • class Complex : public Variant { public: double Re, Im; }; • Variant max( Variant a, Variant b); • Real x, y, z = max( x, y);// nelze přeložit • Complex u, v, w = max( u, v);// nelze přeložit

  25. Objekt a ukazatel na objekt • C++ důsledně odlišuje objekt a ukazatel na něj • Nefunguje naivní implementace polymorfního typu: • class Variant { enum { REAL, COMPLEX } t; }; • class Real : public Variant { public: double Re; }; • class Complex : public Variant { public: double Re, Im; }; • Variant max( Variant a, Variant b); • Real x, y, z = max( x, y);// nelze přeložit • Complex u, v, w = max( u, v);// nelze přeložit • Parametry a, b nedokážou přenést atributy Re, Im • Návratovou hodnotu nelze (ani explicitně) přetypovat na potomka • Real x, y, z = (Real)max( x, y); // nelze přeložit • Complex u, v, w = (Complex)max( u, v);// nelze přeložit • I kdyby to šlo, typ Variant vracený hodnotou nedokáže přenést atributy Re, Im

  26. Objekt a ukazatel na objekt • C++ důsledně odlišuje objekt a ukazatel na něj • Nefunguje naivní implementace polymorfního typu: • class Variant { enum { REAL, COMPLEX } t; }; • class Real : public Variant { public: double Re; }; • class Complex : public Variant { public: double Re, Im; }; • V tomto případě lze tento problém řešit referencemi: • Variant & max( Variant & a, Variant & b); • vyžaduje ovšem explicitní přetypování, které je nebezpečné • Real x, y, z = (Real&)max( x, y); // funguje • Complex u, v, w = (Complex &)max( u, v);// funguje • Vracení referencí ovšem funguje pouze pro funkce max a min

  27. Objekt a ukazatel na objekt • C++ důsledně odlišuje objekt a ukazatel na něj • Nefunguje naivní implementace polymorfního typu: • class Variant { enum { REAL, COMPLEX } t; }; • class Real : public Variant { public: double Re; }; • class Complex : public Variant { public: double Re, Im; }; • V tomto případě lze tento problém řešit referencemi: • Variant & max( Variant & a, Variant & b); • vyžaduje ovšem explicitní přetypování, které je nebezpečné • Real x, y, z = (Real&)max( x, y); // funguje • Complex u, v, w = (Complex &)max( u, v);// funguje • Vracení referencí ovšem funguje pouze pro funkce max a min • Tyto funkce mají speciální vlastnost: vrací jeden ze svých parametrů

  28. Objekt a ukazatel na objekt • Funkce jako add nemůže vracet referenci • add vrací hodnotu různou od všech svých parametrů • hodnotu parametrů nesmí měnit • reference nemá na co ukazovat • Špatné řešení č. 1: Lokální proměnná • Complex & add( const Complex & a, const Complex & b) • { • Complex r( a.Re + b.Re, a.Im + b.Im); • return r; • } • BĚHOVÁ CHYBA: r zaniká při návratu z funkce

  29. Objekt a ukazatel na objekt • Funkce jako add nemůže vracet referenci • add vrací hodnotu různou od všech svých parametrů • hodnotu parametrů nesmí měnit • reference nemá na co ukazovat • Špatné řešení č. 2: Dynamická alokace • Complex & add( const Complex & a, const Complex & b) • { • Complex * r= new Complex( a.Re + b.Re, a.Im + b.Im); • return * r; • } • PROBLÉM: kdo to odalokuje ?

  30. Objekt a ukazatel na objekt • Funkce jako add nemůže vracet referenci • add vrací hodnotu různou od všech svých parametrů • hodnotu parametrů nesmí měnit • reference nemá na co ukazovat • Špatné řešení č. 3: Globální proměnná • Complex g; • Complex & add( const Complex & a, const Complex & b) • { • g = Complex( a.Re + b.Re, a.Im + b.Im); • return g; • } • CHYBA: globální proměnná je sdílená • Complex a, b, c, d, e = add( add( a, b), add( c, d));

  31. Třídy v C++ • Konstrukce class, dědičnost a virtuální funkce jsou silný mechanismus, užívaný k různým účelům • Různé pohledy na třídy a různá pojmenování • Abstraktní a konkrétní třídy • Třídy jako datové typy • Kontejnery (třídy logicky obsahující jiné objekty) • Singletony (jednou instanciované třídy) • Traits (neinstanciované třídy) • Různé účely dědičnosti • Rozšíření požadovaného rozhraní • Implementace požadovaného rozhraní • Rozšíření implementované funkčnosti • Využití k implementaci

  32. Nesprávné užití dědičnosti • Nesprávné užití dědičnosti č. 1 • class Real { public: double Re; }; • class Complex : public Real { public: double Im; }; • Vypadá jako reusabilita kódu

  33. Nesprávné užití dědičnosti • Nesprávné užití dědičnosti č. 1 • class Real { public: double Re; }; • class Complex : public Real { public: double Im; }; • Vypadá jako reusabilita kódu • Porušuje pravidlo "každý potomek má všechny vlastnosti předka" • např. pro vlastnost "má nulovou imaginární složku"

  34. Nesprávné užití dědičnosti • Nesprávné užití dědičnosti č. 1 • class Real { public: double Re; }; • class Complex : public Real { public: double Im; }; • Vypadá jako reusabilita kódu • Porušuje pravidlo "každý potomek má všechny vlastnosti předka" • např. pro vlastnost "má nulovou imaginární složku" • Důsledek - slicing: • doubleabs( const Real & p) { return p.Re > 0 ? p.Re : - p.Re; } • Complex x; • double a = abs( x);// tento kód LZE přeložit, a to je špatně • Důvod: Referenci na potomka lze přiřadit do reference na předka • Complex => Complex & => Real & => const Real &

  35. Nesprávné užití dědičnosti • Nesprávné užití dědičnosti č. 1 • class Real { public: double Re; }; • class Complex : public Real { public: double Im; }; • Slicing nastává i u předávání hodnotou • doubleabs( Realp) { return p.Re > 0 ? p.Re : - p.Re; } • Complex x; • double a = abs( x);// tento kód LZE přeložit, a to je špatně • Důvod: Předání hodnoty x do parametru p je provedeno implicitně vytvořeným konstruktorem: • Real::Real( const Real & y){ Re = y.Re; } • Parametr x typu Complex do tohoto konstruktoru lze předat • Complex => Complex & => Real & => const Real &

  36. Nesprávné užití dědičnosti • Nesprávné užití dědičnosti č. 2 • class Complex { public: double Re, Im; }; • class Real : public Complex { public: Real( double r); }; • Vypadá jako korektní specializace:"každé reálné číslo má všechny vlastnosti komplexního čísla"

  37. Nesprávné užití dědičnosti • Nesprávné užití dědičnosti č. 2 • class Complex { public: double Re, Im; }; • class Real : public Complex { public: Real( double r); }; • Vypadá jako korektní specializace:"každé reálné číslo má všechny vlastnosti komplexního čísla" • Chyba: Objekty v C++ nejsou hodnoty v matematice • Třída Complex má vlastnost "lze do mne přiřadit Complex" • Tuto vlastnost třída Real logicky nemá mít, s touto dědičností ji mít bude

  38. Nesprávné užití dědičnosti • Nesprávné užití dědičnosti č. 2 • class Complex { public: double Re, Im; }; • class Real : public Complex { public: Real( double r); }; • Vypadá jako korektní specializace:"každé reálné číslo má všechny vlastnosti komplexního čísla" • Chyba: Objekty v C++ nejsou hodnoty v matematice • Třída Complex má vlastnost "lze do mne přiřadit Complex" • Tuto vlastnost třída Real logicky nemá mít, s touto dědičností ji mít bude • void set_to_i( Complex& p) { p.Re = 0; p.Im = 1; } • Real x; • set_to_i( x);// tento kód LZE přeložit, a to je špatně • Důvod: Referenci na potomka lze přiřadit do reference na předka • Real => Real & => Complex &

  39. Nesprávné užití dědičnosti • Nesprávné užití dědičnosti č. 2 • class Complex { public: double Re, Im; }; • class Real : public Complex { public: Real( double r); }; • Vypadá jako korektní specializace:"každé reálné číslo má všechny vlastnosti komplexního čísla" • Chyba: Objekty v C++ nejsou hodnoty v matematice • Třída Complex má vlastnost "lze do mne přiřadit Complex" • Tuto vlastnost třída Real logicky nemá mít, s touto dědičností ji mít bude • Poznámka: při přímem přiřazování tento problém nenastane • Complex y; • Real x; • x = y;// tento kód NELZE přeložit • Důvod: operátor = se nedědí • Complex & Complex::operator=( const Complex &); // nezdědí se • Real & Real::operator=( const Real &);// nesouhlasí typ argumentu

  40. Třídy v C++ • Třídy sloužící jako datové typy • Proměnné typu T • Časté kopírování, vracení hodnotou • Přiřazení bývá jediný způsob změny stavu objektu • Dědičnost nemá smysl • Bez virtuálních funkcí • Třídy reprezentující „živé“ objekty • Proměnné typu T *, případně T & • Objekty alokovány dynamicky • Kopírování nemívá smysl • Metody měnící stav objektu • Většinou s dědičností a virtuálními funkcemi

  41. Třídy v C++ • Abstraktní třída • Definice v C++: Třída obsahující alespoň jednu čistě virtuální funkci • Běžná definice: Třída, která sama nebude instanciována • Představuje rozhraní, které mají z ní odvozené třídy (potomci) implementovat • Konkrétní třída • Třída, určená k samostatné instanciaci • Implementuje rozhraní, předepsané abstraktní třídou, ze které je odvozena

  42. class UUU { public: virtual ~UUU(); }; class XXX : public UUU { public: virtual ~XXX(); }; XXX * px = new XXX; // konverze potomek-předek UUU * pu = px; delete pu; Pokud je objekt destruován operátorem delete aplikovaným na ukazatel na předka, musí být destruktor v tomto předku deklarován jako virtuální Odvozené pravidlo: Každá abstraktní třída má mít virtuální destruktor Je to zadarmo Může se to hodit Dědičnost a destruktor

  43. Ideální užití dědičnosti a virtuálních funkcí • Abstraktní třída • Definuje rozhraní objektu jako množinu předepsaných virtuálních funkcí • class GraphicObject { • public: • virtual ~GraphicObject();// každá abstraktní třída má mít v.d. • virtual void paint() = 0; // čistě virtuální funkce • virtual void move( int dx, int dy) = 0; // čistě virtuální funkce • };

  44. Ideální užití dědičnosti a virtuálních funkcí • Abstraktní třída • Definuje rozhraní objektu jako množinu předepsaných virtuálních funkcí • Abstraktní třídy se mohou dědit • Dědičnost jako rozšiřování předepsaného rozhraní • class ClickableObject : public GraphicObject { • public: • virtual void click( int x, int y) = 0; // čistě virtuální funkce • };

  45. Ideální užití dědičnosti a virtuálních funkcí • Abstraktní třída • Definuje rozhraní objektu jako množinu předepsaných virtuálních funkcí • Konkrétní třída • Implementuje předepsané virtuální funkce • Je potomkem abstraktní třídy • Dědičnost jako vztah rozhraní-implementace

  46. Ideální užití dědičnosti a virtuálních funkcí • Abstraktní třída • Definuje rozhraní objektu jako množinu předepsaných virtuálních funkcí • Konkrétní třída • Implementuje předepsané virtuální funkce • class Button : public ClickableObject { • public: • Button( int x, int y, const char * text); • protected: • virtual void paint(); • virtual void move( int dx, int dy); • virtual void click( int x, int y); • private: • int x_, y_; char * text_; • };

  47. Ideální užití dědičnosti a virtuálních funkcí • Abstraktní třída • Definuje rozhraní objektu jako množinu předepsaných virtuálních funkcí • Konkrétní třída • Implementuje předepsané virtuální funkce • Polotovar třídy • Mezi abstraktní a konkrétní třídou - třída implementující část předepsaných virtuálních funkcí • Jejím potomkem je konkrétní třída nebo jiný polotovar • Dědičnost jako reusabilita kódu

  48. Ideální užití dědičnosti a virtuálních funkcí • Polotovar třídy • Mezi abstraktní a konkrétní třídou - třída implementující část předepsaných virtuálních funkcí • class PositionedObject : public ClickableObject { • public: • PositionedObject( int x, int y); • protected: • int get_x() const { return x_; } • int get_y() const { return y_; } • virtual void move( int dx, int dy); • private: • int x_, y_; • };

  49. Ideální užití dědičnosti a virtuálních funkcí • Konkrétní třída • Implementuje předepsané virtuální funkce • Konkrétní třídy mohou mít potomky - jiné konkrétní třídy se změněnými vlastnostmi (redefinovanými virtuálními funkcemi) • Dědičnost jako reusabilita kódu se změnou chování • class IconButton : public Button { • public: • IconButton( int x, int y, const char * text, BitMap icon); • protected: • virtual void paint(); • private: • BitMap icon_; • };

  50. Ideální užití dědičnosti a virtuálních funkcí • Různé významy dědičnosti • Rozšiřování předepsaného rozhraní • GraphicObject => ClickableObject • Vztah rozhraní-implementace • ClickableObject => PositionedObject, Button • Reusabilita kódu • PositionedObject => Button • Reusabilita se změnou chování (overriding) • Button => IconButton • A to není zdaleka všechno... • C++ pro odlišné účely využívá tytéž mechanismy • Některé jazyky tyto účely rozlišují (Java)

More Related