Objektově orientované programování RNDr. Jan Lánský, Ph.D. Katedra softwarového inženýrství MFF UK Katedra informatiky VŠFS (Autor původní verze slajdů: Mgr. Zbyněk Winkler) (Autor prapůvodní verze slajdů: RNDr. Filip Zavoral, Ph.D.) (Část slajdů převzata od: RNDr. David Bednárek) [email protected]http://kocour.ms.mff.cuni.cz/~lansky/
RND r. Jan Lánský, Ph.D. Katedra softwarového inženýrství MFF UK Katedra informatiky V Š FS (Autor původní verze slajd ů : Mgr. Zbyněk Winkler ) (Autor prapůvodní verze slajd ů : RND r. Filip Zavoral, Ph.D. ) ( Část slajdů převzata od : RND r. David Bednárek ) [email protected] - PowerPoint PPT Presentation
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Objektově orientované programování
RNDr. Jan Lánský, Ph.D.Katedra softwarového inženýrství MFF UK
Katedra informatiky VŠFS
(Autor původní verze slajdů: Mgr. Zbyněk Winkler)(Autor prapůvodní verze slajdů: RNDr. Filip Zavoral, Ph.D.)
Chybějící účast lze nahradit: Vypracováním a předvedením příkladů probraných na cvičení [v
semestru] Zápočtový test (praktický příklad, odladěný, 3 hodiny) [kdykoliv]
Zápočtový program Téma (do 2. přednášky) Specifikace (do 3. přednášky) Betaverze (do konce semestru) Finální verze (do 30.6.)
Zkouška Ústní, s přípravou na PC (2 hodiny) Na zkoušku lze jít i bez zápočtu
Literatura
Miroslav Virius: Programování v C++Miroslav Virius: Pasti a propasti jazyka C++Miroslav Virius: Od C k C++Scott Meyers: Effective C++, More Effective C++, Effective STLHerb Sutter: Exceptional C++, More Exceptional C++Que: ANSI/ISO C++ Professional Programmer's HandbookBruce Eckel: Myslíme v jazyce C++James O. Coplien: Advanced C++ Programming Styles and IdiomsBjarne Stroustrup: The C++ Programming Language
ISO/IEC 14882, ANSI: Programming languages - C++ (1998, 2003)
Procedurální programování jakou akci mám provést vstup – výpočet (algoritmus) – výstup black box: procedura / funkce
Modulární programování rozdělení problému na komponenty procedury pracují nad daty - rozhraní black box: modul
Datová abstrakce vytvoření vlastního datového typu (abstract/user defined datové typy) kompletní množina operací nad tímto typem black box: datový typ
Objektové programování dědičnost – obecné / konkrétní vlastnosti Polymorfismus – odlišné chování potomků možnost pozdějších rozšíření zapouzdření
Paradigmata programování
side effects, údržba
nelze rozumně rozšiřovat
dále – generické programováníšablony, STL
Koncepční pohled objekt: entita reagující na vnější podněty třída: množina stejně reagujících entit
Technický pohled objekt: struktura obsahující data a funkce, instance třídy (proměnná) třída: typ objektu – jednotná struktura dat, stejné operace nad daty
Zobecnění pojmu struktura (struct) Rozdíl mezi class a struct v C++ je nepatrný, užívání class 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)
Rozhraní – veřejné informace a služby pro uživateleImplementace – (neveřejná) interní data a metody (funkce)
Třídy a objekty
Třída zvíře v C++ - rozhraní
class Zvire{private: int zaludek;
public: Zvire() { zaludek = 1; };
int zije() { return zaludek>0; }; int jez( int jidlo); int vymesuj( int objem);};
definice třídy
vnitřní stav(privátní)
rozhraní(veřejné)
metody
zvire.h
konstruktor(inicializace) inline
tělo funkce
Datová položka
Deklarace metody
Třída zvíře - implementace
#include ”zvire.h”
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;}
class Zvire{private: int zaludek;
public: Zvire() { ... };
int zije() { ... }; int jez( int jidlo); int vymesuj( int objem);};
zvire.hzvire.cpp
Třída metody
:: operátor kvalifikace
Implementace (tělo) metody
Přístup k datům metody
Středník !!!
Třída zvíře - použití
#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;
.....
}
-1 0
class Zvire{private: int zaludek;
public: Zvire() { ... };
int zije() { ... }; int jez( int jidlo); int vymesuj( int objem);};
zvire.hmujprogram.cppImport
rozhraní
Automatický konstruktor
Instance třídy = objekt
zaludek = 1zaludek = 6zaludek = 3
Objekt - instance třídy
int Zvire::jez( int jidlo){ if( ! zije()) return 0; return zaludek += jidlo;}
..... Zvire pytlik, beruska;
pytlik.jez( 5); beruska.jez( 1);.....
dvě instance třídy
6zaludek
2zaludek
pytlik:
beruska:
?
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);.....
this
int jez( Zvire* this, int jidlo){ if( ! zije( this)) return 0; return this->zaludek += jidlo;}
..... Zvire pytlik, beruska;
jez( &pytlik, 5); jez( &beruska, 1);.....
6zaludek 2zaludekpytlik: beruska:this
C C++
Každá metoda dostane 'tajný' parametr this – ukazatel na
objekt
zvire:: znamena
zvire * this
this->zije()
this->zaludek
Reference
int x = 1, y = 2;int *px;px = &x;*px = 3;
int &ry = y;ry = 4;
return *px + ry;
referencepouze
inicializacenelze měnit
3x: :px
4y: :ry
reference i ukazatele jsou reprezentovány
adresou
swap( int& a, int& b){ int c = a; a = b; b = c;}
int x = 1, y = 2;swap( x, y);
skutečné parametryodkazy na proměnné
1x: :a
2y: :b
zpřehlednění kódupřetěžování funkcí
Přetěžování funkcí
int pocitej( int x){ return x+1;}
int pocitej( int a, int b){ return 2*a + b;}
int pocitej( int a, const char* s){ return a + strlen( s);}
pocitej( 1); // int pocitej( int)pocitej( 1, 2); // int pocitej( int, int)pocitej( 1, "ahoj"); // int pocitej( int, char*)
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ů
Správná funkce podle počtu a typů skutečných parametrů
Funkce se stejným počtemale různým typem parametrů
Implicitní parametry
Některé parametry funkce mohou mít implicitní hodnoty pokud nejsou všechny parametry implicitní – implicitní parametry
odzadu
Při volání funkce lze implicitní parametry vynechat použije se implicitní hodnota
Kdy použít přetěžování a kdy implicitní parametry? Stejný kód pro různý počet parametrů implicitní parametry Pro různé počty nebo typy parametrů různý kód přetěžování
Volá se stále stejná funkce int fce( int, int,
int)
int fce( int a, int b = 2, int c = 4){ return 2*a + b - c;}
fce( 1); // int fce( 1, 2, 4)fce( 1, 5); // int fce( 1, 5, 4)fce( 1, 5, 6); // int fce( 1, 5, 6)
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(); }; virtual ~Pesak() { delete sam; };};
pure virtual function
⇒ abstraktní třídaspolečné rozhraní
POZOR!!!Nutný virtuální
destruktor
abstraktní třída nelze vytvořit
objektspolečný předek
Abstraktní třídy, virtuální destruktory
// Vojak v; // NELZE – abstraktní třídaPesak p; // OK – Pesak VojinPesak* pp = new Pesak; // OKpp->pal(); // Pesak::palVojak* pv = new Pesak; // OKpv->pal(); // Pesak::paldelete pp; // OK, Pesak::~Pesakdelete pv; // !!! 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
pokud by ~Vojak nebyl virtuální
Nesprávné užití dědičnosti
Letadlo není potomkem svého motoru Důkaz: Co když má dva motory... Násobná dědičnost? Ne: Je třeba je odlišit
Jezevčík umí vyhnat lišku z nory... Myslivec s jezevčíkem tedy také...
Myslivec není potomkem svého jezevčíka Důkaz: Nežere granule... Kompozice? Ne: Nerodí se zároveň
Mlok není potomkem ryby a savce Důkaz: Nemá dvě hlavy... Virtuální dědičnost? Ne: Nekojí
Tlačítko není potomkem obdélníku a textu
Kompozice Skládání velkých objektů z malých C++: Třída s datovými položkami
Delegace Převedení funkčnosti na jiný objekt C++: Ukazatel
Společný abstraktní předek Obratlovec Vizuální objekt
Prostory jmen (namespaces)
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));
zapouzdření identifikátorůprevence kolizí (velké projekty, knihovny)stejné identifikátory v různých prostorech jmen
definice prostoru jmen
přístup k identifikátoru
ze stejného prostoru
definice funkce mimo prostor jmen
přístup k identifikátorům přes ::
using namespace std;
namespace aa { int p; int q;}
int g( int n) { cout << (n + aa::p);}
namespace aa { int f3( int x) { return 1 + ::g( x);}
Prostory jmen
prostor jmen se může opakovaně otevírat a zavíratexplicitní přístup ke globálnímu identifikátoru ::idstandardní knihovny – namespace std
rozbalení std
znovuotevření prostoru aa
přístup do aa
přístup ke globálnímu identifikátoru
přístup k identifikátorům std
Prostory jmen a standardní knihovny
stará konvence: stdio.h, ctype.h, iostream.h identifikátory v globálním prostoru jmen
strlen, FILE
nová konvence: cstdio, cctype, iostream identifikátory uzavřené do namespace std
std::strlen, std::FILE
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
<iostream> – základní operace, standardní v/v, manipulátory 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, ...
Hlavičkové soubory
do proudu lze vkládat manipulátory – změní stav proudu
endl pošle buffer na výstup a odřádkujeleft, right zarovnávej doleva / dopravadec, 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ásledující číselnou položku)setfill(int) výplňkový znak
pro binární vstup a výstup nelze použít operátory << a >>
Výstup 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;
spřátelená (friend) funkce může přistupovat k privátním
položkám
POZOR!Toto není metoda
třídy!
množina funkcí/tříd lišících se pouze typem parametrů/položekvzor, podle kterého překladač vytvoří funkci nebo třídu (instanci) pro konkrétní typ
template <typename 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;
Šablony
Definice šablony funkce
Typový parametr T nahrazuje skutečný
typmísto typename lze
class
int max( int a, int b) double max( double a, double b)
template<typename T> class Guma{private: int size; T* array;public: const int default_size = 10; Guma( int _size = default_size) { size = _size; array = new T[size]; }; ~Guma() { delete array; } T& operator[] (int n);};
int main(){ Guma<int> ip(5); ip[3] = 999;
Šablony tříd - definice
přetížený operator[]
size: 5
array:
?
3
????
4210
instance šablony třídy
definice proměnné
pole neznámého typu
template<typename T> class Guma{ private: int size; T* array;public: T& operator[] (int n);};
template<typename 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];}
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 << "]";
STL – Standard Template Library
obousměrný seznam
kontejnery – datové struktury pro ukládání dat a manipulaci s nimiiterá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 ...
umožňuje v konst. čase přidávat na začátek i konec implementace typicky pomocí polí adaptéry (specializované použití i rozhraní): stack, queue, priority_queue
vector – pole (gumové) přístup k prvku v konstantním čase jako vector se chová i string a standardní pole (T x[]) string – chytré řetězce
=, +, += a mnoho dalších operací a metod list – dvousměrný seznam
implementace: spojový seznam umožňuje v konstantním čase přidávat prvky na libovolné místo
kontejner<T>::iterator iterátor příslušného kontejneruT& iterator::operator* přístup k prvku přes iterátor
begin(), end() iterátor na začátek / za(!) konec kontejnerupush_front(), push_back() přidání prvku na začátek / konecpop_front(), pop_back() odebrání prvku ze začátku / konce – nevrací hodnotu!front(), back() prvek na začátku / koncioperator[], at() přímý přístup k prvkuinsert(iterator,T) vložení prvku na místo určené iterátoremsize(), empty(), clear() velikost / neprázdost / smazání kontejneru
push(), pop(), top() přidání / odebrání / prvek na vrcholu zásobníku
STL – použití iterátorů
vector<int> pole;vector<int>::iterator p;for( p = pole.begin(); p != pole.end(); p++) cout << "[" << *p << "]";
for( ti = ts.begin(); ti != ts.end(); ti++) cout << ti->first << ": " << ti->second << endl;
STL – použití asociativního pole
pair<string,string> iterator::operator*
ti->first ≡ (*ti).first
ts:
pair:
string second
string first
operator [] (const string&)
vyhledání podle first
STL – algoritmy
Inicializacefill Fills a sequence with an initial valuefill_n Fills n positions with an initial valuecopy Copies a sequence into another sequencecopy_backward Copies a sequence into another sequencegenerate Initializes a sequence using a generatorgenerate_n Initializes n positions using a generator swap_ranges Swaps values from two parallel sequences
Vyhledávánífind Finds an element matching the argument
find_if Finds an element satisfying a conditionadjacent_find Finds consecutive duplicate elementsfind_first_of Finds one member of a seq. in another seq.
find_end Finds the last occurr. 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
Mazáníremove Removes elements that match conditionunique Removes all but first of duplicate values
Ostatnífor_each Applies a function to each element
Transformace prvkůreverse Reverses the elements in a sequencereplace Replaces specific values with new valuereplace_if Replaces elements matching predicaterotate Rotates elements in a sequence around a point
next_permutation Generates permutations in sequenceprev_permutation Generates permutations in reverse seq.
inplace_merge Merges two adjacent sequences into one
random_shuffle Randomly rearranges elements in a seq.
Tříděnísort Sorts all elementsmake_heap Converts a range into a heap
Skalární výpočtycount Counts number of elements matching value
count_if Counts elements matching predicateaccumulate Reduces sequence to a scalar valueequal Checks two sequences for equalitylexicographical_compare Compares two sequences
Výpočty generující sekvencetransform Transforms each elementpartial_sum Generates sequence of partial sumsadjacent_difference Gen. sequence of adjacent differences
+ mnoho dalších
STL – použití algoritmů
void tiskni( int x) { cout << " [" << x << "]"; }
vector<int> pole;vector<int>::iterator b, e, p;
generate( b = pole.begin(), e = pole.end(), rand);for_each( b, e, tiskni);p = max_element( b, e);sort( p, e);unique( p, e);for_each( b, pole.end(), tiskni);
Changes the number of characters (deletes or appends chars at the end)
resize()
Removes all characters (makes it empty)
clear()
Deletes characters erase()
Inserts characters insert()
Append characters +=,append(),push_back()
Swaps values between two strings swap()
Assign a new value =, assign()
Destroys a string destructor
Create or copy a string constructors
Returns the allocator get_allocator()
Provide reverse iterator support rbegin(), rend()
Provide normal iterator support begin(), end()
Search for a certain substring or character
find functions
Returns a certain substring substr()
Returns the value as character array data()
Returns the value as C-string c_str()
Copies or writes the contents to a C-string
copy()
Writes the value to a stream <<
Read the value from a stream >>, getline()
Access a character [], at()
Returns the number of characters that can held without be reallocation
capacity()
Returns whether the string is empty empty()
Returns the maximum possible number of characters
max_size()
Return the number of characters size(), length()
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 problém s více vlákny, nutnost neustále testovat
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ů)
při výjimce se dále nepokračuje, hledá se nejbližší volný handler
nalezený handler
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