Objektově orientované programování
Zápočet
Zkouška
Literatura
Obsah předmětu
Paradigmata programování
Třídy a objekty
Třída zvíře v C++ - rozhraní
Třída zvíře - implementace
Třída zvíře - použití
Objekt - instance třídy
this
Reference
Přetěžování funkcí
Implicitní parametry
Konstruktory
Konstruktor s parametry
Přetěžování operátorů - deklarace
Přetěžování operátorů – těla metod
Přetěžování operátorů - pravidla
Přetěžování operátorů – ekvivalence
copy konstruktor a operator=
Udržovatelnost kódu
Objekt a ukazatel na objekt
Operátory new a delete
Chytré řetězce – nápad
Chytré řetězce - třída
Destruktory
Vyvolání destruktoru
Řetězce – implementace
O něco lepší implementace
Implementace kopírování
Zřetězení
Připojení řetězce
Str a jednotlivé znaky
Výstup
... and together
Dědičnost
pes jako potomek zvířete - definice
Konstruktor a destruktor předka
Kompatibilita předka a potomka
Polymorfismus
Polymorfismus - motivace
Polymorfismus – takto nelze
Polymorfismus – takto bych to chtěl
Virtuální funkce - deklarace
Virtuální funkce - implementace
Virtuální funkce a konstruktory a destruktory
Volání virtuálních funkcí
Abstraktní třída, čistě virtuální funkce
Abstraktní třídy, virtuální destruktory
Nesprávné užití dědičnosti
Prostory jmen (namespaces)
Prostory jmen
Prostory jmen a standardní knihovny
Vstup a výstup - proudy (streams)
Streams – hierarchie tříd
Hlavičkové soubory
Manipulátory
Výstup do souboru
Další metody vstupních proudů
Spřátelené funkce – vlastní výstup
Šablony
Šablony tříd - definice
Šablony metod, instance šablon
STL – Standard Template Library
STL – kontejnery
STL – kontejnery
STL – iterátory a metody kontejnerů
STL – použití iterátorů
STL – použití asociativního pole
STL – algoritmy
STL – použití algoritmů
STL – chybová hlášení
string
Výjimky
Výjimky - jednoduchý příklad
Výjimky - jednoduchý příklad
Výjimky - pravidla
Specifikace výjimek funkcí
... co jsme neprobrali
Dodelat na priste
948.50K

Objektově orientované programování

1. Objektově orientované programování

doc. RNDr. Jan Lánský, Ph.D.
Katedra informatiky a matematiky 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]

2. Zápočet

Zdrojové kódy v minimálním rozsahu 1500 řádků, doporučeno 2500
řádků.
Nejlépe: Vlastní ucelený příklad, který něco rozumného dělá
Vlastní jednoduché příklady, zadání může být z knihy
Nejhůře: Příklady probírané na cvičení
PS: Aktivní účast na cvičeních (8 účastí z 12 možných)
KS: Aktivní účast na soustředěních, 4 účasti z 9 možných)
Chybějící účast (pod stanovený limit) lze nahradit:
PS: +200 řádků zdrojových kódů za 1 hodinu neúčasti
KS: +400 řádků zdrojových kódů za 1 neúčast na soustředění. Pozor v
jeden den bývají obvykle 2 až 3 soustředění)
Příklad: PS student X se zúčastnil jedné hodiny cvičení. Na zápočet odevzdá
1500 + (8 – 1)*200 = 2900 řádků zdrojových kódů.
Příklad: KS student Y se zúčastnil pouze výuky 1.4.2015 kdy proběhly 2
hodiny soustředění. Na zápočet odevzdá 1500 + (4 – 2)*400 = 2300 řádků
zdrojového kódu.

3. Zkouška

Diskuze nad zdrojovými kódy předloženými k získání
zápočtu.
Zkušební okruhy
Reference jako parametr funkce a návratová hodnota
Přetěžování funkcí a operátorů, new a delete
Bezparametrický konstruktor, copy konstruktor, operator =,
destruktor
Dědičnost, Virtuální funkce, abstraktní třídy
Prostory jmen
Streamy, práce se soubory
Šablony funkcí a tříd
STL kontejnery, iterátory a algoritmy
Výjimky

