Upozornění pro čtenáře a uživatele této knihy

Všechna práva vyhrazena. Žádná část této tištěné či elektronické knihy nesmí být reprodukována ani šířena v papírové, elektronické či jiné podobě bez předchozího písemného souhlasu nakladatele. Neoprávněné užití této knihy bude trestně stíháno.

Miroslav Virius

Programování v jazyce C++

od základů k profesionálnímu použití

Vydala Grada Publishing, a.s.

U Průhonu 22, 170 00 Praha 7

tel.: +420 234 264 401, fax: +420 234 264 400

www.grada.cz

jako svou 6791. publikaci

Odpovědný redaktor Petr Somogyi

Sazba Petr Somogyi

formát ePub vytvořil Petr Somogyi

Počet stran 416

První vydání, Praha 2018

© Grada Publishing, a.s., 2018

Cover Design © Grada Publishing, a.s., 2018

V knize použité názvy programových produktů, firem apod. mohou být ochrannými známkami nebo registrovanými ochrannými známkami příslušných vlastníků.

Vytiskly Tiskárny Havlíčkův Brod a.s.

ISBN 978-80-271-0957-9 (ePub)

ISBN 978-80-271-0956-2 (pdf)

ISBN 978-80-271-0502-1 (print)

Předmluva

Kniha, kterou držíte v ruce, vás seznámí se základy programování v jazyce C++. Je určena jak čtenářům, kteří ještě vůbec neprogramovali, tak i těm, kteří již v nějakém jazyce programovali a chtějí se seznámit s jazykem C++. Předpokládám, že čtenář je sice začátečníkem v programování, ale umí s počítačem zacházet uživatelsky, tedy dokáže spustit program, zkopírovat nebo smazat soubor atd. V průběhu dvaceti kapitol této knihy se jej pokusím dovést na úroveň lehce pokročilého programátora.

Co v této knize najdete

Jediným způsobem, jak se naučit nějaký programovací jazyk, je psát v něm programy, a proto už ve druhé kapitole začneme programovat. Cílem druhé, třetí a čtvrté kapitoly je uvést na scénu vybrané konstrukce jazyka C++ a umožnit čtenářům zkoušet si vše, o čem si v následujících kapitolách povíme, na vlastních programech – jednoduchých a možná nešikovných, ale fungujících.

Než se ovšem pustíme do programování, musíme si ujasnit některé pojmy a sjednotit terminologii. Proto se v první kapitole seznámíme s pojmy, které budeme používat. Povíme si, co je třeba vědět o počítači, o programovacích jazycích, algoritmech, objektově orientovaném programování a některých dalších věcech, bez nichž se při programování neobejdeme.

Ve druhé kapitole napíšeme svůj první program, ukážeme si, jak ho přeložit (neboť jazyk, v němž ho píšeme, je jiný než jazyk, v němž „myslí“ počítač) a jak ho spustit. Seznámíme se s integrovaným vývojovým prostředím Code::Blocs a s překladačem g++, které budeme v této knize používat.

Ve třetí kapitole napíšeme několik verzí jednoduchých programů, které přečtou číslo, vypočtou z něj jistou hodnotu a výsledek vypíší. To nám umožní seznámit se alespoň povrchně s některými základními programovacími konstrukcemi, s rozdělením programu do několika souborů, s pojmem projektu apod. Se znalostmi z této kapitoly byste měli být schopni zkoušet si vše, co se v dalších kapitolách naučíte, na vlastních programech.

Ve čtvrté kapitole si ukážeme jednoduchý objektový program, seznámíme se velmi povrchně se šablonami a předvedeme si, jak ladit program – tedy jak zjistit, proč dělá něco jiného, než co jsme chtěli naprogramovat.

Od páté kapitoly začíná výklad „naostro“. Po seznámení se základními pojmy postupně poznáme vestavěné datové typy, příkazy jazyka C++, naučíme se používat tzv. pole a ukazatele. V deváté kapitole napíšeme první větší program – jednoduchou hru, v níž počítač klade otázky a podle uživatelových odpovědí hádá zvíře.

V následujících kapitolách se seznámíme s uživatelem definovanými neobjektovými typy, s výrazy a deklaracemi, s funkcemi, s preprocesorem jazyka C++, s objektovými typy a s tzv. výjimkami (nástroj pro ošetřování chyb za běhu). V předposlední kapitole probereme nástroje pro vstupní a výstupní operace (tedy pro čtení údajů z klávesnice, ze souboru apod.) a pro zápis údajů na obrazovku, do souboru apod.

V poslední kapitole postupně vyvineme několik verzí programu pro seřazení obsahu textového souboru. Jde o analogii filtru sort, který je standardní součástí běžných operačních systémů; naše verze se ovšem bude od standardního programu v mnoha ohledech lišit. To nám umožní seznámit se s řadou nástrojů ze standardní knihovny jazyka C++ a s některými užitečnými programátorskými technikami.

V poslední kapitole si krátce povíme o věcech, o nichž jsme v této knize nehovořili nebo jsme si řekli jen nejnutnější informace, ale které by měl pokročilý programátor v C++ znát.

Nástroje

Výklad v této knize je založen na mezinárodním standardu jazyka C++ [3] z roku 2017. Pro psaní, překlad, sestavení a ladění programů používáme vývojové prostředí Code::Blocs, které lze zdarma získat na stránkách [15] spolu s překladačem g++. Vedle toho zde najdeme poznámky pro čtenáře, kteří se rozhodnou pro Visual C++, jehož základní verzi lze také získat zdarma. Poznamenejme, že verze 4.9.2 překladače g++, která je implicitně dodávána s prostředím Code::Blocs, ve skutečnosti implementuje jazyk C++ na úrovni standardu z roku 2011. Není však problém instalovat si a používat nejnovější verzi tohoto překladače (v době dokončování této knihy to byla verze 6.4), která plně implementuje standard z roku 2014 a většinu novinek standardu z roku 2017. Místo překladače g++ si také můžete instalovat jakýkoli jiný překladač C++. Je však třeba poznamenat, že rozšíření, která přinesly pozdější verze standardu, v této knize nepoužívám, neboť výklad o nich přesahuje možnosti knihy určené začátečníkům.

