+ All Categories
Home > Documents > PRG029 Programov ání v C a C++ ( LS 200 5 /0 6 )

PRG029 Programov ání v C a C++ ( LS 200 5 /0 6 )

Date post: 12-Jan-2016
Category:
Upload: hallie
View: 34 times
Download: 0 times
Share this document with a friend
Description:
PRG029 Programov ání v C a C++ ( LS 200 5 /0 6 ). RNDr. Filip Zavoral, Ph.D. Katedra softwarového inženýrství Filip.Zavoral @mff.cuni .cz http ://ulita.ms.mff.cuni.cz -> Výuka 24. 9. 2014 1:59. Studijní povinnosti. Zápočet není podmínkou složení zkoušky Požadavky na zápočet - PowerPoint PPT Presentation
255
PRG029 Programování v C a C++ (LS 2005/06) RNDr. Filip Zavoral, Ph.D. Katedra softwarového inženýrství [email protected] http://ulita.ms.mff.cuni.cz -> Výuka 11.06.2022 06:55
Transcript
Page 1: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

PRG029

Programování v C a C++ (LS 2005/06)

RNDr. Filip Zavoral, Ph.D.Katedra softwarového inženýrství

[email protected]

http://ulita.ms.mff.cuni.cz -> Výuka

21.04.2023 04:24

Page 2: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Studijní povinnosti

Zápočet není podmínkou složení zkoušky

Požadavky na zápočet SIS – Grupíček – každý musí být v nějaké skupině

Platí i pro 'pokročilé', repetenty, externisty a jakékoliv jiné úchylky Zkontrolujte, resp. přihlašte se do volné skupiny Termín 5.3.2005 Ověřte platnost e-mailu – Hladání studenta -> Změna údajů

Účast na cvičeních ’Pokročilí’ programátoři – domluvit se s vyučujícím na začátku semestru Během semestru 3 'domácí úkoly' (krátké prográmky) DÚ lze nahradit jedním větším zápočťákem

Závěrečný test Odladit krátký program v omezeném čase (v labu)

Konkrétní požadavky určuje a jejich plnění hodnotí cvičícíVše nestandardní předem domluvit s cvičícím

Page 3: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Pravidla pro budoucí neúspěšné

Zkouška Pokud letos složíte zkoušku se známkou 1 nebo 2

a nedostanete zápočet, bude vám příští rok automaticky uznána Tento mechanismus je implementován zkoušejícími, nikoliv studijním

odd.

Zápočet Pokud letos splníte zápočet, bude vám příští rok automaticky uznán Pokud nedostanete zápočet, budete příští rok opakovat nesplněné

části Podmínky splněné letos se automaticky uznávají V příštím roce se musíte na začátku semestru přihlásit na některé

cvičenía dohodnout se s cvičícím na konkrétních podmínkách

Page 4: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

PRG025 - Programování v C a C++ PRG035 - OOP LS 1. roč ZS 2. roč

Obsah předmětu

C++

C

C++

Nejdůležitější: vlastní praxeNa přednáškách se nikdo nikdy programovat

nenaučil

C

Page 5: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Obsah přednášky

Kurz jazyka C Přesněji: část C++ shodná s C Překlad programů, spojování Základní vlastnosti C, odlišnosti od jiných programovacích jazyků Datové typy, operátory a řídící konstrukce C Pole a ukazatele v jazyce C, práce s řetězci Vstup a výstup, standardní knihovy C Programování není (jen) zápis algoritmů

Úvod do C++ Zbývající cca 2/5 semestru Třídy a objekty, dědičnost, virtuální funkce, polymorfismus Povídání o C++ bude plynule pokračovat v 2. ročníku

Page 6: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Obsah cvičení

Střídavě v S7 a v laboratoři SW2 Začínáte tam, kde to máte napsané v rozvrhu Základní vlastnosti jazyka C Práce s datovými strukturami, triky Standardní knihovy C Zajímavé a záludné vlastnosti C Cvičení z C++ až v 2. ročníku (pro ty, kteří přežijí)

Laboratoř SW2 Microsoft Visual Studio .NET 2005 Praktické programování Ladění programů (!)

Prosíím, já jsem napsal program a ono to řeklo 'Váš program provedl neplatnou instrukci a bude ukončen '. Co mám dělat?

Page 7: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Literatura

Základní učebnice a popis jazyka Andrew Koenig, Barbara E. Moo: Rozumíme C++ (C++ Accelerated)

Miroslav Virius: Programování v C++ (ČVUT 2001)

Miroslav Virius: Pasti a propasti jazyka C++ Bruce Eckel: Myslíme v jazyku C++

Thinkinkg in C++ 2nd ed. - volně stáhnutelné . . .

C++ In-depth Alexandrescu, Sutter: C++ 101 programovacích technik (C++ Coding

Standards)

Meyers: Effective C++ (2nd ed.), More Effective C++, Effective STL Sutter: Exceptional C++, More Exceptional C++, Exceptional C++

Style Josuttis: The C++ Standard Library Josuttis: Object-Oriented Programming in C++

Jak správně C++ používat

pro středně pokročilé

Page 8: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Literatura

Pro velmi pokročilé Alexandrescu: Modern C++ Design

Generic Programming and Design Patterns Applied Vandevoorde, Josuttis: C++ Templates Abrahams, Gurtovoy: C++ Template Metaprogramming

Normy ISO/IEC 14882, ANSI: Programming languages - C++ (1998, 2003)

C++ 2003 TR1 (2005) C++0x

ISO/IEC 9899: Programming languages - C (1999)

WWW http://mindview.net/Books

Eckel: Thinking in C++ ... and more http://www.parashift.com/c++-faq-lite

v češtině: Moderní programování v

C++

Page 9: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Nevhodná literatura - nepoužívat!

Brian W. Kernighan, Dennis M. Ritchie: The C Programming Language

Martin Beran: Učebnice Borland C++ - hrubé chyby

Jan Pokorný: Rukověť uživatele Borland C++ - staré, BC 3.1

Vladimír Rudolf: ABC programátora v C++ - neúplné, zastaralé

Dirk Louis: C und C++ — Programierung und Referenz - chyby

Dalibor Kačmář: Jazyk C — učebnice pro střední školy – chyby

Brodský, Skočovský: Operační systém Unix a jazyk C – neúplné, zastaralé

Eric Gunnerson: Začínáme programovat v C# – C# není C++

Page 10: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Pascal vs. C a C++

Programování I, II heslo: programování = zápis algoritmů algoritmické myšlení, algoritmizace problému soustředění se na řešení problému formulace algoritmu a jeho zápis v nějakém formalismu (jazyku) základní datové a řídící struktury nedůležité: kontrola vstupů, uživatelské rozhraní, obedněnost, vazba

na OS a HW, přenositelnost, optimalizace, udržovatelnost

výuka (v) Pascalu dobrý jazyk pro zápis algoritmů nezatěžuje technickými detaily (alokace paměti, vazba na OS, ...) slabá podpora pro kontrolu vstupů, uživatelské........

Page 11: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Pascal vs. C a C++

Programování v C a C++, OOP heslo: programování = vývoj software důležité: kontrola vstupů, uživatelské rozhraní, obedněnost, vazba na

OS a HW, přenositelnost, optimalizace, udržovatelnost zvládnutí knihoven a vývojových nástrojů