4. 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 STL
Herb Sutter: Exceptional C++, More Exceptional C++
Que: ANSI/ISO C++ Professional Programmer's Handbook
Bruce Eckel: Myslíme v jazyce C++
James O. Coplien: Advanced C++ Programming Styles and Idioms
Bjarne Stroustrup: The C++ Programming Language
ISO/IEC 14882, ANSI: Programming languages - C++ (1998, 2003)

5. Obsah předmětu

ZS (PJC)
LS (OOP)
C++
C++
C
C
Paradigmata programování, OOP
Objekty, zapouzdření, dědičnost, konstruktory a destruktory
Přetěžování funkcí, předefinování operátorů
Pozdní vazba, virtuální funkce
Abstraktní datové typy
Šablony, výjimky, prostory jmen.
Objektové knihovny: streams, STL
RTTI, OO styly a idiomy...

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
Datová abstrakce
vytvoření vlastního datového typu (abstract/user defined datové typy)
kompletní množina operací nad tímto typem
nelze rozumně rozšiřovat
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í
dále – generické
programování
šablony, STL

7. Třídy a objekty

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živatele
Implementace – (neveřejná) interní data a metody (funkce)

8. Třída zvíře v C++ - rozhraní

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

9. Třída zvíře - implementace

zvire.h
class Zvire
{
Třída metody
private:
int zaludek;
public:
Zvire() { ... };
int zije() { ... };
int jez( int jidlo);
int vymesuj( int objem);
};
Přístup k
datům metody
Středník !!!
zvire.cpp
:: operátor
kvalifikace
#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;
}
Implementace
(tělo) metody

10. Třída zvíře - použití

zvire.h
class Zvire
{
private:
int zaludek;
mujprogram.cpp
Import rozhraní
public:
Zvire() { ... };
int zije() { ... };
int jez( int jidlo);
int vymesuj( int objem);
};
zaludek = 1
zaludek = 6
#include ”zvire.h”
.....
Automatický
konstruktor
{
.....
Zvire pytlik;
pytlik.jez(5);
pytlik.vymesuj(3);
zaludek = 3
if( ! pytlik.zije())
return -1;
-1 0 pytlik.vymesuj(4);
if( ! pytlik.jez(1))
return -2;
.....
}
Instance třídy
= objekt

11. Objekt - instance třídy

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

12. this

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

13. Reference

int x = 1, y = 2;
int *px;
px = &x;
*px = 3;
reference
pouze inicializace
nelze měnit
int &ry = y;
ry = 4;
x:
3
:px
y:
4
:ry
reference i ukazatele jsou
reprezentovány adresou
return *px + ry;
x:
1
:a
y:
2
:b
swap( int& a, int& b)
{
int c = a;
a = b;
b = c;
}
int x = 1, y = 2;
swap( x, y);
skutečné parametry
odkazy na proměnné
zpřehlednění kódu
přetěžování funkcí

14. Přetěžování funkcí

Funkce je definována svým identifikátorem a počtem a typem parametrů
int pocitej( int x)
{
return x+1;
}
Funkce se stejným identifikátorem
ale různým počtem parametrů
int pocitej( int a, int b)
{
return 2*a + b;
}
int pocitej( int a, const char* s)
{
return a + strlen( s);
}
pocitej( 1);
pocitej( 1, 2);
pocitej( 1, "ahoj");
Funkce se stejným počtem
ale různým typem parametrů
Správná funkce podle počtu a
typů skutečných parametrů
// int pocitej( int)
// int pocitej( int, int)
// int pocitej( int, char*)

15. 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
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)
Volá se stále stejná funkce
int fce( int, int, int)
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í

16. Konstruktory