Terminologie

V celé knize používám důsledně českou terminologii. Vím, že má mnoho odpůrců, jsem však přesvědčen, že použití vhodných českých názvů výrazně usnadní pochopení, oč jde. Anglické termíny samozřejmě uvádím alespoň při prvním výskytu také.

Příklady

Výklad v této knize doprovází velké množství příkladů. Jejich zdrojové texty si můžete stáhnout z webových stránek nakladatelství Grada Publishing (www.grada.cz, vyhledejte příslušnou sekci této knihy), nebo z mých osobních stránek, jejichž adresu najdete dále. Tyto příklady jsem odladil pod překladačem g++ verze 4.9.2 a pod Visual C++ 2015.

Poděkování

Na závěr bych chtěl poděkovat všem, kteří svými radami a připomínkami napomohli zdárnému dokončeni tohoto díla, především pak Ing. Rudolfu Pecinovskému, CSc., z VŠE v Praze a Ing. Vladimiru Jarému, Ph.D., z KSI FJFI ČVUT, kteří četli vybrané části této knihy a měli k nim řadu připomínek. I přes veškerou péči, kterou jsem této knize věnoval, se do ní ovšem mohly vloudit chyby; za ty nesu pochopitelně veškerou zodpovědnost já. Jestliže v této knize nějakou chybu najdete, pošlete mi prosím zprávu na níže uvedenou adresu. Bude-li to možné, uveřejním na svých webových stránkách opravu.

Ženeva, CERN, 21. srpna 2017

Miroslav Virius

miroslav.virius@fjfi.cvut.cz

http://people.fjfi.cvut.cz/virius

1Než začneme

Než si začneme povídat o programovacím jazyce C++, musíme se alespoň povrchně seznámit s některými pojmy, které budeme používat. Začneme od počítače jako takového, pak si něco povíme o programovacích jazycích, algoritmech a objektově orientovaném programování a skončíme u C++ a nástrojů, které budeme potřebovat. Některé z uvedených pojmů nepochybně znáte; přesto vás prosím, abyste si toto povídání alespoň zběžně přečetli, abychom se mohli shodnout na terminologii.

1.1Počítač

S osobními počítači se v současné době setkáváme denně – najdeme je nejen v každé kanceláři, ale i v téměř každé domácnosti. Dovolím si tedy předpokládat, že s počítačem umíte zacházet jako uživatelé – umíte ho zapnout, vytvořit na něm textový dokument apod. Ovšem programátor (a to i začínající) o něm musí přece jen vědět víc než běžný uživatel. I když bude povídání v této kapitole silně zjednodušené, pro naše účely bude stačit.

Obvykle se říká, že počítač obsahuje čtyři základní části:

■Procesor je součást, která opravdu „počítá“, lépe řečeno která zpracovává informace. Zároveň také řídí činnost všech ostatních částí počítače.

■Operační paměť slouží k ukládání dat (informací), která počítač zpracovává, a programů, tedy příkazů, které určují, co má dělat. Vše, co je v této paměti, se při vypnutí počítače ztratí, „zapomene“. Používá se pro ni označení RAM, což je zkratka anglických slov Random Access Memory, tedy paměť s náhodným přístupem.

■Vstupní a výstupní zařízení slouží k výměně informací s okolím. (Počítač by nám nebyl nic platný, kdyby nám nemohl předat výsledky své práce.) Typickými příklady vstupních zařízení jsou klávesnice, myš, skener atd. Typickým příkladem výstupních zařízení může být obrazovka monitoru nebo tiskárna. Pro vstupní a výstupní zařízení se používá zkratka V/V nebo I/O (z anglického input/output).

■Trvalá paměť slouží k trvalému ukládání dat a programů.[1] Data v ní se při vypnutí počítače neztrácejí, má zpravidla mnohonásobně větší kapacitu než operační paměť, ale práce s ní je mnohonásobně pomalejší než práce s operační pamětí. Jako trvalá paměť se používají převážně magnetické disky (pevný disk, disk SSD – jeho název pochází z anglických slov solid state drive a je to paměťové zařízení podobné jako flash disk neboli „fleška“, ovšem s větší kapacitou) a samozřejmě také disky CD nebo DVD.

1.1.1Operační paměť

Základem operační paměti jsou elektronické obvody, které mohou mít dva stavy – například vypnuto nebo zapnuto. Jeden z těchto stavů obvykle odpovídá číslici 0, druhý číslici 1. Údaje v paměti jsou proto vyjádřeny jen pomocí nul a jedniček, v tzv. dvojkové soustavě. Místo, na které můžeme uložit číslici 0 nebo 1, označujeme jako bit. Operační paměť je tedy dlouhá řada bitů.

Ovšem práce s jednotlivými bity je nepohodlná, a proto se bity sdružují do větších celků. V dnešních počítačích se téměř bez výjimky používají skupiny velikosti 8 bitů, které se nazývají bajty (anglicky byte, tedy slabika). Poznamenejme, že pro bity se používá značka b a pro bajty značka B.

