18. února 2015, Brno Připravil: David Procházka Základy programování v C++ Programovací jazyk C++
Historie C++: od Fortranu po C++11 Strana 2 / 53 Obsah přednášky 1 Historie C++: od Fortranu po C++11 2 Připomenutí základů OOP v C++ 3 Překlad aplikace 4 Proměnné a práce s nimi 5 Štábní kultura 6 Const 7 Static 8 Override a final 9 Oddechnutí
Historie C++: od Fortranu po C++11 Strana 3 / 53 Trocha historie nikoho nezabije... Na počátku bylo slovo, to slovo bylo... Fortran Lze ho považovat za jeden z prvních programovacích jazyků současného typu. Dodnes je jeho nová verze používána pro programování různých matematických úloh. Jazyků postupně přibývalo... Simula, Cobol, LISP, Prolog, Smalltalk, C... Fortran inspiroval Algol, Algol CPL, CPL BPL, BCPL, BCPL B, B C
Historie C++: od Fortranu po C++11 Strana 4 / 53 Jazyk C Nízkoúrovňový jazyk. Systémový jazyk. Operační systémy, překladače, drivery. Rozsáhlé možnosti díky knihovnám. Nižší efektivita vývoje vyvážená rychlým a elegantním kódem a velkými možnostmi. Implementace OOP podle Smalltalku Objective C.
Historie C++: od Fortranu po C++11 Strana 5 / 53 Jazyk C++ Od základu zaměřen na OOP. Rychlejší vývoj aplikací oproti C. Spousta IDE Code::Blocks, Microsoft Visual Studio, Eclipse, Qt Creator, XCode (MacOS X)... a překladačů GCC, LLVM, IBM, Ms Vzor pro další OO jazyky Java, C#.
Historie C++: od Fortranu po C++11 Strana 6 / 53 Historie C/C++ 1972 Ritchie, Thomson (pro OS Unix) 1978 specifikace Ritchie, Kerninghan 1984 první standardizace ANSI C 1990 definitivní standardizace ANSI C 1980 C with Classes (první pokus o budoucí C++) 1983 C++ 1998, 2003 standardizace ANSI/ISO C++ 2011 standardizace C++11 (dříve C++0x)
Historie C++: od Fortranu po C++11 Strana 7 / 53 C++11 Kompatibilita s C++98, tenký základ rozšířený zejména prostřednictvím STL, důraz na výkon a přímou práci s hadwarem, zlepšení vícevláknového a generického programování, doplněny požadované vlastnosti konkurence: rozsahové for cykly, podpora UTF-8/16/32... nové elegantní konstrukce: lambda výrazy, regulární výrazy, silně typové výčty, uživatelem definované literály atp. http://en.wikipedia.org/wiki/c++11
Historie C++: od Fortranu po C++11 Strana 8 / 53 Je už C++ ideální volbou? NE Ideální univerzální jazyk neexistuje. Ale Je to stabilní, odladěný jazyk obsahující většinu moderních nástrojů. Je podporovaný prakticky na všech platformách. Ačkoliv je relativně vysokoúrovňový, je rychlý. Nehodí se na všechno např. zpracování textů. Není tak pohodlný mj. silně typový.
Připomenutí základů OOP v C++ Strana 9 / 53 Obsah přednášky 1 Historie C++: od Fortranu po C++11 2 Připomenutí základů OOP v C++ 3 Překlad aplikace 4 Proměnné a práce s nimi 5 Štábní kultura 6 Const 7 Static 8 Override a final 9 Oddechnutí
Připomenutí základů OOP v C++ Strana 10 / 53 Připomenutí triviální aplikace 1 class Car { 2 private : // soukroma cast 3 string m_ model ; 4 public : // verejne rozhrani 5 Car ( string model ){ // konstruktor 6 m_ model = model ; 7 } 8 9 string getmodel (){ 10 return m_ model ; 11 } 12 13 void setmodel ( string model ){ 14 m_ model = model ; 15 } 16 };
Připomenutí základů OOP v C++ Strana 11 / 53 Připomenutí triviální aplikace 1 int main ( void ) { 2 // vytvoreni promenne s ukazatelem 3 Car * ford ; 4 5 // vytvoreni objektu a prirazeni uk. 6 ford = new Car (" Fiesta "); 7 8 // volani metody 9 cout << " Model : " << ford -> getmodel (); 10 11 // smazani objektu na ktery ford ukazuje 12 delete ford ; 13 14 // predani OS informaci o korektnim konci aplikace 15 return 0; 16 }
Připomenutí základů OOP v C++ Strana 12 / 53 Statické a dynamické instance tříd Zásobník (Stack) je oblast využívaná pro volání funkcí, ukládání návratových adres, parametrů funkce a lokálních proměnných. Zásobník je koncipován na ukládání lokálních proměnných, není vhodný pro objemná data. Pro ty je halda (heap). V jazyce C slouží k alokování a uvolňování paměti na haldě funkce malloc(), resp. free(). V C++ jsou zde pak operátory new a delete.
Připomenutí základů OOP v C++ Strana 13 / 53 Statické a dynamické instance tříd Následující kód ilustruje vytvoření proměnné ukazatel na zásobníku, která ukazuje na objekt alokovaný na haldě. Objekt lze kdykoliv vytvořit a zrušit. 1 Car * ukazatel ; // vytvor promennou s ukaz. 2 ukazatel = new Car ; // vloz adresu objektu 3 ukazatel - > metoda (); // zavolani metody 4 delete ukazatel ; // smaz objekt za ukazatelem 5 ukazatel = new Car ; // a dosadime opet jiny Následující kód ilustruje vytvoření proměnné objekt na zásobníku, která přímo obsahuje hodnotu objektu. Objekt je lokální proměnnou, tedy zanikne automaticky na konci metody, ale není možné jej explicitně zrušit. 1 Car objekt ; // vytvorime promennou s obj. 2 objekt. metoda (); // opet volame metodu 3 Car objekt2 ( parametr ); // zavolani par. konst.
Připomenutí základů OOP v C++ Strana 14 / 53 Štábní kultura Odsazujte tak, aby byla patrná struktura kódu (ale nepřepisujte). Délku řádku udžujte na rozumné velikosti (ale nepřepisujte) Pojmenovávejte jednotným způsobem třídy (Trida, JinaTrida), proměnné (mojeinstance), metody (vypisinformace nebo VypisInformace), atributy (m mujatribut), proměnné třídy (s promtridy), globální proměnné (fuj, ale g pocet) atp. Pište krátké a jasné metody princip Keep It Stupid Simple. Každá entita by měla mít pouze jeden účel.
Připomenutí základů OOP v C++ Strana 15 / 53 Prostory jmen Třídy, ale i proměnné a případně další nástroje C++ lze třídit do skupin prostorů jmen. Smyslem je logicky rozčlenit aplikaci a vyhnout se potenciálním duplicitám v označení. Nemá smysl využívat u triviálních aplikací. Využíváme při tvorbě knihoven nebo komplexnějších aplikací. Pro identifikaci jmenného prostoru používáme operátor :: nebo deklaraci using namespace. Existuje implicitní prostor jmen, který nemá jméno. Podle ANSI C++ existuje standardní prostor jmen std, tam patří mnoho nástrojů.
Připomenutí základů OOP v C++ Strana 16 / 53 Implicitní a standardní prostory jmen 1 using namespace std ; 2 3 class Foo { 4... 5 }; 6 7 int main ( void ) { 8 Foo * ukazatel = new Foo (); 9 ukazatel -> metoda (); 10 delete ukazatel ; 11 return 0; 12 }
Připomenutí základů OOP v C++ Strana 17 / 53 Příklad prostoru jmen 1 namespace JmennyProstor { 2 class Foo { 3... 4 }; 5 } 6 7 class Foo { 8... 9 };
Připomenutí základů OOP v C++ Strana 18 / 53 Použití prostoru jmen 1 int main ( void ) { 2 JmennyProstor :: Foo * ukazatel1 3 = new JmennyProstor :: Foo (); 4 ukazatel1 -> metoda (); 5 delete ukazatel1 ; 6 7 Foo * ukazatel2 = new Foo (); 8 ukazatel2 -> metoda (); 9 delete ukazatel2 ; 10 11 return 0; 12 }
Připomenutí základů OOP v C++ Strana 19 / 53 Další použití direktivy using 1 int main ( void ) { 2 // import v ramci metody / funkce 3 using namespace std ; 4... 5 } nebo 1 // import jedineho prikazu 2 using std :: cout ; 3... 4 int main ( void ) { 5...
Překlad aplikace Strana 20 / 53 Obsah přednášky 1 Historie C++: od Fortranu po C++11 2 Připomenutí základů OOP v C++ 3 Překlad aplikace 4 Proměnné a práce s nimi 5 Štábní kultura 6 Const 7 Static 8 Override a final 9 Oddechnutí
Překlad aplikace Strana 21 / 53 Překlad 1 preprocesor předzpracovává zdrojový soubor.cc (.cpp) (include, defined). 2 kompilátor překladač provádí překlad zdrojového souboru.obj (.o) relativní strojový kód, adresy proměnných a fcí nejsou známy.lis protokol o překladu 3 linker sestavovací program provede přidělení absolutních adres.exe, spustitelný soubor Je doporučováno kompilovat při vysoké citlivosti kompilátoru (c++ -Wall -pedantic -o program program.cc). Pro překlad C++11 musíte také zvolit knihovnu libc++ (-std=c++0x -stdlib=libc++). V XCode je nalezneme pod nastavením C++ Standard Library a C++ Language Dialect.
Překlad aplikace Strana 22 / 53 Překlad více souborů U větších projektů je zvykem rozdělovat kód do více souborů. Obvykle pro každou třídu vytvoříme samostatný hlavičkový (.h) a implementační (.cc) soubor. Hlavní soubor programu (main.cc) vkládá pomocí direktiv include pouze hlavičkové soubory modulů (nikdy implementační soubory). Ty jsou překládány samostatně. c++./main.cc./lev.cc./zirafa.cc -o zookoutek
Překlad aplikace Strana 23 / 53 Hlavičkové soubory a jejich podmíněné načtení Hlavičkové soubory vždy obsahují veškeré direktivy include nezbytné pro samostatný překlad modulu (třídy). Implementační soubor (.cc) obsahuje pouze implementace nešablonových metod a jedinou direktivu include, která vloží hlavičkový soubor dané třídy. Hlavičkové soubory jsou často includovány vícekrát. je nutné zabránit jejich vícenásobnému načtení. K tomu slouží definice podmíněného bloku: Pokud blok kódu s tímto jménem nebyl definován, nadefinuj ho. 1 # ifndef _ MEDVED_ H 2 # define _ MEDVED_ H 3 // samotny obsah souboru medved. h 4 # endif
Proměnné a práce s nimi Strana 24 / 53 Obsah přednášky 1 Historie C++: od Fortranu po C++11 2 Připomenutí základů OOP v C++ 3 Překlad aplikace 4 Proměnné a práce s nimi 5 Štábní kultura 6 Const 7 Static 8 Override a final 9 Oddechnutí
Proměnné a práce s nimi Strana 25 / 53 Datové typy (část) Základní Celočíselné: int, long int, short int, long long Reálné: float, double, long double Znaky a řetězce: char[16 t 32 t], string. Speciální: void, auto Velikosti typu záleží na dané architektuře. Zjistíme pomocí příkazu sizeof(int) nebo konstant INT MAX INT MIN, aj. Speciální Záznam, union, výčtový typ enumerate, výčtová třída, pole (inicializace int pole[3], resp. int pole[3] = {1,2,3} 1, přístup pole[0]) STL: seznam, fronta, zásobník,... U celočíselných typů existují také neznaménkové varianty unsigned. Číselný rozsah posunut pouze do kladných čísel. 1 možnost vložení objektů { { 1,2,3 },... }
Proměnné a práce s nimi Strana 26 / 53 Kontrola rozsahu 1 # include < climits > 2 using namespace std ; 3... 4 int main (){ 5 cout << " int is " << sizeof ( int ) << " B" << endl ; 6 cout << " short : " << sizeof ( short ) << " B" << endl ; 7 cout << " long : " << sizeof ( long ) << "B" << endl ; 8 cout << " Maximum values :" << endl ; 9 cout << " int : " << INT_ MAX << endl ; 10 cout << " short : " << SHRT_ MAX << endl ; 11 cout << " long : " << LONG_ MAX << endl ; 12 cout << " Minimum int value = " << INT_ MIN << endl ; 13 return 0; 14 }
Proměnné a práce s nimi Strana 27 / 53 Typy s garantovaným rozsahem (C++11) Znaménkový int o přesné bitové velikosti int8 t, int16 t, int32 t, int64 t uint8 t, uint16 t, uint32 t, uint64 t Rychlá (nativní) implementace int fast8 t, int fast16 t, int fast32 t, int fast64 t uint fast8 t, uint fast16 t, uint fast32 t, uint fast64 t Implementace zabírající nejméně paměti int least8 t, int least16 t, int least32 t, int least64 t uint least8 t, uint least16 t, uint least32 t, uint least64 t
Proměnné a práce s nimi Strana 28 / 53 Klíčové slovo auto (C++11) Automaticky se dosadí typ na základě inicializace. Nepoužívat pokud není typ zřejmý! 1 int x = 10; 2 auto y = x; // y je int
Proměnné a práce s nimi Strana 29 / 53 Deklarace a inicializace proměnných typ jmeno = inicializacni hodnota 1 int i = 1; // globalni promenna 2 int main ( void ) { 3 int j = 10; // lokalni prom. 4 int & ref = j; // reference na j, nutno hned inic. 5 return 0; 6 } Proměnná by měla mít co nejmenší možnou platnost. Při vytvoření prom. je vždy vhodné ji okamžitě inicializovat.
Proměnné a práce s nimi Strana 30 / 53 In-class inicializace proměnných (C++11) Dříve: 1 int var = 7; 2 class X { 3 static const int m1 = 7; // ok 4 const int m2 = 7; // error : not static 5 static int m3 = 7; // error : not const 6 static const int m4 = var ; // error : init. not const 7 static const string m5 = " odd "; // error : not integr 8 }; Nyní inicializace v době překladu: 1 class X { 2 int m_a = 7; 3 };
Proměnné a práce s nimi Strana 31 / 53 Konstruktory: inicializace v době překladu In-class inicializace je ekvivalent 1 class A { 2 int m_a ; 3 public : 4 A() : m_a (7) {} 5 }; Tento způsob inicializace atributů je nezbytný pokud atributem je objekt, který nemá bezparametrický konstruktor 1 class Vektor { 2 Bod m_x ; 3 Bod m_y ; 4 public : 5 Bod ( Bod x, Bod y): m_x (x), m_y (y ){...} 6 };
Proměnné a práce s nimi Strana 32 / 53 Konstruktory: delegování konstruktorů (C++11) Dříve: 1 class Bod { 2 int m_x ; 3 validate ( int x) { if (0 <x && x <= max ) a=x; else...} 4 public : 5 Bod ( int x) { validate (x); } 6 Bod () { validate (42); } 7 Bod ( string s) { int x= lexical_cast <int >(s); 8 validate (x );} 9 }; Nyní: 1 class Bod { 2... 3 Bod ( int x) { validate (x); }
Proměnné a práce s nimi Strana 33 / 53 Příklad metody vracející jednu hodnotu 1 class Vypocet { 2 public : 3 int secti ( int cislo1, int cislo2 ){ 4 return cislo1 + cislo2 ; 5 } 6 }; 7... 8 9 int x = 12; 10 int y = 45; 11 int a = objekt -> secti (a,b); 12 int b = objekt -> secti (10,12);
Proměnné a práce s nimi Strana 34 / 53 Vracení více hodnot Situace se lehce komplikuje, pokud potřebujeme vracet z metody více hodnot. Máme 2 možnosti, jak to realizovat: pomocí ukazatelů (*) nebo refencí (&). Subjektivně jednodužší je: 1 class Vymena { 2 public : 3 void vymen ( int &a, int &b){ 4 int pom = a; 5 a = b; b = pom ; 6 } 7 }; 8... 9 objekt -> vymen (a, b);
Proměnné a práce s nimi Strana 35 / 53 Vracení více hodnot varianta * 1 class Vymena { 2 public : 3 void vymen ( Student * a, Student * b){ 4 Student pom = a; 5 a = b; 6 b = pom ; 7 } 8 }; 9 10 int main ( void ){ 11 Student * karel = new Student (" Karel ", 11) 12 Student * pepa = new Student (" Pepa ", 11) 13 objekt -> vymen ( karel, pepa ); Často je doporučováno spojit hodnoty do jedné třídy a vrátit je pomocí return. Např. místo x a y vracet instanci Bod2D s vlastnostmi x a y.
Štábní kultura Strana 36 / 53 Obsah přednášky 1 Historie C++: od Fortranu po C++11 2 Připomenutí základů OOP v C++ 3 Překlad aplikace 4 Proměnné a práce s nimi 5 Štábní kultura 6 Const 7 Static 8 Override a final 9 Oddechnutí
Štábní kultura Strana 37 / 53 Štábní kultura parametrů Hodnotou předáváme triviální vestavěné typy. Parametry, které slouží pouze pro vstup by měli být označeny const. Pokud se jedná o ukazatele na prom. je velmi doporučené označit je const. Reference (&) se používá nejen pro vracení hodnoty, ale i z důvodu efektivity. Reference na vstupní proměnnou by měla být vždy const. (nebezpečí modifikace původních dat) Např: void zpracuj(const vector<string>& vec), void udelej(const Velka3DMatice& prvek) Parametry by měly být pokud možno jednoduché typy a třídy.
Const Strana 38 / 53 Obsah přednášky 1 Historie C++: od Fortranu po C++11 2 Připomenutí základů OOP v C++ 3 Překlad aplikace 4 Proměnné a práce s nimi 5 Štábní kultura 6 Const 7 Static 8 Override a final 9 Oddechnutí
Const Strana 39 / 53 Konstanty Pokud má mít parametr nebo proměnná stále stejnou hodnotu, použijte klíčové slovo const. Pozor na odkazy: const x* zajistí neměnnost ukazatele nikoli hodnoty. 1 const int kheight = 10; // konstantni lokalni prom. Všimněte si názvu. Bývá zvykem používat předponu k.
Const Strana 40 / 53 Konstanty Nepoužívat céčkové #define Má neomezenou platnost a nelze specifikovat typ. Konstanta na úrovni jmenného prostoru: const int kpagesize = 365; Konstanta na úrovni třídy: 1 class Window { 2 static const int s_ kwidth = 400; 3 static const int s_ kheigth ; 4 }; 5 6 const int Window :: s_ kheigth = 300;
Const Strana 41 / 53 Další aplikace const const u parametru metody označuje, že pouze vstupní. Pokud píšeme const za metodou, říkáme, že metoda nemění stav objektu. int vrathodonotuatributu() const; V C++ lze vytvořit i konstantní instanci, u které nelze nijak měnit vnitřní stav. U takové instance lze volat pouze metody deklarované s klíčovým slovem const.
Const Strana 42 / 53 Constexpr (C++11) constexpr umožňuje definovat, že funkce/metoda atp. se vyhodnocuje v době překladu. Může významně pomoci při optimalizaci kódu. Funkci/metodu ale lze volat i za běhu programu. Tj. není nutné oddělovat řešení pro výpočet v době překladu a v době běhu. 1 constexpr int secti ( int x, int y){ 2 return x+y; 3 } 4 5 // prekladac muze vyraz vyhodnotit pri prekladu 6 const int val = secti (10, 10);
Static Strana 43 / 53 Obsah přednášky 1 Historie C++: od Fortranu po C++11 2 Připomenutí základů OOP v C++ 3 Překlad aplikace 4 Proměnné a práce s nimi 5 Štábní kultura 6 Const 7 Static 8 Override a final 9 Oddechnutí
Static Strana 44 / 53 Členské proměnné třídy Veškeré atributy, které jsme doposud používali byli atributy objektů byly unikátní pro jednotlivé objekty. V C++ můžeme definovat i atributy, které náleží přímo třídám členské proměnné. Pro deklaraci atributů třídy používáme static. Lze k nim přistupovat pomocí názvu třídy, :: a názvu proměnné (Třída::proměnná). 1 class Trida { 2 private : 3 static int s_ pocetinstanci ; // nelze napsat = 0; 4 int m_ normaniatribut ; 5...
Static Strana 45 / 53 Členské metody Členská metoda (označena static) nemá jako svůj první implicitní parametr this. Je to logické, protože není jasné pro který objekt je volána (není parametr this). V těle metody lze pracovat jen se statickými atributy a metodami třídy. Lze ji také zavolat, aniž by existovala nějaká instance dané třídy. 1 static int vratpocetinstanci () { 2 return pocetinstanci ; 3 }
Static Strana 46 / 53 Jiné využití static Je-li static globální proměnná (nebo funkce), je viditelná pouze v daném souboru zdrojového textu (modulu). Je-li static lokální proměnná funkce, potom její hodnota je uchovávána mezi jednotlivým voláním (zaniká při ukončení programu)
Override a final Strana 47 / 53 Obsah přednášky 1 Historie C++: od Fortranu po C++11 2 Připomenutí základů OOP v C++ 3 Překlad aplikace 4 Proměnné a práce s nimi 5 Štábní kultura 6 Const 7 Static 8 Override a final 9 Oddechnutí
Override a final Strana 48 / 53 Override (C++11) Explicitní stanovení překrytí virtuální metody. 1 class Father { 2 virtual void A( float age ); 3 virtual void B() const ; 4 virtual void C (); 5 void D (); 6 virtual void E (); 7 }; 8 9 class Son : public Father { 10 virtual void A( int age ) override ; // zmena typu 11 virtual void B() override ; // predkovi const 12 virtual void C() override ; // korekni prekryti 13 void D() override ; // neni v predkovi virt. 14 void E() override ; // korektni prekryti 15 };
Override a final Strana 49 / 53 Final (C++11) Klíčovým slovem final označujeme metody nebo třídy, které nesmí být použity pro dědění. 1 class Father { 2 virtual void A() final ; // nelze prekryvat 3 }; 4 5 class Son : public Father { 6 virtual void A (); // chyba prekladace 7 }; V případě třídy nelze vytvářet potomka této třídy. 1 class Father final {}; 2 3 class Son : public Father {}; // chyba prekladace
Override a final Strana 50 / 53 struct vs. class struct znamená v praxi téměř přesně totéž, co class. U stuct, pokud není řečeno jinak, jsou složky veřejné. Struktura může být předkem třídy a opačně. 1 struct Trida { 2... 3 }; 4 5 class Trida { 6 public : 7... 8 };
Override a final Strana 51 / 53 Výčtová třída (enumerate class) Nahrazuje zastaralé výčtové typy, které hodnoty vnitřně reprezentovaly jako inty. To vedlo na možnost porovnání nesouvisejících hodnot. 1 enum class Color { 2 Red, Blue 3 }; 4 5 enum class Fruit { 6 Banana, Apple 7 }; 8 9 Color a = Color :: Red ; // musime pouzit predponu tridy 10 Fruit b = Fruit :: Banana ; 11 if ( a == b) // zde bude chyba, coz je dobre
Oddechnutí Strana 52 / 53 Obsah přednášky 1 Historie C++: od Fortranu po C++11 2 Připomenutí základů OOP v C++ 3 Překlad aplikace 4 Proměnné a práce s nimi 5 Štábní kultura 6 Const 7 Static 8 Override a final 9 Oddechnutí
Oddechnutí Strana 53 / 53 Hello World!