Implicitní konstruktor
class Zvire
{
private:
int zaludek;
public:
Zvire() { zaludek = 1; };
Zvire( int zal) { zaludek = zal; };
Zvire( const Zvire& vzor)
{ zaludek = vzor.zaludek; };
};
Zvire beruska;
Zvire pytlik( 20);
Zvire beberuska( beruska);
Zvire tlustoch = pytlik;
bez parametrů
Konstruktor s
parametry
Copy konstruktor X (const X&)
vytvoří objekt jako kopii jiného
různé zápisy
copy konstruktoru
Pro U≠T nejsou zcela ekvivalentní:
U u;
T t(u);
// T::T( U&)
T t = u;
// T::T( T(u)) nebo
// T::T( u.operator T())
zatím lze ignorovat

17. Konstruktor s parametry

Tímto zakážeme
deklarovat objekt bez
použití NEimplicitního
konstruktoru
class Clovek
{
private:
char jmeno[50];
Clovek();
Využití
public:
//Clovek() { jmeno[0] = 0; };
Clovek( char * jmeno) {
strcpy(this->jmeno, jmeno);
};
};
Clovek honza("Honza");
//Clovek petr;
Nejde, zakázali
jsme
Předání nastavení objektu
Šetří řádky kódu
Zakázat implicitiní konstruktor
Dobře rozvážit zda zakázat
Bezpečnost proti nezadání
klíčové hodnoty
identifikátor

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+( const Bod&);
Bod operator=( const Bod&);
};
implicitní parametry
implicitní konstruktor
přetížení operátoru +
a + b a.operator+(b)
a = b a.operator=(b)
Bod::Bod(0,0);
Bod a(1,2), b, c;
c = a + b;
c.operator=(a.operator+(b));
c.assign( a.add( b));

19. Přetěžování operátorů – těla metod

x this->x
Bod Bod::operator=( const Bod& b)
{
x = b.x;
y = b.y;
return *this;
}
Bod Bod::operator+( const Bod& b)
{
return Bod( x+b.x, y+b.y);
}
co to je ???
vytvoření dočasného objektu
konstruktor Bod::Bod(int, int)
reference
aktualizace stavu
kopie objektu
(hodnotou přiřazení je
přiřazovaná hodnota)

20. Přetěžování operátorů - pravidla

Většinu operátorů jazyka C++ lze definovat pro uživatelské datové typy
Nelze předefinovat tyto operátory:
.
.*
::
? :
sizeof
Alespoň jeden z operandů musí být třída nebo výčtový typ nebo reference na ně
Nelze předefinovat operace na číselných typech a ukazatelích
Předefinováním nelze měnit prioritu a asociativitu operátorů
Pro předefinované operátory nemusí platit identity definované pro základní typy
++a nemusí být ekvivalentní a=a+1
a[b] nemusí být ekvivalentní *(a+b)
ani b[a]
je však velmi doporučeno dodržovat běžnou sémantiku
Pro předefinované operátory && a || neplatí pravidla o zkráceném
vyhodnocování
Typy skutečných operandů nemusejí přesně odpovídat typům formálních
parametrů
stejná pravidla jako pro přetížené funkce

21. 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
Bod Bod::operator+=( const Bod& b)
{
x += b.x;
y += b.y;
return *this;
}
a[b] *(a+b)
Bod Bod::operator+=( const Bod& b)
{
return *this = *this + b;
}
this->operator=( this->operator+( b))

22. copy konstruktor a operator=