Jednotlivé bajty, tvořící operační paměť, jsou očíslovány. Počáteční bajt má číslo 0, následující má číslo 1 atd. Toto pořadové číslo se nazývá adresa bajtu. (Ve skutečnosti může být záležitost s adresami trochu složitější, ale to nás v souvislosti s C++ vůbec nebude zajímat.)

1.1.2Soustava SI, bity a bajty

Vnitřní paměť běžného počítače má dnes velikost několik miliard bajtů, kapacita disků a podobných zařízení se vyjadřuje v bilionech bajtů. Podobně jako v běžném životě nevyjadřujeme například vzdálenosti měst v metrech, ale v kilometrech, i v informatice se používají k vyjádření kapacity paměti (nebo obecně množství informace) větší jednotky. Běžně se hovoří o kilobajtech (kB), megabajtech (MB), gigabajtech (GB) atd.

Vzhledem k tomu, že počítače jsou založeny na dvojkové soustavě, je však přirozenější používat jednotky založené na mocninách dvou, nikoli na mocninách deseti, jak je tomu v soustavě SI. Proto by se měly používat jednotky kibibajt (1 KiB = 2^10 B = 1024 B), mebibajt (1 MiB = 1024 KiB = 2^20 B = 1048576 B), gibibajt (1 GiB = 2^30 B = 1073741824 B) atd. Předpony těchto jednotek jsou složeny z první slabiky odpovídající předpony soustavy SI a slabiky bi ze slova binary.[2]

1.2Datové typy a proměnné

Snadno zjistíme, že nejmenší číslo, které může jeden bajt obsahovat, se skládá z osmi nul a představuje i v desítkové soustavě nulu. Největší takové číslo se bude skládat z osmi jedniček a v desítkové soustavě představuje 255. To je samozřejmě málo – s počítačem, který by znal jen čísla od 0 do 255, bychom si nedokázali ani přepočítat výplatu. Proto se pro ukládání dat obvykle používají různě velké skupiny za sebou následujících bajtů.

Ani to ovšem nestačí. Snadno se přesvědčíme, že kdybychom vzali například skupinu dvou za sebou následujících bajtů, mohli bychom do ní uložit celá čísla v rozmezí od 0 do 65 535. Ale co když budeme potřebovat záporná čísla? Co když budeme potřebovat reálná čísla? Co když budeme chtít vyjádřit znaky nebo logickou hodnotu (nějaké tvrzení platí nebo neplatí)?

Musíme tedy zajistit způsob, který nám umožní reprezentovat data různých „druhů“ v paměti počítače. Jinými slovy, musíme najít způsob, jakým určité skupině bitů přiřadíme hodnotu, kterou tato skupina představuje – jak ji v počítači zakódovat.

Můžeme se například dohodnout, že bajt s hodnotou 01000001 bude představovat znak ‘A’. Táž skupina bitů může za jiných okolností ovšem také představovat celé číslo, které má hodnotu 65. Stejný bajt ale může být i součástí většího celku s úplně jiným významem.

Předchozí příklady ukazují, že pracuje-li počítač s nějakým kouskem paměti, s nějakou skupinou za sebou následujících bajtů na určité adrese, musí vědět, jak je tato skupina velká a jak má její obsah interpretovat. Jinými slovy, musí znát datový typ hodnoty, která je tam uložena, musí vědět, zda jde o celé číslo, znak, logickou hodnotu atd.

Podle datového typu se také budou lišit operace, které lze s danou hodnotou provádět. Celá čísla lze například sčítat a odečítat, znaky lze spojovat do řetězců, tedy do souvislého textu.

Nyní se na celý problém podívejme trochu jinak. Už víme, že když budeme chtít pracovat s nějakou hodnotou, musíme si ji uložit do paměti. To ale znamená, že si tam pro ni musíme vyhradit místo a říci, jakého typu budou údaje, které bude obsahovat. Takové místo pro ukládání hodnoty budeme nazývat proměnná.

Abychom s proměnnou mohli zacházet, musíme ji pojmenovat, musíme jí přidělit identifikátor. Tomu se v programování říká deklarace proměnné.[3]

1.3Programy a programovací jazyky

Aby mohl počítač nějak zpracovávat data, která mu předložíme, musíme mu také říci, co má vlastně dělat – musíme mu dát program.

Procesor umí s daty řadu operací, ovšem velice jednoduchých. Lze mu například říci „vezmi celé číslo, které je na adrese 6548, a přičti k němu celé číslo z adresy 7895“. Protože do jeho paměti nelze uložit nic jiného než čísla, musí být tyto příkazy vyjádřeny – zakódovány – také čísly. Toto číselné vyjádření instrukcí (příkazů) pro procesor se nazývá strojový kód a je to jediná věc, které procesor rozumí. Jedním z problémů je, že různé druhy počítačů používají různé strojové kódy, takže programy ve strojovém kódu nejsou přenositelné mezi počítači s různými procesory.

Jiným – a možná horším – problémem je, že programování ve strojovém kódu je velice namáhavé a nepřehledné. Také to téměř nikdo nedělá; místo toho se používají tzv. vyšší programovací jazyky – PHP, Java, C, Basic, a také C++.

Zápis programu ve vyšším programovacím jazyce se zpravidla skládá z vybraných anglických slov a z výrazů zapsaných podobně jako v matematice. Programování ve vyšším jazyce je pochopitelně daleko jednodušší než programování ve strojovém kódu. Je tu ovšem jeden háček: takovýto program nelze přímo spustit, neboť počítač mu nerozumí. Program ve vyšším programovacím jazyce se proto musí buď přeložit do strojového kódu, nebo interpretovat. V obou případech k tomu potřebujeme další program (nebo skupinu programů), které to za nás udělají.

