Date post: | 04-Apr-2015 |
Category: |
Documents |
Upload: | ivan-merka |
View: | 89 times |
Download: | 0 times |
FAKULTA ELEKTROTECHNIKY A KOMUNIKAČNÍCH TECHNOLOGIÍ VYSOKÉ UČENÍ TECHNICKÉ V BRNĚ
Seminář C++
Garant předmětu:
Ing.Pavel Fiala, Ph.D.
Autor textu: Ing. Pavel Fiala, Ph.D.
Brno 1.2.2005
Seminář C++ VUT FEKT v Brně
Obsah 1 ÚVOD ................................................................................................................................4
1.1 ZÁKLADNÍ POJMY A UJEDNÁNÍ.....................................................................................4 1.2 VLASTNOSTI C/C++ ....................................................................................................6 1.3 ZÁSADY, SMĚRNICE ANSI...........................................................................................8 1.4 OBJEKTOVĚ ORIENTOVANÉ PROGRAMOVÁNÍ ...............................................................9 1.5 PROGRAM- OPERAČNÍ SYSTÉM.....................................................................................9 1.6 SESTAVENÍ PROGRAMU..............................................................................................10 1.7 ZÁKLADNÍ PRVKY ZÁPISU BLOKOVÉHO SCHÉMATU ...................................................12 1.8 ALGORITMY...............................................................................................................13 1.9 KONTROLNÍ OTÁZKY .................................................................................................20 1.10 ÚKOLY ......................................................................................................................20
2 NĚKTERÉ ROZDÍLY C A C++...................................................................................20 2.1 KLÍČOVÁ SLOVA C++ ................................................................................................21 2.2 ÚKOLY ......................................................................................................................23
3 TŘÍDY .............................................................................................................................23 3.1 DATOVÉ SLOŽKY .......................................................................................................24 3.2 ČLENSKÉ FUNKCE- METODY ......................................................................................26 3.3 UKAZATEL THIS ........................................................................................................31 3.4 AGREGÁTY ................................................................................................................31 3.5 OBLASTI PLATNOSTI A DOSAŽITELNOSTI IDENTIFIKÁTORŮ ........................................32 3.6 PROSTORY JMEN ........................................................................................................32 3.7 PAMĚŤOVÉ TŘÍDY ......................................................................................................34 3.8 KONTROLNÍ OTÁZKY .................................................................................................34 3.9 ÚKOLY ......................................................................................................................34
4 OBJEKTY .......................................................................................................................34
4.1 PŘIŘAZOVÁNÍ OBJEKTŮ .............................................................................................35 4.2 PŘEDÁVÁNÍ OBJEKTŮ FUNKCÍM .................................................................................35 4.3 VRÁCENÍ OBJEKTŮ FUNKCEMI ...................................................................................36 4.4 ÚKOLY ......................................................................................................................37
5 OPERÁTORY.................................................................................................................37
5.1 PŘEHLED OPERÁTORŮ................................................................................................37 5.2 POPIS, UŽITÍ OPERÁTORŮ ...........................................................................................39 5.3 PŘETĚŽOVÁNÍ OPERÁTORŮ ........................................................................................42 5.4 ÚKOLY ......................................................................................................................43
6 DĚDIČNOST ..................................................................................................................44 6.1 SYNTAKTICKÝ ZÁPIS..................................................................................................44 6.2 PŘÍSTUPY V DĚDIČNOSTI............................................................................................44 6.3 ÚKOLY ......................................................................................................................47
7 POLYMORFISMUS ......................................................................................................47
7.1 ÚKOLY ......................................................................................................................48
8 PŘETĚŽOVÁNÍ FUNKCÍ ............................................................................................48 8.1 PŘETĚŽOVÁNÍ KONSTRUKTORŮ .................................................................................49
str. 2
Seminář C++ VUT FEKT v Brně
8.2 ANACHRONISMUS PŘETĚŽOVÁNÍ ...............................................................................50 8.3 PŘETĚŽOVÁNÍ A NEJEDNOZNAČNOST.........................................................................50 8.4 ÚKOLY ......................................................................................................................51
9 ŠABLONY FUNKCÍ A TŘÍD .......................................................................................51 9.1 PARAMETRY ŠABLON.................................................................................................51 9.2 ŠABLONY FUNKCÍ ......................................................................................................52 9.3 ŠABLONY OBJEKTOVÝCH TYPŮ ..................................................................................52 9.4 ÚKOLY ......................................................................................................................53
10 OBSLUHA VÝJIMEK...............................................................................................53 10.1 ÚKOLY ......................................................................................................................54
11 ZÁVĚR ........................................................................................................................54 11.1 LITERATURA..............................................................................................................55
str. 3
Seminář C++ VUT FEKT v Brně
1 Úvod
Předmět Seminář C++ je vyučován v letním semestru 2. ročníku bakalářského studia FEKT VUT v Brně. Předmět předpokládá úspěšné absolvování kurzů Počítače a programování 1 a Počítače a programování 2. Volně navazuje na znalosti získané v těchto kurzech a bude používat také prostředí Borland C++ Builder 6.0.
Kurz si klade za cíl rozšířit základní znalosti jazyka C a doplnit o prvky C++ . Usiluje o hlubší poznatky a dovednosti cestou praktických zkušeností. Ty získá při sestavování zadaných programů a jejich odlaďování. Proto je volena forma semináře s nachystanými neřešenými úkoly a jejich realizace pod odborným dohledem a vedením student bude dále budovat své programátorské schopnosti. Student se tak velmi efektivně a individuálně rozvíjí. Může dosáhnout dobrých výsledků a získat návyky vedoucí k samostatnému vzdělávání v oblastech nejen tvorby počítačových programů.
Kurzy Počítače a programování 1 a Počítače a programování 2 byly z velké části zaměřeny na koncepci událostmi řízeného programování, jeho úvod a procvičení s prvky API. Seminář C++ naopak bude budovat klasicky orientované programování- tvorba funkcí, zařazení do událostmi řízeného programu. Bude dbát na efektivní využití prvků C/C++, pro tvorbu krátkých a rychlých programů se všemi výhodami jazyka C++. Nelze v přiděleném čase pro seminář zvládnout špičkově problematiku C++, ale je zde prostor pro vybudování základních programátorských návyků a potlačení programátorských zlozvyků. V programování platí mnoho základních pravidel, jak se stát programátorem, a mezi ně patří: „nejdříve mysli, pak piš“, „programátorem se stáváme podle počtu dobře napsaných vlastních programů, nikoliv opsaných“, „programátor se pozná podle algoritmu“ atd. V kurzu se budeme snažit psát takové programy, které nezávisí na platformě, na které se budou provozovat.
Následující text lze označit přeneseně za kostru pravidel C++, mnohdy „děravou“. Existuje několik přístupů k výuce programování. Jedna cesta je založena na dodání budoucímu programátoru veškerých informací na stůl a stačí začít programovat. Jiná cesta, která si myslím je bližší skutečnému životu, je taková, že programátor získá pouze základní informace o jazyku, základní příklady použití. Student sám si musí najít nebo získat doplňující informace, samozřejmě musí mít velmi dobré základny algoritmizace. Touto cestou se orientuje kurz Seminář C++.
1.1 Základní pojmy a ujednání
Programátoři mezi sebou komunikují specifickým jazykem. Abychom tomuto jazyku porozuměli, seznámíme se nyní společně s pojmy, s nimiž se budeme setkávat.
Abstrakce pojem je převážně používán v souvislosti s implementací tříd. Označuje skutečnost, kdy třída je chápána jako vnějšími vlastnostmi popsaný objekt a není dále vysvětlena jeho vnitřní funkce.
Členská funkce je taková, která patří k jedné třídě. Zahrnuje chování objektů této třídy. Někdy se mluví o metodě.
Funkce je část kódu, která definuje odezvu programu na určitou událost. Funkce je posloupnost příkazů, které jsou při jejím volání postupně vykonávány.
str. 4
Seminář C++ VUT FEKT v Brně
Třída jako datový typ je reprezentace skupiny objektů z řešeného problému se společnými vlastnostmi a způsobem chování.
Objekt je označení jak reálných typů, tak i objektových typů (instancí). Označení objekt se používá i pro oblast paměti, se kterou lze manipulovat (proměnná, konstanta, funkce, atd.)
Dědění je označení vztahů v hierarchii objektů a tříd. Třídy lze uspořádat do hierarchie a předávat (přebírat)-dědit tak vlastnosti (základních, rodičovských) tříd. Odvozená třída přebírá jak datové složky, tak metody. Odvozená třída představuje specializovanější objekt. Základní vlastností objektově orientovaného programování (OOP) je možnost zastoupení předka dědicem.
Událost popisuje přesně definovanou situaci nebo akci, na níž má program reagovat. Událostí je kliknutí na tlačítko v okně (OnClick), událostí je stisknutí klávesy na klávesnici (onKeyDown) či otočení kolečkem mezi tlačítky myši (OnMouseWheel). Pracujeme-li v Borland C++ Builder, píšeme tzv. událostmi řízený program. Pro události, na které má náš program reagovat, sestavujeme obslužné funkce. Vznik události odpovídající funkci automaticky vyvolá.
Instance je vzor, příklad, případ typu třídy. Někdy se označuje jako objekt.
Objektově orientovaný je nazýván přístup, kdy problémy jsou řešeny jako zavádění, určování a implementace objektů ve formě tříd a práce s nimi. Jádro práce programátora spočívá v implementaci tříd do řešení problému a volání metod z implementovaných tříd. Knihovny tříd se dají opakovaně používat, tím se práce poněkud zjednoduší a OOP se přiblíží k lidskému způsobu uvažování.
Polymorfismus (mnohotvarost) je vlastnost, která umožňuje, aby jediný název byl použit jak pro více souvisejících a technicky odlišných účelů, tak pro rozdílné metody. Uvnitř třídy procesů je volba procesu dána typem dat.
Předefinování je proces, kdy se mění vlastnosti zděděné funkce v odvozené třídě. Důvodem je úprava funkce tak, aby reagovala správně na požadované volání. Předefinování je základním klíčem a krokem k realizaci polymorfismu.
Přetěžování funkcí je pojem, kdy několik funkcí má stejné jméno. Překladač potom rozlišuje podle počtu a složení a typů parametrů. Někdy se tento termín používá v souvislosti s hierarchií tříd a polymorfismem. Zde je ale namístě přesnější mluvíme-li o předefinování.
Přetěžování operátorů je schopnost rozšířit operátory o uživatelem definované typy. Překladač určuje, kterou operaci chceme provést.
Zapouzdření je mechanismus, kdy objekty v programu lze popsat svými vlastnostmi (data) a chováním (metoda), je spojen dohromady kód a data v jednom objektu. To lze shrnout do třídy, která objekt reprezentuje. Tím se přistupuje k objektu z vnějšku jako k souhrnu vlastností a reakcí.
Rozhraní je prostředek pro výměnu informací mezi funkcemi, třídami, moduly, atd. Rozhraní funkce je určeno jejími parametry, rozhraní třídy datové složky nebo členské funkce.
Skrývání informací a implementace je tendence vývoje překladače, taková, aby programátor o funkci nemusel vědět příliš mnoho informací, ale mohl ji používat.
V textu budeme střídat různá písma:
Times New Roman – zvýraznění částí textů (zejména různé názvy)
str. 5
Seminář C++ VUT FEKT v Brně
Courier – části zdrojových textů Courier – klíčová slova ve zdrojovém textu Arial – název diskového souboru nebo adresáře Arial – nově zaváděný termín
1.2 Vlastnosti C/C++
V dnešní době je jazyk C a C++ považován za jeden ze základních programovacích jazyků. Jazyk umožňuje velmi rychle sestavit program, aplikaci pro graficky orientovaný systém, dokáže pracovat s daty, přistupovat k hardweru. Generuje velmi rychlý kompaktní kód a ten zůstává přenositelný mezi velkou skupinou počítačů. Jazyk má vlastnosti vyššího programovacího jazyka.
Při vyvíjení C++ byla zachována kompatibilita s jazykem C, nikoliv striktně. V jazyce C++ jsou některé konstrukce nepřípustné i když v jazyce C jsou běžné. Také se vyskytují shodné tvary konstrukce v obou jazycích, ale jsou jinak interpretovány. Základním rysem a krokem od C k C++ bylo zavedení tříd. Tím se otevřela cesta do objektového světa programování. Úspěch zavedení a používání obou jazyků spočíval v tom, že přechod od C k C++ byl snadnější díky téměř úplné kompatibilitě obou variant jazyka. Další výhodou C++ je jeho použití bez nutného využívání objektově orientovaného programování. Několik slov o koncepci jazyka C.
Jazyk C byl navržen pro systémové programování v UNIXu, byl pomocný prostředek pro velmi rychlé a snadné sestavení spustitelného kódu. Jeho rysy lze bodově označit
• Malé bohatství prvků • Velká rychlost programů • Připravenost pro modulární programování • Dobrá přenositelnost • Blízkost k operačnímu systému
Jazyk C++ postupem času reagoval na změny v hodnotách ve světě programování. Strojový čas je levnější, práce a čas programátora dražší. Charakteristika jazyka C++ je vyjádřena v několika bodech
• Jednoduchý a spolehlivý • Vysoký stupeň opakovaného použití (modulární stavba) • Snadná údržba • Srozumitelný (až intuitivně)
Požadavek srozumitelnosti a přenositelnosti vedl ke vzniku rozsáhlého množství knihovních funkcí, čímž se přenositelnost zhoršila. Různí výrobci překladačů přidávali různá vylepšení, čímž se vytvořila paleta modifikací jazyka. Tyto problémy bylo nutné vyřešit a vytvořit závazný standard. Problém řešila komise založená v roce 1983 Americkým národním institutem pro standardizaci (American National Standard Institute - ANSI). V roce 1989 přijala komise koncept jazyka ANSI a po té také organizace ISO (International Standards Organization).
Nabízí se otázka, co je to objektově orientované programování? Odpověď není snadná. Je to především způsob myšlení, uvažování a organizace vztahů objektů. Pokusíme se tento
str. 6
Seminář C++ VUT FEKT v Brně
pojem rozvést. Programování lze chápat jako organizování závislostí, vztahů a výkonných operací s předpokladem, že budou provedeny za předem dohodnutých podmínek (syntaxe jazyka, algoritmus programovaného problému, … ). První programy byly tvořeny nastavením přepínačů, později pomocí děrných štítků, pásek -jazyka symbolických instrukcí. Po roce 1955 se vývoj zaměřil na první překladače jazyka. Začaly se ale vyvíjet lineární dlouhé programy s často se opakujícími algoritmy. A tak se začalo programování vyvíjet směrem ke strukturovanému programování – definované struktury, podprogramy s rekurzivním voláním. Díky svým omezením v rozsahu bylo nutné vyvinout kvalitativně lepší přístup než je strukturované programování. A bylo na světě objektově orientované programování (OOP). OOP se inspirovalo dobrými znaky strukturovaného programování a doplnilo je novými koncepty. Základním znakem OOP je rozložení problému na základní prvky (komponenty) a ta je používaná jako samostatný a nezávislý objekt. Obsahuje své vlastní instrukce a data používané uvnitř objektu. Tím se sníží komplikovanost celkového programu a je možné vytvořit rozsáhlejší algoritmus. Charakteristickými vlastnostmi OOP je
• Zapouzdření (encapsulation)
• Polymorfismus-mnohotvarost (polymorphism) • Dědičnost (inheritance).
Zapouzdření je způsob chování objektu, kdy jsou kód i data objektu chráněny před zásahem z venčí. Při spojení kódu a dat vzniká objekt. Uvnitř objektu jak kód, tak data, funkce mohou být neveřejná (private) nebo veřejná (public). Neveřejná data jsou dostupná jen v daném objektu nebo jeho části. Pro uživatele se objekt jeví jako proměnná. Pokaždé, když si definujeme nový typ objektu, vytváří se nový typ dat. Uveďme příklad na deklaraci třídy. class BasicClass { // neveřejné vzhledem k BasicClass int a; public: // veřejné vzhledem k BasicClass double add(double x, double y; };
nebo jiná třída class camera { // znaky popsane hodnotami char *vyrobce, *typ; int PocetObjektivu, PocetOptickychElementu; Boolean digital, zrcadlovka, profi; public: // zpusob chovani void zapnout(); void manual(); void program(); void snimek(); void vyvolani();
str. 7
Seminář C++ VUT FEKT v Brně
void prohlizeni(); void vypnout(); };
Polymorfismus je vlastnost jazyka, překladače, kdy mohou být použity stejné názvy pro různě účely (objekty, funkce,…). Tam, kde polymorfismus nebyl zaveden, hrozilo nebezpečí shody názvů interních i uživatelských a následná kolize programu. Polymorfismus dovoluje vytvářet standardní rozhraní k příslušným procesům. Někdy se polymorfismem označuje přetěžování funkcí a operátorů. Původní význam byl zaveden pro virtuální funkce. Ukážeme si jednoduchý příklad na deklaraci třídy:
class TrA { public: void Fce(int); }; class TrB { public: void Fce(char*); }; void main() { TrA prvni; TrB druha; prvni.Fce(3); druha.Fce("pokus"); }
Dědičnost je proces, kdy jeden objekt může získat vlastnosti jiného procesu. Přesněji řečeno, může zdědit původní vlastnosti a doplnit je o vlastní, charakteristické pouze pro něj. Tato vlastnost OOP podporuje hierarchické uspořádání programu na místo plošného nebo lineárního uspořádání. Tím se zkracuje kód a zpřehledňuje.
1.3 Zásady, směrnice ANSI
Příčinou úspěšného zavedení jazyka C a C++ do počítačového světa bylo vytvoření a respektování několika zásad komisí ANSI. Zásady lze shrnout do následujících bodů:
• Důležitý je existující kód, ne existující implementace (v překladači). Kód by měl být zachován za cenu změny implementace překladače.
• Kód napsaný v jazyce C je přenositelný. ANSI kód nabízí programátorům možnost přenositelnosti programu v jazyce C ANSI mezi různými operačními systémy.
• Kód napsaný v C může být nepřenositelný. Existuje možnost vytvořit programový kód, který je vázán na určitý hardware a tím není přenositelný na ostatní.
str. 8
Seminář C++ VUT FEKT v Brně
• Ohlašovat odlišnosti od standardu. Neměla by nastat varianta, kdy překlad jednoho textu programu bude na různých překladačích interpretován různě. Pokud ano, musí být na tyto odlišnosti od ANSI programátor upozorněn.
• Standard je dohodou mezi implementátorem a programátorem. Zásada by měla vést k respektování jak výrobce překladače, tak programátora.
Nyní, když máme definovány základní pojmy a stanovena základní pravidla, budeme se věnovat procvičování jednotlivých částí. Dále si uvedeme některé příklady základních rozdílů mezi C, C++ a nové směry v C++.
1.4 Objektově orientované programování
Objektově orientované programování se nesestává pouze z rozšíření znalostí C na některé nové prvky C++. (použití namísto printf() nového cout<<). OOP začíná tam, kde se definuje třída, kde se používá zapouzdření, polymorfismus, kde vznikají knihovny tříd. Cesta k tomuto způsobu programování je v
• opakovaném používání stejných kódů • sestavení datových typů s použitím dědičnosti a polymorfismu • používání zapouzdření.
Kde jsou tato kritéria nepodstatná, je možné používat program napsaný v jazyce C.
1.5 Program- operační systém
Při psaní programu je dobré mít povědomí o hrubém rozdělení prvků v ovládaném zařízení (počítač,...). Jsou zde prvky, které vědomě ovládáme programem a prvky, které jsou ovládány „systémem“ bez našeho velkého přičinění. Například alokace paměti, adresace, uvolňování, ... se nás příliš nedotkne, my pouze požadujeme
int a=5;
a tím je pro nás nachystán prostor v příslušné části RAM a je podle syntaxe k dispozici. Schéma základních částí počítače je na obr.1.
Obr. 1 Událostmi řízený OS – osobní počítač
Operační systém
Zobrazovací jednotka - display
Vstupní jednotka- klávesnice
RAM Programy
Procesor
Sběrnice
Smyčka „server“
SW
Systémová fronta
HW
Fronta aplikací
str. 9
Seminář C++ VUT FEKT v Brně
1.6 Sestavení programu
Program lze v současných překladačích sestavovat pomocí generátorů, které přednastaví v textu umístění našeho programu, který reaguje na prvky graficky orientovaných aplikací. Rád bych velmi stručně naznačil organizaci a možnosti korektního vstupu do tohoto systému s vlastním programem, funkcí. Na obr.2 je schéma konstrukce klasických překladačů, pro DOS , MS Windows 1.0-95. V levé části je klasický způsob sestavení programu pro konzolový typ systému. K tomu se v 80-tých letech přidal systém s objekty a událostmi řízené programování. První prostředky používaly klasické konstrukce programu, jen přidávaly nové prvky. Bylo velmi snadné připojit pomocí souborů *.OBJ jakýkoliv externí program. Programování pro událostmi řízený chod se vyvíjelo a základní jádro organizace je na obr.3.
DOS MS Windows 1.0, 2.0, 3.0, 3.1, 95 Obr.2 Schéma sestavení programů pro platformy
Obr.3 Schéma toku událostí v systému událostmi řízeném
str. 10
Seminář C++ VUT FEKT v Brně
Pro korektní vložení vlastního zdrojového programu do existující šablony existuje několik přístupů. Pokusím se vybrané postupy vysvětlit. První, známý z kurzu Počítače a programování 2 je vložení textu přímo do vygenerované „šablony“. Tak se text přeloží a je spustitelný. Tato metoda je poněkud nepružná a „nemotorná“. Musíme mít editor textu, správný formát atd. #pragma hdrstop #include "Unit1.h" //------------------------------------------------------------------ #pragma package(smart_init) #pragma resource "*.dfm" TForm1 *Form1; //--------__fastcall TForm1::TForm1(TComponent* Owner): TForm(Owner)
----------------------------------------------------------
{} int void mojeExtFunkce( ) {/* text vlozene funkce*/} //-- ----------void __fastcall TForm1::fPokus(TObject *Sender)
- -----------------------------------------------------
{} //------------------------------------------------------------------ Účelnější a možná ne tak „obrázkově “ podporované je řešení, kdy do textu vložíme naši funkci pomocí hlavičkového souboru. Pokud funkce neobsahuje složité vazby na API a objekty uživatelského rozhraní, je to velmi rychlý způsob. Nepotřebuji k napsání programu žádný složitý prostředek, snad tužku papír a dostupný textový editor na použitém počítači. Text by vypadal si takto: #pragma hdrstop #include "Unit1.h" #include "mojeExtFunkce.h" //------------------------------------------------------------------ #pragma package(smart_init) #pragma resource "*.dfm" TForm1 *Form1; //--------__fastcall TForm1::TForm1(TComponent* Owner): TForm(Owner)
----------------------------------------------------------
{} //------------------------------------------------------------------ void __fastcall TForm1::fPokus(TObject *Sender) {} //------------------------------------------------------------------ Soubor mojeExtFunkce.h v adresáři, kde jsou umístěny soubory projektu má tento obsah int void mojeExtFunkce( ) {/* text vlozene funkce*/} Ještě snad chybí uvést schéma sestavování programu v současných překladačích. Na obr.4 je velmi zjednodušeně naznačeno. Některé typy souborů nemusí být použity, tvůrci překladačů
str. 11
Seminář C++ VUT FEKT v Brně
vytvářejí jiné soubory, dočasné soubory jsou mazány. Ale v zásadě je postup překladu zachován, směřuje od horních řádků k dolním.
*.h *.c *.h Soubory na disku Uživatelské soubory Systémové soubory
*.i
*.obj *.obj *.lib
*.dll
*.obj *.dll
*.lib
*.exe*.com
*.exe
Sestavení
DDE
Předzpracování, kontrola chyb
Překlad, kontrola chyb
Obr.4 Postup sestavení spustitelného souboru
1.7 Základní prvky zápisu blokového schématu
Abychom mohli srozumitelně zapisovat algoritmy programů, seznámíme se se základ-ními značkami, které se objevují v blokových schématech.
Značka pro předepsaný postup:
A=B, A=A+1, A=A*B
Značka pro načtení, výstup
Vstup A, Výstup A
Značka pro rozhodnutí
A<B, A>B, A=B, A≠B, A≥B, A≤B a, nebo ∧ , ∨ negace A A
Značka pro začátek, konec
začátek konec
Značka pro funkci, podprogram
str. 12
Seminář C++ VUT FEKT v Brně
Značka pro cyklus
cyklus I = 1, .., N
Značka pro skok
skok na
1.8 Algoritmy
Má-li se řešit nějaká programátorská úloha, naskytne se více přístupů a postupů řešení. Z nich je třeba vybrat jeden postup a ten formulovat pomocí vývojového diagramu. Pro výběr se musí určit nějaká kritéria, podle kterých se zvolí postup řešení programu. Musí se tedy roz-hodnout, který postup je „lepší“ a který je „horší“. Co to je „lepší“ a „horší“? Kritéria pro po-suzování kvality algoritmu jsou jak subjektivní tak objektivní. Dále se budeme zabývat více těmi objektivními kritérii. Základní objektivní kritéria hodnocení algoritmu tedy jsou:
1. Rychlost algoritmu (výpočtu) 2. Paměťová náročnost – operační i externí paměť 3. Stabilita algoritmu
Problematika těchto kritérií je velmi rozsáhlá, ale pro účely tohoto textu se budeme držet nut-ných pojmů a praktických důsledků bez uvedení odvození a důkazů.
Prvně dvě kritéria jsou významná hlediska při hodnocení algoritmů. Jsou odlišná a velmi často stojí proti sobě. Bývají algoritmy takové, že jeden z nich je pomalejší, ale po-užívá malou operační paměť, zatímco druhý je rychlejší, ale má vysoké nároky na operační paměť. To je často způsobeno tím, že pro zrychlení algoritmu je použita další pomocná pro-měnná nebo množina proměnných, které budou uchovány v operační paměti. Tím se zvětší nároky na paměť za cenu zrychlení výpočtu. Pro volbu paměťové náročnosti a rychlosti ne-existuje obecné řešení, záleží vždy na požadavcích, které jsou kladeny na program. Samozřej-mě první dvě kritéria jsou závislá také na použitém technickém vybavení (hardware). Jako příklad lze uvést úlohu vyhledání telefonního čísla v seznamu. Jedním z postupů je vyhledání čísla tak, že začneme procházet seznam od počátku, až nalezneme to hledané. Tento postup se nazývá sekvenčním vyhledáváním. Ve skutečnosti jsou jména v seznamu seřazena podle abecedy. Postup při vyhledávání je podle srovnání rostoucích n-tic písmen jména. Pokud hledané jméno je Novák, první n-tice je N. Dále je hledána druhá n-tice No, atd.
Stabilita algoritmu závisí jak na vstupních údajích programu, tak na zvolené metodě algoritmu. Doba výpočtu i paměťové nároky bývají také závislé na vstupních údajích. Pro-gram většinou řeší celou třídu podobných problémů, které se liší právě zadávanými vstupními údaji. Ale trvání výpočtu i paměťové nároky často neovlivňují konkrétní zadané hodnoty, jen velikost vstupních dat. Prakticky, je jedno zda vyhledávám jedno telefonní číslo v telefonním seznamu s 3000 položkami nebo vyhledávám naměřenou teplotu s 3000 údaji. Ale je rozdíl, pokud vyhledávám telefonní číslo v seznamu Znojma a Brna. Potom bude algoritmus mít rozdílnou dobu trvání.
str. 13
Seminář C++ VUT FEKT v Brně
Paměťová náročnost u algoritmů se uvádí v jednotkách jakými jsou bit nebo bajt. Bit je jednotka, která může být nuď ve stavu logické jednotky nebo ve stavu logické nuly. Bajt je jednotka (slovo), která je složena z několika bitů. Počet bitů v bajtu je dán mnoha kritérii. Jsou obvykle používány 8, 16, (24), 32, 64, 128, … bitová slova.
Časová náročnost se udává v souvislosti s použitým typem procesoru, velikostí RAM a její rychlosti, konfiguraci základní desky, typem a výrobcem operačního systému. Udává se buď jako doba pro nejhorší případ složitosti algoritmu se vstupními daty velikosti N nebo jako průměrný případ výpočtu z N vstupních dat.
Algoritmy se porovnávají v jejich časové náročnosti. Ta je porovnána a je rozhodnuto, který z nich je rychlejší. Stává se, že vstupní data a jejich rozsah nejsou specifikovány. Potom nelze stanovit časovou náročnost. Postupuje se tak, že se zvolí pro rozsah dat velké číslo N a provede se srovnání algoritmů s uvedením podmínek. Jedná se tedy o asymptotickou časo-vou náročnost. Tedy časová náročnost lepšího algoritmu roste pomaleji s rostoucími hodno-tami N. Časovou náročnost lze popsat typem funkce a jejím řádem. Rozeznáváme tedy zá-kladní polynomiální a exponenciální funkce. Následuje ukázka zadání a vypracování algoritmů základních až triviálních úloh.
Příklad 1. Sestavte a nakreslete diagram algoritmu pro nalezení minimálního čísla z řady N zadaných. Nechť je výsledek zobrazen na výstupním zařízení.
Začátek
čti N
A=1e99
I=1,..,N
čti číslo X
X<A + -
A=X
vypiš MinimumA
Konec
Příklad 2. Sestavte a nakreslete diagram algoritmu pro nalezení maximálního čísla
z řady N zadaných. Nechť je výsledek zobrazen na výstupním zařízení.
str. 14
Seminář C++ VUT FEKT v Brně
Začátek
čti N
A=1e99
I=1,..,N
čti číslo X
X<A + -
A=X
vypiš MinimumA
Konec
Příklad 3. Sestavte a nakreslete diagram algoritmu pro nalezení součtu čísel z množiny
A a množiny B . Prvky množiny A i B jsou celá čísla, počet prvků množiny A je N a množiny B je M. Nechť je výsledek zobrazen na výstupním zařízení.
Začátek
čti N, M
celá A(N), celá B(M) A(1)= .., A(N)=… B(1)= .., B(M)=… SOUCET=0
I=1,..,N
B(J) ≠0 + -
SOUCET= SOUCET+B(J)
vypiš Součet prvků množinyA a B, SOUCET
Konec
J=1,..,M
A(I)≠0 + -
SOUCET= SOUCET+A(I)
Příklad 4. Sestavte a nakreslete diagram algoritmu pro nalezení součinu čísel z množiny A a množiny B . Prvky množiny A i B jsou reálná čísla, počet prvků množiny A je N a mno-žiny B je M. Platí, že M=N. Nechť je výsledek zobrazen na výstupním zařízení.
str. 15
Seminář C++ VUT FEKT v Brně
Začátek
čti N, M
reálná A(N), reálná B(M) A(1)= .., A(N)=… B(1)= .., B(M)=… SOUCIN=1
B(J) ≠0 ∧ A(J) ≠0
+ -
SOUCIN= SOUCIN+A(J)*B(J)
vypiš Součin prvků množinyA a B, SOUCIN
J=1,..,M
M≠N +
Konec
-
SOUCIN A a B je roven 0
Příklad 5. Sestavte a nakreslete diagram algoritmu pro porovnání obsahu množiny A
a množiny B . Prvky množiny A i B jsou celá čísla, počet prvků množiny A je N a množiny B je M. Pokud množiny mají společný prvek (číslo) zobrazte je na výstupním zařízení.
Začátek
čti N, M
celá A(N), celá B(M), celá C(X) A(1)= .., A(N)=…B(1)= .., B(M)=… Spolecna=0, K=0
I=1,..,N
B(J)=A(I) + -
C(K)= A(I)
Počet společných prvků KSpolečné prvky C(1,..,K)
Konec
J=1,..,M
M>N +
X=M - X=N
K=K+1 Spolecna=1
Spolecna = 0+
-
Příklad 6. Sestavte a nakreslete diagram algoritmu pro průnik C obsahu množiny A a množiny B . Prvky množiny A i B jsou reálná čísla, počet prvků množiny A je N a množiny B je M. Množinu C zobrazte na výstupním zařízení.
str. 16
Seminář C++ VUT FEKT v Brně
Začátek
čti N, M
reálná A(N), reálná B(M), reálná C(X) A(1)= .., A(N)=…B(1)= .., B(M)=… Prunik=0, K=0
I=1,..,N
B(J)=A(I) + -
C(K)= A(I)
Počet společných prvků KC(1,..,K)
Konec
J=1,..,M
M>N +
X=M - X=N
K=K+1 Prunik=1
Prunik = 0 +
-
Příklad 7. Sestavte a nakreslete diagram algoritmu pro sjednocení C obsahu množiny A a množiny B. Prvky množiny A i B jsou reálná čísla, počet prvků množiny A je N a množiny B je M. Množinu C zobrazte na výstupním zařízení.
Začátek
čti N, M
reálná A(N), reálná B(M), reálná C(M+N) A(1)= .., A(N)=…B(1)= .., B(M)=… Reálná Pomocna=0, celá L=0
I=1,..,N
B(J)≠A(I) + -
Pomocna= A(I)
Počet prvků L C(1,..,L)
Konec
J=1,..,M
K=1,..,M+N
C(K)=Pomocna + -
L=L+1 C(L)=Pomocna
Příklad 8. Sestavte a nakreslete diagram algoritmu pro zjištění, zda zadané číslo N je prvočíslo.
str. 17
Seminář C++ VUT FEKT v Brně
Začátek
čti N
I=2,..,celé(√N)
+ -
N je prvočíslo
Konec
A=B
Prvocislo= 1
A=celé(N/I)
reálné A, reálné B
B=N/I
Prvocislo= 0
Prvocislo=1 +
-
N není prvočíslo
Začátek
čti N, M
reálná A(N), reálná B(M), reálná C(M+N) A(1)= .., A(N)=…B(1)= .., B(M)=… Reálná Pomocna=0, celá L=0
I=1,..,N
B(J)≠A(I) + -
Pomocna= A(I)
Počet prvků L C(1,..,L)
Konec
J=1,..,M
K=1,..,M+N
C(K)=Pomocna + -
L=L+1 C(L)=Pomocna
Příklad 9.Sestavte a nakreslete diagram algoritmu pro výpočet funkce 5555.
Začátek
reálná A(40), reálná D A(1)=1.0
I=1,..,555
Konec
J=1,..,39
D=0.0
A(J)= 5*A(J)+D D=celé číslo (A(J)/1010 ) A(J)=A(J)-D*1010
I=39,..,1
Výpis A(I)
Příklad 10. Sestavte a nakreslete diagram algoritmu pro součet matic A a B. Prvky množiny A i B jsou reálná čísla, počet prvků množiny A je N×N a množiny B je M×M. Mno-žinu C zobrazte na výstupním zařízení.
str. 18
Seminář C++ VUT FEKT v Brně
Začátek
čti N, M
reálná A(M,N), reálná B(M,N), reálná C(M,N) A(1,1)= .., A(1,N)=…B(1,1)= .., B(1,N)=… C(1,..,M,1,..,N)=0.0
I=1,..,N
Výstup matice C(M,M)
Konec
J=1,..,M
C(I,J)= C(I,J)+A(I,J)+B(I,J)
Příklad 11. Sestavte a nakreslete diagram algoritmu pro součin matice A a vektoru B.
Prvky množiny A i B jsou reálná čísla, počet prvků množiny A je N×N a množiny B je M. Množinu C zobrazte na výstupním zařízení.
Začátek
čti N, M
reálná A(M,N), reálná B(N), reálná C(N) A(1,1)= .., A(1,N)=…B(1)= .., B(M)=… C(1,..,N)=0.0
J=1,..,N
Výstup sloupcové matice C(M)
Konec
I=1,..,M
C(J)= C(J)+A(I,J)*B(I)
Příklad 12. Sestavte a nakreslete diagram algoritmu pro součin matic A a B. Prvky
množiny A i B jsou reálná čísla, počet prvků množiny A je N×N a množiny B je M×M. Množi-nu C zobrazte na výstupním zařízení.
str. 19
Seminář C++ VUT FEKT v Brně
Začátek
čti N, M
reálná A(M,N), reálná B(N,M), reálná C(N,N) A(1,1)= .., A(M,N)=…B(1,1)= .., B(N,M)=… C(1,..,N, 1,..,N)=0.0
I=1,..,N
Výstup matice C(N,N)
Konec
J=1,..,M
C(I,K)= C(I,K)+A(J,I)*B(K,J)
K=1,..,N
1.9 Kontrolní otázky
1. Vysvětlete, co je to abstrakce a jak se využívá?
2. Vysvětlete, co je to polymorfismus a kde se s ním setkáme?
3. Vysvětlete, co je to přetěžování funkcí a operátorů, jak ovlivní naše možnosti při programování?
4. Jak byste charakterizovali vlastnosti jazyka C++?
5. Jaké jsou základní vlastnosti a rysy objektově orientovaného programování?
6. Pro uvedené příklady algoritmů napište v C++ jednoduché funkce.
1.10 Úkoly
1. Sestavte jednoduchou funkci, odlaďte ji a spojte s jednoduchým programem v Borland Builderu.
2 Některé rozdíly C a C++
Mezi jazyky C a C++ i přes jejich podobnost existují drobné rozdíly. Předpokládejme, že čitatel má základní znalosti z programování v C a orientuje se v problematice. Pokusím se pomocí tabulky ukázat některé rozdíly v obou jazycích.
str. 20
Seminář C++ VUT FEKT v Brně
OBSAH C C++ VÝZNAM
prototyp funkce Fce() int Fce (void)
prototyp funkce Fce() int Fce (),
int Fce(void)
prototyp funkce nepovinný povinný
deklarace funkce s návratem hodnoty
nemusí vracet (nebo vrací int)
musí vrátit vždy
deklarace lokálních proměnných
začátek bloku před výkonnými proměnnými
kdekoliv
typ proměnné bool, klíčová slova true, false
Zde ještě pro doplnění a upřesnění doplníme některé často používané pojmy, které se mohou nesprávně interpretovat. Mezi první dva patří deklarace a definice. Deklarace seznamuje počítač s názvem proměnné, funkce, třídy šablony nebo datového typu.
• Deklarací stanovíme její typ, paměťovou třídu a viditelnost jejího identifikátoru. Stanovíme také typ vracené hodnoty a počet, pořadí a typy parametrů a eventuálně jejich implicitní hodnoty.
• Deklarace v C++ začíná klíčovým slovem extern.a neobsahuje inicializaci • Popis statické datové složky v deklaraci třídy je jen deklarace, nikoliv definice • Mezi deklarace patří typedef, using.
Definice nejen popisuje objekt, ale přikazuje překladači, aby ji zřídil.Proměnné, funkce a další součásti programu dostupné v celém těle programu mohou mít více deklarací. Statické proměnné a funkce mohou mít v kterémkoliv z modulů jinou definici.
• Definice proměnné v C++ buď neobsahuje klíčové slovo extern nebo obsahuje inicializaci.
• Definice funkce obsahuje její tělo • Statické datové složky tříd musíme definovat někde za deklarací třídy (mimo tělo
funkce) Z kurzů Počítače a programování 1 a Počítače a programování 2 jsou známy základní informace o datových typech, výčtových typech, polích jedno a vícerozměrných, řetězcích, strukturách, bitových polích, uniích, ukazatelích, dynamických proměnných, práci s ukazateli. Pokračovali bychom dále v prohloubení znalostí z oblasti tříd.
2.1 Klíčová slova C++
NÁZEV VÝZNAM POZNÁMKA
asm auto
str. 21
Seminář C++ VUT FEKT v Brně
bool break case catch char class const const_cast continue default delete do double dynamic_cast else enum explicit extern false float for friend goto if inline int long mutable namespace new operator private protected public register reinterpret_cast return short signed sizeof static satic_cast struct switch teplate this throw true
str. 22
Seminář C++ VUT FEKT v Brně
try typedef typeid typename union unsigne using virtual void volatile wchar_t while
2.2 Úkoly
1. Sestavte jednoduchou funkci, vyzkoušejte změny mezi syntaxí C a C++, odlaďte ji a spojte s jednoduchým programem v Borland Builderu.
3 Třídy Třídy slouží ke spojení (zapouzdření) dat a funkcí do jednoho (nového) typu. Umožňují
předepisovat různá oprávnění k přístupu k jednotlivým prvkům. Třídy mají díky dědičnosti hierarchické uspořádání. Deklarace může být zapsána:
klíč třída[:seznam_předků] { deklarace_prvků }[případ1,případ2,...];
kde jsou klíč .... class, struct nebo union. V C++ struktury a unie představují pouze zvláštní
případy tříd. třída ....identifikátor třídy, :seznam_předků....seznam identifikátorů tříd, jejichž vlastnosti má nová třída zdědit deklarace_prvků....v těle třídy se deklarují její složky. Přístup k prvkům mohou
upravovat specifikátory přístupových práv (public, protected, private). případ1....zde se mohou definovat případy (instance), ukazatele na případy, pole
případů. Uveďme si konkrétní příklad. class Priklad { int H
public: odnota; // private
druha(){protected:
Hodnota=1;}; //konstruktor
int treti(){ return Hodnota;};
str. 23
Seminář C++ VUT FEKT v Brně
private: int Posledni();
}; • Specifikace přístupových práv platí pro všechny složky, které jsou zapsány za ní, až
do další specifikace. • Specifikace přístupových práv se mohou v deklaraci třídy vyskytovat vícekrát. • Složky třídy na začátku deklarace před první specifikací přístupových práv jsou
automaticky považovány za o soukromé (private) ve třídách definovaných pomocí klíčového slova class. o veřejné (public) ve třídách definovaných jako struct a union.
Specifikace přístupových práv se nevztahují na spřátelené funkce. Používání tříd v OOP se řídí jistými pravidly. Rozlišují se vlastnosti a způsob chování objektů. Společné objekty lze zahrnout do jedné třídy. Například: class Mesto { /* znaky popsane hodnotami*/ char *Nazev; int PocetObyvatel; boolean MestskaDoprava, Silnice, Dalnice, Metro, Letiste, Divadlo, park, Obchod, Skola; public: /*zpvoid Ubytovani();
usob chovani*/
void Zamestnani(); void Odpocinek(); void Sport(); void Doprava(); }; Pokud podle dané třídy deklarujeme proměnnou – případ (instance), musí být datovým složkám přidělena hodnota. Potom deklarovaná proměnná představuje jediné identické město- např. Brno. Mluvili jsme o zapouzdření dat a členských funkcí . Pro práci s třídami se může ještě přidat další pojem- skrývání dat. Je to stav, kdy programátor používá členské funkce třídy a nestará se jak program vykoná na připojeném HW zamýšlené operace. Například v třídě Mesto pro případ Brno bychom spustili funkci Brno.Doprava(); a tím by program podle těla funkce řídil dopravu v celém městě Brně. Programátora ale již nezatěžuje, jak se přes rozhraní počítače provádí spouštění systémů pro řízení křižovatek, tram. a autobusové dopravy. Dalším pojmem je uzavřenost. Tím se myslí takové nadefinování třídy, které je úplné (neobsahuje zbytečně mnoho nebo málo údajů) a je právě vhodná k provádění operací podle jejího chování.
3.1 Datové složky
Třídy mají datové složky. Každý případ dostane k dispozici paměť pro datové složky. Při jejich tvorbě dojde k jejich inicializaci- přiřazením hodnot. Toto přiřazení provede konstruktor. Datové složky zanikají se zánikem proměnné. Operaci má na starosti destruktor.
Datové složky mohou být deklarovány jako:
str. 24
Seminář C++ VUT FEKT v Brně
• veřejně přístupné (public) • chráněné (protected) • soukromé (private) • Mohou být deklarovány jako statické (static). • Statické složky jsou společné pro všechny případy (instance). Vznikají při spuštění
programu- jedná se o globální proměnnou, zapsanou ve třídě. • Statické složky nemohou být deklarovány jako auto, register, extern. • Zápis statické složky v definici třídy je jen deklarace. Definice se provede vně třídy. • Statické složky se mohou používat prostřednictvím jména třídy
(JmenoTridy::StatickyPrvek) • Statické složky nelze deklarovat pomocí const.
Složky, které jsou deklarovány jako const, musí se inicializovat, ale pak je dále nelze měnit (konstanty). Složky mohou být deklarovány jako mutable. Tyto složky jsou měnitelné i když je případ deklarován jako const. Složky mohou být deklarovány jako volatile, ta může neočekávané (asynchronně) měnit svůj obsah. Překladač neoptimalizuje (zkracuje, upravuje) operace s touto proměnnou. Třída nemůže obsahovat jako datovou složku sebe sama. Ale může obsahovat ukazatel nebo reference na nedefinovanou třídu (i na sebe sama). Příklad 1: class test { int PocetObyvatel; class priklad a; //chyba class priklad* b; //dobre class priklad &c; //dobre }; Lokální třídy Třídy, které jsou definovány v příkazové části funkce, se označují jako lokální. Jsou omezeny a všechny metody se musí definovat v těle třídy. Vnořené třídy Uvnitř třídy se může jako složka deklarovat datový typ. Tedy i třídu. Příklad 2: int i; class Vnejsi {
static int n; public:
int i; static float f; class vnitrni { void test(Vnejsi &glob) { i=5; // Ma byt glob.i
str. 25
Seminář C++ VUT FEKT v Brně
f=1; // Spravne ::i=1; // odkaz na globalni i glob.i=-1; // Spravne, i z tridy global n=5; // Chyba }; }; class priklad* b; //Dobre class priklad &c; //Dobre
};
3.2 Členské funkce- metody
• Mohou být deklarovány jako public, protected, private. • Pokud jsou definované jako static, pak pracují pouze s datovými složkami static. • Metody mohou pracovat s objekty typu const. Metody mohou být deklarovány jako
virtual, inline. • Mohou být přetěžovány pouze členskými funkcemi stejné třídy. • Mají přístup ke všem prvkům své třídy bez ohledu na přístupová práva. • Jsou jediným prostředkem s funkcemi typu friend, jak získat přístup k soukromým
prvkům- private. • Metody mohou být deklarovány jak uvnitř, tak vně deklarace třídy.
Příklad 3: class test {
int n; public:
test() { n=1; } void test2() const {n=2;} // Chyba int test3() const {return n;} int test4(){return n;}
}; Definice metody uvnitř definice třídy Metody definované uvnitř definice třídy jsou překládány jako inline. Doporučuje se definovat uvnitř třídy pouze krátké přehledné funkce. Definice metody vně definice třídy U této definice se musí ke jménu metody připojit jméno třídy pomocí operátoru rozsahu.
str. 26
Seminář C++ VUT FEKT v Brně
Příklad 4: class test {
int n; public:
test() { n=1; } int Test3Vrat() const {return n;} //definice int Test4Smaz() //definice
}; inline test::Test4Smaz() {n=0;} Přístup k prvkům tříd Velmi osvědčené je, jsou-li třídy navrženy tak, že prvky jsou typu private. Potom je mohou používat jenom metody dané třídy. Vně třídy k nim mají přístup pouze členské funkce. Přístup zevnitř třídy Příklad 5: class test { private:
int n1, n2; int fun1() {return n1*n2;};
public: void fun2(int j) { n1=j+1; n2=fun1(); }
}; test z; z.fun2(222); // Změna z.n1 a z.n2 Přístup z vnějšku třídy Pokud se pracuje a přistupuje z vnějšku třídy k prvkům třídy, musí se uvést případ, pro který chceme složky měnit. Přístup je pomocí případu a operátoru tečka- jméno složky nebo ukazatel a připojíme jméno složky pomocí operátoru -> .
• Přístup přes případ je filtrován specifikátory public, protected, private.
str. 27
Seminář C++ VUT FEKT v Brně
Příklad 6: class test { //První dvě jsou soukromé
int n1; int fun1();
public: int n2; int fun2();
}; void main() {
test z, *PokusD; int i; i=z.n1; // Nespravne i=PokusD->fun1(); // Nespravne i=z.n2; // Spravne i=
return 0; PokusD->fun2(); // Spravne
}
• Přístupem přes přátele se obejdou pravidla přístupu. Klíčové slovo je friend. Zápis je
friend ProtoypFunkce; friend class JmenoTridy; Aby se tyto přístupy podařilo provést, musí být funkci předán ukazatel na případ, reference na případ nebo přímo případ třídy. Příklad 7: class test {
int n1; friend void fun1(test&);
}; void fun1(test& objekt) { int a; a=objekt.n1; } void main() { class test T;
fun1(T); return 0; }
• Třída určuje, které funkce jsou spřátelené a chrání tak data před nekontrolovaným použitím.
• Jako spřátelené funkce mohou být deklarovány i metody jiných objektových typů. • Mimo deklarace spřátelených funkcí se může deklarovat celá třída jako spřátelená.
str. 28
Seminář C++ VUT FEKT v Brně
Přetěžování a předefinování Pokud se v odvozené třídě deklaruje nevirtuální metoda se stejným jménem jako v bázové třídě, zastíní deklarace v odvozené třídě deklaraci z bázové třídy. To je stav, kdy zděděná metoda nebude přímo dostupná i když je odlišná. Pro její použití se musí použít jméno předka. Příklad 8: class Zaklad {
public: void fun1(int);
}; class Odvozena:Zakld {
public: void fun1(char*);
} ;
void main() { Odvozena odv;
odv.fun1(3); // chyba odv.Zakld::fun1(3); // spravne
return 0; } Zvláštní metody Mezi zvláštní metody patří vytvoření případu- konstruktor. Ten má několik pravidel použití. Základní jsou:
• Konstruktor má vždy stejné jméno jako jeho třída • Konstruktor nemá žádnou návratovou hodnotu • Pokud konstruktor nedeklarujeme, překladač v třídě sám vytvoří veřejně přístupný
konstruktor bez parametrů • Pokud explicitně deklarujeme jakýkoliv konstruktor, nebude překladač žádný další
vytvářet • Konstruktory mohou být přetěžovány • Konstruktory se nedědí, konstruktor potomka automaticky volá konstruktory
bezprostředních prvků • Nelze deklarovat ukazatel na konstruktor • Konstruktory, které mají právě jeden parametr, mohou provádět konverzi na typ své
třídy • Konstruktor se volá při dynamické alokaci případu pomocí operátoru new.
Příklad 9: class test { int privat;
public: test(int i){privat=1;} //Konstruktor
str. 29
Seminář C++ VUT FEKT v Brně
explicit test(float g){privat=(int)g;} } ;
void main() { test pripad(100); test pripad2=100; //Implicitni konverze test pripad3(3.2); test pripad4=3.2; //Chyba: explicitni konverze
// parametru neni return 0; } Inicializační část konstruktoru Inicializační část je určena k inicializaci datových složek třídy. Má tvar identifikátor_složky (hodnota) identifikátor_složky (SeznamParametruKonstruktoru) identifikátor_třídy (SeznamParametruKonstruktoru) Příklad 10: class test { int i;
public: test(int j):i(j){} //do i je uložena hodnota parametru
}; class testB { test T; int x;
public: testB(int y):x(y-1), a(10){fce1();}
}; Zrušení případu -destruktor Destruktory se volají automaticky při zániku případu (například delete- zrušení dynamické proměnná).
• Destruktor nemá žádnou návratovou hodnotu • Pokud v třídě nedeklarujeme explicitně destruktor, vytvoří si překladač veřejně
přístupný standardní destruktor • Destruktor se nedědí • Nelze definovat ukazatel na destruktor • Destruktor nemá žádné parametry • Destruktory mohou být i virtuální • Destruktory můžeme explicitně volat.
str. 30
Seminář C++ VUT FEKT v Brně
3.3 Ukazatel this
Každý případ má svou kopii nestatických datových složek třídy. Metody jsou v paměti uloženy jen jednou a používají je všechny případy třídy společně. Je-li v nestatické metodě odvolávka na nestatickou datovou složku jejím identifikátorem, je to odvolání na aktuální případ vytvořené třídy. Ukazatel na aktuální případ Na aktuální případ se můžeme odkázat pomocí klíčového slova this. Ukazatel this se předává jako skrytý parametr a tedy programátor jej nemusí deklarovat. Na jednoduchém příkladu je ukázáno použití ukazatele. Příklad 11: class complex { double e, Im; R
public: complex(double _Re, double _Im):Re(_Re), Im(_Im){} double Real(); double Imag();
}; double complex::Real(){return Re;} double complex::Imag(){return Im;}
V metodě Real() je příkaz return Re vlastně return this->Re.
3.4 Agregáty
Agregáty jsou třídy, struktury nebo unie, které nemají
• žádný explicitně definovaný konstruktor • nestatické prvky, deklarované jako private nebo protected • nestatické reference • nestatické konstatní složky (const) • bázové třídy • virtuální členské funkce.
Agregáty je možné inicializovat výčtem hodnot ve složených závorkách. Příklad 12: class test {
public: struct Struktura { int i; float p;
}Str;
str. 31
Seminář C++ VUT FEKT v Brně
void fun1(); }; test T = {3,3.1415926};
3.5 Oblasti platnosti a dosažitelnosti identifikátorů
Blok Identifikátor deklarovaný v těle funkce je platný v místě jeho deklarace a končí na konci
bloku. Formální parametr funkce je platný na začátku jeho deklarace a končí na konci těla
funkce.
Funkce Oblast platnosti se týká pouze návěští pro příkaz skoku.
Prototyp funkce Oblast platnosti končí s koncem prototypu.
Soubor Oblast platnosti se týká globálních identifikátorů (deklarované mimo tělo funkce). Platnost začíná v místě deklarace a končí na konci souboru.
Třída Oblast platnosti identifikátoru definovaného uvnitř třídy začíná v místě deklarace, obsahuje celé tělo třídy, těla všech metod, specifikace formálních parametrů a jejich implicitních hodnot a také inicializační část konstruktorů i mimo tělo třídy. Jména deklarovaná uvnitř třídy jsou dostupná i mimo třídu když jsou zapsány případem (operátor tečka), ukazatelem na případ (operátor ->), někdy jménem třídy (operátor ::).
3.6 Prostory jmen
Tyto prostory jsou nástroje vhodné pro organizaci identifikátorů v programu, aby nedošlo ke konfliktům identifikátorů v rozsáhlém programu. Deklarace prostoru jmen je
namespace [jmenovka]{deklarace}
• Pokud překladač najde druhý prostor jmen se stejnou jmenovkou, bude jej považovat za rozšíření prostoru.
Příklad 13: namespace test { int i=1; //test::i
void fun1(int); struct T { int i=2; //test::T::i };
str. 32
Seminář C++ VUT FEKT v Brně
} namespace test // pokracovani { int i=3; //nepripustne- opakovana definice
void fun1(float); // pretizeni void fun2(float); // korektni namespace // nepojmenovany prostor { int i=4; //test::T::i };
} void test::fun1(float x); // definice vne prosteru { return i; // test::i }
• Prostory jmen můžeme deklarovat pouze na úrovni souboru nebo uvnitř jiného prostoru jmen.
• Spřátelené funkce, které jsou deklarovány uvnitř třídy, která zase byla deklarována uvnitř prostoru jmen, patří do daného prostoru jmen.
• Pomocí klíčového slova using lze zpřístupnit objekt z libovolného prostoru jmen bez nutnosti opakované deklarace.
using jmenovka :: idetnifikátor using namespace jmenovka V prvním příkladu se zpřístupní uvedený identifikátor, v druhém všechny identifikátory z daného prostoru. Příklad 14: namespace A { int i=1; } namespace B { int i=2; using namespace A; } void main() { i=i+1; // Není zpřístupněn A::i=A::i+1; // korektní using namespace B; i=i+6; // Není jasné o který prostor jde A::i nebo B::i return 0; }
str. 33
Seminář C++ VUT FEKT v Brně
3.7 Paměťové třídy
Při deklaraci můžeme ještě zadat pro proměnnou její paměťovou třídu. Paměťová třída a místo deklarace určují viditelnost a dobu života proměnné.
auto register static extern mutable
Auto proměnné jsou lokální v bloku. Register proměnné jsou automatické proměnné, u kterých požadujeme umístění do registru procesoru. Static proměnná je globální a má omezenou viditelnost. Extern se přiřazuje proměnné nebo funkci z vnějšího přístupu. Mutable povoluje měnit konstantní objekty.
3.8 Kontrolní otázky
1. V čem spočívají výhody tříd?
2. Má nějakou roli v úspoře času a prostoru při programování v C++ hierarchické členění objektů?
3. Existuje nějaké rozdělení přístupu k prvkům třídy?
3.9 Úkoly
1. Sestavte program pro načtení a uložení dat na disk s daty z tabulky jednoduché aplikace. Využijte maximálně vlastností OOP.
2. Sestavte program pro zadání a řešení soustavy lineárních rovnic Gaussovou eliminační metodou. Využijte maximálně vlastností OOP.
4 Objekty
Toto označení je používáno jak v běžném životě, tak v programovacích jazycích. Tam se pro srozumitelnost a pochopení snaží tvůrci jazyka napodobit vlastnosti prvků a názvosloví běžnému každodennímu životu. Objektem je tedy nazýván jak obraz třídy, tak i její případ (instance). Někdy se používá název objekt i pro přístupnou část paměti (konstanta, proměnná, pole proměnných, funkce, ...)
str. 34
Seminář C++ VUT FEKT v Brně
4.1 Přiřazování objektů
Předpokládejme, že objekt je popsán třídou. Pokusme se provést jednoduchou operaci se dvěmi objekty. Pokusme se objekt O1 přiřadit objektu O2. Příklad 15: using namespace A; class test { int a,b;
public: void fun1(int int j){a=i;b=j} i,void show()(cout << a<< ’ ’<<b<< ”\n”;)
}; void main() { test O1,O2; O1.fun1(5,6); O2=O1; // Prirazeni O1.show(); O2return 0;
.show();
} Při přiřazení objektů jsou data obou totožná, ale objekty jsou oddělené.
4.2 Předávání objektů funkcím
Objekty mohou být jako argumenty předávány funkcím tak jak známe z jazyka C. Platí shodná pravidla předávání (deklarace parametrů funkce – typ třídy, objekt třídy je argument funkce) Příklad 16: using namespace A; class test { int a;
public: pri =i} int get_a()(return a;)
(int i){a
}; int kva_a(test x) { return x.get_a()* x.get_a(); } int main() {
str. 35
Seminář C++ VUT FEKT v Brně
test a(5),b(6); cout << kva_a(a)<< ”\n”; cout << kva_a(b)<< ”\n”; return 0; } Program vytvoří třídu test. V ní je proměnná a. Funkce kva_a() přebírá argument třídy test. Na výstupu programu je číslo 25 a 36. Toto předání bylo provedeno hodnotou. Existuje také možnost předání adresou.
4.3 Vrácení objektů funkcemi
Tak jak je možné předávat objekty funkcím, mohou funkce objekty vracet. Funkce musí být deklarovaná tak, aby mohla třídu vrátit- return. Při této operaci se dočasně vytvoří objekt, v němž je návratová hodnota. Objekt je vrácen a dočasný objekt je zrušen. Příklad 17: using namespace A; class test { char a[100];
public: void show(){cout << a << ”\n”;} void set_a(char *str)(strcpy(a,str);)
}; // navrat typu test test inp() { char a[100]; tets str; cout << “Vloz znak:”; cin >> a; str.set(a); return str; } int main() { test O1; O1=inp; O1.shoreturn 0;
w();
}
str. 36
Seminář C++ VUT FEKT v Brně
V programu funkce inp() vytváří lokální objekt str. Následuje načtení řetězce z klávesnice. Řetězec je nakopírován do str.a pak jej funkce vrací do str. Objekt je vrácen po volání inp() do O1 v hlavním programu.
4.4 Úkoly
1. Sestavte program pro načtení a uložení dat z tabulky. Provádějte základní operace
s prvky tabulky.
5 Operátory V této části se budeme blíže zabývat vlastnostmi operátorů.
5.1 Přehled operátorů
V následující tabulce je uveden seznam a původní význam operátorů.
OPERÁTOR POPIS POZNÁMKA + součet operandů (binární) + identita (unární) - rozdíl operandů (binární) - změna znaménka (unární) += součet operandů a přiřazení výsledku
levému operandu
-= rozdíl operandů a přiřazení výsledku levému operandu
* aritmetické násobení * přístup k hodnotě proměnné (ukazatel) *= aritmetické násobení a přiřazení výsledku
levému operandu
/ aritmetický podíl dvou operandů /= aritmetický podíl dvou operandů výsledek je
přiřazen levému
% výsledek po celočíselném dělení %= výsledek po celočíselném dělení výsledek
přiřazen levému operandu
! logická negace not logická negace != logická relace nerovná se not_eq logická relace nerovná se & adresa operandu (unární) & konjunkce po bitech (binární) bitand konjunkce po bitech (binární)
str. 37
Seminář C++ VUT FEKT v Brně
&= konjunkce po bitech a výsledek přiřadí levému operandu
and_eq konjunkce po bitech a výsledek přiřadí levému operandu
&& konjunkce- logický součin and konjunkce- logický součin (int).... přetypování na int, lze libovolně použít dynamic_cast přetypování v rámci dědické hierarchie
s dynamickou kontrolou typů
static_cast změna typů objektů a standardní C/C++ const_cast změna typů, kdy se předávají nebo
odstraňují modifikátory const a volatile
reinterpret_cast nepřenositelné přetypování , čárka, operátor pro sekvenční
vyhodnocování
++ zvýšení hodnoty operandu o jednu -- snížení hodnoty operandu o jednu -> přístup ke složce případu (instance)
prostřednictvím ukazatele
. tečka, přístup ke složce případu prostřednictvím případu
= přiřazení == logická relace rovno < logická relace menší než > logická relace větší než <= logická relace menší nebo rovno => logická relace větší nebo rovno << posunutí bitů doleva <<= posunutí bitů doleva a přiřazení výsledku
levému operandu
>> posunutí bitů doprava >>= posunutí bitů doprava a přiřazení výsledku
levému operandu
?: podmíněný výraz [] indexování pole () volání funkce ^ bitová nerovnost XOR xor bitová nerovnost XOR ^= bitová nerovnost a přiřazení výsledku
levému operandu
xor_eq bitová nerovnost a přiřazení výsledku levému operandu
| logická relace disjunkce – OR po bitech bitor logická relace disjunkce – OR po bitech |= logická relace disjunkce po bitech a
přiřazení výsledku levému operandu
or_eq logická relace disjunkce po bitech a přiřazení výsledku levému operandu
|| logická relace disjunkce - OR
str. 38
Seminář C++ VUT FEKT v Brně
or logická relace disjunkce - OR ~ doplněk (binární) compl doplněk (binární) : inicializace třídy :: operátor rozsahu, zpřístupnění globálního
jména, jména ze tříd a prostorů jmen
.* přístup k hodnotě třídy s pomocí případu ->* přístup k hodnotě třídy s pomocí ukazatele
na případ
sizeof vrací velikost operandu v bytech typeid dynamické určení typu new dynamické přidělení paměti delete uvolnění dynamicky přidělené paměti delete[] uvolnění dynamicky přidělené paměti pole # převod parametru makra na řetězec
(preprocesor)
## spojování symbolů (preprocesor) defined test na přítomnost definovaného makra
(preprocesor)
Podle počtu operátorů můžeme operátory klasifikovat na
• unární • binární • ternární
Práce s operátory se řídí jistými pravidly. Pro jistotu a zvýšenou přenositelnost programu je vhodné používat k vymezení priority operátorů závorek. Operandy, které vstupují do relace, by měly být stejného typu. Pokud nejsou, bude provedeno jejich převedení (konverze). Tento převod má svá pravidla. Podle zkušeností ale nelze na ně spoléhat, mohou způsobit při přenosu zdrojového kódu a následného překladu nedozírné komplikace. Proto dobří programátoři řádně definují převody již při psaní zdrojového programu. Nebudeme se proto dále zabývat pravidly konverze. Na následujících příkladech zkusme ukázat některé použití operátorů.
5.2 Popis, užití operátorů
Unární operátory + , - mění hodnoty operandu. Pro binární operátory +, -, /, * , % platí
známá pravidla. Přiřazovací operátory jsou obdobně používány jako v jazyce C a ostatních jazycích. V jazyce C jsme se seznámili se složenými operátory.
Příklad 18: void main() { int a,b;
a=1; b=2; a+=b; // ekv. a=a+b return 0;
str. 39
Seminář C++ VUT FEKT v Brně
} Použití relačních a logických operátorů je standardní jako v jazyce C, podobně přístup k datům je shodný jako v jazyce C. Snad někdy mohou dělat obtíže přístupy k objektům. Pokusme se na jednoduchých příkladech ukázat použití možností přístupu. Příklad 19: struct test { char jmeno[100]; int cislo_vyr; }; void main() { test auto;
strcpy(auto.jmeno, ”Jaguar”); auto.creturn 0;
islo_vyr=51023659874515926;
} Příklad 20: struct test { char jmeno[100]; int cislo_vyr; }; void main() { struct test auto; struct test* p_auto=&auto;
strcpy(p_auto->jmeno, ”Jaguar”); p_auto->cislo_vyr=51023659874515926; return 0;
} Bitové operátory jsou definovány pouze pro celočíselné typy proměnných. V operandech se pracuje s jednotlivými bity. Patří sem operace AND, OR, NOT, COMPL.
Jako příklad práce s bitovými operátory lze uvést:
Příklad 20:
0110 0001 znak ´a´ &1101 1111 maska 0100 0001 znak ´A´
0100 0001 znak ´A´ |0010 0000 maska 0110 0001 znak ´a´
0001 1001
str. 40
Seminář C++ VUT FEKT v Brně
^0000 1100 0001 0101 Často nejsou používané nebo známé operátory new a delete. Slouží k přidělování a uvolňování dynamické paměti. Jsou náhradou dříve používaných funkcí ze skupiny malloc() a free(). Na několika příkladech si ukažme její použití. Příklad 21:
long double *x=new long double; //alokace neinicia- lizovane promenne
x=new long double (1,2); //alokace hodnotou 1,2
long double *xx=new long double*; //neinicial. promenna long double *x=new long double [5]; //alokace pole void (**fce_ptr)(int)); //deklarace ukazatele na
fci fce_ptr = new (void(*[3])(int)); //dekl. 3 ukaz. na fci class test { int i; public: test(); test(int); }*x_test; char te[sizeof(test)]; //deklarace tridy x_test=new test[10]; //alokace pole x_test=new(te) test; //konstrukce pripadu
tridy test * utest = new(nothrow) test(5); //nevyvolava vyjimky,
alokuje pripad tridy
Objekty vytvořené pomocí new mají neomezenou dobu trvání. Paměťová místa se musí uvolnit operátorem delete. Příklad 22:
class test *p =new test[10]; //alokace delete[] p; int **xx = new int*; delete x;
V následující části textu se velmi stručně dotkneme přetypování. Klasické přetypování z C je asi takovéto: Příklad 22:
int a; // double b,c; c=(double) a/b;
str. 41
Seminář C++ VUT FEKT v Brně
Pokud se setkáme s komplikovanějším přetypováním, jakým je například přetypování ukazatele, je k tomu určen operátor dynamic_cast. Ukažme si na příkladu jeho použití. Příklad 23:
class zakl { public: virtual void fce(); }; // class dcera: public virtual zakl { public: virtual void fce(){} virtual void gfce(){int a=1;} }; // void pracuj(zakl *ub) { dcera* up = dynamic_cast<dcera*> (ub) if(up) up->gfce(); else return -1; }void main() { zakl X; dcera Y; pracuj (&Y); // pretypovani OK, ret.1 pracuj (&X); // pretypovani FALSE, ret. -1 }
5.3 Přetěžování operátorů
Některé operátory (většina) v C++ lze předefinovat. Přetížené operátory se definují jako funkce (operátorové funkce). Při práci s operátory se mohou rozdělit do čtyř skupin:
1. Operátory ::, ?:, ., .*, sizeof, typeid, dynamic_cast, static_cast, reinterpret_cast, const_cast, defined, #, ## NELZE PŘETĚŽOVAT.
2. Operátory ->, [], (), =, (typ) lze přetěžovat pouze jako nestatické metody objektových typů.
3. Ostatní operátory s výjimkou new a delete lze přetěžovat jako nestatické metody objektových typů.
4. Operátory new a delete lze přetěžovat jako statické metody objektových typů nebo jako obyčejné funkce.
• Přetěžování operátorů má také svá pravidla. Například nelze definovat nové operátory. • Není přípustné měnit charakteristiky operátorů (počet operandů, prioritu,…) • Nelze měnit definici operátoru pro standardní datové typy. • Jméno operátorové funkce se vždy skládá z klíčového slova operator a symbolu
operátoru.
str. 42
Seminář C++ VUT FEKT v Brně
• Kromě new a delete operátoru není pro žádný z operátorů předepsán typ vrácené hodnoty.
Příklad 24:
class complex // komplexni cisla { double re,im; public: complex (double r, double i); // konstruktor x operator ; // unarni minus comple –() friend bool operator !(complex&); //logicka negace }; // complex complex::operator-() // vrati komplexni cisla
// s opacnym znamenkem { return complex (-re, -im); } complex operator!(complex& c) // pokud je aspon jedna slozka // nenulova, vrati true { if(c.re || c.im) return true; else return false; } void main() {
complex c(0,0), d(0,1); c=-d; // ekvivalent c=d.operator-() if(!c) test(c);
return 0; }
Takto bychom mohli pokračovat v dalších příkladech.
5.4 Úkoly
1. Sestavte program pro změnu editovaných písmen z malé na velkou abecedu a
obráceně.
str. 43
Seminář C++ VUT FEKT v Brně
6 Dědičnost Dědičnost je jedním ze základních vlastností a prvků OOP. Tím se dokáže rychleji
sestavit struktury vlastností objektů. Původní – bázové třídy slouží jako základ pro nové – odvozené třídy – potomky nebo dceřiné třídy. Třídy, které se vážou dědičnými vlastnostmi, se také označují jako dědické hierarchie.
Existuje několik forem dědičnosti. • Jednoduchá- jedna bázová a jedna odvozená • Vícenásobná – jeden potomek má více předků.
Odvozená třída dědí vlastnosti předků. Bude obsahovat všechny nestatické datové složky předků, bude používat jejich metody, typy a statické složky podle definovaných práv. Některá pravidla lze bodově shrnout:
• Kritérium sdílení- Odvozené třídy by měly korektně sdílet vlastnosti základní třídy. • Kritérium nezávislosti- Vlastní definice odvozené třídy by neměly ovlivňovat použití
zděděných vlastností. • Kritérium specializace- Je-li odvozená třída speciálním případem základní, použije se
k odvození polymorfismu – virtuálních metod. Speciální případy tříd nejsou rozdílné úrovně v hierarchii.
• Kritérium jednotnosti – dědičnost by měla zajistit rovnoprávnost tříd – jednotný způsob implementace.
Jak se s dědičností pracuje.
6.1 Syntaktický zápis
Zápis dědičnosti je podle následujícího tvaru
klíč jméno_třídy:seznam_bázových_tříd { složky_třídy }; kde jsou klíč .... class, struct , jméno_třídy je identifikátor odvozené třídy,
seznam_bázových_tříd je výběr tříd, jejichž vlastnosti má odvozená třída dědit a způsob dědění. Položka má tvar [virtual][specifikátor_přístupu]jméno_bázové_třídy , specifikátor_přístupu je jeden z public, protected, private. Složky_třídy jsou definice odvozených tříd.
6.2 Přístupy v dědičnosti
Přístupová práva u děděných vlastností tříd lze řízeně měnit pomocí základních modifikátorů public, protected, private. Podle jednoduché tabulky se mohou skutečné přístupy řídit.
Modifikátor v deklaraci
Modifikátor v bázové třídě
Přístupová práva v odvozené třídě
poznámka
str. 44
Seminář C++ VUT FEKT v Brně
public public public public protected protected public private private protected protected protected protected public protected protected private private private private private private protected private private public private Omezení přístupu způsobené dědičnými právy se mění tak, že zděděnou složku uvedeme bez specifikace typu, ale se specifikací předka. Příklad 25:
class zakl // baze { int i; // private public: int j; // public }; // class odvozena: private zakl // odvozena { int i; // private public: zakl::j; // opet public }; //
Některé překladače mění práva pomocí deklarace using. Příklad 26:
class zakl_x // baze { int e(); // private fc public: int j; // public }; // class odvozena_x: private zakl_x // odvozena { int i; // private public: using zakl_x::fce; // opet public }; //
Dědická práva platí u všech složek i metod třídy. Příklad 27:
str. 45
Seminář C++ VUT FEKT v Brně
class zakl_x // baze { int prom_a, prom_b; // private public: int sou_a(){return prom_a;}; int sou_b(){return prom_b;}; zakl_x: prom_a(10), prom_b(20) {}; }; // class odvozena_x: public zakl_x // odvozena { int ma; // private su public: ozena_x: suma(0){}; // odv int scitej(); { suma+=prom_a+prom_b; return suma; } }; //
V tomto příkladě zřejmě překladač ohlásí chybu, protože je proveden nekorektní zápis odvozené třídy. Složky prom_a, prom_b jsou v odvozené třídě nepřístupné. Jsou dvě možnosti změny. První je, že v základní třídě se změní z private na protected.
class zakl_x // baze { protected: // smi pouzivat potomek int prom_a, prom_b; // private public: int sou_a(){return prom_a;}; int sou_b(){return prom_b;}; zakl_x: prom_a(10), prom_b(20) {}; }; //
Druhá metoda je založena na změně přístupových práv.
class odvozena_x: public zakl_x // odvozena { int suma; // private public: odvozena_x: suma(0){}; // int scitej(); { suma+=sou_a()+sou_b(); return suma; } }; //
str. 46
Seminář C++ VUT FEKT v Brně
Konstruktory a destruktory tříd se nedědí, ale při tvorbě případu odvozené třídy jsou zděděné datové složky inicializovány konstruktorem základní třídy. Příklad 28:
class zakl_x // baze { int prom_a; // private public: int sou_a(){return prom_a;}; zakl_x(void): prom_a(10) {}; zakl_x(int prom_b): prom_a(prom_b) {}; }; // class odvozena_x: public zakl_x // odvozena { int ma; // private su public: odvozena_x(void): suma(0){}; // odvozena_x(int prom_b, int prom_c): zakl_x(prom_b),
suma(prom_c){}; // void scitej(zakl_x& b); }; //
V deklaraci konstruktoru odvozena_x(void) nevoláme konstruktor předka. Potom překladač použije konstruktor zakl_x(void) . V konstruktoru odvozena_x(int) se volá konstruktor zakl_x(prom_b) .
6.3 Úkoly
1. Sestavte program pro měřicí ústřednu s okny měřicího zařízení (ručkový měřicí přístroj, osciloskop) tak, aby byly využity vlastnosti dědičnosti měněné podle nastavení uživatele.
7 Polymorfismus
Polymorfismus souvisí s principy dědičnosti. Je tak nazýván jev, kdy jedna metoda (ekv. funkce) je v různých třídách svázaných dědičností, implementována rozdílně.
Vhodné je používat dědění pomocí společné bázové třídy. V odvozených třídách jsou metody předefinovány a tak se pozmění účel metody. Metody, které se mají v odvozených třídách změnit, se deklarují s klíčovým slovem virtual.
Příklad 29:
struct bod_1 {double x,y;}; class kres_obj //
str. 47
Seminář C++ VUT FEKT v Brně
{ protected: bod_1 ref_bod; virtual int kresli(); }; // { //nakresli se bod v danych souradnicich //........ }; // class obdelnik: public kres_obj // { protected: bod_1 rohy[4]; virtual int kresli(); }; // { //nakresli obdelnik o danych rozmerech //........ }; class kruznice: public kres_obj //
//
{ protected: bod_1 stred; float r; virtual int kresli(); }; // { //nakresli kruznici o danych rozmerech //........ }; //
7.1 Úkoly
Sestavte program, který podle příkladu 29 provede v okně vykreslení základních
geometrických obrazců – kružnice, elipsa, čtverec, obdélník, kosočtverec, přímka, trojúhelník,....
8 Přetěžování funkcí
Již jsme o přetěžování kratičce mluvili. Mimo přetěžování funkce z poznámek v předcházejících kapitolách se nyní ještě k tomuto tématu vrátíme v několika odstavcích.
str. 48
Seminář C++ VUT FEKT v Brně
8.1 Přetěžování konstruktorů
Pro snadnější programování a nezatěžování schopností programátora jsou zaváděny všechny systémy přetěžování. Patří mezi ně i přetěžování konstruktorů. Mimo jiné také přetěžování konstruktorů pomáhá k mnohotvárnosti používání polí, tvorbě kopírovacích konstruktorů. Při tvorbě tříd musíme vytvářet konstruktory, pokud nejsou vytvořeny, překladač ohlásí chybu.
Příklad 30: class test { int i;
public: // přetížení konstruktoru dvojí způsobem test(){i=0} //bez inicializátoru test(int n){i=n} //inicializátor
int getx() {return i}; }; int main() { test o1(10); // deklarace s pocatecni hodnotou 2; // deklarace bez inicializatoru test o
cout<<”o1:”<<o1.getx()<< ‘\n ‘; cout<<”o2:”<<o2.getx()<< ‘\n ‘; return 0;
}; V tomto příkladu je dána počáteční hodnota o1, ale není dána o2. Je-li odstraněn
konstruktor, který má prázdný seznam argumentů - test(){i=0}//bez inicializátoru, program nebude úspěšně pracovat. Je-li odstraněn opačně konstruktor s argumenty, výsledek překladu bude stejný test(int n){i=n}//inicializátor. V jiném příkladě se může ukázat výhodnost přetěžování konstruktorů pro to, aby v programu byly jak samostatné objekty, tak pole objektů. Pokud se deklaruje z předchozího příkladu test o1(10); test o1[25]; jsou obě deklarace platné. Pokud se v programu použije parametrizovaných i neparametrizovaných konstruktorů, program umožní vytváření objektů, které mohou nebo nemusí být inicializovány. Příklad 31: class test { int i;
public: // přetížení konstruktoru dvojí způsobem test(){i=0} //bez inicializátoru test(int n){i=n} //inicializátor
str. 49
Seminář C++ VUT FEKT v Brně
int getx() {return i}; }; int main() { test o1[10]; // deklarace pole bez inicializátorů test o2[3]={1,2,3}; // deklarace s inicializatory
.
. return 0;
}; Přetěžováním se dosáhne toho, že programátor si pohodlně může vybrat libovolný typ inicializace objektu. Při přetěžování se může použít prvek – standardní argument. Je to způsob předávání parametrů při volání funkci, které je zkráceným zápisem přetěžování funkce. Zadání standardního argumentu může vypadat například takto: void test_f (int a=0, int b=0); Nyní funkce může být volána třemi způsoby: 1. test_f (); //a,b=0 2. test_f (15); //a=15,b=0 3. test_f (1,56); //a=1, b=56
8.2 Anachronismus přetěžování
V době vzniku C++ bylo pro přetěžování vymezeno klíčové slovo overload. Nyní je zastaralé a není používáno, je možné se s ním setkat ve starších zdrojových textech. Jeho tvar a používání je
overload name_fce; kde name_fce je jméno funkce, která se má přetížit. Příkaz předchází deklaracím přetěžované funkce.
8.3 Přetěžování a nejednoznačnost
Pokud se používá přetěžování funkcí, může se do programu zanést nejednoznačnost. Bývá to převodem typů, pomocí parametrů odkazů, pomocí standardních argumentů. Někdy ale nejednoznačnost je vnesena samotným přetížením funkce. Jednoduchou ukázkou je následující příklad
Příklad 32: float fce_1(float x) { return x/2.0; } double fce_1(double x)
str. 50
Seminář C++ VUT FEKT v Brně
{ return x/3.0; } int main() { float x=1.01; dougle y=1.01, a; a= fce_1(x); // jednoznačné a= fce_1(y); // jednoznačné
a= fce_1(48); // nejednoznačné, převod 48 na double nebo // float???
.
. return 0;
}; Takto by s různými typy šlo pokračovat dále.
8.4 Úkoly
1. Sestavte program, který pomocí zjednodušeného zápisu umožní více typů zobrazení aktuálního data, hodiny.
9 Šablony funkcí a tříd Šablony jsou vzory, podle kterých překladač může sestavit skupiny podobných vlastností.
Tyto skupiny se nazývají případy (instance) šablony. Deklarace šablony má tvar template <seznam_parametru> deklarace; template je klíčové slovo, které uvádí deklaraci šablony, seznam_parametru je seznam formálních parametrů, deklarace je deklarace obyčejné funkce, metody, objektového typu, statické datové složky objektového typu. Šablony nemohou být lokální ve funkcích, šablony funkcí se mohou deklarovat na úrovni souboru, šablony objektových typů můžeme deklarovat na úrovni souboru, jako složky objektových typů nebo šablon objektových typů. Lokální třídy nemohou obsahovat deklarace šablon. Dále existuje ještě několik pravidel nebo zaběhlých použití šablon.
9.1 Parametry šablon
Rozlišují se hodnotové, typové a šablonové parametry. Typový parametr zastupuje
datový typ, hodnotový parametr zastupuje konstantu. Hodnotové parametry se deklarují podobně jako formální parametr funkce. Typový parametr se deklaruje pomocí klíčového slova class. Pokud předepíšeme, že parametr je šablona, získáme poslední typ parametru.
str. 51
Seminář C++ VUT FEKT v Brně
Příklad 33: class test // prvni tvar class test =int // druhy tvar typename test // treti tvar typename test=float // ctvrty tvar template< class test, ...>class test_1 // paty tvar template<class test, ... >class test_1=Jmeno_Sablony //sesty tvar První a třetí tvar představuje typový formální parametr bez implicitní hodnoty. Druhá a čtvrtá možnost prezentuje typový formální parametr s implicitní hodnotou. Pátý a šestý tvar zachycují šablonový formální parametr. .
9.2 Šablony funkcí
Zápis šablony funkce je následující template <seznam_parametru> typ jmeno (seznam_parametru_fce ){ telo fce }; Uveďme si na příkladu. Příklad 34: template<class test>test ma(test a, test b) { return a>b?a:b; };
9.3 Šablony objektových typů
Zápis šablony objektového typu je následující template <seznam_parametru> klíč jméno { telo }; Kde klíč je buď class, struct nebo union. Uveďme si na příkladu. Příklad 35: template<typename test, int i=3>class pole{
test x[i]; public:
pole(); };
str. 52
Seminář C++ VUT FEKT v Brně
9.4 Úkoly
Sestavte program, který pomocí šablon zjednoduší výpočet diferencí prvního až n-tého
řádu.
10 Obsluha výjimek
Jazyk C++ má vestavěn mechanismus pro ošetření chyb. Mechanismus je nazýván obsluha výjimek. Toto ošetření se děje pomocí klíčových slov try, catch, throw. Mechanismus pro zpracování výjimek dokáže oddělit běžný zdrojový kód od kódu pro zpracování chyby. Syntaxe je následující try {
pokusny_blok } catch(typ1[identifikator]) { telo_osetreni_vyjimky } catch(typ2[identifikator]) { telo_osetreni_vyjimky } catch(typn[identifikator]) { telo_osetreni_vyjimky };
pokusny_blok je kód, v němž může nastat výjimka, v bloku catch je uveden případ pro zadanou výjimku. Pokud nastane výjimka a není zde uvedeno tělo catch, může dojít k nekorektnímu ukončení programu. Pokud nenastane ani jedna výjimka, všechny bloky catch jsou přeskočeny.
Pokud nechceme přístup k samotné výjimce, v klíčovém slovu catch specifikujeme pouze typ . Pro specifikaci, které výjimky se smějí rozšířit z těla funkce, se používá funkce throw. Pokusme se podívat na nějaký snadný příklad. Příklad 35: void test(int x)throw(int, char, double) { if(x==0) throw x; //odmitne int if(x==1) throw ’abcd’; //odmitne char if(x==2) throw 122.333; //odmitne double if(x==0) throw x; // } int main()
str. 53
Seminář C++ VUT FEKT v Brně
{ int err=0;
try{ test (0)} catch(int i) { err=1; } catch(char c) { err=2; } catch(double d) { err=3; }
return err; } V příkladu je definovaná funkce test, která zachycuje výjimky s omezené množiny (celé číslo, znak, reálné s dvounásobnou přesností). V hlavní funkci se deklaruje proměnná err a volá se blok try s funkcí test. Níže jsou zachyceny výjimky a podle jejich pořadí je do proměnné err zapsána hodnota. Ta se na konci hlavní funkce předá. Jako doplnění pro ošetření výjimek slouží funkce unexpected(), terminate(), set_unexpected(), set_terminate(). Funkce unexpected(), terminate() volá systém v případě, že se má ukončit program. Funkce set_unexpected(), set_terminate() mohou změnit nastavení funkcí unexpected(), terminate().
10.1 Úkoly
1. Pro váš sestavený program nastavte kontrolu neočekávaných výjimek tak, abyste ošetřili program proti nestandardnímu ukončení.
11 Závěr
Společně jsme prošli základy programování v jazyce C++ a velmi bodově jsme se dotkli některých témat jazyka. Měli bychom získat základní návyky programátora, naučit se používat různé druhy vysvětlujících textů. Největší škola programování je vlastní práce s jasně definovaným cílem. K tomuto kurzu se nabízelo použití vývojového prostředí Borland C++ Builder pro platformu MS Windows. Kurz se zaměřil z 90-ti procent na programy klasického typu (na událostmi řízené programování se orientoval kurz Počítače a programování II). Tím jsme učinili první krok k tomu, abychom byli schopni vyvíjet praktické aplikace pro řešení problémů z oblasti elektrotechniky, informatiky a komunikačních technologií.
str. 54
Seminář C++ VUT FEKT v Brně
Pevně věřím, že nabyté znalosti využijete i ve svém další studiu při práci na ročníko-vých projektech, na bakalářských a diplomových pracích.
Musíme si však uvědomit, že náš základní kurs pokryl základy programování C++. Tyto základy budete muset již sami ve své další práci rozvíjet, budete se muset sami seznamovat s dalšími možnostmi, které Borland C++ Builder a další nadplatformní programy nabízí, a sami budete muset bedlivě sledovat vývoj, jímž programovací nástroje procházejí. Určitě není třeba upozorňovat na skutečnost, že informační technologie se vyvíjejí velmi bouřlivě a že programátoři musejí studovat nové technologie celý život.
Při tomto neustálém studiu vám přeji mnoho úspěchů.
11.1 Literatura
[1] ECKEL, B. Myslíme v jazyku C++. Praha: Grada Publishing, 2002. ISBN 8-0247-9009-2
[2] VIRIUS, M. Programovací jazyky C/C++. Praha: Gcomp, 1992. ISBN 8-0901-0735-4.
[3] PRATA, S. Mistrovství v C++. Praha: Computer Press, 2001. ISBN 8-0722-6339-0
[4] KADLEC, V. Učíme se programovat v Borland C++ Builder a jazyce C++. Praha: Computer Press, 2001. ISBN 8-0722-6550-4
[5] HOLAN, T., NERUDA, R. C++ Builder v příkladech. Praha: BEN, 2002. ISBN 8-0730-0042-3
[6] HEROUT, P. Učebnice jazyka C. České Budějovice: Kopp, 1992. ISBN 8-0858-2821-9
[7] HEROUT, P. Učebnice jazyka C, 2.díl. Č. Budějovice: Kopp, 1992. ISBN 80-85828-50-2
[8] Virius,M.a kol. Jazyky C a C++ podle normy ANSI/ISO. GRADA, 1999. ISBN 80-7169-631-5
[9] Schildt,H. Nauč se sám C++. Softpress, 2001. ISBN 80-86497-13-5
str. 55