class Bod
{
private:
int x, y;
public:
Bod( const Bod& b)
{ x=b.x; y=b.y; };
Bod operator=( const 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
definice nového objektu
operator=
přiřazení do existujícího objektu
Rozdíl mezi copy konstruktorem a přiřazením:
copy konstruktor se nemusí starat o předchozí stav objektu, přiřazení ano
přiřazení vrací (přiřazovanou) hodnotu, copy konstruktor nevrací nic

23. Udržovatelnost kódu

class Bod
{
public:
Bod( const Bod & b)
{ dosad(b); };
Bod operator=( const Bod & b)
{ dosad(b); return *this; };
Těla operátorů a konstruktorů
Public část před private
};
Funkce Get a Set
Těla metod vždy v *.cpp souboru
private:
int x, y;
void dosad( const Bod & b)
{ x=b.x; y=b.y; };
Private položky nejsou zajímavé
Datové položky vždy private
int GetX() {return x; };
int GetY() {return y; };
void SetX(int x) { this->x = x; }
void SetY(int y) { this->y = y; }
volání jiné funkce
Pro pozdější rozšíření
Lépe se hledá kde je implementované
Jména tříd
ToJeMojeTrida
Jména funkcí proměnných
mojePrvniFunkce

24. Objekt a ukazatel na objekt

C++ odlišuje objekt a ukazatel na něj
Rozdíl oproti jiným jazykům
Java, JavaScript, PHP, VisualBasic, ...
Analogie s chováním stuct v C
Ukazatel nelze použít dokud není splněna jedna z možností:
Přiřazen existující objekt
Reference
Dynamicky vytvořen nový objekt
Operátor new
class Zvire {
.....
};
Zvire * pytlik;
Zvire beruska;
pytlik = &beruska;
pytlik = new Zvire;
Nevzniká tu
žádný objekt
vzniká nový
objekt

25. Operátory new a delete

new: alokace paměti, zavolání konstruktoru
není nutno testovat úspěšnost – mechanismus výjimek
delete: zavolání destruktoru, dealokace paměti
jako parametr lze i 0
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;
char* buf = new char[10];
strcpy( buf, “ahoj”);
...
delete[] buf;
dynamická alokace,
implicitní konstruktor
náhrada za malloc()
uvolnění paměti
další alokace,
explicitní konstruktory
alokace pole objektů
uvolnění paměti u alokovaných polí nutno []

26. Chytré řetězce – nápad

Práce s řetězci v C
+ efektivní
– nepohodlná a těžkopádná
– časté chyby
Chtěl bych: přiřazování, zřetězení, automatická alokace místa
Str s1 = “ahoj”;
Str s2 = “babi”;
Str s3;
s3 = (char*) malloc( strlen(s1) + strlen(s2) + 2);
strcpy( s3, s1);
s3[ strlen(s1)] = ‘ ‘;
strcpy( s3 + strlen(s1) + 1, s2);
s3 = s1 + ‘ ‘ + s2;
s3 += “.”;
‘obyčejné‘ zřetězení – nechci se starat o to, kde sebrat
místo

27. Chytré řetězce - třída

class Str
{
private:
char* buf;
ukazatel na
alokovaná data
public:
Str() { buf = 0; };
Str( const Str& s);
Str( const char* s);
implicitní konstruktor
prázdný řetězec
destruktor objekt si musí po sobě uklidit
delete přežije i 0, nemusím testovat
~Str() { delete[] buf; };
Str& operator=( const Str& s);
Str operator+( const Str& s);
operace s řetězci
int len() const { return buf ? strlen(buf) : 0; };
};
další metody
(délka řetězce)
Konstantní funkce,
nemodifikuje objekt

28. Destruktory

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

29. Vyvolání destruktoru

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

30. Řetězce – implementace

Str& Str::operator=( const Str& s)
{
delete[] buf;
if( ! s.len()) {
buf = 0;
} else {
buf = new char[ s.len()+1];
strcpy( buf, s.buf);
}
return *this;
}
Str::Str( const Str& s)
{ ....
}
uklidit po
předchozím řetězci
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

31. O něco lepší implementace

později si ukážeme ještě
lepší – counted pointers
class Str
{
private:
char* buf;
void copy( const char* s);
privátní metoda –
alokace a kopírování
public:
Str() { buf = 0; };
Str( const Str& s) { copy( s.buf); };
Str( const char* s) { copy( s); };
~Str() { clear(); };
Str& operator=( const Str& s)
{ clear(); copy( s.buf); return *this; };
Str& operator=( const char* s)
{ clear(); copy( s); return *this; };
void clear() { delete[] buf; };
};
konstruktory: jen
alokace a kopírování
přiřazení: i uklizení a
návratová hodnota
často potřebujeme uklízet
!!! buf = 0; nebo
private !!!

32. Implementace kopírování

class Str
{
private:
char* buf;
void copy( const char* s);
public:
Str() { buf = 0; };
Str( const Str& s) { copy( s.buf); };
Str( const char* s) { copy( s); };
~Str() { clear(); };
Str& operator=( const Str& s)
{ clear(); copy( s.buf); return *this; };
Str& operator=( const char* s)
{ clear(); copy( s); return *this; };
void clear() { delete[] buf; };
};
Jde clear() přidat
do copy() ???
předpokládáme prázdný buf
zařídí volající metoda - copy je private
void Str::copy( const char* s)
{
if( !s || !*s) {
buf = 0;
} else {
buf = new char[ strlen( s)+1];
if( buf) strcpy( buf, s);
}
}
alokace a kopírování
zkontrolovat
prázdný
řetězec

33. Zřetězení

Str Str::operator+( const 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+( const char* s)
{
Str newstr;
newstr.buf = new char[ len() + strlen(s) + 1];
strcpy( newstr.buf, buf);
strcat( newstr.buf, s);
nelze návrat reference
return newstr;
(lokální dočasný objekt)
}
nové hodnoty VŽDY
vracet hodnotou
nový prázdný řetězec
místo na znaky
první operand
druhý operand
návratová hodnota

34. Připojení řetězce

když už umíme + a =
proč si neudělat +=
class Str
{
....
public:
....
Str& operator=( const Str& s);
Str& operator=( const char* s);
Str operator+( const Str& s);
Str operator+( const char* s);
Str& operator+=( const Str& s) { *this = *this + s; return *this; };
Str& operator+=( const char* s) { *this = *this + s; return *this; };
};
lze vracet referencí
existující hodnota
operator+( char*)
operator+( Str&)

35. Str a jednotlivé znaky

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

36. Výstup

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

37. ... and together

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

38. Dědičnost

vztah tříd předek-potomek – hierarchie
přesnější názvosloví: základní (base) / odvozená třída (derived class)
vícenásobná dědičnost
dvakrát měř, jednou řež, protokoly
specializace
potomek má/umí něco navíc
reusabilita
jiné chování bez změny původní třídy
Zvíře
jez, vyměšuj
Pes
sedni, lehni
Člověk
uč_se
Pitbul
trhej

39. pes jako potomek zvířete - definice

class Zvire
{
protected:
int zaludek;
Přístup pro
třídu a
potomky
public:
Zvire();
Zvire( int jidlo);
potomek
class Pes : public Zvire
(odvozená třída od)
{
Zvířete
private:
enum t_stav { Stoji, Sedi, Lezi };
t_stav stav;
přidaná položka
public:
Pes() { stav = Stoji; };
int zije();
int jez( int jidlo);
int vymesuj( int objem);
};
void sedni() { stav = Sedi; };
t_stav codela() { return stav; }
};
položky
předka
položky
potomka
metody
předka
žaludek
stav
jez, vyměšuj
sedni
potomek obsahuje všechny
položky a metody předka
metody
potomka
Zvire pytlik;
Pes azor;
pytlik.jez();
azor.jez();
azor.sedni();

40. Konstruktor a destruktor předka

class Zvire
{ ...
~Zvire() { printf( "zabijim zvire "); };
};
class Pes : public Zvire
{ ...
public:
Pes() { stav = Stoji; };
Pes( int jidlo) : Zvire( jidlo)
{ stav = Stoji; };
~Pes() { printf( "zabijim psa "); };
};
{
implicitní konstruktor předka
(automaticky)
explicitní konstruktor předka
konstruktory předků a
vložených tříd se volají před
konstruktorem potomka
destruktor předka se vyvolá
automaticky po ukončení
destruktoru potomka
Pes azor;
...
}
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 ukazatele)
pes umí jíst, brouk neumí štěkat
Zvire pytlik, *pz;
Pes azor, *pp;
pytlik
žaludek
azor
žaludek
stav
pytlik = azor;
pz = &azor;
azor
azor = pytlik;
pp = &pytlik;
pytlik
žaludek
stav
nelze
žaludek
???

42. Polymorfismus

odlišné chování potomků – pozdní vazba (late binding)
Zvíře
Pes
jez
jez
Pitbul
jez
sní maso
najde něco v
přírodě
Člověk
jez
jde do
restaurace
sní hodně
masa

43. Polymorfismus - motivace

class Zvire
{ jez() { priroda(); };
};
class Pes : public Zvire
{ jez() { maso(1); };
};
class Pitbul : public Pes
{ jez() { maso(10); };
};
Tohle není polymorfismus !
Zvire pytlik;
Pes punta;
Pitbul zorro;
Clovek pepa;
pytlik.jez();
// priroda();
punta.jez();
// maso(1);
zorro.jez();// maso(10);
pepa.jez(); // hospoda();
class Clovek : public Zvire
{ jez() { hospoda(); };
};
Každá třída má vlastní
implementaci (tělo) metody jez
'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

do ukazatele na základní třídu (předka) dám ukazatel
na nově vytvořený objekt odvozené třídy (potomka)
Zvire* z;
z je ukazatel na zvíře
volá se Zvire::jez()
z = new Pes;
z->jez(); // priroda();
z = new Clovek;
z->jez(); // priroda();
pokus – 'na tvrdo' chci
metodu potomka
Zvire* z;
z = new Pes;
z->Pes::jez();
nelze - syntaktická chyba
pes není předkem zvířete
// priroda();
z = new Clovek;
z->Clovek::jez(); // priroda();

45. Polymorfismus – takto bych to chtěl

chtěl bych, aby se volaly 'správné' metody
Zvire* z;
Zvire* naseRodina[3];
z = new Pes;
z->jez(); // maso(1);
naseRodina[0] = new Clovek;
naseRodina[1] = new Pes;
naseRodina[2] = new Pitbul;
z = new Clovek;
z->jez(); // hospoda();
for( int i = 0; i < 3; i++)
naseRodina[i]->jez();
Chci pokaždé se zavolat jinou metodu
Rozlišení metody se musí dít 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
žaludek
jez
tabulka
virtuálních
funkcí
žaludek
jez
stav
Zvire::jez() { priroda(); };
z->jez();
Pes::jez() { maso(1); };
zavolá se správná metoda
podle tabulky virtuálních funkcí

48. Virtuální funkce a konstruktory a destruktory

v konstruktoru a destruktoru se vždy
volá metoda vytvářeného/rušeného
objektu
class A
{ public:
virtual f();
A() { f(); }; // A::f
~A() { f(); }; // A::f
g() { f(); }; // A/B::f
};
určí se za běhu podle
skutečného typu objektu
nejdřív se zavolá
konstruktor předka
class B : public A
{ public:
virtual f();
B() { f(); }; // A::A B::f
~B() { f(); }; // B::f A::~A
g() { f(); }; // B::f
};
nejdřív se provede kód destruktoru,
pak se zavolá destruktor předka

49. Volání virtuálních funkcí

a
A::f
paa
pab
b
B::f
pbb
// A::f
// B::f
paa->f();
pab->f();
pbb->f();
// A::f
// B::f
// B::f
b.A::f();
b.B::f();
a.B::f();
paa->A::f();
pab->A::f();
pab->B::f();
pbb->A::f();
pbb->B::f();
// A::f
// B::f
// NE!
// A::f
// A::f
// NE!
// A::f
// B::f
kvalifikované volání
A a;
// A::A
B b;
// B::B
A * paa = &a;
A * pab = &b;
B * pbb = &b;
// B * pba = &a; nelze!! (předka do potomka)
a.f();
b.f();
pozdní vazba
class A { public: virtual f(); };
class B : public A { public: virtual f(); };

50. Abstraktní třída, čistě virtuální funkce

int armada;
class Vojak
{
public:
enum THod
{ vojin, desatnik, porucik, general };
Vojak( THod hod = vojin)
{ hodnost=hod; armada++; };
virtual void pal() = 0;
virtual ~Vojak() { armada--; };
private:
THod hodnost;
};
POZOR!!!
Nutný virtuální destruktor
abstraktní třída
nelze vytvořit objekt
společný předek
pure virtual function
⇒ abstraktní třída
společné rozhraní
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; };
};