Zápis programu ve vyšším programovacím jazyce se zpravidla označuje jako zdrojový kód nebo zdrojový program, v „programátorštině“ zdroják. Textový soubor, který tento zápis obsahuje, označujeme jako zdrojový soubor. O jeho překlad do strojového kódu (kompilaci) se stará program zvaný překladač neboli kompilátor (anglicky nazývaný compiler). V mnoha případech s ním spolupracuje ještě sestavovací program neboli linker, který může spojit několik nezávisle přeložených částí programu do jednoho celku. Sestavovací program také připojí knihovny – části programu, které už někdo naprogramoval předem a které můžeme už jen používat.

Překladem a sestavením programu vznikne soubor obsahující strojový kód, který lze na cílovém počítači rovnou spustit. Mezi často používané překládané programovací jazyky patří například C nebo C++.

Můžeme však také použít speciální program, jenž bude číst zdrojový text a provádět příkazy, které v něm najde – interpretovat ho. Typickým interpretovaným jazykem je klasický Basic.[4]

Interpretované programy zpravidla běží výrazně pomaleji než překládané programy. Navíc musíme na cílový počítač spolu s naším programem dodat také interpretační program.

Doplňme, že překladač libovolného programovacího jazyka (i C++) zároveň kontroluje syntaktickou správnost programu – tedy zda program je napsán podle jistých formálních pravidel, které zaručují, že mu počítač porozumí. (Syntaktická správnost programu bohužel nezaručuje věcnou správnost programu, tedy nezaručuje, že program bude dělat to, co si přejeme. Zaručuje pouze, že ho překladač dokáže přeložit.)

1.3.1Jazyk C++

Už víme, že C++ patří mezi překládané programovací jazyky. Jeho zdrojový kód se může skládat z několika souborů. Překlad takového programu probíhá ve třech základních fázích:

1.Nejprve preprocesor upraví zdrojové texty – odstraní z nich komentáře (v následující kapitole se dozvíme, co to znamená) a provede některé další úpravy. Výsledkem jsou zdrojové soubory připravené k vlastnímu překladu.

2.Pak překladač přeloží samostatně jednotlivé zdrojové soubory. Překladem z nich vzniknou tzv. relativní soubory (anglicky nazývané object file). Relativní soubor se typicky jmenuje stejně jako zdrojový soubor, má však jinou příponu – pod Windows to je zpravidla .obj, v prostředí Linuxu to je .o.

3.Nakonec sestavovací program (linker) spojí relativní soubory v jeden celek, připojí k nim potřebné knihovny (už hotové součásti, které má překladač k dispozici) a vytvoří z nich spustitelný soubor; ten má pod Windows příponu .exe. V jiných operačních systémech nemusí mít žádnou zvláštní příponu.

Preprocesor, překladač a linker mohou být – a dnes zpravidla jsou – spojeny do jednoho programu, který provede postupně všechny potřebné kroky. Přepínači zadanými při spuštění tohoto programu lze ovšem zajistit, že proběhne například jen zpracování preprocesorem, jen zpracování preprocesorem a překlad nebo jen sestavení relativních souborů do spustitelného programu. Podrobněji se s tím seznámíme v příští kapitole.

1.3.2Asembler

Mezistupněm mezi strojovým kódem a vyššími programovacími jazyky je asembler (assembler, assembly language). Je to jazyk složený především z mnemotechnických zkratek jednotlivých instrukcí strojového kódu. Například instrukce:

MOV EAX, 0

znamená v jednom z asemblerů procesorů Intel používaných na PC „ulož 0 do registru EAX“. (Registry jsou součásti procesoru, v nichž se provádějí operace s daty.) Asembler také zavádí proměnné jako pojmenovaná místa v paměti, a proto se pro ně dříve používalo označení jazyk symbolických adres. Poznamenejme, že pro jeden procesor může existovat (a zpravidla existuje) více asemblerů.

Programování v asembleru je sice nesrovnatelně jednodušší než programování ve strojovém kódu, ale na druhé straně je nesrovnatelně obtížnější než programování ve vyšších programovacích jazycích.

Překladače C++ zpravidla umožňují vytvořit také překlad zdrojového kódu do asembleru.

1.4Operační systém

S počítačem se typicky dodává vždy alespoň jeden program, a to operační systém. To je program, který startuje automaticky hned po spuštění počítače a běží po celou dobu jeho běhu. „Oživuje“ počítač: přijímá pokyny uživatele (nerozhoduje, zda jsou vyjádřeny slovem zapsaným v příkazové řádce nebo kliknutím na myší na ikoně), stará se o jejich provedení a informuje uživatele o výsledcích.

Vedle toho ovšem má ještě řadu dalších úloh, z nichž pro nás nejdůležitější je, že poskytuje služby běžícím programům. Stará se o jejich spouštění, o přidělování paměti, poskytuje nástroje pro práci se soubory atd. Chceme-li například v programu otevřít soubor, program prostě předá náš požadavek operačnímu systému a ten se postará o vše potřebné.

Mezi nejznámější operační systémy na osobních počítačích patří různé verze Windows a Linuxu, na mobilních zařízeních je to například Android, iOS a další.

1.5Program a algoritmus

C++, podobně jako ostatní programovací jazyky, slouží k zápisu programu. Už víme, že program je nějaký soubor instrukcí (příkazů), které počítači říkají, co má dělat.

Program vždy představuje návod k provedení nějaké úlohy nebo k vyřešení nějakého problému. Přitom musíme mít na paměti, že počítač za nás problém nevyřeší, jen za nás udělá hrubou práci – prohledá obrovské množství záznamů v databázi, vypočítá něco podle složitých vzorců, vykreslí obrázek a podobně. My mu ovšem musíme říci, jak to má udělat. Jinými slovy, musíme mu poskytnout návod, jak dospět k požadovanému výsledku.