výuka (v) C++ standardní jazyk pro vývoj software další jazyky vycházejí z C++ (Java, C#, ale i PHP, ...) dobrá podpora pro kontrolu vstupů, uživatelské........ nutnost zvládnout technické detaily (alokace paměti, vazba na OS..) velké množství hotového kódu (knihovny, komponenty, ...)

'Vše' již bylo naprogramován

o

Page 12: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Historie

1970-3 první verze C, společný vývoj s UNIXem1973 přepsání jádra UNIXu do C1978 Kerninghan, Ritchie: The C Programming Language1980 standardy – ANSI X3J11, od r. 1999 ISO 98991980 AT&T - "C with Classes"1983 poprvé název C++ (Rick Mascitti)1985 Stroustrup: The C++ Programming Language1989 ANSI X3J16 norma C++2003 nejnovější ISO/ANSI norma C++2005 C++ 2003 TR1

rozšíření knihoven (částečně podporováno GCC 4.0) založeno na knihovně Boost

2007-9 plán nové normy C++

Normy se vyvíjí, aktuální překladače o několik let zpětImplementace novinek často nekorektní nebo neefektivní

Page 13: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Part I - C

Cpřesněji společná část C a C++ se zdůrazněním

odlišností

Page 14: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

hello.c

#include <stdio.h>#include <conio.h>

int main( int argc, char ** argv){ printf( "Hello\n"); getch(); return 0;}

Page 15: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

hello.c

#include <stdio.h>#include <conio.h>

int main( int argc, char ** argv){ printf( "Hello\n"); getch(); return 0;}

tělo funkce

hlavička funkce

příkaz

deklarace knihovních funkcí

direktiva preprocesoru

vložení souboru

formální parametr

y

název funkce

typ návratové hodnoty

skutečné parametr

yvolání funkce

bez parametr

ů

Page 16: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Struktura programu

Program se skládá z modulů Překládány samostatně kompilátorem Spojovány linkerem

Modul z pohledu programátora Soubor s příponou .cpp (.c)

Hlavičkové soubory Soubory s příponou .h Deklarují (a někdy i definují) identifikátory používané ve více

modulech Vkládány do modulů direktivou include

Direktivu zpracovává preprocesor čistě textově Preprocesor je integrován v kompilátoru jako první fáze překladu

Modul z pohledu kompilátoru Samostatná jednotka překladu Výsledek práce preprocesoru

Page 17: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Překlad jednoho modulu a sestavení

.cpp

.h

CC .obj Link .exe

.obj.obj.obj.obj.obj.lib

kompilacespojování(linkování

)

knihovnystandardní i

jiné

knihovní headery

objektový modul

(přeložený kód)

spustitelný

program

Page 18: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Překlad více modulů – oddělený překlad

.c

.h .h

CC .obj Link .exe

.obj.obj.obj.obj.obj.lib

.obj.obj.obj

kompilace jednoho modulu

knihovnyknihovní headery

vlastní headery

.cpp

.c.cpp

další moduly

Page 19: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Modul - ucelená funkčí jednotkamodul.cpp - implementacemodul.h - definice rozhraní

Oddělený překlad - dělení na moduly

fotbal.cpp

fotbal.h

hriste.cpp hrac.cpp mic.cpp

hriste.h hrac.h mic.h

rozdělení projektu do modulů

a vytváření headerů je umění,

nedá se to naučit na přednášce

Page 20: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Překladače a vývojová prostředí

Windows - překladač součástí integrovaného prostředí MS Visual Studio - Visual C++ (.Net2005) integrovaný make, linker, debugger klikabilní konfigurace další překladače - Borland C++ Builder, Intel, Watcom

Unix (Linux) - samostatné programy, příkazová řádka gcc make - pro 'opravdové' programátory pokusy o vývojová prostředí (kDevelop, ...)

nepoužívat !

vývoj ukončen

Page 21: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Integrované vývojové prostředí

.c

.h .h

CC Link .exe

.obj.obj.obj.obj.obj.lib

.obj.obj.obj.c

.cpp

debugger

projekt

editor

Page 22: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

make

.c

.h .h

CC Link .exe

.obj.obj.obj.obj.obj.lib

.obj.obj.obj.c

.cpp

makemakefile

Page 23: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Program a modul

Program v C++ nemá (vnořovanou) blokovou strukturuNeexistuje "hlavní blok"

Běh programu začíná vyvoláním funkce main Před funkcí main běží inicializace běhového prostředí, po ní úklid Funkce main musí mít tuto hlavičku:

int main( parametry příkazové řádky)

Modul: posloupnost globálních deklarací a definic Deklarace

Oznámení překladači, že identifikátor existuje Určení některých vlastností (typ, parametry)

Definice Doplnění zbývajících vlastností (kód funkce, obsah struktury) Překladač vygeneruje kód funkce, vyhradí místo pro proměnnou

Page 24: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Příklad - malá násobilka

#include <stdio.h>

int vynasob( int c){ int i = 1, v; if( c < 1 || c > 10) return -1; while( i <= 10) { v = i * c; printf( "%d * %d = %d\n", i, c, v); i = i + 1; } return 0;}

int main(){ int cislo = 7; vynasob( cislo); return 0;}

inicializovaná

celočíselná proměnná

neinicializovaná proměnná

hlavička funkce, formální parametr

deklarace knihovních funkcí, ...

konec cyklu

začátek cyklu

kontrola parametrů

okanžitý návrat z funkce

2 * 7 = 14

++i

konec, OK

konec, OK

hlavní program

ignorování návratové hodnoty volání funkce

se skutečným

parametremThe END

Page 25: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Funkce

Základní programová jednotka je funkceNeexistují vnořené funkceZačátek programu – funkce main

int fce1( int x, int y){ return x+y;}

int fce2( int a){ return fce1( 1, 2*a+5);}

int main( int argc, char** argv){ ...}

int fce2( int a){ int fce1( int x, int y) { return x+y; }

return fce1( 2*a+17);}

vnořené

funkce nelze!

začátek program

u

argumenty z příkazové řádky

později

Page 26: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Funkce - návratový typ

Typ funkce = typ návratové hodnotyHodnota se vrací pomocí klíčového slova return

Speciální typ void - 'prázdný' typ ekvivalent procedury Pascalu

int fce1( int x, int y){ return x+y;}

void fce2( char* text){ printf( text);}

void fce3( char* text){ if( ! text) return; printf( text);}

návrat celočíselné hodnoty

návrat z funkce

Page 27: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Parametry funkce

Pevný počet, pevný typ možnost proměnného počtu parametrů - printf

Parametry jsou odděleny čárkouU každého parametru musí být uveden jeho typFunkce bez parametrů - void

int fce1( int x, int y, float z){ ...}

int f2( double a[5], char* str){ ...}

int f3( void){ ...}

int fce1( int x, y){ ...}

int fce3{ ...}

každý parametr musí

mít typ

Page 28: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Volání funkce

Shoda počtu formálních a skutečných parametrůKompatibilita typů formálních a skutečných parametrůI funkce bez parametrů musí obsahovat operátor ()Návratová hodnota - lze ignorovat

int fce1( int x, int y, float z){ ... }

int fce3( void){ ... }

int fce2( int a){ fce1( a, 1, a); fce3(); return 0;}

int fce1( int x, int y, float z){ ... }

int fce2( int a){ fce1; fce1( a, 1); fce1( a, 1, "ahoj");}

Page 29: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Předávání parametrů funkci

Všechny parametry se předávají hodnotou'Výstupní' parametry pouze přes ukazatele nebo reference

vymění se jen lokální proměnné

funkce

předají se pouze hodnoty (1, 2) nikoliv 'proměnné'

void swap( int x, int y){ int pom; pom = x; x = y; y = pom;}

void fce( void){ int a = 1; int b = 2; int c = 0; swap( a, b); c = 2 * a + b;}

Page 30: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Lokální proměnné

Definice lokálních proměnných C: na začátku těla funkce (bloku) C++: kdekoliv v těle funkce

Možná inicializace – při každém běhu funkce neinicializovaná proměnná – náhodná hodnota !!!

int fce( void){ int x, y; int z = 0; return z + x;}

deklarace celočíselný

ch proměnnýc

hdeklarace

s inicializací

náhodná hodnota !!!

int fce2( void){ int i = 0; while( i < 100) { int j = i + 1; i = j * i; } // j jiz neexistuje return i;}

hlavní blok

funkce

vnořený blok

deklarace proměnné

ve vnořeném blokuinicializace se

provádí při každém průběhu

po ukončení bloku již proměnná

neexistuje

Page 31: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Globální proměnné

Definice mimo tělo funkceViditelné v jakékoliv funkciMožná inicializace – při startu programuPoužívat s rozvahou!!

pouze pro sdílená dataint g = 1;

void fce( int x){ int z = 2; g = g + z * x;}

int main( void){ fce( 2); fce( 3); return g;}

globální proměnná

formální parametr

skutečný parametr

lokální proměnná

co vrátí main ??

Page 32: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Výraz

Norma: "Výraz je posloupnost operací a operátorů specifikující výpočet hodnoty"

Přiřazovací 'příkaz' je také výraz jeho hodnotou je přiřazovaná hodnota

Výrazy mohou mít vedlejší efekty

1

a+b*sin(x)

printf( "Ahoj")

q = &b[17]+*++p

"retezec"

a = b = 0;

if( (x = fnc()) != 0) ...

užitečné:test přiřazované

hodnoty

přiřazení je také výraz

Page 33: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Příkaz

Příkaz je výraz ukončený ';' (středníkem) složený příkaz - posloupnost příkazů mezi '{' a '}' programová konstrukce

1;a+b*sin(x);printf( "Ahoj");q = &b[17]+*++p;"retezec";

{ 1; a+b*sin(x); printf( "Ahoj"); q = &b[17]+*++p; "retezec";}

složený příkaz

Page 34: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Podmíněný příkaz

if (výraz) příkazif (výraz) příkaz else příkaz

if( a > 1) printf( "OK");

if( a > 1) b = 0; printf( "OK");

if( a > 1) b = 0; printf( "OK");else printf( "nee");

if( a > 1){ b = 0; printf( "OK");}else{ printf( "nee");}

if( a > 1) printf( "OK");else printf( "nee");

syntakticky správně, ale dělá

něco jiného

syntakticky špatně

if( a > 1) { b = 0; printf( "OK");} else { printf( "nee");}

Page 35: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Vnořené podmíněné příkazy

if( a > 1) { if( b > 0) printf( "OK");} else { printf( "nee");}

Syntakticky správně, ale nepřehledné

Na pohled nejasné párování

if( a > 1) { if( b > 0) printf( "OK"); else printf( "nee");}

U vnořených podmínek

vždy používat { }

if( a > 1) if( b > 0) printf( "OK");else printf( "nee");

Page 36: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Vícenásobné větvení – konstrukce switch

switch (výraz) { case konstanta: posloupnost příkazů break; case konstanta: case konstanta: posloupnost příkazů break; default: posloupnost příkazů}

switch( opcode) {case 0: // no op break;case 10: add(); break;case 11:case 12: cmp(opcode); break;default: error(opcode); break;}

switch( ch) {case '0'..'9': x += ch - '0'; break;case 'A'..'F': x += ch - 'A'; break;}

switch( opcode) {case 0: // no opcase 10: ...

zapomenutý break syntakticky

OK,ale dělá něco

jiného

interval nelze

celočíselný výraz

ukončení větve

pokud výraz není roven žádné z

konstant

více návěští pro jednu

větev

Page 37: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Cyklus – konstrukce while a do-while

while (výraz) příkaz podmínka na začátkudo příkaz while (výraz) ; podmínka na konci

while( a > 1) { fce( a); a = a / 2;}

while( a > 1) a = a / 2;

do { fce( a); a = a / 2;} while( a > 1);

tělo se vždy alespoň jednou

provede

Pozor! cyklus pokračuje pokud je podmínka

platná

Page 38: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

for (výraz1 ; výraz2 ; výraz3 ) příkaz

je ekvivalentem

výraz1;while (výraz2 ) { příkaz výraz3 ;}

Cyklus – konstrukce for

i=0;while( i<=9) { fce( i); i=i+1;}

inicializace

for( i=0; i<=9; i=i+1) { fce( i);}

podmínka inkrement

tělo cyklu

FOR I := 0 TO 9 DO FCE(I)

ekvivalent v jiném jazyce

for( init(a); i<9 && a[i] >0; a[i++]=0) { fce( i);}

for v C++: obecnější, širší

možnosti použitíjako inicializaci, podmínku i inkrement lze libovolný

výraz init(a);while( i<9 && a[i] >0) { fce( i); a[i++]=0;}

Page 39: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

break okamžité ukončení celého cyklu cyklus s podmínkou uprostřed ošetření chybových stavů

continue ukončení (jednoho) běhu těla cyklu

Ukončení cyklu - break, continue

for(;;) { errc = fce(); if( errc < 0) break; jinafce();}

n = 1;while( n<1000) { val = get(); if( val == 0) continue; n = n * val;}

Page 40: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Nepoužívat! .... pokud k tomu není dobrý důvodKdyž už, tak pouze dopředu (skok dozadu = cyklus)

Dobrý důvod: výskok z vícenásobně vnořených cyklů

Goto

for( i=0; i<10; ++i) { for( j=0; j<10; ++j) { if( fnc( i, j) == ERROR) goto konec_obou_cyklu; } }konec_obou_cyklu: dalsi_funkce();

nelze break -ukončil by pouze vnitřní cyklus, vnější cyklus by

pokračoval

labelnávěští

Page 41: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Celočíselné typy

typ 8 bit 16 bit

32 bit 64 bit

char 8 8 8 8

short 8 / 16

16 16 16 / 32

int 16 16 32 32 / 64

long 16 32 32 32 / 64

long long

- - 64 64

size_t 32 64

ptrdiff_t 32 64

wchar_t 16/32 16/32

Základní celočíselné typy jsou znaménkovéPro každý typ existuje unsigned varianta

možné využití unsigned: unsigned char, pole bitů, modulová aritmetika pokud není dobrý důvod, unsigned raději nepoužívat

char short int long long long

-2GB .. +2GB

velikost objektů

rozdíl ukazatelů

rozšířená znaková sada

1 byte

Page 42: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Logické a znakové hodnoty a typy

C: Až do r. 1999: neexistuje typ 'boolean'Porovnání a logické operátory jsou celočíselné výrazy

FALSE (nepravda) 0 TRUE (pravda) 1 (libovolná hodnota různá od 0)

důsledek: if( x != 0) if( x) if( x == 0) if( !x)

C++, C99 celočíselný typ bool (C99: _Bool) hodnoty true (=1), false (=0)

char norma neurčuje signed / unsigned (!)korektní porovnání na nerovnost pouze 0 .. 127'a' < 'ž' ?

signed char -128 .. 127unsigned char 0 .. 255 - 'byte'wchar_t stddef.h: znak rozšířené sady (Unicode)

časté použití:test

(ne)nulovosti

záleží na implementaci

většinou char = signed

40 > 200 !!!

200 -56

Page 43: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

enum pohlavi { p_muz, p_zena };

pohlavi p = p_muz;int pp = p_zena + 1;pohlavi q = 0;

enum flags { f1 = 1, f2 = 2, f3 = 4, f4 = 8 };if( x & f1)

...

enum porty { pop3 = 111, ftp = 21, smtp = 80 };

Výčtový typ

C++: samostatný typ - nelze

( C: celočíselné konstanty - OK )

test bitů

hodnoty doplní překladač (od 0)

explicitní hodnoty

lze použít jako celočíselnou hodnotu

(ale většinou to nemá rozumný smysl)

Page 44: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

'Reálné' typy

float double long double

malá přesnost -

nepoužívat!standard pro

'reálné' výpočty

zvýšená přesnost

double x = 1;double y = x / 3;if( x == 3 * y) printf( "Presne");else printf( "Nepresne");

Pozor!Reálné výpočty

jsou vždy nepřesné

raději nepoužívatpouze pro fyzikální

nebo numerické veličiny

double zustatek = 15.60;

long zustatek_v_halerich = 1560;

pro přesné hodnoty

používejte přesné

typy

Page 45: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Celočíselné konverze

Automatické konverze (integral promotions)Výpočty výrazů vždy v šíři alespoň int

signed char, unsigned char, signed short signed int unsigned short signed int (pokud je int delší) / unsigned int

Automatické konverze u binárních operací signed int unsigned int signed long unsigned long

float double long double

vždy když je použit menší typ

než int

při nestejných operandech

moudro: prostě se to zkonvertuje na ten větší

Page 46: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Přehled operátorů, asociativita a priorita

postfi

x

++ --( )[ ]-> .::

post-in/de-krementacevolání funkceindexpřístup k položce strukturykvalifikace identifikátoru

pre

fix

++ --! ~+ -& *sizeof( )newdelete

pre-in/de-krementacebooleovská a bitová negaceunární +/-reference, dereferenceměření velikostipřetypovánídynamická alokacedynamická dealokace

L .* ->* dereference member-ptru

L * / % multiplikativní operátory

L + - aditivní operátory

L << >>

bitové posuny

L < <=> >=

uspořádání

L == != rovnosti

L & bitové AND

L ^ bitové XOR

L | bitové OR

L && booleovské AND

L || booleovské OR

L ? : podmíněný výraz

P =*= /= %= +=-= &=^= |= <<= >>=

přiřazeníkombinované přiřazení

L , sekvence

Page 47: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Základní aritmetické operátory

+ - * / % podle typu operandů automatická konverze na větší typ % - modulo

x / y 1 x / b 1.666

x % y 2 x % b Error

a / b 1.666 a / y 1.666

a % b Error a % y Error

int x=5, y=3;

double a=5, b=3; modulo je pouze celočíselná

operaceceločíselné dělení

reálné dělení

Page 48: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Bitové a logické operátory

& | ^ ~ - bitové operace AND, OR, XOR, NOT&& || ! - logické operace AND, OR, NOT

5 & 3 1 5 && 3 1

5 | 3 7 5 || 3 1

5 ^ 3 6 5 ^^ 3 Error

5 ^ 15 10

5 & 0 0 5 && 0 0

5 | 0 5 5 || 0 1

neexistuje

5 = 01012

3 = 00112

1 = 00012

7 = 01112

9 = 10012

15 = 11112

10 = 10102

oba op. 0

alespoň jeden

operand 0

alespoň jedenoperand = 0

Page 49: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Zkrácené vyhodnocování, relační operátory

a && b - je-li a=0, b se nevyhodnocuje, výsledek = false (0)a || b - je-li a=1, b se nevyhodnocuje, výsledek = true (1)

< <= >= >== !=

výraz typu int (bool) - výsledek vždy 0 nebo 1 (false, true) porovnávání na (ne)rovnost float/double ! porovnání vs. přiřazení !

int x[10]; // pole 0..9

if( i < 10 && x[i] != 0) y = y / x[i];

test mezí pole předpřístupem k prvku

pole

if( x==y && *x++) ...

Pozor! operátory s vedlejšími efekty se

nemusí provést !

if( x = 1) ...

POZOR!!! Přiřazení!(zde hodnota vždy =

1)

Page 50: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Přiřazení, inkrementace, bitový posun

=+= -= *= /= %= &= |= ^= <<= >>=

kombinované přiřazení a op= b a = a op b

++ -- ++a a = a + 1 , výsledkem je nová hodnota a a++ a = a + 1, výsledkem je stará hodnota a přesněji: a++ (tmp = a, a = a + 1, tmp)

<< >> bitový posun C++ - časté použití pro jiné účely (streams) - přetěžování

i += 2;x[ i+=1] /= 3;

int sum = 0;int i, x[10];

...for( i=0; i<9; sum += x[i++]) ;

pozor - vždy si uvědomit, zda jde

o pre- nebo post- inkrementaci

pokud si lze vybrat, preferujte

preinkrement

Page 51: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Podmíněný výraz, sekvence

a ? b : c po vyhodnocení podmínky a se vyhodnotí buď b (je-li a != 0) nebo c (je-li a

== 0)

a , b po úplném vyhodnocení a se vyhodnotí b

x = (y>0 ? y : 0);

x = (tmp = y, y = y + 1, tmp);

ekvivalentx = y++;

ternární operátor

operátor sekvence

('zapomnění')

Page 52: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

i = 0;p[ i++] = i++;

Pravidla vyhodnocování

a( b,c)vedlejší efekty parametrů jsou vyhodnoceny před zavoláním fcea && b je-li a nulový, b se nevyhodnocujea || b je-li a nenulový, b se nevyhodnocujea ? b : c po vyhodnocení a se vyhodnotí buď b nebo ca , b po úplném vyhodnocení a se vyhodnotí b

Žádná další pravidla nejsou ! ostatní operátory jsou vyhodnocovány v libovolném pořadí vedlejší efekty se mohou projevit kdykoliv během výpočtu

možné výsledky:

p[0] = 0; p[1] = 0; p[0] = 1;

Page 53: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Fungující triky vs. chyby

Fungující triky Test ukazatele nebo indexu

while ( i<MAX && pole[i]<v )

++pole[i];

Volání funkce s vedlejším efektem

while ( (c = getchar()) != EOF && c != '\n' );

Kopie řetězce

while ( *a++ = *b++ );

Chyby Vícenásobný výskyt modifikované proměnné

p[ i++] = i++;

Nadbytečné volání funkce s vedlejším efektem

if ( getchar() == 'A' && getchar() == 'B' )

nevím, jestli se provede

není definováno pořadí

while( p && p->v < v)

p = p->next;

Page 54: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Typové kostrukce - přehled

A x[ n] pole n prvků typu A, n je konstantní výraz

A x[] pole neznámého počtu prvků typu A (pouze v některých kontextech)

A * x ukazatel na typ A

void * x ukazatel na neurčený typ *x ++x nelze

A const * xconst A * x

ukazatel na konstantní hodnotu typu A ++x lze ++*x nelze

A * const x konstantní ukazatel na typ A ++x nelze ++*x lze

A & x C++: reference na typ A

A const & xconst A & x

C++: reference na konstantní hodnotu typu A

A x() funkce vracející typ A - C++: bez parametrů, C: bez určení parametrů

A x( par) funkce s určenými parametry

A x( void) funkce bez parametrů

void x( par) funkce bez návratové hodnoty (procedura)

Page 55: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Pole

Deklarace: t x[n] - pole x o n prvcích (0..n-1) typu tIndexy polí vždy začínají od 0 !Při přístupu se nikdy nekontrolují meze !!!

Vícerozměrné pole je pole políDeklarace: t x[m][n];Přístup: x[m][n] = a;

int x[5];for( i=1; i <=5; ++i) x[i] = i;

0 1 2 3 4 ???

? 1 2 3 4 5

Přepis náhodného místa v paměti !

Nepředvídatelné následky !!

int x[8][8];

for( i=0; i < 8; ++i) for( j=0; j < 8; ++j) x[ i ] [ j ] = i * j;

Pozor! x[m,n] není prvek dvojrozměrného

poleo souřadnicích m a n

čárka = operátor sekvence

význam:m-prvkové pole typu(n-prvkové pole typu

t)

Page 56: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Inicializace pole

Při deklaraci pole lze obsah pole inicializovat Nejde o přiřazení, lze pouze při deklaraci Deklarace inicializovaného pole nemusí obsahovat velikost

překladač dopočítá z inicializace Při nesouhlasu velkosti pole a počtu inicializátorů

velikost > inicializátory: inicializace začátku, obsah zbytku nedefinován velikost < inicializátory: kompilační chyba (Too many initializers)

int cisla[] = { 1, 2, 3, 4 };char* jmena[] = { "Josef", "Karel", "Jana" };int matice[][3] = { { 11, 12, 13 }, { 21, 22, 23 } };

Page 57: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Struktury

struct osoba {char jmeno[20];char prijemni[30];int rok_narozeni;int pohlavi;

};

osoba os, *po, zam[20];osoba beda = { "Béda", "Trávníček", 1980, p_muz };

strcpy( os.jmeno, "Venca");zam[3].rok_narozeni = 1968;po = &zam[3]; po->pohlavi = p_muz;

definice struktury

položky struktury

struktura, ukazatel na strukturu, pole

struktur

přístup k položkámx.y

(*px).y px->y

definice proměnné typu struktura s

inicializací

Béda

Trávníček

1980

0

Page 58: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Pojmenování struktur a výčtových typů

C++ Jméno třídy/struktury/unie/výčtového typu je samostatný typ

C Jméno (tag) struktury/unie/výčtového typu je možno používat pouze s

příslušným prefixem struct/union/enum

struct STR { int a, b; struct STR * next;};

struct STR * p;

struct STR { int a, b; STR * next;};

STR * p;

C++ - samostatný typ

C - pouze tag

Page 59: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Ukazatele

Co to je proměnná?místo v paměti, typ ( velikost), hodnota

hodnota se dá číst a většinou i zapisovat

Co to je ukazatel (pointer)?něco, čím si můžu ukazovat na proměnnou(nebo na jiné paměťové místo – pole, položka struktury, dynamická

alokace)

K čemu jsou ukazatele dobré:zpracování řetězců, dynamické datové struktury,předávání parametrů odkazem, práce s buffery, ...

Pro C i C++ je práce s ukazateli typická

1někde bydlí

je nějak velká (typ)

má hodnot

u

Page 60: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Ukazatele

Deklarace:t x – proměnná x typu tt *p - ukazatel p na typ t

Operátor reference: p = &xOperátor dereference: x = *p

Neinicializovaný ukazatel vs. nulový ukazatel C++: 0 C: #define NULL 0

17x:

p:

proměnná ukazatel na ni

ukazatel hodnota na kterou ukazuje

Page 61: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Ukazatele - příklad

int x = 1, y = 3;int * px, * py;*px = 5;py = NULL; *py = 7;if( ! py) etwas();px = &x; py = &y;(*py)++;px = py; y = x;py = &x; *py = 9;

přepsání náhodného místa v

paměti

1x: :px

3y: :py

?

? 5

jaký zde bude obsah x a y?

Page 62: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Ukazatele - příklad

int x = 1, y = 3;int * px, * py;*px = 5;py = NULL; *py = 7;if( ! py) etwas();px = &x; py = &y;(*py)++;px = py; y = x;py = &x; *py = 9;

typicky 'segmentation fault'váš program bude ukončen

pro pokus o porušení ochrany paměti

1x: :px

3y: :py

0: 7

umožní test

Page 63: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Ukazatele - příklad

int x = 1, y = 3;int * px, * py;*px = 5;py = NULL; *py = 7;if( ! py) etwas();px = &x; py = &y;(*py)++;px = py; y = x;py = &x; *py = 9;

přístup k hodnotě proměnné přes

ukazatel

1x: :px

4y: :pyPozor na prioritu!

*py++ *(py++)

1x: :px

3y: :py

Page 64: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Ukazatele - příklad

int x = 1, y = 3;int * px, * py;*px = 5;py = NULL; *py = 7;if( ! py) etwas();px = &x; py = &y;(*py)++;px = py; y = x;py = &x; *py = 9;

1x: :px

1y: :py

9x: :px

1y: :pyjaký zde bude obsah x a y?

Page 65: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Pole a ukazatele, aritmetika ukazatelů

t a[n];t *p = &a[i]; ukazatel p ukazuje na nějaký prvek pole (stejného typu)p + j přičtení celočíselné hodnoty - posun o j prvků v rámci polep - j odečtení - posun zpět

int a[5];int *p;

a[2] = 20;p = &a[2];

a[0] = *p - 15;p++;*p = 30;

0 1 2 3 4

? ? 20 ? ?

5 ? 20 30 ?

p

p

reference na prvek pole

inkrementace ukazatele - posun na další prvek

a

reference na prvek pole

Page 66: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Pole a ukazatele, aritmetika ukazatelů

p = &a[1];*(p+3) = 40;

Operátor []

p[i] *(p+i)

&p[i] p+i

a &a[0]

Automatické konverze pole-ukazatel identifikátor pole se chová jako ukazatel na nultý prvek

Pole nelze přiřazovat ani předávat hodnotou ukazatel na nultý prvek p = a je ekvivalentní p = &a[0]

5 ? 20 30 40

ppřičtení čísla k ukazateli posun o n

prvků

identifikátor pole je ukazatelna svůj nultý prvek

indexování pole (ukazatele) je jen jiný zápis přístupu přes

ukazatel

Page 67: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Pole a ukazatele, aritmetika ukazatelů

int a[5];int *p;

identifikátor pole je konstantní nelze do něj přiřazovat

0 10 20 30 40

p = &a[0];p = a;*p = a[1];*(p+2) = a[2] – 1;p = a + 2;p[1] = *(a+1);a[3] = p[2];*(a+2) = p[-1];3[a] = 2[p];

a[4] = p + 1;p = a[0];p[1] = a;

a = p + 2;

nekompatibilní typynestejná úroveň

indirekce

p[i] *(p+i) *(i+p) i[p]

Page 68: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Řetězce

Řetězec je pole znaků (char) zakončené nulou konvence, knihovny

"Ahoj"

X proměnná'X' znaková konstanta - celočíselná hodnota"X" řetězec - ukazatel

'A' 'h' 'o' 'j' '\0'

Každý řetězec musí být vždy

ukončen nulou

'A' 'h' 'o' 'j' '\0'

vždy myslet na koncovou nulu !

pozor na uvozovky a apostrofy !

char buffer[4];strcpy( buffer, "Ahoj");

'\0' = 0

kód znaku v použitém kódování

(ASCII, CP1250, ISO8859-2, EBCDIC, ...)když chcete říct mezera, napište

mezeru (' ')ať vás ani nenapadne napsat 32

přestože to na VAŠEM počítači funguje

Page 69: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Řetězcové proměnné a konstanty

static char s1[] = "Uno";

const char *s2 = "Due";

puts( "Uno");

'U' 'n' 'o' '\0'

'D' 'u' 'e' '\0'

s1:

s2:

Inicializovaná proměnná typu ukazatel

s2++ se přesune na další znak

Inicializované pole (konstantní ukazatel)

s1++ nelze!

anonymní globální proměnná

const char[]

ekvivalent globální proměnné typu const char[ ], inicializované obsahem konstanty

... = { 'U', 'n', 'o', 0 };

Page 70: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Předávání řetězců

Jazyk C/C++ nedovoluje kopírování pole není možné pole přiřazovat, předávat jako parametr ani vracet z

funkce

Předávání řetězců do funkcí Předává se vždy odkazem Parametr typicky typu const char *

Vracení řetězců z funkcí Nahrazuje se "návratovým" parametrem Parametr typu char * Je vhodné jej doplnit parametrem typu size_t, určujícím velikost pole

ukazatel na pole,které má funkce

vyplnit

standardní C knihovny to ale

většinou nedělají

Page 71: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Řetězce – knihovní funkce, délka řetězce

v C neexistují 'řetězcové operace' (C++: třída string) přiřazení, zřetězení, porovnání, podřetězec, ... vše standardní knihovní funkce

#include <string.h>

size_t strlen( const char* s);

A h o j \0 ? ? ?pole:

počet znaků(bez koncové

nuly)

char pole[8] = "Ahoj";x = strlen( pole); // 4

skutečný počet znaků (4)nikoliv velikost pole

deklarace řetězcových funkcí

inicializované pole typu char

Page 72: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Délka řetězce – přes index

int strlen ( const char* s){ int i = 0; while ( s[i] != '\0') { i++; } return i;}

přístup přes index

Page 73: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Délka řetězce – přes ukazatel

int i = 0;while ( *s != '\0') { i++; s++;}return i;

int strlen ( const char* s){ int i = 0; while ( s[i] != '\0') { i++; } return i;}

přístup přes ukazatel

Page 74: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Délka řetězce – cyklus for

int i = 0;while ( *s != '\0') { i++; s++;}return i;

int strlen ( const char* s){ int i = 0; while ( s[i] != '\0') { i++; } return i;}

for( i=0; *s != '\0'; i++) s++;

podmínka for cyklu může být

libovolná

Page 75: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Délka řetězce – for bez těla

int i = 0;while ( *s != '\0') { i++; s++;}return i;

int strlen ( const char* s){ int i = 0; while ( s[i] != '\0') { i++; } return i;}

for( i=0; *s != '\0'; i++) s++;

for( i=0; *s != '\0'; i++, s++) ;

více inkrementací prázdné tělo

nezapomenout na ';' !!

Page 76: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Délka řetězce – podmínka s vedlejším efektem

int i = 0;while ( *s != '\0') { i++; s++;}return i;

int strlen ( const char* s){ int i = 0; while ( s[i] != '\0') { i++; } return i;}

for( i=0; *s != '\0'; i++) s++;

for( i=0; *s != '\0'; i++, s++) ;

int i=0;while ( *s++ != '\0') i++;

složitější podmínka:test nenulovostiinkrementace

ukazatele

Page 77: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Délka řetězce – nenulovost výrazu v podmínce

int i = 0;while ( *s != '\0') { i++; s++;}return i;

int strlen ( const char* s){ int i = 0; while ( s[i] != '\0') { i++; } return i;}

for( i=0; *s != '\0'; i++) s++;

for( i=0; *s != '\0'; i++, s++) ;

int i=0;while ( *s++ != '\0') i++;

int i=0;while ( *s++) i++;

while(a!=0) while(a)

podmínka je splněnapokud je nenulová

Page 78: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Délka řetězce – rozdíl ukazatelů

int i = 0;while ( *s != '\0') { i++; s++;}return i;

int strlen ( const char* s){ int i = 0; while ( s[i] != '\0') { i++; } return i;}

char *p = s;while (*p++) ;return p-s-1;

for( i=0; *s != '\0'; i++) s++;

for( i=0; *s != '\0'; i++, s++) ;

int i=0;while ( *s++ != '\0') i++;

int i=0;while ( *s++) i++;

rozdíl ukazatelů = počet prvků mezi

nimi pozor na ± 1 !

Page 79: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Délka řetězce – různé způsoby implementace

int i = 0;while ( *s != '\0') { i++; s++;}return i;

int strlen ( const char* s){ int i = 0; while ( s[i] != '\0') { i++; } return i;}

char *p = s;while (*p++) ;return p-s-1;

for( i=0; *s != '\0'; i++) s++;

for( i=0; *s != '\0'; i++, s++) ;

int i=0;while ( *s++ != '\0') i++;

int i=0;while ( *s++) i++;

přístup přes index

přístup přes ukazatel

podmínka for cyklu může být

libovolná

více inkrementací prázdné tělo

nezapomenout na ';' !!

složitější podmínka:test nenulovostiinkrementace

ukazatele

while(a!=0) while(a)

podmínka je splněnapokud je nenulová

rozdíl ukazatelů = počet prvků mezi

nimi pozor na ± 1 !

Page 80: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Řetězce - kopírování

char* strcpy( char* d, const char* s);

zkopíruje obsah sdo místa začínajího od

dchar buf[8];char pozdrav[] = "Ahoj";strcpy( buf, pozdrav);

A h o j \0pozdrav

A h o j \0 ? ? ?buf

kopíruje pouze do koncové '\0'

Page 81: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Řetězce – chyby při kopírování

D o b r y d e n \0pozdrav

buf

char buf[6];char pozdrav[] = "Dobry den";strcpy( buf, pozdrav);

D o b r y d e n \0

vždy pozor na dostatek místa

funkce nic nekontroluje !!!váš program provedl...

char *ptr;char pozdrav[] = "Ahoj";strcpy( ptr, pozdrav);

kopírování na neinicializovaný ukazatel !!!

váš program provedl...

A h o j \0pozdrav

ptr?

A h o j \0

ptr neinicializovaný !!!

Page 82: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Řetězce – zřetězení, vyhledávání

char* strcat( char* d, const char* s); připojí s za dchar* strchr( const char* s1, int c); vyhledá první pozici c v s1char* strstr( const char* s1, const char* s2); vyhledá podřetězec s2 v s1

char buf[10];char* bp;strcpy( buf, "Ahoj");strcat( buf, "Babi");bp = strstr( buf, "oj");

A h o j \0

? ? ? ? ?po strcpy

A h o j B a b i \0

?po strcat

buf

bp

A h o j B a b i \0

?pozor na dostatek

místa !

Page 83: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Řetězce – porovnávání a další funkce

int strcmp( const char* s1, const char* s2);s1 < s2 -1s1 = s2 0s1 > s2 +1

lexikografické uspořádání (jako ve slovníku)

další řetězcové funkce:strncat, strncmp, strncpy strrchr Find last occurrence of given character in string strspn, strcspn Get length of substring composed / not composed of given

characters strpbrk Find first occurrence of character from one string in another string strtok Find next token in string, sequentially truncate string if delimiter is

found sprintf Write formatted data to a string

memcpy, memset, memcmp, memchr

co znamená 's1 < s2'? A B C E

= = =

A B C D E

výsledek podle prvního rozdílného

znaku

Page 84: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Problém vracení řetězců - lokální proměnná

Naprosto chybné řešení Nekontroluje přetečení pole buf Vrací odkaz na lokální proměnnou, která v okamžiku návratu zaniká

char * cele_jmeno( const char * jm, const char * prijm){ char buf[ 100]; strcpy( buf, jm); strcat( buf, " "); strcat( buf, prijm); return buf;}

Page 85: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Problém vracení řetězců - statická proměnná

Chybné řešení Nekontroluje přetečení pole buf Používá statickou proměnnou

zbytečně zabírá místo i v době, kdy funkce není vyvolána opakovaná volání ji sdílejí:

podmínka nikdy nebude splněna, protože strcmp vždy dostane stejné ukazatele na totéž pole buf

char * cele_jmeno( const char * jm, const char * prijm){ static char buf[ 100]; strcpy( buf, jm); strcat( buf, " "); strcat( buf, prijm); return buf;}

if ( strcmp( cele_jmeno( j1, p1), cele_jmeno( j2, p2)) )

Page 86: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Problém vracení řetězců - parametr

Funkční řešení, ale nebezpečné Nekontroluje přetečení pole buf Pokud volající nemá spolehlivý horní odhad velikostí jména a

příjmení, nemůže tuto funkci bezpečně volat

void cele_jmeno( char * buf, const char * jm, const char * prijm){ strcpy( buf, jm); strcat( buf, " "); strcat( buf, prijm);}

void tisk( const char * jm, const char * prijm){ char buf[ 100]; cele_jmeno( buf, jm, prijm); puts( buf);}

Page 87: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Problém vracení řetězců - správné a bezpečné řešení

int cele_jmeno( char * buf, size_t bufsize, const char * jm,const char * prijm)

{ size_t lj = strlen( jm); size_t lp = strlen( prijm); if ( lj + lp + 2 > bufsize ) { /* error */ return -1; } memcpy( buf, jm, lj); buf[ lj] = ' '; memcpy( buf + lj + 1, prijm, lp); buf[ lj + lp + 1] = 0; return lj + lp + 1;}

void tisk( const char * jm, const char * prijm){ enum { N = 100 }; char buf[ N]; if( cele_jmeno( buf, N, jm, prijm) > 0) puts( buf);}

max velikost pole

kontrola korektnostivýsledku

kontrola velikosti polepozor na mezeru a konec!

kopírování jednotlivých částí

návrat výsledné délky

Page 88: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Kombinace typových kostrukcí

A * x[10] pole ukazatelů

A (* x)[10] ukazatel na pole

A * x() funkce vracející ukazatel

A (* x)() ukazatel na funkci

A x[10]() pole funkcí - zakázáno

A (* x[10])() pole ukazatelů na funkci

A x()[10] funkce vracející pole - zakázáno

A (* x())[10] funkce vracející ukazatel na pole

čtení deklarací: od identifikátoru doprava, až to nepůjde, tak

doleva

typicky se nepoužívápole = ukazatel na 1.

prvek

Page 89: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

int*(*pf[10])(void);

int*(*maso(int*(*p1)(void),int*(*p2)(void)))(void);

Kombinace typových kostrukcí - příklad

co to je za maso ???

Page 90: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

int*(*pf[10])(void);

int*(*maso(int*(*p1)(void),int*(*p2)(void)))(void);

typedef int* fce( void);

fce * pf [10];

fce * maso( fce* p1, fce* p2);

Kombinace typových kostrukcí - typedef

použitím typedef se může výrazně

zpřehlednit kód

Page 91: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Parametry příkazové řádky

C:\> myprog.exe -n -w a.txt b.txt

0

m y p r o g . e x e \0

- n \0

- w \0

a . t x t \0

b . t x t \0

argv

5argc

int main( int argc, char** argv)

pole řetězců(ukazatelů na char)

Počet parametrůvčetně názvu programu !

= počet ukazatelů v argv

Page 92: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Zpracování příkazové řádky – výpis parametrů

int main( int argc, char** argv){ while( *argv) { printf( "%s\n", *argv); ++argv; }}

C:\> myprog.exe -n -w a.txt b.txt

myprog.exe-n-wa.txtb.txt

výstup řetězce a

odřádkováníposun na další

parametr

Page 93: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Zpracování příkazové řádky

int main( int argc, char** argv){ while( *argv) { printf( "%s\n", *argv); ++argv; }}

m y p r o g . e x e \0

- n \0

- w \0

a . t x t \0

b . t x t \0

argv

0

argvtyp: char**

**argv argv[0][0]

typ: char

argv[4][1]

*argv argv[0]

typ: char*

argv[4]

C:\> myprog.exe -n -w a.txt b.txt

Page 94: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Zpracování příkazové řádky

int main( int argc, char** argv){ while( *argv) { printf( "%s\n", *argv); ++argv; }}

m y p r o g . e x e \0

- n \0

- w \0

a . t x t \0

b . t x t \0

argv

0

argv++ **argv

Page 95: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Zpracování příkazové řádky

int main( int argc, char** argv){ while( *argv) { printf( "%s\n", *argv); ++argv; }}

m y p r o g . e x e \0

- n \0

- w \0

a . t x t \0

b . t x t \0

argv

0

*argv == 0

Page 96: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Zpracování parametrů příkazové řádky

int main( int argc, char** argv){ int n=0, w=0; while( *++argv && **argv=='-') { switch( argv[0][1]) { case 'n': n = 1; break; case 'w': w = 1; break; default: error(); } } if( !argv[0] || !argv[1]) error(); doit( argv[0], argv[1], n, w); return 0;}

options

usage: myprog [-n] [-w] fileA fileB

nastavení přepínače

zbývající parametry

výkonná funkce

p r g . e x e \0

- n \0

- w \0

a . t x t \0

b . t x t \0

0

argv

Page 97: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Zpracování parametrů příkazové řádky

int main( int argc, char** argv){ int n=0, w=0; int x = 0; char* f = 0; while( *++argv && **argv=='-') { switch( argv[0][1]) { case 'n': n = 1; break; case 'w': w = 1; break; case 'x': x = atoi( argv[0]+2); break; case 'f': f = argv[0]+2; break; default: error(); } } if( !argv[0] || !argv[1]) error(); doit( argv[0], argv[1], n, w, x, f); return 0;}

číselný parametr

usage: myprog [-n] [-w] [-x123] [-ffilename]

fileA fileB

řetězcový parametr

- x 1 2 3 \0

- f f i l ...

argv

Page 98: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Zpracování parametrů příkazové řádky

int main( int argc, char** argv){ int n=0, w=0; int x = 0; char* f = 0; while( *++argv && **argv=='-') { switch( argv[0][1]) { case 'n': n = 1; break; case 'w': w = 1; break; case 'x': x = atoi( argv[0]+2); break; case 'f': if( argv[0][2]) f = argv[0]+2;

else f = *++argv; break;

default: error(); } } if( !argv[0] || !argv[1]) error(); doit( argv[0], argv[1], n, w, x, f); return 0;}

-ffile

usage: myprog [-n] [-w] [-x123] [-f filename]

fileA fileB

-f file

- f \0

argv- f f i l ...

f i l e n ...

Page 99: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Dynamická alokace paměti

C: standardní knihovny <alloc.h>, <stdlib.h>

void* malloc( size_t size); void free( void* p);

#include <alloc.h>

ELEM * p;p = malloc( sizeof( ELEM));if ( !p ) { /* chyba */ }free( p);

int n = 100;p = malloc( n * sizeof( ELEM));if ( !p ) { /* chyba */ }free( p);

C++ nutnost přetypováníp = (ELEM*)malloc( sizeof( ELEM));

vždy ověřit !!!váš program

provedl...

C++: součást jazyka new T new T[ n] delete p delete[] p

ELEM * p;p = new ELEM;delete p;

int n = 100;p = new ELEM[ n];delete[] p;

mechanismus výjimek

Jeden objekt

Pole objekt

ů

Pole objekt

ů

Jeden objekt

Page 100: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

int main( int argc, char** argv){ char* buf; ... buf = new char[ strlen(argv[1]) + strlen(argv[2]) + 1))]; strcpy( buf, argv[1]); strcat( buf, argv[2]);

Velikost pole určena za běhu programu

int main( int argc, char** argv){ char* buf; ... buf = malloc( strlen(argv[1]) + strlen(argv[2]) + 1))); if( ! buf) error(); strcpy( buf, argv[1]); strcat( buf, argv[2]);

spočítá potřebnou velikost

ze vstupních parametrů

pozor na koncovou '\0'

nutný test na úspěšnost

Page 101: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Ladicí implementace alokačních funkcí

Obložit každý alokovaný blok prostorem vyplněným značkami

Při dealokaci zkontrolovat neporušenost značek a změnit je

void * my_malloc( size_t s){ char * p = (char *)malloc( s+sizeof(size_t)+2*AB_SIZE); if ( ! p ) return 0; *(size_t *)p = s; memcpy( p+sizeof(size_t), AB_FILL, AB_SIZE) memcpy( p+sizeof(size_t)+AB_SIZE+s, AB_FILL, AB_SIZE) return p+sizeof(size_t)+AB_SIZE;}

void my_free( void * vp){ char * p; if ( ! vp ) ERROR(); p = (char *)vp - (sizeof(size_t)+AB_SIZE); if ( memcmp( p+sizeof(size_t), AB_FILL, AB_SIZE) ) ERROR(); if ( memcmp( p+sizeof(size_t)+AB_SIZE+*(size_t *)p,

AB_FILL, AB_SIZE) ) ERROR(); /* ... zmenit znacky ... */ free( p); }

size

####

####

velikost bloku

kontrolní výplň

Page 102: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Organizace paměti procesu

Kódový segment Kód programu

Datový segment Globální proměnné

Heap Dynamicky alokovaná data

Zásobník Lokální proměnné a parametry

funkcí

IP

R0R1...

SP

Page 103: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Organizace paměti procesu – kódový segment

Kódový segment připraven kompilátorem

součást spustitelného souboru

kód uživatelských i knihovních funkcí

obvykle chráněn proti zápisu Datový segment Heap Zásobník

IP

R0R1...

SP

int fce( int x) { ... }

{ int (*fp)( int); fp = fce; ... (*fp)(17); fp(17)

alternativní syntaxe

Page 104: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Organizace paměti procesu – datový segment

Kódový segment Datový segment

připraven kompilátorem součást spustitelného souboru

explicitně nebo implicitně (nulami) inicializované globální proměnné

řetězcové konstanty data knihoven

Heap Zásobník

IP

R0R1...

SP

int bigpole[ 1000];char retezec[] = "CHAIN";

{ int* p = bigpole; const char* s = "ahoj"; ...

inicializované pole

Page 105: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Organizace paměti procesu - heap

Kódový segment Datový segment Heap

vytvářen startovacím modulem knihoven

dynamicky alokovaná data new/delete malloc/free obsazené bloky různé velikosti

+ seznam volných bloků Zásobník

IP

R0R1...

SP

{ char* s; s = new char[128]; ...

nemixovat

Page 106: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Organizace paměti procesu - zásobník

Kódový segment Datový segment Heap Zásobník

připraven operačním systémem lokální proměnné pomocné proměnné generované

kompilátorem návratové adresy aktivační záznamy funkcí

IP

R0R1...

SP

{ char pole[100]; char s[] = "Ahoj"; int x = 1 + 2 * 3; ...

inicializace při každém

průchodu

Page 107: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Statické proměnné

static int x;

int fce( int a){ static int y = 0; return y += a;}

globální proměnná neviditelná z jiných

modulů

de facto globální (!) proměnná neviditelná z

jiných funkcí

inicializace:C: před vstupem do mainC++: před prvním průchodem

C++: lepší řešení - namespace

C++: raději skrýt do třídy

Page 108: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Organizace paměti procesu – příklad

const int max = 100;char buf[max];

char* prefix( char* s){ char* p = new char[ strlen(s)+2]; *p = '#'; strcpy( p + 1, s); return p;}

int main( int argc, char** argv){ char* p; strcpy( buf, argv[ argc – 1]); p = prefix( buf); p = prefix( p); ....}

co je v kterém segmentu?

Page 109: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Organizace paměti procesu – příklad

const int max = 100;char buf[max];

char* prefix( char* s){ char* p = new char[strlen(s)+2]; *p = '#'; strcpy( p + 1, s); return p;}

int main( int argc, char** argv){ char* p; strcpy( buf, argv[ argc – 1]); p = prefix( buf); p = prefix( p); ....}

program pokus

pokus\0 buf

p

D

Z

H

Page 110: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Organizace paměti procesu – příklad

const int max = 100;char buf[max];

char* prefix( char* s){ char* p = new char[strlen(s)+2]; *p = '#'; strcpy( p + 1, s); return p;}

int main( int argc, char** argv){ char* p; strcpy( buf, argv[ argc – 1]); p = prefix( buf); p = prefix( p); ....}

program pokus

pokus\0 buf

p

D

Z

H

s

p

Page 111: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Organizace paměti procesu – příklad

const int max = 100;char buf[max];

char* prefix( char* s){ char* p = new char[strlen(s)+2]; *p = '#'; strcpy( p + 1, s); return p;}

int main( int argc, char** argv){ char* p; strcpy( buf, argv[ argc – 1]); p = prefix( buf); p = prefix( p); ....}

program pokus

pokus\0 buf

p

D

Z

H

s

p

#pokus\0

Page 112: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Organizace paměti procesu – příklad

const int max = 100;char buf[max];

char* prefix( char* s){ char* p = new char[strlen(s)+2]; *p = '#'; strcpy( p + 1, s); return p;}

int main( int argc, char** argv){ char* p; strcpy( buf, argv[ argc – 1]); p = prefix( buf); p = prefix( p); ....}

program pokus

pokus\0 buf

p

D

Z

H

#pokus\0

Page 113: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Organizace paměti procesu – příklad

const int max = 100;char buf[max];

char* prefix( char* s){ char* p = new char[strlen(s)+2]; *p = '#'; strcpy( p + 1, s); return p;}

int main( int argc, char** argv){ char* p; strcpy( buf, argv[ argc – 1]); p = prefix( buf); p = prefix( p); ....}

program pokus

pokus\0 buf

p

D

Z

H

s

p

#pokus\0

Page 114: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Organizace paměti procesu – příklad

const int max = 100;char buf[max];

char* prefix( char* s){ char* p = malloc(strlen(s)+2); *p = '#'; strcpy( p + 1, s); return p;}

int main( int argc, char** argv){ char* p; strcpy( buf, argv[ argc – 1]); p = prefix( buf); p = prefix( p); ....}

program pokus

pokus\0 buf

p

D

Z

H

s

p

#pokus\0

##pokus\0

Page 115: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Organizace paměti procesu – příklad

const int max = 100;char buf[max];

char* prefix( char* s){ char* p = malloc(strlen(s)+2); *p = '#'; strcpy( p + 1, s); return p;}

int main( int argc, char** argv){ char* p; strcpy( buf, argv[ argc – 1]); p = prefix( buf); p = prefix( p); ....}

program pokus

pokus\0 buf

p

D

Z

H

#pokus\0

##pokus\0

Page 116: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Organizace paměti - ukazatele na funkcetypedef double DoubleFce(double);const int DF_POCET = 4;DoubleFce* fce[DF_POCET]= { cos, sin, log, tan};

double* spocti( double vysl[], DoubleFce* f, int pocet, double hod, double krok){ for( int i = 0; i < pocet; ++i) { vysl[i] = f(hod); hod += krok; } return vysledek;}

int main(){ const int pocet=8; const double zac=0.1; const double krok=0.4; double vysledek[ pocet]; for( int i = 0; i < DF_POCET; ++i) { spocti( fce[i], vysledek, pocet, zac, krok); zobraz( vysledek, ....); } return 0;}

C

cos { ...

sin { ...

log { ...

fce

D

vysled.

Z

f

vysl

Page 117: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Souborový vstup a výstup

struktura definovaná

v <stdio.h>

Neznámý obsah

Pro knihovní funkce

FILE *

FILE

deskriptor souboru -deklaruje

programátor

Otevření souboru: kontrola existence a práv vytvoření vnitřních knihovních struktur asociace s otevřeným souborem předání deskriptoru souboru (FILE*)

soubor(na disku)

OS

soubor'na síti'

Page 118: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

#include <stdio.h>

FILE* fp;int c;

if( !(fp = fopen("c:\\f.txt", "r")))error();

while( (c = getc( fp)) != EOF)putchar( c);

fclose( fp);

Práce se soubory

typ 'soubor'(ukazatel na strukturu)

otevření souborupojmenovávací konvence

dle OS

čtení ze soubor

u

zavření souboru

pozor na '\\' !!!

Page 119: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Otevření souboru

FILE* fopen( const char* fname, const char* mode);

r open file for readingw truncate to zero length or create file for writinga append; open or create file for writing at end-of-filer+ open file for update (reading and writing)w+ truncate to zero length or create file for updatea+ append; open or create file for update, writing at end-of-file

rb binary file... mod

esoubor ex.

soubor neex.

seek

r R Error 0

w Del, W W 0

a W W End

r+ R/W Error 0

w+ Del, R/W R/W 0

a+ R/W R/W End

+: vždy čtení i zápis

a: otevřít na konci

r: soubor musí existovat

w: soubor se smaže

Page 120: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Textové vs. binární soubory

Textový soubor konverze konců řádek ('\n') na platformově závislou vnější reprezentaci typicky 0x0D 0x0A (Win) nebo 0x0A (Unix) konverze je automatická, programátor se o to nemusí starat vhodné pro ukládání lidsky čitelných dat getc/putc, fgets/fputs, fprintf, ... chování fseek/ftell na '\n' nedefinován - nepoužívat

Binární soubor žádné konverze se neprovádí v souboru je přesný binární obraz zapisovaných dat vhodné pro ukládání vnitřních datových struktur lidsky přímo nečitelné typicky fread/fwrite, lze i getc/putc (přístup po bajtech) fseek/ftell OK

Page 121: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Funkce pro práci se soubory

FILE* fopen( const char* fname, const char* mode);int fclose( FILE* fp);int fprintf( FILE* fp, const char* format, ...);int getc( FILE* fp);int putc( int c, FILE* fp);char* fgets( char* buffer, size_t limit, FILE* fp);int fputs( const char* buffer, FILE* fp);

size_t fread( void* ptr, size_t size, size_t n, FILE* fp);size_t fwrite( const void* ptr, size_t size, size_t n, FILE* fp);long ftell( FILE* fp);int fseek( FILE* fp, long offset, int whence);

whence: SEEK_SET, SEEK_CUR, SEEK_END

int fflush( FILE *fp);

Page 122: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Práce se soubory - příklad

#include <stdio.h>

const int buflen = 1024;

int main(int argc, char ** argv){ FILE *f; char s[buflen]; int n; if (argc <= 1) return 1; f = fopen(argv[1], "r"); if (!f) return 2;

while ((n = fread(s, 1, buflen, f)) > 0) { fwrite(s, 1, n, stdout); }

fclose(f); return 0;}

catkopírování

obsahu souboru na standardní

výstup

Page 123: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Práce se soubory - příklad

#include <stdio.h>int main( int argc, char** argv){FILE* f;long l;

if( argc < 2) return 8;f = fopen( argv[1], "r");if( !f) return 4;

fseek( f, 0, SEEK_END);l = ftell( f);fclose( f);

printf( "Delka %s je %ld.\n", argv[1], l);

return 0;}

zjištění skutečné velikosti souboru

seek na koneczjištění pozice

Pozor! long

Page 124: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Souborový vs. standardní v/v

funkce pro práci se standardním vstupem/výstupem int getchar( void); int putchar( int c); int printf( const char* format, ...);

char* gets( char* buffer);

standardní vstup/výstup FILE* stand. otevřený na čtení/zápis před vstupem do main

FILE *stdin;FILE *stdout;

getchar() getc(stdin)putchar(c) putc(c, stdout)

FILE* fp = stdout;if( ...) fp = fopen( "...", "r");c = getc( fp);

jednotný zápisna std výstup nebo

do souboru

Nepoužívat!Nelze ohlídat přetečení

bufferu

všechny souborové

funkce lze použíti pro std. v/v

Page 125: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Knihovní funkce C

<string.h> <cstring>strlen, strcmp, stricmp, strcpy, strncpy, strcat, strchr, strrchr, strstr,memset, memcmp, memcpy, memchr<stdio.h> <cstdio>getchar, putchar, fopen, tmpfile, fclose, getc, putc, fgets, fputs, fread, fwrite,ftell, fseek, printf, fprintf, vfprintf, fflush, ungetcFILE, stdin, stdout, EOF, SEEK_SET, ...<stdlib.h> <cstdlib>malloc, free, atoi, atof, strtol, qsort, rand, exit<ctype.h> <cctype>isalpha, isdigit, isxdigit, isalnum, isspace, ispunct, iscntrl, islower, isupper, tolower, toupper<math.h> <cmath>abs, floor, sin, sqrt, exp, exp, log, ...<time.h> <ctime>time, gmtime, strftime, asctime, clock, ...

... a mnoho mnoho dalších

C++ - vše v prostoru jmen std

Page 126: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

printf

int printf( const char *, ...); % [flags] [width] [.precision] [opt_pref] type %c - char - znak %d - int - decimálně %x - int - šestnáctkově %ld - long %f - double - s desetinnou tečkou %g - double - s exponentem %s - char * - řetězec

fprintf( FILE*, sprintf( char*,swprintf( wchar_t*,_snprintf( char*, int n,_scprintf(...

printf(":%c:%6d:%08X:%7.3f:%7.3f:\n", 'a', 17, 1234, -1234.56, -1234.5678);printf(":%s:%6s:%6s:%-6s:%-6.3s:%.3s:\n",

"ahoj", "ahoj", "ahojbabi", "ahoj", "ahoj", "ahoj");printf(":%*d:%-*.*s:\n", 6, 17, 6, 3, "ahoj");printf(":%c:%c:%d:%s:\n", 0xffeedd41, "ahoj", "ahoj", 'a');

:a:▫▫▫▫17:000004D2:▫▫-1234.560:▫▫-1234.568::ahoj:▫▫ahoj:ahojbabi:ahoj▫▫:aho▫▫▫:aho::▫▫▫▫17:aho▫▫▫::A::78263451:

místo width a/nebo precision znak *hodnota následujícího parametru

Unhandled exception at 0x0041470c :Access violation reading location

0x00000061

width: min. počet míst na výstupuprecision: max. počet zpracovávaných znaků

Page 127: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Direktivy preprocesoru

#include <stdio.h>#include <cstdio>#include <iostream>#include "mymodul.h"

#define KZR#define KZR 17#define KZR( pzr) ((pzr) * 2)#undef

#ifdef#ifndef#if#else#endif###

knihovní headery – C, C/C++, C++

uživatelské headery

definice symbolu – viz Spojování modulů - #ifndef

definice makra, lépe const int kzr = 17;

definice parametrického makraraději vůbec nepoužívat, lépe inline

funkcetest na (ne)definovanost symbolu

obrana před vícenásobným #includeviz Spojování modulů - #ifndef

test konstantního výrazu - #if sizeof( int) == 4

'ouvozovkování' - #abc "abc"

spojení identifikátorů - a##b ab

Page 128: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

x.c

double A() { return B( 7);}

Spojování modulů – problém hlaviček funkcí

error:Undefined 'B'

y.c

double B() { return 3.14;

}

Page 129: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

x.cdouble B();double A() { return B();}

Spojování modulů – externí deklarace

externí deklarace

y.c

double B() { return 3.14;

}

Page 130: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Spojování modulů – nekonzistence

C: nedefinované chování

C++: linker error

x.cdouble B();double A() { return B();}

y.c

int B( int q) { return q+1; }

x.obj

import Bexport A

y.obj

export Bapp.exe

nekonzistence funkce B

(počet a typy parametrů, návratová hodnota)

Page 131: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Spojování modulů – header

x.c#include "y.h"double A() { return B( 7);}

y.c

int B( int q) { return q+1; }

y.h

int B( int q);

int B( int q);double A() { return B( 7);}

preprocesor

možná nekonzistence

Page 132: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Spojování modulů – řešení

x.c#include "y.h"double A() { return B( 7);}

y.c#include "y.h"double B() { return 3.14;

}

y.h

int B( int q);

int B( int q);double A() { return B( 7);}

int B( int q);double B() { return 3.14;

}

error:Redefinition of 'B'

Page 133: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

y.obj

export c

Spojování modulů – definice dat

x.c#include "y.h"double A() {}

y.c#include "y.h"int c;

y.h

int c;

int c;double A() {}

int c;int c;

x.obj

export c export A

linker error: Duplicate symbol 'c'

Page 134: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

y.obj

export c

Deklarace vs. definice

x.c#include "y.h"double A() {}

y.c#include "y.h"int c;

y.h

extern int c;

extern int c;double A() {}

extern int c;int c;

x.objimport c export A

Deklarace

Definice

Deklarace

Definice

Page 135: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Spojování modulů - typy

x.c#include "y.h"double A() { return C; }

y.c#include "y.h"

enum T C;

y.henum T { P, Q};extern enum T C;

enum T { P, Q};extern enum T C;double A() { return C; }

enum T { P, Q};extern enum T C;

enum T C;

Definice nového typu Deklarace proměnné tohoto typu

Page 136: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Spojování modulů - duplicita typů

x.c#include "y.h"#include "z.h"double A() { return C+D; }

t.henum T { P, Q};

enum T { P, Q};extern enum T C;

enum T { P, Q};extern enum T D;

double A() { return C + D; }

y.h#include "t.h"extern enum T C;

z.h#include "t.h"extern enum T D;

error:Type redefinition: 'T'

Přes y.h a z.hje t.h vložen dvakrát

Page 137: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Spojování modulů - #ifndef

x.c#include "y.h"#include "z.h"double A() { return C+D; }

t.h#ifndef T_H_#define T_H_enum T { P, Q};#endif

#ifndef T_H_#define T_H_enum T { P, Q};#endifextern enum T C;

#ifndef T_H_#define T_H_enum T { P, Q};#endifextern enum T D;

y.h#include "t.h"extern enum T C;

z.h#include "t.h"extern enum T D;

symbol již definován

nepřekládá se

není-li symbol definován ...

definice nového symbolu (makra)

vlastní headery obkládejte ifndefy

Page 138: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Uživatelské knihovny

Uživatelské

.h

Standardní

.h

KompilátorUživatelské

.c

Přeložené

.obj

Linker Spustitelný soubor

.exe

Standardní

.obj

Standardní .lib

Knihovní

.obj

Knihovna .lib

Knihovní

.c

KompilátorLibrarian

Privátní

.h

Veřejné

.h

Page 139: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Dynamicky linkované knihovny

Uživatelské

.h

Standardní

.h

KompilátorUživatelské

.c

Přeložené

.obj

Linker Spustitelný soubor

.exe

Standardní

.obj

Standardní .lib

Stub

.obj

Stub .lib

Knihovní

.c

KompilátorLinker

Privátní

.h

Veřejné

.h

Knihovna

.dll

Loader

Page 140: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Programování není zápis algoritmů

Nízkoúrovňové (technické) Běhové prostředí programu Vazba programu na operační systém Přenositelnost mezi platformami Typické chyby a ochrana proti nim Ladění programů debuggerem a bez debuggeru Udržovatelné programy, kultura programování

Vysokoúrovňové ('manažerské') Komunikace se 'zákazníkem' - uživatelské požadavky Analýza a specifikace, programátorské zadání Testy - aplikační, integrační, zátěžové Nasazení (deployment) Pilotní provoz, roll-out, konverze dat Dokumentace - vývojová, uživatelská Školení 'běžných uživatelů'

Softwarové inženýrstvíInformační systémy

Programování ≈ výroba software

Page 141: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Odlišnosti mezi platformami

Vlastnosti hardware Velikost adresového prostoru a velikostí ukazatelů Pořadí ukládání vícebajtových hodnot (little/big endian) Dostupné formáty celých a reálných čísel

Vlastnosti operačního systému Znaková sadou (ASCII/EBCDIC, Win/ISO), oddělovače řádků Konvence jmen souborů (oddělovače, povolené znaky, délka) Další vlastnosti souborového systému (sémantika delete, links, přístupová práva) Základní služby a konvence OS (environment, registry) Konvence (/usr/bin, .exe, $HOME)

Vlastnosti překladače Volba velikosti základních aritmetických typů Způsob zarovnání položek struktur Rozpoznávaná pod-/nad-množinou jazyka Chyby v diagnostice a generovaném kódu

Vlastnosti knihoven Dostupnost, pojmenování a sémantika funkcí

Page 142: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Přenositelnost mezi platformami

Zákaz konstrukcí závislých na vlastnostech hardware a překladače

Užívání základních typů prostředníctvím typedef

typedef unsigned long UINT32; Používání funkcí definovaných normou Nelze-li jinak, užívání direktiv #ifdef

#ifdef _MSC_VER // Microsoft typedef __int64 INT64; const char delimiter = '\\'; #else typedef long long INT64; #ifdef UNIX const char delimiter = '/'; #else const char delimiter = '\\'; #endif#endif

int x; char * p = (char *)&x;struct { char a; int b; } S; fwrite( &S, 1, sizeof( S), fp);

Ideál: Program přenositelný bez úpravy zdrojového textu

Page 143: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Vazba programu na operační systém

Proces je izolován od ostatních procesů a jádra OS Virtuální adresový prostor, ochrana paměti Přímá komunikace s I/O zařízeními není možná Přímá komunikace s jinými procesy by byla možná technikou sdílené paměti

Není ovšem všude dostupná a standardizována Použití efektivní ale obtížné a nebezpečné

Veškerá komunikace přes systémová volání Systémové volání zajišťuje:

Přechod z uživatelského režimu do privilegovaného a zpět Možnost suspendování procesu uvnitř systémového volání

Konkrétní technika systémového volání závisí na HW a OS Softwarové přerušení, brány, speciální volání, falešné výjimky Obvykle není možné volání přímo z C/C++ Relativně pomalé (změna kontextu, přeplánování)

Množina systémových volání je definována OS Může být přímo zpřístupněna knihovnou (Unix, "io.h") Nemusí být zveřejněna, nebo pouze částečně (Microsoft)

Page 144: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Zveřejněné rozhraní operačního systému

"C-API" - zpřístupněno knihovnami Nejtypičtějsí část je standardizována Většina je závislá na OS

Knihovní funkce obvykle provádějí více než jedno systémové volání Knihovny mohou změnit logiku systémových volání

Soubory: Buffering, překlad znakových sad, statefull/stateless

Standardizované rozhraní služeb OS stdio.h - souborový vstup a výstup

Sjednocení přístupu k souborům a rourám - stdin, stdout, stderr Buffering - snížení počtu systémových volání / následky při pádu programu -

fflush Textový/binární mód - překlad do jednotné formy - '\n' Neřeší adresářové služby

signal.h, stdlib.h - řízení procesu Vyvolání/příjem signálu (Unix-like), ukončení procesu, system("winword

my.doc")

Page 145: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Vlákna (threads)

Pro realizaci serverů i některých GUI aplikací Je-li třeba souběžně vykonávat více činností Nebo čekat na více událostí různých druhů

Proces může mít více vláken (threads) Všechna vlákna žijí uvnitř společného adresového prostoru Každé vlákno má vlastní zásobník (a tedy jiný SP) První vlákno je spuštěno při spuštění procesu

Další vlákna vznikají na pokyn již existujících vláken Vlákna běží kvazi-paralelně, na multiprocesorech paralelně (!)

Všechny moderní OS vlákna podporují Způsoby implementace se liší Lze je implementovat i na úrovni knihoven bez vědomí OS

Norma C ani C++ o vláknech nehovoří Neexistuje přenositelný způsob práce s vlákny Pokusy o unifikaci - nestandardních knihovny

Programování s vlákny je obtížnější Nešikovná vzájemná komunikace vláken může zdržovat i zablokovat Využití vláken na multiprocesorech vyžaduje zvláštní opatrnost - Pozor na externí

knihovny! Nutnost synchronizace práce se sdílenými datovými strukturami

Page 146: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Ladění programů debuggerem

Spustit program v ladicím režimu Ladicí režim typicky není pro laděný program identický s normálním Chybný program se může chovat (a často chová) při ladění jinak než finální

verze Krokovat a spouštět program Zobrazovat data

lokální i globální proměnné, složitější výrazy zásobník volání paměť laděného procesu

Odchytit chybující program a zobrazit stav těsně před chybou Nastavovat breakpointy do kódu

Mohou být podmíněné Breakpointy na data (změna dat, přístup do paměti, splnění podmínky) Některé typy mohou o několik řádů zpomalit běh programu

Nevýhody Ne všude dostupné (kernely, pračky, banky, jaderné elektrárny, ...) Nevhodné pro paralelní nebo dlouhodobý běh

Page 147: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Ladění programů bez debuggeru

Ladicí 'tisky' (logy) Záznam důležitých okamžiků běhu programu Co, kdy a kde tisknout Jak tisknout ('monitor', soubor, databáze, pípání ...)

Automatické testování Testovací skripty Sady testovacích dat

Lokalizace chyby Minimalizace zdrojového textu, kde se chyba vyskytuje Prevence proti zavlečeným chybám

Ladicí implementace alokačních funkcí Obložit každý alokovaný blok prostorem vyplněným značkami Při dealokaci zkontrolovat neporušenost značek a změnit je

Page 148: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Bezpečné programování

Zapnout všechna varování, která je schopen kompilátor vydat Upravit program do podoby, která nezpůsobí žádné varování V odůvodněných případech lze varování vypnout pomocí #pragma

Dodržovat pravidla pro přenositelné a vícevláknové programy A to i když přenositelnost ani vícevláknovost zdánlivě nemá smysl

Minimum globálních proměnných, pokud možno pouze konstantní Procedura smí číst či měnit pouze objekty, které jsou přímo či nepřímo určeny jejími

parametry Důsledné užívání ochranných prostředků kompilátoru

const, private, ... Důsledná chybová diagnostika

Test úspěšnosti každého malloc, fopen, ... Testy proti interním chybám a špatným parametrům Ochrana proti užívání odalokovaných bloků Ochrana proti přetečením polí

Všechny funkce manipulující s polem dostávají velikost pole jako parametr Žádné strcat, gets a podobné nebezpečné funkce

void f( int* p){ assert( p); /*...*/ }

free(p); p=0;

Největší nepřítel je chyba, která není vždy a ihned smrtelná

Dereference nulového ukazatele se pozná ihnedDereference neinicializovaného ukazatele způsobí pád při odevzdání zápočťáku

Page 149: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Udržovatelné zdrojové texty

Logické rozdělení do modulů a hlavičkových souborů na nižší úrovni datové struktury a funkce, třídy

Jasné oddělení rozhraní od implementace Oddělení obsluhy uživatelského rozhraní od vlastní logiky aplikace

"Vstup/výstup" "výpočet"

Minimum globálních proměnných ideálně žádné, příp. jedna třída App

Komentáře, zejména k rozhraním Indentace, omezená délka řádek Pojmenovávací konvence, logicky zvolené a dlouhé identifikátory

Buď my_big_array nebo myBigArray, žádné pom1, pom2 Obvykle typy a konstanty začínají velkými písmeny, proměnné malými

Pojmenování všech smysluplných konstant Žádné int x[ 100] ani case 27: Jaké jiné konstanty než smysluplné by měly být ve zdrojových textech?

Nepoužívat deprecated features const a = 123; char *s = "abcd"; bool b; b++; správně const int a = 123; const char *s = "abcd"; (bool nelze inkrementovat)

Page 150: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Oblíbené chyby – struktura programu

Chybějící nebo přebývající středník:for (i=0; i<n; i++);{ ... }funkce();{ ... }

Přehozené parametry funkcí nebo části konstrukce:char text[20];strcpy( "Chyba!", text);for( i=0; i++; i<20)...

Nezapomínat na break v konstrukci switch Pozor na define (raději takhle vůbec nepoužívat):#define uint int*uint p1,p2;#define N 100;int delka=N+1; /* rozvine se: int delka=100;+1; */#define square (x) x*x

K čemu patří else?if(podmínka1)  if(podmínka2) /* akce */else /* jiná akce */

Page 151: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Oblíbené chyby – výrazy

Celočíselné dělení:x=1/3;

Zaokrouhlovací chyby:for (x=0; x!=1.0; x+=0.1)...

Odporující si parametry u printf:printf("%d",1.25);

Záměna & | a && ||a=1; b=2; if(a&b)...

Zkrácené vyhodnocování logických výrazů Pozor na záměnu znaků:a=1; if (a<1,5)...

Pozor na prioritu operátorů. Závorka navíc nikdy neuškodí. Nespoléhat na pořadí vyhodnocování (následující výstupy nejsou definovány):printf("%d %d",i++,i--);

a[i++]=b[i++] může být přeloženo 3 způsoby if (0<x<1)...

Page 152: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Oblíbené chyby – ukazatele

Neinicializované proměnné, obzvlášť ukazatele:char *text;strcpy( text, "Chyba!");

Ukazatel na proměnnou, která už neexistuje:char text[20];strcpy( text, ....);return text;

Chybějící nebo naopak přebývající & u parametru předávaného ukazatelem:scanf( "%d %s", i, &text);

Page 153: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

101 mouder

Organizační záležitosti1. Kompilujte bez varování2. Používejte automatizovaný systém kompilace3. Používejte systém pro správu verzí4. Investujte do čtení kóduDesign Style5. Jedna entita jedna zodpovědnost6. Korektnost, jednoduchost a čitelnost především7. Používejte škálovatelné algoritmy a konstrukce8. Neoptimizujte předčasně9. Neoptimizute pozdě10. Minimalizujte lokální a sdílená data11. Skrývejte informace12. Naučte se správně využívat vlákna13. Každý zdroj by měl patřit nějakému objektuCoding Style14. Kompilační chyby jsou lepší než běhové15. Používejte const16. Vyhýbejte se makrům17. Vyhýbejte se magickým číslům18. Deklarujte proměnné s nejmenším možným rozsahem platnosti19. Inicializujte proměnné20. Vyhýbejte se dlouhým funkcím a přílišnému větvení21. Vyhýbejte se inicializačním závislostem mezi moduly22. Minimalizujte závislosti, vyhýbejte se cyklickým závislostem23. Hlavičkové soubory by měly být samostatné24. Používejte ochranu vícenásobného vkládání #include

Sutter, Alexandrescu:C++ 101 programovacích

technik (C++ Coding Standards)

Page 154: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Co (a proč ) dělá tento program?

#define _ F-->00||F-OO--;

int F=00,OO=00;main(){F_OO();printf("%1.3f\n",4.*-F/OO/OO);}F_OO()

{

_-_-_-_

_-_-_-_-_-_-_-_-_

_-_-_-_-_-_-_-_-_-_-_-_

_-_-_-_-_-_-_-_-_-_-_-_-_-_

_-_-_-_-_-_-_-_-_-_-_-_-_-_-_

_-_-_-_-_-_-_-_-_-_-_-_-_-_-_

_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_

_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_

_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_

_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_

_-_-_-_-_-_-_-_-_-_-_-_-_-_-_

_-_-_-_-_-_-_-_-_-_-_-_-_-_-_

_-_-_-_-_-_-_-_-_-_-_-_-_-_

_-_-_-_-_-_-_-_-_-_-_-_

_-_-_-_-_-_-_-_

_-_-_-_

}

Pozor! Je v čistém C, nikoliv v C++

Page 155: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Part II - C++

C++

Page 156: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Významné vlastnosti jazyka C++

Run-time: vlastnosti C++ s reprezentací za běhu programu dědičnost (inheritance) virtuální metody, polymorfismus, pozdní vazba (virtual functions) násobná dědičnost, virtuální dědičnost (multiple/virtual inheritance) zpracování výjimek (exception handling) typová informace za běhu (RTTI)

Syntaxe: vlastnosti C++ bez reprezentace za běhu pomůcky (reference, implicitní parametry, přetěžování funkcí) pro zapomnětlivé (konstruktory, přesnější typová kontrola) proti šťouralům (zapouzdření, ochrana přístupu, prostory jmen) pro estéty (přetěžování funkcí a operátorů, uživatelské konverze) pro zobecnění (šablony)

Knihovny proudy (streams) STL (Standard Template Library)

Page 157: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Třída a objekt

Třída (class) Zobecnění pojmu struktura (struct)

Rozdíl mezi class a struct v C++ je nepatrný Užívání class místo struct je pouze konvence

Deklarace třídy obsahuje Deklarace datových položek (stejně jako u struktury) Funkce (metody), virtuální / statické funkce

metody můžou přistupovat k datovým položkám Definice výčtových konstant a typů

včetně vnořených tříd

Objekt (instance třídy) Běhová reprezentace jednoho exempláře třídy Reprezentace objektu v paměti obsahuje

Datové položky Skryté pomocné položky

virtuálních metody, výjimky, RTTI, virtuální dědičnost

class A {public: A() : x(0), y(0) {} void Set( int x, int y) { x_ = x; y_ = y; } int Prod() { return x_ * y_); }private: int x_, y_;};

A a;A * pa = &a;a.Set( 1, 2);cout << pa->Prod();

Page 158: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Princip a účel dědičnosti

Princip dědičnosti Třída (struktura) může mít jednoho (nebo více) předků

relace předek-potomek je orientovaný acyklický graf není povinný společný prapředek pro všechny třídy

Účel dědičnosti Lze napsat kód, který pracuje s daty společného předka několika tříd

bez závislosti na tom, jaký je typ celého objektu tento kód lze přeložit bez znalosti potomků

Reusabilita potomci třídy mají automaticky její datové položky a další vlastnosti a

schopnosti Inherit to be reused, not to reuse

Polymorfismus lze vytvořit strukturu sdružující objekty různých tříd, pokud mají společného

předka

Page 159: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Implementace dědičnosti v C++

Je-li třída B (přímým či nepřímým) potomkem třídy A, pak:

Paměťová reprezentace objektu typu B obsahuje část se shodným tvarem jako reprezentace samostatného objektu typu A

Z každého ukazatele na typ B je možno odvodit ukazatel na část typu A

konverze je implicitní, tj. není třeba ji explicitně uvádět ve zdrojovém kódu konverze může vyžadovat jednoduchý výpočet

obvykle pouze při násobné dědičnosti přičtení posunutí

Z ukazatele na typ A je možno odvodit ukazatel na typ B za těchto okolností:

konkrétní objekt, na který ukazuje ukazatel na typ A, je typu B (nebo jeho potomka)

zodpovědnost za ověření skutečného typu objektu má programátor konverzi je třeba explicitně vynutit přetypováním konverze může vyžadovat odečtení posunutí

BA

x y u

Page 160: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Dědičnost - reusabilitaA x y

pa

class A {public: int x, y;};

int f( A * pa){ return pa->x * pa->y;}

kód nic netušící o případných potomcích

Page 161: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Dědičnost - reusabilita

B A x y u

pb pa

A x y

pa

class A {public: int x, y;};

int f( A * pa){ return pa->x * pa->y;}

class B : public A {public: int u;};

int g( B * pb){ return pb->u * f( pb);}

volání kódu pracujícího s předkempřípadné konverze zajístí kompilátor automaticky

Page 162: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Dědičnost - polymorfismus

C A t n u

seznam

B A t n x y

B A t n x y

enum Typ { T_B, T_C };class A {public: Typ t; A * n;};A * seznam;

class B : public A {public: int x, y;};

class C : public A {public: int u;};

seznam objektů se společným předkem

Page 163: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Dědičnost - polymorfismus

C A t n u

pb pa

seznam

B A t n x y

B A t n x y

enum Typ { T_B, T_C };class A {public: Typ t; A * n;};A * seznam;

class B : public A {public: int x, y;};

class C : public A {public: int u;};

A * pa = seznam->n->n;

if ( pa->t == T_B ){ B * pb = (B *)pa;}

odkaz na objekt odvozené třídyzodpovědnost programátora za korektnost

Page 164: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Násobná dědičnost

B A

u

x y

C A x z

B A x yC A x z

D

A xclass A { int x; };

class B : public A{ int y;};

class C : public A{ int z;}

class D : public B, public C{ int u;}

D * dp = ...;// A * ap = dp; chyba: nejednoznačnostA * ap = (B *)dp; // zjednoznačněnídp = (D *)ap; // explicitní přetypování

Page 165: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Virtuální dědičnost

B A

u

xy

C A xz

B A xyC

zD

A xclass A { int x; };

class B : virtual public A{ int y;};

class C : virtual public A{ int z;}

class D : public B, public C{ int u;}

D * dp;A * ap = dp; // OK// dp = (D *)ap; chyba: nelze najít

Page 166: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Názvosloví dědičnosti

Předek - potomek Parent - child Převládající názvosloví v češtině

Základní - odvozená třída Base - derived class Lepší názvy, užívané normou C++

Univerzální - specializovaná třída Nejlépe odpovídá typickému použití dědičnosti Koliduje s pojmem specializace šablon Nepoužívá se

Page 167: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Užití dědičnosti

Je-li třída B odvozena z třídy A, pak: Každý objekt typu B má všechny součásti, vlastnosti a schopnosti typu A Objekt typu B má být použitelný kdekoliv, kde se používá typ A B je specializací A

Zděděné součásti nelze odebrat Kluzák nemůže být potomkem motorového letadla

Vlastnosti a schopnosti lze skrýt, překrýt či ignorovat Skrývání či ignorování je nesystematické a nebezpečné

věznice nemá být potomkem obytného domu Překrývání jiným obsahem téže schopnosti může mít smysl

auto na plyn tankuje jinak

Is-A relationshipjezevčík JE pespes JE zvíře

Page 168: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Nesprávné užití dědičnosti - kompozice

Letadlo není potomkem svého motoru Důkaz: Co když má dva motory... Násobná dědičnost?

Ne: Je třeba je odlišit

Tlačítko není potomkem své ikony Důkaz: Co když má dvě...

KompoziceSkládání velkých objektů z malýchC++: Třída s datovými položkami

class Letadlo { ... Motor motor[N];};

class Letadlo : public Motor {};

class Letadlo : public Motor, public Motor {};

class Tlacitko { ... Icon ico;};

class ZamackavaciTlacitko{ ... Icon icoOn; Icon icoOff;};

Page 169: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Nesprávné užití dědičnosti - delegace

Jezevčík umí vyhnat lišku z nory... Myslivec s jezevčíkem tedy také...

Myslivec není potomkem svého jezevčíka Důkaz: Nežere granule... Kompozice?

Ne: Nerodí se zároveň

Tlačítko Start není potomkem Windows

DelegacePřevedení funkčnosti na jiný objektC++: Ukazatel

class JM1 { ... Myslivec* mysl; Jezevcik* jez;};

class JM1 : public Myslivec, public Jezevcik {};

Page 170: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Nesprávné užití dědičnosti - abstraktní předek

Mlok není potomkem ryby a savce Důkaz: Nemá dvě hlavy... Virtuální dědičnost?

Ne: Nekojí Abstraktní předek obratlovec

Tlačítko není potomkem obdélníku a textu Abstraktní předek vizuální objekt

Společný abstraktní předek

class Obratlovec {};class Ryba : public Obratlovec {};class Savec : public Obratlovec {};class Obojzivelnik : public Obratlovec {};

class Mlok : public Ryba, public Savec {};

class Mlok : virtual public Ryba, virtual public Motor {};

Page 171: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Ideální užití dědičnosti

Objekty: Jednoduchá dědičnost Postupná specializace tříd, reprezentujících objekty Živočich-obratlovec-obojživelník-mlok

Rozhraní: Virtuální násobná dědičnost Kombinování protokolů (tříd, reprezentujících rozhraní) Sjednocení množin schopností Fyzikář+Matikář

C++ pro oba odlišné účely využívá tytéž mechanismy Některé jazyky tyto účely rozlišují

Page 172: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Potomka lze přiřadit do předka (platí i pro ukazatele)Předka NELZE přiřadit do potomka (platí i pro ukazatele)

Kompatibilita předka a potomka

pes umí jíst, brouk neumí štěkat

azorclass zvire {};class pes : public zvire {};zvire pytlik, *pz;pes azor, *pp;

pytlik = azor;*pz = &azor;

azor = pytlik;*pp = &pytlik;

stav

žaludek

pytlik

žaludek

stav

žaludek žaludek

pytlikazor

???nelze

!

Page 173: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

class A {public: int x, y;};

int f( A * pa){ return pa->x * pa->y;}

A oa;A * pa = & oa;int u = f( &oa);int v = f( pa);

class A {private: int x, y;public: int f();};

int A::f(){ return x * y;}

A oa;A * pa = & oa;int u = oa.f();int v = pa->f();

Metoda (member function)

this->x

Každá metoda dostane 'tajný' parametr this - ukazatel na

objekt

A:: => skrytýparametr A* this

Metoda (member function) = funkce uvnitř třídy

implementace (tělo) metody

deklarace (hlavička) metody

volání metody

chráněné položky

přístupné pouze

metodám třídy

veřejné položky přístupné komukoliv

Page 174: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Metoda - umístění funkce uvnitř třídy

Vyvolání na konkrétní instanci třídy Při volání funkce je určen objekt, na kterém je funkce vyvolána Ukazatel na tento objekt je funkci předán jako skrytý parametr Uvnitř funkce je tento objekt přístupný přes ukazatel this Datové položky tohoto objektu jsou přímo přístupné

Zapouzdření a přístupová práva Identifikátor funkce je schován uvnitř třídy K přístupu k prvkům třídy stačí krátká jména Funkce může být chráněna proti volání zvenčí (private) Funkce může přistupovat k chráněným prvkům třídy (private)

Page 175: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Tělo metody uvnitř a vně třídy

Tělo uvnitř třídy Inline tělo vně třídy Ekvivalent těla uvnitř Kompilátor se pokusí rozvinout tělo Tělo v hlavičkovém souboru

class A {

public:

int x, y;

int f()

{

return x * y;

}

};

class A {

public:

int x, y;

int f();

};

inline int A::f()

{

return x * y;

}

int A::f()

{

return x * y;

}

class A {

public:

int x, y;

int f();

};

Tělo vně třídy Ekvivalent externí deklarace a definice globální

funkce Tělo v .cpp souboru

.h .cpp

inline: kompilátor se pokusít tělo funkce rozvinout v místě

volání

inline: kompilátor se pokusít tělo funkce rozvinout v místě

volání

Page 176: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Konstantní metody

konstantní metoda nemodifikuje objekt, na kterém je

vyvolána lze aplikovat na konstantní objekt

class A {public: int x, y;

int f() const { return x * y; }};

const A * pa;...pa->f();

class A {public: int x, y;};

int f( const A * pa){ return x * y;}

const A* this

const A* this

Page 177: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

class A {private: int x, y;public: int f() { return x * y; }};

class B : public A {private: int z;public: int g() { return f() * z; }};

B ob;A * pa = & ob;B * pb = & ob;int u = pa->f();int v = pb->f();int w = pb->g();

Metody základních a odvozených tříd

automatická konverze na ukazatel na předka

volání metody základní třídy

A::f()

volání metody odvozené třídy

Page 178: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

class A {private: int x, y;public: int f() { return x * y; }};

class B : public A {private: int z;public: int f() { return z; }};

B ob;A * pa = & ob;B * pb = & ob;pa->f(); // A::fpb->f(); // B::fpb->A::f(); // A::fpb->B::f(); // B::fpa->A::f(); // A::f// pa->B::f(); nelze

Zakrývání metod – compile time binding

volání odpovídající metody podle typu

objektu

stejná metoda jako předka - zakrývání

kvalifikované volání – explicitně určím která metoda

se má volatnelze (takhle) kvalifikovaně

volat funkce odvozených tříd

Page 179: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Implicitní parametry

int fce( int a, int b = 2, int c = 4){ return 2*a + b - c;}

fce( 1); // int fce( 1, 2, 4)fce( 1, 5); // int fce( 1, 5, 4)fce( 1, 5, 6); // int fce( 1, 5, 6)

Některé parametry funkce mohou mít implicitní hodnoty pokud nejsou všechny parametry implicitní – implicitní parametry

odzadu

Při volání funkce lze implicitní parametry vynechat použije se implicitní hodnota

Definují se u hlavičky funkce U těla funkce se neopakují

Implicitní hodnoty řeší kompilátor pouze na straně volání Volaná funkce nezjistí, zda jsou hodnoty parametrů určeny

explicitně nebo implicitně

Volá se stále stejná funkce int fce( int, int,

int)

Page 180: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Přetěžování funkcí

C++ dovoluje existenci více funkcí téhož jména ve stejné oblasti platnosti Podmínkou je odlišnost v počtu a/nebo typech parametrů Odlišnost typu návratové hodnoty nestačí

Při volání funkce se konkrétní varianta určuje takto: Vyberou se vhodné varianty funkce podle počtu a typu skutečných

parametrů Určí se ceny typových konverzí parametrů, zjednodušeně:

Konverze non-const -> const / typ <-> reference jsou nejlevnější Konverze potomek -> předek / aritmetická konverze na větší typ Uživatelská konverze / ztrátová aritmetická konverze jsou nejdražší

Vybere se nejlacinější aplikovatelná varianta Pokud je jich více, kompilátor ohlásí chybu

int pocitej( int x);int pocitej( int a, int b);int pocitej( int a, const char* s);

Page 181: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Přetěžování funkcí

int pocitej( int x){ return x + 1;}

int pocitej( int a, int b){ return 2 * a + b;}

int pocitej( int a, const char* s){ return a + strlen( s);}

pocitej( 1); // int pocitej( int)pocitej( 1, 2); // int pocitej( int, int)pocitej( 1, "ahoj"); // int pocitej( int, char*)

Funkce je definována svým identifikátorem a počtem a typem parametrů

Funkce se stejným identifikátorem ale

různým počtem parametrů

Správná funkce podle počtu a typů

skutečných parametrů

Funkce se stejným počtem

ale různým typem parametrů

Page 182: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Přetěžování funkcí

int min( int a, int b){ return a < b ? a : b; }

double min( double a, double b){ return a < b ? a : b; }

min( 1, 2); // min( int, int)min( 1, 2.0); // min( double, double)min( 1.0, 2); // min( double, double) min( 1.0, 2.0); // min( double, double)

void f( int, double);void f( double, int);

f( 1, 2); // chybaf( 1.0, 2.0); // chyba

přesná shoda

levnější varianta

přesná shoda

obě varianty stejně drahé

Page 183: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Přetěžování vs. implicitní parametry

Kdy použít přetěžování a kdy implicitní parametry?

Implicitní parametry Stejný kód pro různý počet parametrů Místo chybějících parametrů se dosadí implicitní hodnoty

Přetěžování Pro různé počty nebo typy parametrů různý kód

Page 184: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Reference

C++ definuje vedle deklarátoru ukazatele * deklaráror reference &

z hlediska přeloženého kódu jsou oba deklarátory ekvivalentní ukazatel i reference na objekt jsou reprezentovány adresou objektu odlišné je jejich používání ve zdrojovém textu

Výraz typu reference má hodnotu objektu, na nějž reference odkazuje

tento objekt se určuje při inicializaci reference odkaz na něj trvá po dobu platnosti referenční proměnné

(nebo objektu, jehož je reference součástí) identita reference a referencovaného objektu

implicitní typová konverze T <=> T &int & ref = data;

void f( int & u);

int & g();

Page 185: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Reference

int data;

int * ukazatel = & data;

* ukazatel = 2; // data = 2

int data2;

data2 = * ukazatel; // data2 = data

ukazatel = & data2;

void f( int * u)

{ * u = 2;

}

f( & data);

int * g()

{ return & data;

}

* g() = 3; // data = 3

int data;

int & reference = data;

reference = 2; // data = 2

int data2;

data2 = reference; // data2 = data

// NELZE: & reference = & data2;

void f( int & u)

{ u = 2;

}

f( data);

int & g()

{ return data;

}

g() = 3; // data = 3

Page 186: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Reference

Novinky související s existencí reference Inicializaci reference nelze nahradit přiřazením Nelze rozlišit parametry předávané hodnotou a odkazem Návratová hodnota funkce může být l-hodnota Zvýšené nebezpečí nekorektních konstrukcí

Nulovou referenci je obtížnější vytvořit i testovat

int & f()

{

int x;

return x;

}

int * p = 0;

int & r = * p;

if ( ! & r ) // ...

Page 187: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

class bod{private: int x, y;

public: … bod operator+( const bod&); bod operator=( const bod&);};

bod a, b, c;c = a + b;

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

přetížení operátoru +

a + b a.operator+(b)

a = b a.operator=(b)

c.operator=( a.operator+( b));c.assign( a.add( b));

bod bod::operator=( const bod& b){ x = b.x; y = b.y; return *this;}

bod bod::operator+( const bod& b){ return bod( x+b.x, y+b.y);}

Těla metod

Page 188: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Přetěžování operátorů - pravidla Většinu operátorů jazyka C++ lze definovat pro uživatelské datové typy

Nelze předefinovat tyto operátory: .  .*  ::   ? :  sizeof Alespoň jeden z operandů musí být třída nebo výčtový typ nebo reference na ně

Nelze předefinovat operace na číselných typech a ukazatelích Předefinováním nelze měnit prioritu a asociativitu operátorů Pro předefinované operátory nemusí platit identity definované pro základní typy,

např.: ++a nemusí být ekvivalentní a=a+1 a[b] nemusí být ekvivalentní *(a+b) ani b[a]

Pro předefinované operátory && a || neplatí pravidla o zkráceném vyhodnocování Typy skutečných operandů nemusejí přesně odpovídat typům formálních

parametrů Pro výběr správné varianty platí stejná pravidla, jako pro přetížené funkce

Předefinování operátorů se provádí definováním metody se speciálním jménem operatorxxx ve třídě (prvního operandu), pro kterou má být operátor definován

Některé operátory je možno definovat i jako globální funkce s týmž speciálním jménem

Operátory, které jsou metodami, jsou s výjimkou operátoru přiřazení dědičné a smějí být virtuálníclass bod

{ bod operator+( const bod&);};

Bod& operator+( const bod&, const bod&);

Page 189: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Přetěžování operátorů - binární operátory

běžné binární operátory:+ - * / % << >> < > <= >= <<= >>= ^ & | && || == != += -= *= /= %= ^= &= |= ->*

lze předefinovat jako globální funkce nebo metody

binární operátor [ ]

lze předefinovat pouze metodou

A B::operator xxx( C) A B::operator xxx( const C &) A B::operator xxx( const C &) const

A operator xxx( B, C) A operator xxx( B &, C &) A operator xxx( const B &, const C &)

A B::operator []( C)A B::operator []( C &) A B::operator []( const C &) const

není zde operator=speciální metoda

třídy

speciální operátory -> a

() později

Page 190: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Přetěžování operátorů - unární operátory

unární operátory + - * & ~ ! a prefixové operátory ++ --

lze předefinovat jako globální funkce nebo metody

postfixové operátory ++ a --lze předefinovat jako globální funkce nebo metody

A operator xxx( B) A operator xxx( B &) A operator xxx( const B &)

A B::operator xxx() A B::operator xxx() const

A operator xxx( B, int) A operator xxx( B &, int) A operator xxx( const B &, int)

A B::operator xxx( int) A B::operator xxx( int) const

fiktivní operand typu int

++X

X++

Page 191: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Konstruktory a destruktory

Konstruktor třídy XXX je metoda se jménem XXX Typ návratové hodnoty se neurčuje Konstruktorů může být více, liší se parametry Nesmí být virtuální

Konstruktor je volán vždy, když vzniká objekt typu XXX Parametry se zadávají při vzniku objektu Některé z konstruktorů mají speciální význam

default constructor, copy constructor Některé z konstruktorů může generovat sám kompilátor

Konstruktor nelze vyvolat přímo

Destruktor třídy je metoda se jménem ~XXX Nesmí mít parametry ani návratovou hodnotu Může být virtuální

Destruktor je volán vždy, když zaniká objekt typu XXX Destruktor může generovat sám kompilátor

Destruktor lze vyvolat přímo pouze speciální syntaxí

class A{private: int x;

public: A() {} A( int x_) {} ~A() {}};

Page 192: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Konstruktor, seznam inicializátorů

class A{private: int x; int y;

public: A( int x_, int y_) { x = x_; y = y_; } A( int x_, int y_) : x(x_), y(y_) {}};

seznam inicializátorů položek

member initializer list

zavolají se konstruktory složek s parametry dle seznamu inicializátorů volání konstruktorů je podle pořadí v deklaraci třídy, ne podle pořadí inicializátorů

na složky, které nejsou v seznamu inicializátorů, se použije implicitní konstruktor

nakonec se zavolá tělo konstruktoru povinné použití seznam inicializátorů:

inicializace const položek inicializace referencí předávání argumentů konstruktorům předka nebo vloženého objektu

vždy preferujte seznam inicializátorůparametrický konstruktor vs. implicitní konstruktor +

přiřazení

Page 193: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Implicitní a kopírovací konstruktor

Implicitní konstruktor (bez parametrů, default constructor) Proměnné bez inicializace, dynamická alokace polí Pokud třída nemá žádný konstruktor, kompilátor se jej pokusí

vygenerovat Položky, které nejsou třídami, nejsou generovaným konstruktorem

inicializovány Generovaný konstruktor volá konstruktor bez parametrů na všechny předky

a položky

Kopírovací konstruktor (copy constructor) Používán pro předávání parametrů a návratových hodnot Pokud třída kopírovací konstruktor nemá, kompilátor se jej pokusí

vygenerovat Položky, které nejsou třídami (POD), jsou kopírovány Na předky a položky se volá kopírovací konstruktor To nemusí jít kvůli ochraně přístupu (konstruktor v sekci private)

class A { A();}

class A { A(const A&);}

Page 194: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Konstruktory

class A{private: int x; int y;

public: A() : x(-1), y(-1) {} A( int x_, int y_) : x(x_), y(y_) {} A( const A& a) : x(a.x), y(a.y) {}};

A a1; // A::A()A a2( 1, 2); // A::A(int,int)A a3( a2); // A::A(const A&)A a4 = a2; // A::A(const A&)A* pa;pa = new A;pa = new A( 2,3);pa = new A( a4);pa = new A[ 100];

implicitní konstruktor

default constructor

copy (kopírovací) konstruktor vytvoří objekt

jako kopii jiného

různé zápisy použitícopy

konstruktoru

alokace pole - pouze implicitní konstruktor

Pro U≠T není ekvivalentní:U u;T t(u); // T::T( U&)T t = u; // T::T( T(u)) nebo // T::T( u.operator T())

Page 195: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Konstruktory a dědičnost

class B : public A{private: int z;public: B() : z(-1) {}; B( int x_, int y_, int z_)

: A(x_,y_), z(z_) {} B( const B& b) : A(b), z(b.z) {}};

B b( 1, 2, 3); // B::B(int,int,int)A a(b1); // A::A(const A&)// B ba(a); // errorA* pa = new B; // B::B()// B* pb = new A;// error

class A{private: int x; int y;public: A() : x(-1), y(-1) {} A( int x_, int y_) : x(x_), y(y_) {} A( const A& a) : x(a.x), y(a.y) {}};

neimplicitní konstruktor předka pouze přes seznam

inicializátorů

dědičnost – na místě předka mohu použít potomka

před vstupem do těla konstruktoru potomka se

provedou kostruktory předků a položek

Konstrukce součástí se dějepřed konstrukcí celku,

destrukce součástí po destrukci celku

implicitní konstruktor

předka

Page 196: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Vznik a zánik objektů – lokální proměnné

Lokální proměnné

pro lokální objekt je kostruktor vyvolánpři průchodu deklarací

při zániku lokálního objektu(opuštění bloku s deklarací jakýmkoli způsobem)je vyvolán jeho destruktor

deklarace objektu může být kdekoliv uvnitř těla funkce nebo složeného příkazu

rozsah platnosti objektu je od místa deklarace po konec složeného příkazu

skoky, které by vstupovaly do bloku a obcházely deklaraci, jsou zakázány

void f( void){ int x; x = 1; A a; if( x) { B b; x = 2; } if( !x) return; x = 3;}

A::~A

A::~A

A::A

B::B

B::~B

Page 197: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Vznik a zánik objektů – parametry předávané hodnotou

Parametry předávané hodnotou copy konstruktor, konstruktor s jedním parametrem konstruktor je volán na místě volání funkce před jejím zavoláním kompilátor dokáže tento konstruktor vytvořit automaticky destruktor objektu je vyvolán před návratem z funkce

void f( A a){ } // A::~A

void g(){ A a; B b; // class B : public A f( a); // A::A( const A &) f( b); // A::A( const A &) f( 1); // lze pokud ex. A( int)}

Na místě předka

můžu mít potomka

Page 198: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Vznik a zánik objektů – globální proměnné

Globální a statické proměnné pro každý globální objekt je vyvolán konstruktor před vstupem do

funkce main pro každý statický objekt je vyvolán konstruktor nejpozději při průchodu

deklarací po opuštění main (nebo po zavolání exit) je pro každý globální objekt

vyvolán destruktor pořadí vyvolávání je implementačně závislé !

A a( 1), b;A d( a);

f(){ static A e( 1);}

int main(){ f();}

při vyvolání konstruktoru d nemusí být a inicializováno!

Page 199: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Vznik a zánik objektů – dynamicky alokované objekty

Dynamicky alokované objekty pro dynamickou alokaci slouží operátory new a delete funkce malloc a free s nimi nelze kombinovat

v C++ raději nepoužívat operátor new alokuje pro objekt paměť, vyvolává konstruktor dle parametrů a

vrací ukazatel na vytvořený objekt pokud se (nedostatek paměti) alokace nezdaří:

C++ 98 a novější: vyvolá se výjimka std::bad_alloc starší C++: konstruktor se nevyvolává a operátor vrací nulový ukazatel vrácení nulového ukazatele při nezdaru lze vynutit: new( nothrow ) A

operátor delete vyvolává destruktor objektu a poté dealokuje paměť je odolný proti nulovým ukazatelům parametr delete POUZE alokovaný a doposud neodalokovaný objekt

A *p, *q;p = new A; q = new A( *p);/* ... */delete p;delete q;

A::A()

A::A( const A&)

A *p, **q;p = new A[ 20];q = new A*[ 20];/* ... */delete[] p;delete[] q;

pole ukazatelů

Page 200: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Vznik a zánik objektů – dočasné objekty

Dočasné objekty užití jména třídy jako jména funkce v operátoru volání způsobí:

vyhrazení místa pro objekt na zásobníku mezi okolními lokálními proměnnými

vyvolání konstruktoru s patřičnými parametry na tomto objektu použití tohoto objektu jako hodnoty v okolním výraze vyvolání destruktoru nejpozději na konci příkazu

konstruktor s jedním parametrem je konverzní konstruktor lze použít jako typovou konverzi (function-style cast)

A a, b;a = A();b = A( 1);return A( 2);

konstruktor, kopie, destruktor

konverzní konstruktorz int vyrobí A

použití jako návratové hodnoty

Page 201: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Vznik a zánik objektů – příklad

A f( A y){ return y;}

A p, q;

p = f( q);

kolik konstruktorů a jakých vyvolá zpracování této

řádky?

Page 202: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Vznik a zánik objektů – příklad

A f( A y){ return y;}

A p, q;

p = f( q);

kolik konstruktorů a jakých vyvolá zpracování této

řádky?

odpověď: to nikdo neví

proč? norma C++: kompilátor může ale nemusí vytváření objektů optimalizovat

vždy ale platí: pokud se zavolá konstruktor, vždy se zavolá i destruktor

jiná otázka: jak to tedy může být v nejhorším a v optimalizovaném případě?

Page 203: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Vznik a zánik objektů – hloupý kompilátor

A f( A y){ return y;}

A p, q;

p = f( q);

0. pro návrat z funkce se alokuje místo pro dočasnou proměnnou temp2

1. q ypředání hodnoty skutečného parametru do funkcecopy konstruktor

2. y temp1'spočítá' se hodnota výrazu pro return a vytvoří se dočasný objektcopy konstruktor

3. temp1 temp2předání návratové hodnoty ven z funkcecopy konstruktor

4. temp2 ppřiřazení návratové hodnoty funkce proměnnéoperátor přiřazení

Page 204: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Vznik a zánik objektů – chytrý kompilátor

A f( A y){ return y;}

A p, q;

p = f( q);

1. q ypředání hodnoty skutečného parametru do funkcecopy konstruktor

2. y temp'spočítá' se hodnota výrazu pro return a vytvoří se dočasný objektcopy konstruktor

4. temp ppřiřazení návratové hodnoty funkce proměnnéoperátor přiřazení

Page 205: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

odlišné chování potomků – pozdní vazba (late binding)

Polymorfismus

najde něco v přírodě

zvíře pes pitbul

člověk

jez jez jez

jez

sní maso sní hodně masa

jde do restaurace

Page 206: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Polymorfismus - motivace

class zvire{ jez() { priroda(); }};

class pes : public zvire{ jez() { maso(1); }};

class pitbul : public pes{ jez() { maso(10); }};

class clovek : public zvire{ jez() { hospoda(); }};

zvire pytlik;pes punta;pitbul zorro;clovek pepa;

pytlik.jez(); // priroda();punta.jez(); // maso(1);zorro.jez(); // maso(10);pepa.jez(); // hospoda();

Tohle není polymorfismus !Funkce je známa v době

překladu

'normální' vlastnost třídzakrývání metod

Při překladu je známoze které třídy se volá

metoda

Každá třída má vlastní implementaci (tělo)

metody jez

Page 207: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Polymorfismus – pozdní vazba

zvire* rodina[4];

rodina[0] = new clovek;rodina[1] = new pes;rodina[2] = new pitbul;rodina[3] = new zvire;

for( int i = 0; i < 4; ++i) rodina[i]->jez();

Chci pokaždé se zavolat jinou metodu

Rozlišení metody se musí dít za běhu

Pozdní vazba (late binding; virtual call)

které tělo bude zavoláno se rozhoduje až za běhu programu podle skutečného typu celého objektu

použije se tělo z posledního potomka, který definuje tuto funkci a je součástí celého objektu

Má smysl pouze u vyvolání na objektu určeném odkazem

chtěl bych, aby se volaly 'správné' metody

Page 208: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Virtuální metody - deklarace

class zvire{ virtual jez() { priroda(); }};

class pes : public zvire{ virtual jez() { maso(1); }};

class pitbul : public pes{ virtual jez() { maso(10); }};

class clovek : public zvire{ virtual jez() { hospoda(); }};

magické klíčové slovo virtual

každý objekt si s sebou nese informaci

kterou virtuální funkci používá

Page 209: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Virtuální metody - implementace

Princip implementace každý objekt obsahuje ukazatel na tabulku virtuálních funkcí

tabulka ukazatelů na funkce při volání metody se volá tělo funkce z této tabulky

By

A x

fg

A::f

A::g

A x

fg

B::f

class A {public: int x; virtual int f() { return 1; } virtual int g() { return 2; }};

class B : public A {public: int y; virtual int f() { return 9; }};

Page 210: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Virtuální metody - implementace

class A {public: int x; virtual int f() { return 1; } virtual int g() { return 2; }};

class B : public A {public: int y; virtual int f() { return 9; }};

A a;B b;A* pa = &b;pa->f();

int A_f( struct A* th) { return 1; }int A_g( struct A* th) { return 2; }

struct A { int (*pf)( A*); int (*pg)( A*); int x; int f() { return pf( this); } int g() { return pg( this); } A() { pf = A_f; pg = A_g; }};

int B_f( struct B* th) { return 9; }

struct B : public A { int y; B() { pf = (int(*)(A*))B_f; }};

A a;B b;A* pa = &b;pa->f();

Page 211: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Volání virtuálních metod

class A {public: virtual f();};class B : public A {public: virtual f();};

A a; B b; A * paa = &a;A * pab = &b;B * pbb = &b;// B * pba = &a; nelze!

a.f(); // A::f

b.f(); // B::f

paa->f(); // A::f pab->f(); // B::f

pbb->f(); // B::f

b.A::f(); // A::f

b.B::f(); // B::f

a.B::f(); // NE!

paa->A::f(); // A::f

pab->A::f(); // A::f

pab->B::f(); // NE!

pbb->A::f(); // A::f

pbb->B::f(); // B::f

pozd

vazb

a

b B::f

paa

A::fapab

pbb

kvalifi

kované

volá

zakrývání metod

Page 212: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Virtuální metody a konstruktory a destruktory

class A {

public:

virtual f();

A() { f(); } // A::f

~A() { f(); } // A::f

g() { f(); } // A/B::f

};

class B : public A {

public:

virtual f();

B() { f(); } // A::A B::f

~B() { f(); } // B::f A::~A

g() { f(); } // B::f

};

nejdřív se zavolá konstruktor

předka

nejdřív se provede kód destruktoru, pak se zavolá

destruktor předka

v konstruktoru a destruktoru se vždy volá metoda

vytvářeného/rušeného objektu

určí se za běhu podle skutečného typu

objektu

Konstruktor provádí i vyplnění skrytých položek třídy, zajišťujících funkci virtuálních metod.Toto vyplňování se děje až po konstrukci součástí třídy, což znamená, že v době vyvolání konstruktoru součásti se virtuální funkce vyvolávají tak, jako by tato součást byla celkem. Analogický mechanismus funguje i při destrukci objektů.

Page 213: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Dědičnost a destruktory

int x=0; int ya=0; int yb=0;

class A {

public:

virtual f() { x=1; ya=1; }

~A() { f(); } // A::f

};

class B : public A {

public:

virtual f() { x=2; yb=2; }

~B() { f(); } // B::f A::~A

};

A * pa = new B;

delete pa;

co udělá tohle?x=1 ya=1 ya=2 ?x=1 ya=1 ya=0 ?něco jiného?

Page 214: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Dědičnost a nevirtuální destruktory – POZOR!

int x=0; int ya=0; int yb=0;

class A {

public:

virtual f() { x=1; ya=1; }

~A() { f(); } // A::f

};

class B : public A {

public:

virtual f() { x=2; yb=2; }

~B() { f(); } // B::f A::~A

};

A * pa = new B;

delete pa;

co udělá tohle?

- zformátuje disk- pošle zdrojáky mailem- zaviruje počítač- ... cokoliv!

delete objektu odvozené třídy přes ukazatel na

základní třídus nevirtuálním destruktorem

je NEDEFINOVÁN

Page 215: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

int x=0; int ya=0; int yb=0;

class A {

public:

virtual f() { x=1; ya=1; }

virtual ~A() { f(); } // A::f

};

class B : public A {

public:

virtual f() { x=2; yb=2; }

virtual ~B() { f(); } // B::f A::~A

};

A * pa = new B;

delete pa; // x=1 ya=1 yb=2

Virtuální destruktory

nejdříve se provede tělo ~B, potom se

zavolá ~A

Má-li být třída předkem určeným pro ukazatele na

dynamicky vytvářené potomky, musí mít virtuální destruktor.

Page 216: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Čistě virtuální metody, abstraktní třída

Čistě virtuální metoda Deklarována bez definování těla Je možné ji volat Tělo bude doplněno později u potomka

Abstraktní třída Třída obsahující nějaké čistě virtuální metody (přímo či v předcích), jejichž tělo

ještě nebylo definováno... Takovou třídu nelze instanciovat Lze používat ukazatele na tuto třídu a vyvolávat metody této třídy Často neobsahuje žádné datové položky

B

A

f

A

f B::f

class A {public: virtual int f() = 0;};

class B : public A {public: virtual int f() { return 9; }};

Page 217: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Čistě virtuální metody, abstraktní třída

int armada;

class vojak{ public: enum THod { vojin, desatnik, porucik, general }; vojak( THod hod = vojin) { hodnost=hod; armada++; } virtual void pal() = 0; virtual ~vojak() { armada--; }private: THod hodnost;};

class samopal {};class kalasnikov : public samopal {};

class pesak : public vojak{private: samopal* sam;public: pesak( THod hod=vojin) : vojak( hod) { sam = new kalasnikov; } virtual void pal() { sam->pal(); } virtual ~pesak() { delete sam; }};

pure virtual function

abstraktní třídaspolečné rozhraní

Nutný virtuální destruktor

abstraktní třída nelze vytvořit

objektspolečný předek

Page 218: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Statická data

class A {private: int x; static int c; static char* dny[]; static const int MAX = 100;public: int f() { return x + c + MAX; }};

int A::c;const char* A::dny[] = { "Po", "Ut", ... };

A a;a.f();

Statická data class variables (proměnné třídy)

pouze jedna kopie bez ohledu na počet instancí

objekty statická data sdílejí není součástí instancí (objektů)

nutnost definice! časté použití: konstanty třídy

jednoduché konstanty nemusí mít definici strukturované konstanty mít definici musí

např. řetězce potřebuje paměť potřebuje definici

nekonstantní statická proměnná

strukturovaná statická konstanta

statická konstanta

Page 219: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Statické metody

class A {private: int x; static int y;public: int f() { return x + y; } static int g() { return y; } static int h( A* a) { return a->x; }};

A a;a.f();a.g();A::g();A::h(&a);

Statické metody nedostávají automatický parametr this

protože nepracují s žádnou konkrétní instancí

mohou přímo přistupovat pouze k statickým datům

k nestatickým datům mohou přistupovat přes specifikovaný objekt

mohou přistupovat k private položkám nemohou být virtuální lze je volat jako metody nebo jako globální

funkce a.g() A::g()

Page 220: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

class A{

int f( int a, int b);

virtual int f( int a, int b);

virtual int f( int a, int b) = 0;

static int f( int a, int b);

}

Přehled druhů metod

metodamember function

virtuální metodavirtual function

čistě virtuální metodapure-virtual function

statická metodastatic member

function

Page 221: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Ukládací třídy (storage classes)

data globální uvnitř funkce uvnitř třídy

bez specifikace

statická alokace,export mimo modul

= auto součást každé instance třídy

auto zakázáno zásobník,případně registr

zakázáno

register zakázáno zásobník,přednostně v registru

zakázáno

static statická alokace,bez exportu

statická alokace(jediná instance)

statická alokace(jediná instance), export

extern odkaz na globální definici, bez alokace

odkaz na globální definici, bez alokace

zakázáno

funkce globální uvnitř funkce uvnitř třídy

bez spec. export mimo modul zakázáno metoda - implicitní this

virtual zakázáno zakázáno virtuální metoda

static bez exportu mimo modul zakázáno bez this, export

Page 222: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Ochrana přístupu

Položky tříd jsou z hlediska ochrany přístupu rozděleny na public: veřejně přístupné položky protected: položky přístupné metodám třídy a metodám tříd

odvozených private: položky přístupné pouze metodám této třídy

Implicitní nastavení class: private struct, union: public

Při dědění je možno přístupová práva dále omezit public inheritance: práva zůstávají beze změn private inheritance: všechny položky předka jsou v nové třídě

privátní

jediný rozdíl mezi struct a class

Page 223: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

private inheritance

public inheritance - Is-A potomek JE vše, co předek

private inheritace potomek NENÍ vše, co předek

metody předka jsou private ..... co to teda je???

class Osoba { void jist(); };class Student : public Osoba { void studovat(); };Osoba o;Student s;s.jist(); // Student JE Osoba// o.studovat(); // Osoba NENÍ Student

class Osoba { void jist(); };class Student : Osoba { void studovat(); };Osoba o;Student s;// s.jist(); // Student NENÍ Osoba// o.studovat(); // Osoba NENÍ Student

Page 224: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

private inheritance

private inheritace ' is-implemented-in-terms-of ' odvozená třída může využít kód základní třídy dědičnost implementace, nikoliv rozhraní položka třídy (containment, layering) vs. private inheritance

vždy, pokud to lze, používejte containment private inheritance používejte pokud to jinak nelze

class A { f(); };class B : private A{public: g() { A::f(); }};

class A { f(); };class B{private: A a;public: g() { a.f(); }};

Page 225: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

private inheritance & protected

úkol: obecný zásobník, zásobníky konkrétních typů, ochrana

nevýhody: neexistuje ochrana, kdokoliv může přistupovat k Stack a void*

class Stack { // implem. classpublic: Stack(); ~Stack(); void push( void* object); void* pop();private: struct Node { void* data; Node* next; }; Node* top; Stack( const Stack&); Stack operator=( const Stack&);};

class IntStack { // interface classpublic: void push( int* p) { s.push(p); } int* pop() { return (int*)s.pop(); }private: Stack s;};

class Slon {};class SlonStack {public: void push( Slon* p) { s.push(p); } Slon* pop() { return (Slon*)s.pop(); }private: Stack s;};

Page 226: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

private inheritance & protected

private inheritace, protected constructors & methods

výhody: Stack nelze zkonstruovat ani volat jeho metody každý musí použít iterface class

class Stack {protected: Stack(); ~Stack(); void push( void* object); void* pop();private: ....};

class IntStack : private Stack {public: void push( int* p) { Stack::push(p); } int* pop() { return (int*)Stack::pop(); }};

class Slon {};class SlonStack : private Stack {public: void push( Slon* p) {push(p); } Slon* pop() { return (Slon*)Stack::pop(); }};

Page 227: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Spřátelené funkce a třídy - friend

class X {private: int x;public: friend class Y; friend int patchX( X& x);};

class Y { int patchX( X& x) { return x.x = 1; }};

int patchX( X& x){ return x.x = -1;}

friend funkce a třídy možnost přístupu k private položkám třídy možno použít na třídy nebo funkce nepříliš bezpečné - pokud možno nepoužívat

friend funkce nebo třída závisí na implementaci třídy ... a když už používat, tak jen v dobře odůvodněných případech

např. operator overloading

spřátelená třída

spřátelená funkce

Pozor! Nejde o metodu X!

Page 228: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Symetrický operátor - metoda

class complx {private: int re, im;public: complx( int _re = 0, int _im = 0)

{ re = _re; im = _im; } complx operator+( const complx& b) const

{ return complx( re + b.re, im + b.im); }};

complx x(1,2);complx y;

y = x + 1;// y = 1 + x; error: binary '+' : no global operator found

konverze:konstruktor cmplx(1,0)

Page 229: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Symetrický operátor - globální funkce

class complx {private: int re, im;public: complx( int _re = 0, int _im = 0)

{ re = _re; im = _im; } friend complx operator+( const complx& a, const complx& b)

{ return complx( a.re + b.re, a.im + b.im); }};

complx x(1,2);complx y;

y = x + 1;y = 1 + x;

Symetrické operátory je vhodné implementovat jeko friend globální funkce

Page 230: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Konverzní operátor

class complx {private: int re, im;public: complx( int _re = 0, int _im = 0) { re = _re; im = _im; } operator int() { return (re + im) / 2; }};

complx x(3); // complx( 3, 0);int i(x); // complx::operator int()

uživatelsky definovaná konverze jednoho typu na jiný syntaxe: operator <typ>();

operator int(); operator char*(); nemá žádné parametry

konvertovanou hodnotou je objekt, na který je operátor vyvolán nemá návratový typ

typ je jednoznačně určen samotným operátorem užitečné např. pro kombinaci C a C++ kódu

string vs. char*

Page 231: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Konverzní operátor

class complx {private: int re, im;public: complx( int _re = 0, int _im = 0) { re = _re; im = _im; } friend complx operator+( const complx& a, const complx& b)

{ return complx( a.re + b.re, a.im + b.im); } operator int() { return (re + im) / 2; }};

complx x(1,2);x = x + 1; // error: more similar conversions

Pozor! Konverzní operátory mohou kolidovat s jinými způsoby konverze konverzní konstruktory, integrální promoce, built-in operátory ... používat s rozmyslem!

complx::complx( int _re, int = 0)complx operator +(const complx &,const complx &)

complx::operator int()operator+(int, int)

Page 232: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Prostory jmen (namespaces)

namespace aa { int p; int f1( int x) { return x + p; }}

namespace aa { void f2( int x, int y);}

using namespace std;int aa::f2( int x, int y){ cout << p * (x + y);}

using aa::f2;aa::f1( f2( 5, 6));

zapouzdření identifikátorůprevence kolizí (velké projekty, knihovny)stejné identifikátory v různých prostorech jmenprostor jmen se může opakovaně otevírat a zavíratstandardní knihovny – namespace std

definice prostoru jmen

přístup ze stejného prostoru

definice funkce mimo prostor jmen

direktiva using - rozbalení std

znovuotevření prostoru aa

deklarace using - pouze ident.

Později:argument dependent lookup Koenig lookup

Page 233: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Příklad - polymorfní datové struktury

Zadání: kontejner obsahující čísla libovolného typu (int, double, řetězec,

complex, ...)

Technické upřesnění: třída Seznam operace append, print společný předek prvků AbstractNum konkrétní prvky IntNum, DoubleNum, ... stačí jednoduchá implementace polem pole objektů vs. pole odkazů

INxAN DN

dAN INxAN

S

Page 234: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Polymorfní datové struktury - kostra tříd

class Seznam {public: void append( AbstractNum *p); void print(); Seznam(); ~Seznam(); private: enum { MAX = 100 }; AbstractNum* pole[MAX]; int n;};

int main(int argc, char** argv){ Seznam s; s.append( new .... ); s.append( new .... ); s.append( new .... ); s.print(); return 0;}

class AbstractNum {public: virtual void print()=0; virtual ~AbstractNum() {}};

abstraktní předekumí existovat a vytisknout

se

virtuální destruktor!

přidávání dynamicky vytvořených konkrétních

typů

Page 235: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Polymorfní datové struktury - implementace metod

class Seznam {public: void append( AbstractNum *p); void print(); Seznam(); ~Seznam(); private: enum { MAX = 100 }; AbstractNum* pole[MAX]; int n;};

// konstruktorSeznam::Seznam(){ for(int i=0; i<MAX; ++i) pole[i]=0; n=0;}// destruktorSeznam::~Seznam(){ for(int i=0; i<n; ++i) delete pole[i]; n=0;}// tisk seznamuvoid Seznam::print(){ for(int i=0; i<n; ++i) pole[i]->print();}// pridani prvku do seznamuvoid Seznam::append(AbstractNum* p){ if (n<MAX) pole[n++]=p;}

každý prvek ví jak se vytisknout

Page 236: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Polymorfní datové struktury - konkrétní datové typy

class IntNum : public AbstractNum {public: IntNum(int x_) { x=x_; } virtual ~IntNum() {} virtual void print() { printf("%d ",x); }private: int x;};

class IntDouble : public AbstractNum {public: IntDouble(double d_) { d=d_; } virtual ~IntDouble() {} virtual void print() { printf("%f ",d); }private: double d;};

Seznam s;s.append(new IntNum(234));s.append(new DoubleNum(1.45));s.append(new IntNum(67));s.print();

konkrétní datové typyimplementují vlastní metody jednotného

rozhraní

kontejner obsahuje různé typy

... a všechny vytiskne

konkrétní datové typyimplementují vlastní metody jednotného

rozhraní

Page 237: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Polymorfní datové struktury - konstruktor const položek

class IntNum : public AbstractNum {public: IntNum(int x_) { x=x_; }private: const int x;};

Požadavek: co když chci zakázat měnit hodnotu prvků

compiler error: x must be initialized in

constructor base / member initializer list

class IntNum : public AbstractNum {public: IntNum(int x_) : x(x_) {}private: const int x;}; seznam inicializátorů

používejte všude, kde to lze

Page 238: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Polymorfní datové struktury - přiřazení

int main(int argc, char** argv){ Seznam s, s2; s.append(new IntNum(234)); s.append(new DoubleNum(1.45)); s.append(new IntNum(67)); s.print(); s2 = s; return 0;}

Problém: přiřazení seznamů

Je to korektní kód?

Page 239: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Polymorfní datové struktury - přiřazení

Problém: přiřazení seznamů

Spadne to! Kde?

v destruktoru ~Seznam Proč? Navíc:

memory leaks

int main(int argc, char** argv){ Seznam s, s2; s.append(new IntNum(234)); s.append(new DoubleNum(1.45)); s.append(new IntNum(67)); s.print(); s2 = s; return 0;}

Tady!

problém je v s2 = s; v Seznam není operator=kompilátor si ho vyrobí automatickyokopíruje datové položky a ukazatele !!!destruktor s2 dealokuje prvkydestruktor s znovu odalokuje prvkybloky už ale neexistují !

Page 240: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Polymorfní datové struktury - přiřazení

Možné řešení: zakázání přiřazení

class Seznam {public: void append( AbstractNum *p); void print(); Seznam(); ~Seznam(); private: Seznam& operator=(const Seznam&); enum { MAX = 100 }; AbstractNum* pole[MAX]; int n;};

operator= v sekci privateznemožní přiřazení

seznamů

stačí pouze deklarace (bez těla)

nikdo ho nemůže zavolat

je to už teď konečně korektní ??

Page 241: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Polymorfní datové struktury - copy konstruktor

Není! copy konstruktor!

class Seznam {public: void append( AbstractNum *p); void print(); Seznam(); ~Seznam(); private: Seznam& operator=(const Seznam&); Seznam(const Seznam&); enum { MAX = 100 }; AbstractNum* pole[MAX]; int n;};

je to už teď konečně korektní ??

int main(int argc, char** argv){ Seznam s; s.append(new IntNum(234)); s.append(new DoubleNum(1.45)); s.append(new IntNum(67)); s.print(); Seznam s2 = s; return 0;}

oprator= a copy konstruktorby se měly chovat stejně!

Page 242: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Polymorfní datové struktury - přiřazení

Pokud chceme dovolit přiřazení (kopírování), je nutné si ujasnit logiku

má nebo nemá se změna projevit i v druhém seznamu? kopie hodnot (alespoň logická) nebo jen kopie datové struktury? typicky: chování takové, jako kdyby se okopírovaly všechny prvky

U každé třídy obsahující odkazy na dynamicky alokovaná data buď zakázat přiřazení

operator= a copy konstruktor do sekce private nebo nadefinovat kopírování

napsat vlastní duplikaci VŽDY napsat hlavičku operatoru = a copy konstruktoru!

Seznam a, b;....b = a;a[1]->x = 999; // b[1]->x ???

Page 243: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Polymorfní datové struktury - kopie prvků

class Seznam {public: void append( AbstractNum *p); void print(); Seznam(); ~Seznam(); Seznam& operator=(const Seznam&);private: enum { MAX = 100 }; AbstractNum* pole[MAX]; int n;};

je to správně ??

Seznam& Seznam::operator=( const Seznam& s){ for(int i=0; i<s.n; ++i) pole[i] = s.pole[i]; n = s.n; return *this}

okopíruji všechny prvky

Page 244: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Polymorfní datové struktury - úklid starého stavu

Je to správně? Není !!

nezruší se předchozí odkazy! memory leaks

je to už teď správně ??

Seznam& Seznam::operator=( const Seznam& s){ for(int i=0; i<n; ++i) // jako v destruktoru delete pole[i]; for(int i=0; i<s.n; ++i) // jako v copy konstr. pole[i] = s.pole[i]; n = s.n; return *this}

nejdříve zruším všechny prvky cílového kontejneru

Page 245: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Polymorfní datové struktury - generování nových prvků

Je to už teď správně? Není !!

okopírují se pouze ukazatele data zůstanou stejná prakticky totéž, jako kdybychom nechali automaticky vygenerovaný operator =

musíme vygenerovat nové prvky

je to už teď správně ??

Seznam& Seznam::operator=( const Seznam& s){ for(int i=0; i<n; ++i) delete pole[i]; for(int i=0; i<s.n; ++i) pole[i] = new AbstractNum( *s.pole[i]); n = s.n; return *this}

dynamická alokace nového prvku

přímá konverze odvozené třídy na AbstractNum&

Page 246: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Polymorfní datové struktury - zrušení abstraktnosti

Je to už teď správně? Není !!

AbstractNum je abstraktní třída nelze instanciovat (vytvořit objekt) neprojde kompilátorem

je to už teď správně ??

Seznam& Seznam::operator=( const Seznam& s){ for(int i=0; i<n; ++i) delete pole[i]; for(int i=0; i<s.n; ++i) pole[i] = new AbstractNum( *s.pole[i]); n = s.n; return *this}

class AbstractNum {public: virtual void print() {}; virtual ~AbstractNum() {}};

psychicky zdeptaný programátor:

tak tu abstraktnost odstraníme!

Page 247: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Je to už teď správně? Není !!

vytvoří se pouze část objektu - společný předek mnohem horší chyba než předchozí případ projde kompilátorem, nespadne, ale dělá nesmysly! slicing

Co s tím? když je skutečná hodnota IntNum - vytvořit IntNum když je skutečná hodnota DoubleNum - vytvořit doubleNum

Polymorfní datové struktury - vytvoření správných typů

INxAN

AN

class AbstractNum {public: enum T { T_INT, T_DOUBLE, ...}; virtual T get_t() const; virtual void print()=0; virtual ~AbstractNum() {}};

switch( s.pole[i]->get_t()) {case AbstraktNum::T_INT: pole[i] = new IntNum(*s.pole[i]); break;...

je to už teď správně ??

Page 248: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Polymorfní datové struktury - vytvoření správných typů

Je to už teď správně? Nooo..... dělá to to, co má, ale ...

je to ošklivé - těžko rozšiřitelné přidání nového typu vyžaduje zásah do implementace společného předka!

navíc syntaktická chyba předka nelze automaticky konvertovat na potomka new IntNum(*s.pole[i]) - skutečný parametr typu AbstractNum&

konverze new IntNum(* (IntNum*) s.pole[i]) new IntNum( (IntNum&) *s.pole[i])

Jak to udělat lépe? využít mechanismus pozdní vazby každý prvek bude umět naklonovat sám sebe rozhraní v AbstractNum, implementace v IntNum, DoubleNum, ... virtuální klonovací metoda

Page 249: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Polymorfní datové struktury - klonování

class AbstractNum {public: virtual AbstractNum* clone() const =0; virtual void print()=0; virtual ~AbstractNum() {}};

je to už teď správně ??

class IntNum : public AbstractNum {public: virtual AbstractNum* clone() const { return new IntNum(*this); } IntNum(int x_) : x(x_) {}private: const int x;};

Seznam& Seznam::operator=( const Seznam& s){ ... for(int i=0; i<s.n; ++i) pole[i] = s.pole[i]->clone(); ...

jednotné rozhranína klonovací funkce

musí být typu AbstractNum*jinak by to nebyla stejná virt.

metoda

IntNum

AbstractNum

případné posunutí ukazatelů řeší automaticky mechanismus virt.

funkcí

INxAN

Page 250: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

Polymorfní datové struktury - přiřazení sebe sama

Je to už teď správně? Pořád není !!!!

co když někdo provede s = s ? takhle blbě to asi nikdo nenapíše, ale ... Seznam p[100]; p[i] = p[j];

nejprve se zruší všechny prvky ... a pak se kopírují dealokované bloky!!!

ani vynulování ukazatelů moc nepomůže neokopírovalo by se nic

nutná ochrana!

je to už teď správně ??

Seznam& Seznam::operator=( const Seznam& s){ if( this == &b) return *this; ...

rovnost ukazatelů stejný objekt

this &s

Page 251: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

... to be continued

Jazyk member pointers .* a ->*, true / contractual const, mutable static_cast, dynamic_cast, reinterpret_cast, const_cast funktory výjimky, try, catch, throw, exception safety šablony, explicitní instanciace, parciální specializace, traits & policy classes Koenigovo vyhledávání RTTI, typeid, type_info

Knihovny streams (proudy) STL – kontejnery, iterátory, algoritmy auto_ptr

OOP kánonické formy tříd, abstraktní datové typy, polymorfní typy counted pointers, mělké vs. hluboké kopie návrhové vzory (design patterns) – zprávy, obálkové třídy, forwarding, ... hlouběji o objektovém návrhu, reusabilitě, efektivitě implementace

Page 252: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

101 mouderOrganizational and Policy Issues 0. Don’t sweat the small stuff. (Or: Know what not to standardize.) 1. Compile cleanly at high warning levels. 2. Use an automated build system. 3. Use a version control system. 4. Invest in code reviews. Design Style5. Give one entity one cohesive responsibility. 6. Correctness, simplicity, and clarity come first. 7. Know when and how to code for scalability. 8. Don’t optimize prematurely. 9. Don’t pessimize prematurely. 10. Minimize global and shared data. 11. Hide information. 12. Know when and how to code for concurrency. 13. Ensure resources are owned by objects. Use explicit RAII and smart pointers. Coding Style14. Prefer compile- and link-time errors to run-time errors. 15. Use const proactively. 16. Avoid macros. 17. Avoid magic numbers. 18. Declare variables as locally as possible. 19. Always initialize variables. 20. Avoid long functions. Avoid deep nesting. 21. Avoid initialization dependencies across compilation units. 22. Minimize definitional dependencies. Avoid cyclic dependencies. 23. Make header files self-sufficient. 24. Always write internal #include guards. Never write external #include guards.

Sutter, Alexandrescu:C++ 101 programovacích

technik (C++ Coding Standards)

Page 253: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

101 mouder

Functions and Operators 25. Take parameters appropriately by value, (smart) pointer, or reference. 26. Preserve natural semantics for overloaded operators. 27. Prefer the canonical forms of arithmetic and assignment operators. 28. Prefer the canonical form of ++ and --. Prefer calling the prefix forms. 29. Consider overloading to avoid implicit type conversions. 30. Avoid overloading &&, ||, or , (comma) . 31. Don’t write code that depends on the order of evaluation of function arguments. Class Design and Inheritance32. Be clear what kind of class you’re writing. 33. Prefer minimal classes to monolithic classes. 34. Prefer composition to inheritance. 35. Avoid inheriting from classes that were not designed to be base classes. 36. Prefer providing abstract interfaces. 37. Public inheritance is substitutability. Inherit, not to reuse, but to be reused. 38. Practice safe overriding. 39. Consider making virtual functions nonpublic, and public functions nonvirtual. 40. Avoid providing implicit conversions. 41. Make data members private, except in behaviorless aggregates (C-style structs). 42. Don’t give away your internals. 43. Pimpl judiciously. 44. Prefer writing nonmember nonfriend functions. 45. Always provide new and delete together. 46. If you provide any class-specific new, provide all of the standard forms (plain, in-place, and nothrow).

Page 254: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

101 mouderConstruction, Destruction, and Copying47. Define and initialize member variables in the same order. 48. Prefer initialization to assignment in constructors. 49. Avoid calling virtual functions in constructors and destructors. 50. Make base class destructors public and virtual, or protected and nonvirtual. 51. Destructors, deallocation, and swap never fail. 52. Copy and destroy consistently. 53. Explicitly enable or disable copying. 54. Avoid slicing. Consider Clone instead of copying in base classes. 55. Prefer the canonical form of assignment. 56. Whenever it makes sense, provide a no-fail swap (and provide it correctly). Namespaces and Modules57. Keep a type and its nonmember function interface in the same namespace. 58. Keep types and functions in separate namespaces unless they’re specifically intended to work together. 59. Don’t write namespace usings in a header file or before an #include. 60. Avoid allocating and deallocating memory in different modules. 61. Don’t define entities with linkage in a header file. 62. Don’t allow exceptions to propagate across module boundaries. 63. Use sufficiently portable types in a module’s interface. Templates and Genericity64. Blend static and dynamic polymorphism judiciously. 65. Customize intentionally and explicitly. 66. Don’t specialize function templates. 67. Don’t write unintentionally nongeneric code. Error Handling and Exceptions68. Assert liberally to document internal assumptions and invariants.69. Establish a rational error handling policy, and follow it strictly. 70. Distinguish between errors and non-errors. 71. Design and write error-safe code. 72. Prefer to use exceptions to report errors. 73. Throw by value, catch by reference. 74. Report, handle, and translate errors appropriately. 75. Avoid exception specifications.

Page 255: PRG029         Programov ání v  C a  C++ ( LS  200 5 /0 6 )

101 mouderSTL: Containers76. Use vector by default. Otherwise, choose an appropriate container. 77. Use vector and string instead of arrays. 78. Use vector (and string::c_str) to exchange data with non-C++ APIs. 79. Store only values and smart pointers in containers. 80. Prefer push_back to other ways of expanding a sequence. 81. Prefer range operations to single-element operations. 82. Use the accepted idioms to really shrink capacity and really erase elements. STL: Algorithms83. Use a checked STL implementation. 84. Prefer algorithm calls to handwritten loops. 85. Use the right STL search algorithm. 86. Use the right STL sort algorithm. 87. Make predicates pure functions. 88. Prefer function objects over functions as algorithm and comparer arguments. 89. Write function objects correctly. Type Safety90. Avoid type switching; prefer polymorphism. 91. Rely on types, not on representations. 92. Avoid using reinterpret_cast. 93. Avoid using static_cast on pointers. 94. Avoid casting away const. 95. Don’t use C-style casts. 96. Don’t memcpy or memcmp non-PODs. 97. Don’t use unions to reinterpret representation. 98. Don’t use varargs (ellipsis). 99. Don’t use invalid objects. Don’t use unsafe functions. 100. Don’t treat arrays polymorphically.


Recommended