51. Abstraktní třídy, virtuální destruktory

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

52. 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é...
Kompozice
Skládání velkých objektů z malých
C++: Třída s datovými položkami
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
Delegace
Převedení funkčnosti na jiný objekt
C++: Ukazatel
Společný abstraktní předek
Obratlovec
Vizuální objekt

53. Prostory jmen (namespaces)

zapouzdření identifikátorů
prevence kolizí (velké projekty, knihovny)
stejné identifikátory v různých prostorech 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));
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 ::

54. 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
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);
}
rozbalení std
přístup do aa
přístup k identifikátorům std
znovuotevření prostoru aa
přístup ke globálnímu
identifikátoru

55. 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
použití šablon
kontejnery, iterátory, algoritmy

56. 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
motivace:
rozšiřitelnost
bezpečnost
datum d( 12, 3, 2004);
printf( "dnes je %?", d);
#include <iostream>
using namespace std;
int main()
{
int n;
cout << "Rekni cislo: ";
cin >> n;
cout << "Mam vic: " << (n+1)
<< ", hec!" << endl;
}
int i;
printf( "Jmenuji se %s", i);
definice základních tříd a manipulátorů
ostream cout FILE* stdout
istream cin FILE* stdin
ostream& ostream::operator<< ()
istream& istream::operator>> ()