Tento návod musí mít určité vlastnosti. Některé z nich mohou vypadat jako samozřejmé, ale přesto je zde uvedeme:

■Návod musí vést k požadovanému výsledku.

■Musí se skládat z kroků, kterým počítač rozumí – tzv. elementárních kroků. (To pro nás znamená, že ho musíme umět zapsat v některém programovacím jazyce.)

■Těchto kroků nesmí být nekonečně mnoho. (Nejde o to, že bychom mohli napsat program, který je nekonečně velký; to se nám asi nepodaří. Není ale nic těžkého napsat krátký program, který nikdy neskončí, protože se v něm bude donekonečna opakovat určitá skupina instrukcí.)

■Po každém kroku musí počítač vědět, kterým krokem má pokračovat.

Návod, který tyto podmínky splňuje, se obvykle označuje jako algoritmus. Na program se můžeme dívat jako na zápis algoritmu v programovacím jazyce.

1.5.1Metoda shora dolů

Otázkou je, jak k algoritmu dospět. Je asi jasné, že nejprve musíme umět daný problém vůbec vyřešit sami,[5] a pak se můžeme snažit zapsat ho jako posloupnost elementárních kroků. Přitom se používá obvykle tzv. metoda shora dolů. Návod se rozkládá na menší a menší části, až dospějeme k elementárním krokům. Při tomto zjemňování se samozřejmě může stát, že budeme muset předchozí rozdělení upravit, některé kroky spojit, některé kroky přidat ap.

PŘÍKLAD 1.1: ŘAZENÍ ZADANÝCH HODNOT

Jako příklad metody shora dolů vezmeme tuto úlohu: Máme skupinu N číselných proměnných, které označíme A[0], A[1], ..., A[N-1]. Tato čísla chceme uspořádat tak, aby platilo:

A[0] ≤ A[1] ≤ ... ≤ A[N-1]   (1)

Nejprve zavedeme nové termíny, které nám usnadní vyjadřování.

Skupině proměnných stejného typu, se kterými můžeme zacházet jako s jedním celkem, říkáme v programování pole (v angličtině se používá termín array). Zde tedy máme pole A s prvky A[0], A[1], ..., A[N-1]. Čísla označující jednotlivé prvky pole se nazývají indexy.

Úloha „zpřeházet“ hodnoty uložené v prvcích tohoto pole, aby vyhovovaly podmínce (1), se nazývá třídění pole.[6] Naším úkolem tedy je setřídit pole A. Návod pro třídění pole A může vypadat takto:

1.Najdi v poli A prvek, který obsahuje nejmenší hodnotu, a vyměň ho s prvkem, který je na prvním místě (na místě s indexem 0).

2.Najdi v poli A prvek, který obsahuje druhou nejmenší hodnotu, a vyměň ho s prvkem, který je na druhém místě.

3.A takto postupuj dále, dokud není pole setříděné.

Ovšem program nemůže obsahovat nějaké „takto postupuj dále“ – musíme najít lepší formulaci. Přitom si ale stačí uvědomit, že v prvním kroku vyhledáme nejmenší prvek z celého pole a dáme ho na první místo (do prvku pole s indexem 0). Nejmenší hodnota je tedy už na svém místě a nemusíme se o ni starat. Proto nám ve druhém kroku stačí najít nejmenší prvek ze zbylého úseku pole A[1], ..., A[N-1] a ten dát na druhé místo, ve třetím kroku najít nejmenší hodnotu mezi prvky A[2], ... , A[N-1] atd. V posledním kroku budeme hledat nejmenší z prvků A[N-2], A[N-1]. Pak bude pole setříděné, tedy bude vyhovovat podmínce (1).

To znamená, že opakujeme podobnou akci (vyhledat nejmenší prvek v úseku pole a dát ho na první místo v tomto úseku) se stále menším úsekem pole. Zkoumaný úsek pole začíná postupně prvkem s indexem 0, 1, ..., N-1.

Z těchto úvah může vzejít lepší formulace. Bude používat pomocnou proměnnou i, která nám poslouží jako „počítadlo“.

1.Do proměnné i vlož hodnotu 0.

2.Mezi prvky A[i], ... , A[N-1] najdi nejmenší.

3.Vyměň ho s prvkem, který je na i-tém místě.

4.Zvětši hodnotu proměnné i o 1.

5.Je-li i < N-1, pokračuj krokem 2, jinak skonči.

Kroky 1, 4 a 5 můžeme považovat za elementární, kroky 2 a 3 je třeba zpřesnit.7 Podívejme se nejprve na krok 2. Budeme v něm potřebovat dvě pomocné proměnné. V jedné, kterou pojmenujeme třeba min, si budeme pamatovat index nejmenšího zatím nalezeného prvku, a druhá – k – nám poslouží jako „počítadlo“ při procházení zkoumaného úseku pole.

2. Mezi prvky A[i], ... , A[N-1] najdi nejmenší.

2a. Do obou pomocných proměnných, k a min, ulož i. (To je index počátečního prvku zkoumaného úseku. Zatím jsme prozkoumali jen jeden prvek, a tak ho pokládáme za nejmenší.)

2b. Zvětši k o jedničku. (Přejdi na další prvek v poli.)

2c. Je-li k = N, jdi na krok 3.

2d. Je-li A[k] ≤ A[min], ulož do min hodnotu k.

2e. Přejdi na krok 2b.

Po skončení bude proměnná min obsahovat index nejmenšího prvku v prohledávaném úseku.

Podobně můžeme ještě upřesnit bod 3. V něm budeme potřebovat pomocnou proměnnou x:

3. Vyměň prvek A[min] s prvkem A[i].

