C++ kialakulása
Programozás alapjai II. (1. ea) C++
Veszélyforrások csökkentése
Objektum orientált szemlélet
C+ javítások
C++ kialakulása, nem OO újdonságok:
OOP elemek
Szeberényi Imre BME IIT
C++
<
[email protected]>
A fejlődés során jelentős kölcsönhatások voltak a C és a C++ között
M Ű E GY E T E M 1 7 82 C++ programozási nyelv
© BME-IIT Sz.I.
2017.02.07.
- 1C++ programozási nyelv © BME-IIT Sz.I.
C és C++változatai
C és C++ viszonya
C++03 C++
preprocesszor
C w. classes
preprocesszor buta C C könyvtár
C++11
C++98
1979
1985
1990
C++0x 1998
2003
C++14 2010 2011
okos C 1972
C könyvtár
C++ könyvtár
1978
C K&R C
C++ programozási nyelv © BME-IIT Sz.I.
2017.02.07.
- 3-
1989
198 3
2007
C99
ANSI C
C++ programozási nyelv © BME-IIT Sz.I.
C1X
2017.02.07.
- 4-
C99 • változók és a kód keverése (for fejében is)
• A tárgy a 2003-ban elfogadott C++ nyelvet használja az OO paradigmák bemutatásához eszközként. • Ezt tanítja és ezt kéri számon, de lehet az újabb változatok elemeit használni háziban, zh-ban.
for (int i = 1; i < 12; i++) ….
• // comment, const, enum, inline • változó hosszúságú tömb (függvényben) void f(int b) { int c[b]; // változó méretű tömb }
• A teljes C++11 azonban lényegesen bonyolultabb, amit másik tárgy keretében lehet megismerni. • Bjarne Stroustrup: „C++11 feels like a new language”
• új típusok (pl. long long, double _Complex) • Pontosabb specifikáció pl: -3/5 = 0 -3%5= -3 // C89-ben lehetne -1 és +2
http://www.stroustrup.com/C++11FAQ.html
2017.02.07.
1999
C90
C++11, C++14, C++17?
C++ programozási nyelv © BME-IIT Sz.I.
- 2-
2017.02.07.
- 5-
C++ programozási nyelv © BME-IIT Sz.I.
2017.02.07.
- 6-
Általános kódolási tanácsok (ism)
Mi történik, ha x > 2.3 ?
• Olvasható legyen a kód, ne trükkös! • Mellékhatásoktól tartózkodni! • Nem triviális szintaxist kerülni, akkor is, ha a C nyelv szerint az egyértelmű (a+++b) • Nem feltétlenül kell haragudni a break-re és a continue-ra! Óra végén látni fogjuk, hogy C++-ban még a „goto”-t is gyakran használjuk (bár nem így hívjuk).
C++ programozási nyelv © BME-IIT Sz.I.
while (i < 12 && q != 0 && k > 87 && u < 3) { ................................... if (x > 2.3) q = 0; .................................. } while (i < 12 && k > 87 && u < 3) { ................................... if (x > 2.3) break; ................................... } - 7-
2017.02.07.
C++ programozási nyelv © BME-IIT Sz.I.
Általános kódolási tanácsok/2
2017.02.07.
- 8-
Általános kódolási tanácsok/2
• Makrókat kerüljük, ha lehet #define MAX(a,b) a > b ? a : b int a1 = 1; int x = MAX(a1&7, 3); // x = ???
• Memória foglalás: ki foglal és ki szabadít? char *valami(char *); // lefoglal? Mit csinál? • Ha foglal, kinek kell felszabadítani ? • Oda kell írni kommentbe! • Összetartozó adatok struktúrába • Konstansok, enum • Style guide betartása (pl. google-styleguide)
#define MAX(a,b) (a) > (b) ? a : b
http://google-styleguide.googlecode.com/svn/trunk/cppguide.html
A lényeg a következetességen van! C++ programozási nyelv © BME-IIT Sz.I.
- 9-
2017.02.07.
C++ programozási nyelv © BME-IIT Sz.I.
C++ újdonságok, bővítések
2017.02.07.
- 10 -
Típusok
• Struktúranév típussá válik • Csak preprocesszorral megoldható dolgok nyelvi szintre emelése (const, enum, inline) • Kötelező prototípus, névterek • Referencia, cím szerinti paraméterátadás • Többarcú függvények (overload) • Alapértelmezésű (default) argumentumok • Dinamikus memória nyelvi szint. (new, delete) • Változó definíció bárhol C++ programozási nyelv © BME-IIT Sz.I.
2017.02.07.
- 11 -
• • • • • • • •
logikai char egész felsorolás valós mutató referencia void
integrális aritmetikai
• összetett adatszerkezetek (tömb struktúra) és osztályok
skalár
C++ programozási nyelv © BME-IIT Sz.I.
2017.02.07.
- 12 -
Aritmetikai és logikai konverzió
Logikai típus (új típus) bool false true aritmetikai bool automatikus típuskonverzió, ahogyan a C-ben megszoktuk.
Aritmetikai típus értékkészlete
bool
0 = hamis, a többi = igaz
0 vagy 1
bool b1, b2, b3; int i; b1 = true; b2 = 3; i = b2; b3 = false; (b2 == true, i == 1) C++ programozási nyelv © BME-IIT Sz.I.
2017.02.07.
- 13 -
C++ programozási nyelv © BME-IIT Sz.I.
Struktúra név típussá válik struct Komplex { float re; float im; }; srtruct Lista_elem { int i; Lista_elem *kov; }; C++ programozási nyelv © BME-IIT Sz.I.
- 14 -
Konstans (ism) #define PI 3.14 helyett const float PI = 3.14;
C++-ban a név típus értékű
const: Típusmódosító amely megtiltja az objektum átírását (fordító nem engedi, hogy balértékként szerepeljen)
önhivatkozó struktúránál kényelmes
Mutatók esetén: const char * p; //p által címzett terület nem módosítható char const * p; // ua. char * const q; //q-t nem lehet megváltoztatni
2017.02.07.
- 15 -
Két trükkös próbálkozás
C++ programozási nyelv © BME-IIT Sz.I.
2017.02.07.
- 16 -
Felsorolás típus (szigorúbb lett) enum Szinek { típus piros, sarga, zold = 4 }; Szigorúbb ellenőrzés, mint az ANSI C-ben. Pl:
const int x = 3; int *px = &x; *px = 4;
fordítási hiba
void f(int *i) { *i = 4; } const int x = 3; f(&x);
C++ programozási nyelv © BME-IIT Sz.I.
2017.02.07.
2017.02.07.
Szinek jelzo; jelzo = 4; jelzo = Szinek(8); - 17 -
C++ programozási nyelv © BME-IIT Sz.I.
nincs hiba, de meghatározatlan érték létrehozása 2017.02.07.
- 18 -
Prototípus kötelező
Miért baj ha elmarad?
Előrehivatkozáskor kötelező
a függvényt hívó rész double z=sqrt(2);
Tipikus C hiba: double z = sqrt(2);
C feltételezi, hogy int
2017.02.07.
- 19 -
float-ra mutató pointer
C++ programozási nyelv © BME-IIT Sz.I.
ip = &i; fp = &f; 2017.02.07.
C++ programozási nyelv © BME-IIT Sz.I.
C++ programozási nyelv © BME-IIT Sz.I.
- 21 -
float f;
i cime int *ip; float *fp;
Memória
C++ programozási nyelv © BME-IIT Sz.I.
2017.02.07.
- 22 -
Változó paraméter (ism.)
• A paraméterek nem változhatnak meg, mivel azok értéke adódik át. • Azok eredeti tartalma az eredeti helyen megmarad. • A függvény csak a függvényértéken keresztül tud a külvilágnak eredményt szolgáltatni. (Ez sokszor kevés.) 2017.02.07.
- 20 -
*ip = 13; 13
cím
változó
függvény fv.érték
érték fv.érték
függvény
2017.02.07.
int i;
ip = &i
Értékparaméter (ism.) változó v. konstans
double
x . . return res; ...}
Indirekció (ism.)
• Minden változó és függvény memóriában levő helye (címe) képezhető. (pl: &valtozo) • Ez a cím ún. pointerben vagy mutatóban tárolható. • A pointer egy olyan típus, amelynek az értékkészlete cím, és mindig egy meghatározott típusú objektumra mutat. int-re mutató pointer
double
regiszter
int
Mutatók és címek (ism.)
int i, *ip; float f, *fp;
verem
int
(double) kellene
C++ programozási nyelv © BME-IIT Sz.I.
a hívott függvény double sqrt(double x) {
- 23 -
• A paraméter címe adódik át, így annak tartalma felhasználható, de • meg is változtatható. • A magas szintű nyelvek elfedik ezt a trükköt. Sem az aktuális paraméterek átadásakor, sem a formális paraméterekre való hivatkozáskor nem kell jelölni. • Csupán a paraméter jellegét (változó) kell megadni.
C++ programozási nyelv © BME-IIT Sz.I.
2017.02.07.
- 24 -
Referencia (új típus)
Változó paraméter referenciával
Referencia: alternatív név tipus&
C: void inc(int *a) { (*a)++; } könnyen int x = 2; lemarad inc(&x);
int i = 1; int& r = i; // kötelező inicializálni, mert // valójában egy cím int x = r; // x = 1; r = 2; // i = 2; C++ programozási nyelv © BME-IIT Sz.I.
2017.02.07.
- 25 -
C++ programozási nyelv © BME-IIT Sz.I.
Példa: összeg és négyzetösszeg
2017.02.07.
– skalár – struct
• cím szerint (tömb, változtatni kell, hatékonyság) – típus& – típus*
• Pointer paraméter és a változtatandó paraméter szétválik. - 27 -
int x; … int& f( ) { return x; } … main( ) { f( ) = 5; f( )++; f( ) = f( ) + 2; }
struct Data { double dx[1000]; int px[2000]; } d;
C++ programozási nyelv © BME-IIT Sz.I.
C++ programozási nyelv © BME-IIT Sz.I.
2017.02.07.
- 28 -
Függvényhívás mint balérték
• Pointer, referencia + const használatával a hozzáférés jól szabályozható:
f1(Data); f2(const Data* ); f3(const Data&); f4(Data*); f5(Data&);
- 26 -
• érték szerint
Paraméterátadás /2
void void void void void
2017.02.07.
Paraméterátadás
// int ad(int a, int b, int *no)… int ad(int a, int b, int& no) { no = a*a + b*b; return a+b; } int main() { int x, y, z; y = 5; x = ad(4, y, z); } C++ programozási nyelv © BME-IIT Sz.I.
C++: void inc(int &a) { a++; nem kell } jelölni a int x = 2; címképzést híváskor inc(x);
// f1(d); értékparaméter // f2(&d); nem változhat // f3(d); nem változhat // f4(&d); változhat // f2(d); változhat
2017.02.07.
- 29 -
C++ programozási nyelv © BME-IIT Sz.I.
f() egy alternatív nevet szolgáltat!
2017.02.07.
- 30 -
Inline
Függvény overload
#define max(a,b) (a) > (b) ? a : b
x = 8, y = 1; x = max(x++, y++); x,y = ? inline int max(int a, int b) { return(a > b ? a: b); } Nincs trükk. Pontosan úgy viselkedik, mint a függvény, de a hívás helyére kell beilleszteni a kódot (lehetőleg). C++ programozási nyelv © BME-IIT Sz.I.
2017.02.07.
- 31 -
Függvény argumentumok
2017.02.07.
double f = max(1.2, 0.2);
Többarcú függvények C++ programozási nyelv © BME-IIT Sz.I.
2017.02.07.
- 32 -
– int a; float alma; – de: int fv(int x); - nem definició
• A típus nem hagyható el ! • Több deklaráció is lehet, – extern int error; – extern int error;
• Definició csak egy! - 33 -
C++ programozási nyelv © BME-IIT Sz.I.
2017.02.07.
- 34 -
Deklarációk feltételben és ciklusban if (double d = fx(y)) { cout << d; } else { d = 21.2; cout << d; }
y = 12; … int z = 3; // és egyből inicializáljuk for (int i = 0; i < 10; i++) { élettartam, hatókör z += i; u.a, mint a C-ben int k = i – 1; y *= k; i, és k itt már nem létezik ! }
2017.02.07.
double max(double a, double b) { return(a > b ? a: b); }
• A deklarációs pont továbbra is legtöbbször definició is:
Ott deklaráljunk, ahol használjuk
C++ programozási nyelv © BME-IIT Sz.I.
int x = max(1, 2);
Deklaráció és definíció
• Konvertert írunk, ami tetszőleges számrendszerbe tud konvertálni. A fv. a számrendszer alapját paraméterként kapja. char *int2Ascii(int i, int base = 10); Csak az argumentumlista végén lehetnek default argumentumok, akár több is. • f(), f(void) - nincs paraméter • f(...) - nem kell ellenőrizni • f(int a, int) - nem fogjuk használni C++ programozási nyelv © BME-IIT Sz.I.
int max(int a, int b) { return(a > b ? a: b); }
- 35 -
C++ programozási nyelv © BME-IIT Sz.I.
for (int i = 10; i--;) cout << i; while (cin >> ch) { cout << ch; }
2017.02.07.
- 36 -
Névterek, scope operátor
using direktíva
• A moduláris programozás támogatására külön névterületeket definiálhatunk. • Ez ebben levő nevekre (azonosítókra) a hatókör (scope) operátorral (::), vagy a using namespace direktívával hivatkozhatunk. namespace nevterem { int alma; float fv(int i); char *nev; }
A using namespace direktívával a teljes névteret, vagy annak egy részét láthatóvá tehetjük: using namespace nevterem; alma = 8; float f = fv(3);
nevterem::alma = 12; float f = nevterem::fv(5);
using nevterem::alma; using nevterem::fv; alma = 8; float f = fv(3); nevterem::nev = "Dr. Bubo";
using namespace nevterem; alma = 8; float f = fv(3);
C++ programozási nyelv © BME-IIT Sz.I.
2017.02.07.
- 37 -
Név nélküli névtér
- 38 -
• A névterek egymásba ágyazhatók. • Egy létező névterhez egy újabb nevet rendelhetünk (rövidítés).
namespace { // nincs neve void solveTheProblem() { …. } … } // névtér vége int main() { solveTheProblem(); …
namespace kis_nevterem { namespace belso_terem { int fontos; } } namespace bent = ::kis_nevterem::belso_terem; bent::fontos = 8;
2017.02.07.
- 39 -
C++ programozási nyelv © BME-IIT Sz.I.
Az std névtér
2017.02.07.
- 40 -
standard I/O, iostream
• Standard függvények konstansok és objektumok névtere. Ebben van standard az I/O is. • Az egyszerű példákban kinyitjuk az egész névteret az egyszerűbb írásmód miatt: using namespace std; • Komoly programokban ez nem célszerű. • Header-ben pedig soha ne tegyük! C++ programozási nyelv © BME-IIT Sz.I.
2017.02.07.
Névterek egymásba ágyazása, alias
Biztosítani akarjuk, hogy egy kódrészlet csak az adott fájlból legyen elérhető. Névütközés biztosan nem lesz.
C++ programozási nyelv © BME-IIT Sz.I.
C++ programozási nyelv © BME-IIT Sz.I.
2017.02.07.
• cin • cout • cerr
iostream, iostream.h
Az "új" változatot illik használni! (névtér, wchar_t,...)
#include
int main() { int a, b; std::cin >> a >> b; std::cout << "a+b=" << a + b << std::endl; return 0; } - 41 -
C++ programozási nyelv © BME-IIT Sz.I.
2017.02.07.
- 42 -
Miért iostream ?
Ezek új operátorok? • Nem új operatorok! A már ismert << és >> operatorok felüldefiniálása. • Az operatorok a C++ -ban függvények a függvények pedig többarcúak.
C-ben ezt írtuk: printf("i=%d j=%d\n", i, j); C++-ban ezt kell: cout << "i = " << i << " j=" << j << endl; Kinek jó ez ?
ostream& operator<<(ostream& os, int i); ostream& operator<<(ostream& os, double d); istream& operator>>(istream& is, int& i); … Részletek később!
• A printf, scanf nem biztonságos! Nem lehet ellenőrizni a paraméterek típusát. • A printf, scanf nem bővíthető új típussal. • Lehet vegyesen ? (sync_with_stdio()) C++ programozási nyelv © BME-IIT Sz.I.
2017.02.07.
- 43 -
Lanc *p; p = new Lanc; .... delete p;
2017.02.07.
- 45 -
Mi van, ha elfogy a memória ?
C++ programozási nyelv © BME-IIT Sz.I.
2017.02.07.
- 46 -
Kivételkezelés
void OutOfMem() { cerr << "Gáz van\n"; exit(1); } int main() { set_new_handler(OutOfMem); double p* = new double; .... C++ programozási nyelv © BME-IIT Sz.I.
- 44 -
C: malloc(), free(), realloc() • C++-ban is használható de csak nagyon körültekintően, ugyanis nem hívódik meg a megfelelő konstruktor ill. destruktor. Ezért inkább ne is használjuk. C++ (operátor): new, delete, new[], delete[] • Figyeljünk oda, hogy a tömböket mindig a delete[] operátorral szabadítsuk fel. C++: nincs realloc()-nak megfelelő.
Tömb: int *p; p = new int[10]; delete[] p;
C++ programozási nyelv © BME-IIT Sz.I.
2017.02.07.
Dinamikus memória /2
Dinamikus memória #include <malloc.h> .... struct Lanc *p; p = malloc(sizeof(Lanc)); if (p == NULL) .... free( p );
C++ programozási nyelv © BME-IIT Sz.I.
• Hibák kezelése gyakran nem a hiba keletkezésének helyén történik. (Legtöbbször nem tudjuk, hogy mit kell tenni. megállni, kiírni valami csúnyát, stb.) • C++ típusorientát kivételkezelése: – figyelendő kódrészlet kijelölése (try) – kivétel továbbítása (throw) – esemény lekezelése (catch)
2017.02.07.
- 47 -
C++ programozási nyelv © BME-IIT Sz.I.
2017.02.07.
- 48 -
Kivételkezelés = globális goto
Kivétel2
Kivételkezelés/2 try { ..... Kritikus művelet1 if (hiba) throw kifejezés_tip1; ..... Kritikus művelet2 if (hiba) throw kifejezés_tip2; } catch (típus1 param) { ..... Kivételkezelés1 } catch (típus2 param) { ..... Kivételkezelés2 } A hiba tetszőleges mélységben (a ... további utasítások try blokkból hívott függvények
Kivétel1
Kritikus műveletek
További műv.
C: setjmp( ) longjmp( )
belsejében) is keletkezhet. C++ programozási nyelv © BME-IIT Sz.I.
2017.02.07.
- 49 -
Kivételkezelés példa Hiba észlelése
double osztas(int y) { if (y == 0) throw "Osztas nullaval"; return((5.0/y); }
- 50 -
#include using namespace std; // csak az egyszerűbb írás miatt int main() { long db = 0; try { while(true) { double *p = new double[1022]; db++; } } catch (bad_alloc) { cerr << "Gaz van" << endl; } cerr << "Ennyi new sikerult:" << db << endl; return(0); }
A típus azonosít
2017.02.07.
- 51 -
Futási példa az ural2-n ural2:~$ cp ~szebi/proga2/mem_alloc.cpp . ural2:~$ g++ -static mem_alloc.cpp -o mem_alloc ural2:~$ ( ulimit -d 24; ./mem_alloc )
# A –static azért kell, hogy a betöltésnél ne legyen szükség # extra loader-re, ami extra memóriát használ. # A zárójel azért kell, hogy új shell induljon.
C++ programozási nyelv © BME-IIT Sz.I.
2017.02.07.
Kivételkezelés a memóriára
int main() Kritikus szakasz { try { cout << "5/2 =" << osztas(2) << endl; cout << "5/0 =" << osztas(0) << endl; } catch (const char *p) { cout << p << endl; Kivétel kez. } } C++ programozási nyelv © BME-IIT Sz.I.
C++ programozási nyelv © BME-IIT Sz.I.
2017.02.07.
- 53 -
C++ programozási nyelv © BME-IIT Sz.I.
2017.02.07.
- 52 -