57. Streams – hierarchie tříd

58. Hlavičkové soubory

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

59. Manipulátory

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

60. Výstup do souboru

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

61. 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()
int i = 17;
ofstream f( "pokus.txt", ios::binary);
if( ! f) error();
f.write( (char*)&i, sizeof( i));
Výstup
put( znak)
write( pole_znaků, délka)
tellp()
seekp(posun, odkud)
flush()
... a další
pole bajtů a jejich počet

62. 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!

63. Šablony

množina funkcí/tříd lišících se pouze typem parametrů/položek
vzor, podle kterého překladač vytvoří funkci nebo třídu (instanci) pro konkrétní typ
Definice šablony funkce
Typový parametr T
nahrazuje skutečný typ
místo typename lze class
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;
int max( int a, int b)
double max( double a, double b)

64. Šablony tříd - definice

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);
};
size:
5
pole
neznámého
typu
array:
0
1
2
3
4
?
?
?
?
?
instance šablony třídy
definice proměnné
int main()
{
Guma<int> ip(5);
ip[3] = 999;
přetížený operator[]

65. Šablony metod, instance šablon

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];
}
instance
šablony třídy
definice typu
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&

66. 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 ...
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 << "]";
obousměrný seznam
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*

67. STL – kontejnery

Sekvenční kontejnery
Asociativní kontejnery
uspořádané
setříděné