3a. Do pomocné proměnné x ulož hodnotu A[min].

3b. Do A[min] přesuň hodnotu A[i].

3c. Do A[i] přesuň hodnotu x.

Tyto kroky již můžeme pokládat za elementární.

1.5.2Metoda zdola nahoru

Občas se také hovoří o tzv. metodě zdola nahoru.[7] Tím se myslí, že budeme svůj počítač postupně učit nové elementární kroky, které poskládáme z kroků, jež počítač už umí. Jestliže například zjistíme, že ve svém programu často třídíme pole, naprogramujeme si tento algoritmus jednou provždy a později ho budeme už jen používat a pokládat za elementární krok.

Naprogramované – a pojmenované – dílčí algoritmy označujeme v jazyce C++ jako funkce nebo jako podprogramy.

Poznamenejme, že součástí každého programovacího jazyka jsou knihovny, jež obsahují řadu naprogramovaných běžných algoritmů a dalších součástí programů, které můžeme ve svých programech používat.

1.6Objekty a třídy

Od devadesátých let minulého století je v programování převládajícím přístupem objektově orientované programování (OOP). Jazyk C++ sice není čistě objektový, což znamená, že nevyžaduje objektový přístup, ale umožňuje ho a řada součástí jeho knihoven je na objektovém přístupu založena, a proto si o něm musíme povědět. V tomto oddílu si vysvětlíme základní principy. Až budeme znát základy C++, vrátíme se k nim a povíme si více.

1.6.1Zapouzdření

Zatím jsme uvažovali o programování a programech převážně z hlediska počítače, hardwaru. Od zobrazování dat v paměti jsme došli k datovým typům, od strojového kódu k programovacím jazykům. Pokusme se nyní na programování podívat z hlediska programátora, který stojí před úkolem něco vyřešit – ať už jde o program pro vedení účetnictví malé či velké firmy, počítačovou hru nebo systém řídící vstřikování paliva v automobilovém motoru. Program musí v každém případě odrážet vybrané stránky řešené úlohy, musí být jejím počítačovým modelem.

Je asi jasné, že programátorovi se bude lépe pracovat, bude-li moci uvažovat v termínech řešeného problému, než když bude muset uvažovat v termínech datových typů, které jsou jednou provždy dány jako součást programovacího jazyka. Jinými slovy, bylo by vhodné, aby si programátor mohl definovat své vlastní datové typy, které by mohl použít k programovému popisu řešené úlohy. V OOP se jim říká objektové typy neboli třídy, neboť popisují třídy objektů, které se vyskytují v řešeném problému.

Jako příklad si představme, že programujeme grafický editor. Jeho uživatel si v něm bude chtít kreslit obrázky složené ze základních geometrických tvarů – bodů, úseček, kružnic apod.

Programátor bude muset ve svém programu tyto grafické objekty nějak reprezentovat. Bude si muset vytvořit programový model bodu, úsečky atd. a bude muset naprogramovat také operace, které lze s grafickými objekty dělat.

Bod jako objekt

Co to znamená? Abychom si to ujasnili, zamysleme se například nad bodem. Z geometrie si nepochybně pamatujete, že bod v rovině (v našem případě na obrazovce monitoru) je určen svými souřadnicemi, tedy dvojicí reálných čísel. Vedle toho ovšem potřebujeme určit také jeho barvu; tu můžeme v počítači vyjádřit jedním celým číslem. Z toho plyne, že k reprezentaci bodu stačí skupina tří čísel. A s touto skupinou budeme chtít často zacházet jako s celkem.

Abychom mohli s bodem snadno pracovat, musíme popsat (naprogramovat) také operace, které s ním chceme dělat. Musíme ho umět vytvořit, zrušit, zobrazit, přemístit, zjistit jeho barvu, změnit jeho barvu, zjistit jeho polohu, změnit jeho polohu atd.

Třída, datová složka

V programu budeme určitě potřebovat větší množství bodů. Abychom nemuseli popisovat každý zvlášť, definujeme bod jako nový datový typ – jako třídu. Jednotlivé body, které nakreslí uživatel našeho grafického editoru, budou v programu představovány proměnnými (budeme také říkat objekty nebo instancemi) třídy bod. Každá instance třídy bod bude obsahovat datové složky,[8] které popisují jeho polohu a barvu.

Metoda

K zacházení s jednotlivými body budeme používat operace, které jsme k tomu účelu naprogramovali. Také tyto operace budou součástí definice třídy; v OOP se nazývají metody.

Při definici nového typu jsme udělali (zatím jen naznačili) dvě věci. Určili jsme:

■datovou reprezentaci nového typu,

■operace s ním (metody).

Ukrývání implementace

Jedno z pravidel objektového programování říká, že s datovými složkami bychom měli manipulovat pouze prostřednictvím metod. Tím před zbytkem programu skrýváme, jaká je skutečná datová reprezentace tohoto typu – ukrýváme jeho implementaci. Později si vysvětlíme, proč je to tak důležité.

Zapouzdření

Ukrývání implementace se v objektovém programování označuje jako zapouzdření (anglicky encapsulation). Někdy se pod tento pojem zahrnuje i společná definice datové reprezentace nového typu a operací s ním.

Objektový program

Objektový program se skládá pouze z objektů, tedy z instancí objektových typů, a tyto objekty si navzájem posílají zprávy. Mohou posílat také zprávy třídám jako celku. Zní to asi velice nesrozumitelně, ale v podání jazyka C++ to prostě znamená, že volají (spouštějí) své metody.