68. STL – kontejnery

Sekvenční kontejnery
deque – dvoustranná fronta [dek]
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
Asociativní kontejnery
map, multimap – zobrazení, asociativní pole, slovník, mapa
uspořádaná struktura indexovaná libovolným typem, pair: klíč, hodnota)
set, multiset – množina, multimnožina
každý prvek nejvýše jednou / vícekrát

69. STL – iterátory a metody kontejnerů

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

70. STL – použití iterátorů

vytvoření
celočíselného
vectoru pole
pole.begin()
vrátí iterátor na
začátek pole
p je iterátor do
vector<int>
jestli p už
nedosáhl
konce
pole.end() vrátí
iterátor za
konec pole
vector<int> pole;
vector<int>::iterator p;
for( p = pole.begin(); p != pole.end(); p++)
cout << "[" << *p << "]";
*p (overl.) vrátí
hodnotu prvku
na nějž ukazuje
iterátor
p++ (overl.)
zařídí, že p
bude ukazovat
na další prvek

71. 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;
pair<string,string> iterator::operator*
ti->first ≡ (*ti).first
operator [] (const string&)
vyhledání podle first
ts:
pair:
string first
string second

72. STL – algoritmy

Inicializace
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
Vyhledávání
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 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
unique
Removes elements that match condition
Removes all but first of duplicate values
Ostatní
for_each
Applies a function to each element
+ mnoho dalších
Transformace prvků
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
next_permutation Generates permutations in sequence
prev_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 elements
make_heap Converts a range into a heap
Skalární výpočty
count
Counts number of elements matching value
count_if
Counts elements matching predicate
accumulate Reduces sequence to a scalar value
equal
Checks two sequences for equality
lexicographical_compare Compares two sequences
Výpočty generující sekvence
transform
Transforms each element
partial_sum Generates sequence of partial sums
adjacent_difference Gen. sequence of adjacent differences

73. STL – použití algoritmů

vlastní funkce pro jeden prvek
vyplní se
náhodnými
čísly
pro každý prvek
se zavolá funkce
najde max. prvek
vrátí iterátor
setřídí část pole od
max. prvku do konce
odstraní duplicity
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);
!! pozor – může
sort( p, e);
zneplatnit iterátor e
unique( p, e);
for_each( b, pole.end(), tiskni);

74. 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'

75. string

constructors
Create or copy a string
size(), length()
Return the number of characters
destructor
Destroys a string
max_size()
=, assign()
Assign a new value
Returns the maximum possible number of
characters
swap()
Swaps values between two strings
empty()
Returns whether the string is empty
+=,append(),
push_back()
Append characters
capacity()
Returns the number of characters that can
held without be reallocation
insert()
Inserts characters
[], at()
Access a character
erase()
Deletes characters
>>, getline()
Read the value from a stream
clear()
Removes all characters (makes it empty)
<<
Writes the value to a stream
resize()
Changes the number of characters
(deletes or appends chars at the end)
copy()
Copies or writes the contents to a C-string
c_str()
Returns the value as C-string
replace()
Replaces characters
data()
Returns the value as character array
+
Concatenates strings
substr()
Returns a certain substring
==,!=,<,<=,
>,>=,
compare()
Compare strings
find functions
Search for a certain substring or character
begin(), end()
Provide normal iterator support
rbegin(), rend()
Provide reverse iterator support
get_allocator()
Returns the allocator

76. 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
Nastavit do globální funkce příznak chyby
FUJ! Nikdy!
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ů)
Řešení v C++: mechanismus výjimek

77. Výjimky - jednoduchý příklad

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;
}
vyvolání výjimky
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

78. Výjimky - jednoduchý příklad

char* mojefce( long n)
{
char* bigbigbig = new char[n];
cout << "Proslo to" << endl;
return bigbigbig;
}
int main(int argc, char* argv[])
{
char* p = 0;
try {
mojefce( 2000000000);
cout << "Vratil jsem se" << endl;
} catch( runtime_error& e) {
cout << "Chyba: " << e.what() << endl;
}
return 0;
}
pokud se nepovede
naalokovat, nastane výjimka
při výjimce se dále
nepokračuje, hledá se
nejbližší volný handler
nalezený handler

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

80. 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 může vyvolat libovolnou výjimku
funkce nevyvolává
žádnou výjimku

81. ... co jsme neprobrali

spoustu věcí
jazyk
protected, volatile, static, operátory .* a ->*, ukazatele na funkce a metody, ...
vícenásobná dědičnost, protokoly
RTTI, typeid, type_info
static_cast, dynamic_cast, reinterpret_cast, const_cast
podrobněji knihovny, zejména streams a STL, efektivní používání knihoven
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
spoustu věcí
kdo chcete C++ opravdu profesionálně používat, přečtěte si literaturu (Meyers, Sutter)
nebuďte líní – zkoušejte i jednoduché věci naprogramovat 'profesionálně'

82. Dodelat na priste

Vice slajdu o pretezovani operatoru (i unarni)
Vice slajdu o referenci
Chytre retezce – pocitane odkazy
English     Русский Rules