Vezměme opět grafický editor a podívejme se na něj jako na celek. Celá aplikace bude nejspíš představována instancí třídy editor, jednotlivé součásti obrázku budou představovány instancemi tříd bod, úsečka atd. Když uživatel stiskne tlačítko, kterým určí, že chce někde vytvořit nový bod, tedy instanci třídy bod, dozví se to editor. Ten požádá o vytvoření instance třídy bod (pošle třídě bod zprávu, která bude představovat žádost o vytvoření instance určitých vlastností). Bude-li třeba vybraný bod přemístit, pošle editor této instanci zprávu „přemísti se“, tedy zavolá odpovídající metodu.

Poznamenejme, že v objektovém programu představuje i třída samotná zvláštní objekt, kterému lze poslat zprávu – například žádost o vytvoření instance.

Modelovací jazyk UML

Při návrhu objektového programu se dnes často využívá tzv. jednotný modelovací jazyk (Unified Modeling Language, UML). Je to soubor pravidel pro vytváření diagramů, které popisují různé aspekty řešené úlohy. Mezi jiným popisuje také třídy a jejich instance, které se v úloze vyskytují, a jejich vzájemné vztahy.

Třídy a jejich vztahy popisuje tzv. diagram tříd (class diagram). Pro znázornění jednotlivých tříd se používá ikona ve tvaru obdélníka. V horní části je jméno třídy, pod ní – oddělený vodorovnou čarou – je seznam datových složek a pod ním, opět pod vodorovnou čarou, seznam metod. (Pokud seznamy datových složek nebo metod nepotřebujeme, můžeme je samozřejmě vynechat.) Možné znázornění třídy bod ukazuje obrázek 1.1.

Poznamenejme, že zejména ve složitějších diagramech se ve znázornění tříd vynechávají jak datové složky, tak metody a uvádějí se pouze jména tříd.

Obrázek 1.1 Znázornění třídy bod v jazyce UML

Skládání objektů

Pojďme dál. Vedle bodů budeme v programu potřebovat také kružnice. Jak víme, je každá kružnice určena svým středem a poloměrem. Vedle toho ovšem musíme ještě určit tloušťku čáry a její barvu. Mohli bychom tedy tvrdit, že k popisu kružnice nám stačí pětice čísel; ovšem podíváme-li se na to pozorněji, uvědomíme si, že střed kružnice je bod a k jeho popisu můžeme využít už hotový typ bod.

Konec ukázky

Table of Contents

Tiráž

Předmluva

Co v této knize najdete

Nástroje

Terminologie

Příklady

Poděkování

1 Než začneme

1.1 Počítač

1.1.1 Operační paměť

1.1.2 Soustava SI, bity a bajty

1.2 Datové typy a proměnné

1.3 Programy a programovací jazyky

1.3.1 Jazyk C++

1.3.2 Asembler

1.4 Operační systém

1.5 Program a algoritmus

1.5.1 Metoda shora dolů

1.5.2 Metoda zdola nahoru

1.6 Objekty a třídy

1.6.1 Zapouzdření

Bod jako objekt

Třída, datová složka

Metoda

Ukrývání implementace

Zapouzdření

Objektový program

Modelovací jazyk UML

Skládání objektů

1.6.3 Polymorfizmus

1.7 Céčko se dvěma plusy

2 První program

2.1 Bez použití vývojového prostředí

2.1.2 Překlad a spuštění

2.1.3 Když se něco nezdaří

2.2 Používáme vývojové prostředí

2.3 Co jsme naprogramovali

2.3.10 Jak zapisujeme zdrojový program

3 Složitější programy

3.1 Dvojnásobek zadaného čísla

3.1.1 Nástroje

3.2 Větší ze dvou čísel

3.2.4 Operátor podmíněného výrazu

3.3 Počítáme faktoriál

3.3.1 Co bude program dělat

3.4 Samostatná funkce

3.4.2 Funkce faktorial()

3.5 Deklarace a použití

3.5.2 Lokální a globální proměnné

3.6 Několik zdrojových souborů

3.7 Testování programu

3.7.2 Velká čísla

3.8 Rozmezí hodnot

3.8.1 Konjunkce dvou podmínek

3.9 Zpřehledňujeme program

3.9.4 Tisk zprávy o chybě

3.10 Proč počítat spočítané

3.10.2 Jiná možnost

3.11 Jmenný prostor pro naše funkce

3.12 Program neumí pod Windows česky

3.12.4 Nastavujeme kódovou stránku programově

4 Pokročilejší konstrukce a techniky

4.1 První objektový program

4.1.1 Třída Napis

4.1.2 Vytvoření a použití instance

4.1.3 Přístup ke složkám instance

4.1.4 Sledujeme počet nápisů (statické složky)

4.2 Mnoho verzí téže funkce

4.2.3 Šablona funkce

4.3 Mnoho verzí téže třídy

4.3.1 Deklarace šablony objektového typu

4.4 Potřebujeme počítat

4.4.1 Třída vektor

4.4.3 Přetěžování operátorů

4.5 Ladění programu

5 Začínáme naostro

5.1 Jak budeme jazyk C++ popisovat

5.2 Základní pojmy

5.2.4 Zápis programu

5.3 Organizace programu

5.3.1 Implementační a hlavičkové soubory

6 Základní datové typy

6.1 Celočíselné datové typy

6.1.1 Typy se znaménkem a bez znaménka

6.1.2 Celočíselné literály

6.1.3 Mezní hodnoty celočíselných typů

6.1.4 Operace s celočíselnými typy

6.2 Znakové typy

6.2.1 Znakové typy v C++

6.2.2 Znakové literály

6.2.4 Znakové řetězce

6.3 Logické hodnoty

6.4 Reálná čísla

6.4.3 Operace s reálnými čísly

7 Příkazy

7.1 Jednoduché příkazy

7.2 Blok (složený příkaz)

7.3 Rozhodování (větvení algoritmu)

7.3.1 Příkaz if

7.3.2 Příkaz switch

7.4 Cykly

7.4.3 Příkaz for (klasický)

7.5 Příkazy pro přenos řízení

7.5.4 Příkaz goto a návěští

7.6 Další příkazy

8 Pole

8.1 Jednorozměrné pole

8.1.2 Inicializace jednorozměrného pole

8.1.5 Znakové řetězce ukončené nulou

8.1.6 Surové řetězcové literály

8.2 Vícerozměrná pole

9 Práce s pamětí

9.1 Ukazatele

9.1.2 Deklarace proměnné typu ukazatel

9.1.3 Užití ukazatele k nepřímému přístupu

9.1.8 Funkce, které vracejí ukazatel

9.2 Vztah polí a ukazatelů

9.2.1 Konverze pole na ukazatel

9.2.3 Adresová aritmetika

9.2.4 Ukazatele a znakové řetězce

9.3 Dynamické proměnné

9.3.2 Vytvoření dynamické proměnné

9.3.3 Když se alokace nepodaří

9.4 Reference

9.4.1 Reference na l-hodnotu

9.4.2 Reference na r-hodnotu

9.5 Program, který hádá zvířata

9.5.3 Strom v programu

10 Výčtové typy, struktury a unie

10.1 Výčtové typy

10.2 Struktury

10.2.1 Deklarace struktury (datového typu)

10.2.2 Operace se strukturami

10.3 Unie

10.3.1 Deklarace unie

11 Výrazy

11.1 Pořadí operací

11.2 Přehled operátorů

11.2.1 Operátory, u nichž je určeno pořadí přípravy operandů

11.2.2 Některé další operátory

11.3 Typ výrazu

11.3.1 Konverze číselných typů

12 Deklarace a proměnné

12.2 Paměťové třídy proměnných

12.2.4 Statické proměnné

12.3 Konstantní a nestálé proměnné

12.3.1 Konstanty (const)

12.4 Deklarace proměnné

12.4.5 Inicializace

12.5 Nové jméno existujícího typu

12.6 Platnost a viditelnost deklarace

12.6.1 Obor platnosti

13 Funkce

13.1 Deklarace funkce

13.1.1 Hlavička funkce

13.1.2 Tělo funkce

13.1.3 Různé modifikátory

13.2 Parametry funkce

13.2.1 Předávání parametrů

13.2.2 Proměnný počet parametrů

13.3 Přetěžování funkcí

13.3.2 Která funkce se zavolá?

13.4 Ukazatele na funkce

13.4.2 Operace s ukazateli na funkce

13.5 Lambda-výrazy

14 Program a jeho běh

14.1 Vlastnosti funkci main()

14.2 Systémové proměnné (proměnné prostředí)

14.3 Běh programu

14.3.2 Operace po ukončení funkce main()

14.3.3 Předčasné ukončení programu

15 Preprocesor

15.2 Direktivy preprocesoru

15.2.4 Makra

15.2.5 Podmíněný překlad

15.3 Samostatný preprocesor

16 Objektové typy

16.1 Deklarace objektového typu

16.1.3 Přístup ke složkám

16.1.4 Metody

16.2 Vytvoření a zánik instance

16.2.1 Konstruktor

16.2.2 Konstruktory, shrnutí

16.2.4 Destruktor

16.3 Kopírování instancí

16.3.2 Vlastní přiřazovací operátor

16.4 Datové složky a metody třídy jako celku

16.4.1 Statické datové složky

17 Dědění

17.1 Odvozená třída

17.1.2 Jak vypadá odvozená třída

17.2 Polymorfizmus

17.2.1 Přiřazování instancí různých typů

17.2.2 Virtuální metody

17.3 Abstraktní třídy a čistě virtuální metody

17.4 Dědění, nebo skládání?

18 Chyby za běhu programu

18.1 Aserce

18.2 Výjimky

18.2.1 Jak používáme výjimky

18.2.3 Zachycení a obsluha výjimky

18.2.4 Co se děje v programu s výjimkami

18.2.5 Výjimky, konstruktory a destruktory

19 Vstupy a výstupy

19.1 Soubor a proud

19.1.3 Textové a binární soubory

19.2 Datové proudy v C++

19.2.2 Vstupní a výstupní proudy

19.3 Nástroje zděděné od jazyka C

19.3.1 Datový proud a základní operace s ním

19.3.2 Další operace s datovými proudy

19.3.3 Formátovaný zápis

19.3.4 Formátované čtení

19.3.5 Některé další funkce

20 Příklad

20.1 Filtr sort, základní verze

20.1.2 Kontejnery v C++

20.1.7 Rozdělení zodpovědnosti

20.2 Filtr sort s volbami

20.2.2 Volby

20.2.3 Řazení

20.3 Čeština pod Windows

20.3.2 Lokální nastavení

20.4 Příprava na další volby

20.4.1 Odstraňujeme typ zvoleno

20.4.2 Určení komparátoru

20.4.3 Implementace

20.5 Abecední řazení

20.5.1 První implementace

20.6 Vlastní implementace abecedního řazení

20.7 Opačné řazení

20.8 Jak snadno změnit pravidla abecedního řazení

20.8.5 Reprezentace inicializačního souboru

20.9 Objektová implementace komparátorů

20.9.2 Třídy komparátorů

20.9.4 Třída volba

20.9.5 Řazení

20.9.6 Opačné řazení

20.10 Komparátor na přání

20.10.2 Implementace tabulkou

20.10.5 Uvolnění komparátoru

20.11 Několik slov na závěr

21 O čem jsme nehovořili

21.1 Jazyk C++

21.2 Standardní knihovna

Literatura