C++ előadás és gyakorlat
Kitlei Róbert
2008/2009 tavaszi félév
Bevezetés
A tárgy célja
- a programozási nyelvek alapfogalmainak bemutatása
- a C++ nyelven keresztül
- egy kis programozási gyakorlatszerzés
Eredet
- C
- 1978: Kernighan/Ritchie
- 1989, 1990: ANSI és ISO szabvány
- 1999: jelenlegi szabvány
- új szabványtervezet: C1x
- Simula
- 1967: Dahl, Nygaard
- objektum-elvűség
Történet
- C with Classes
- C++
- 1983: Bjarne Stroustrup
- 1989: C++ 2.0
- 1998, 2003: ISO szabvány
Kapcsolódó nyelvek
- Java: Sun (James Gosling), 1995
- D: Walter Bright, 1999
- C#: Microsoft, 2001
- C++0x
- a C++ következő ISO szabványa
- sok újítás
- várhatóan idén véglegesítik
Milyen egy jó programnyelv?
- egyszerre vonatkoztat el a számítógéptől és az alkalmazásoktól
- jó jelölésrendszert biztosít az algoritmusok megadásához
- eszköz a programok bonyolultságának kezelésére
Miért érdemes C++-t tanulni?
- általános célú nyelv
- magas szintű nyelv
- több paradigma bemutatására alkalmas
- imperatív
- strukturált
- procedurális
- objektumorientált
- adatabsztrakció támogatása
- osztályokba sorolt objektumok
- (többszörös) öröklődési hierarchia
- generikus
Miért érdemes C++-t tanulni?
Trendek a tiobe.com oldalon: Java, C, C++, Visual Basic, PHP, C#, Python, Perl, Delphi, JavaScript
Mit nem tartalmaz a C++?
- deklaratív programozás
- funkcionális programozás
- Lisp: John McCarthy, 1958
- modern: Haskell, Erlang, Clean, OCaML, Scheme,
- logikai programozás
- Prolog: Alain Colmerauer, 1972
- párhuzamosság nyelvi támogatása
- könyvtárak, pl.
PVM
, MPI
, pthreads
- C++0x: nyelvi szintű támogatás
- aspektusorientált programozás
Tervezési szempontok
- általános célú programnyelv
- a Simula osztályainak átvétele
- erős típusosság
- hatékony futási idejű kód generálása
- fordítási egységek könnyű összeszerkeszthetősége
- hordozhatóság
- könnyű legyen a fordítóprogramot átvinni más platformra
- a lefordított program minden platformon azonos működésű legyen
Interpreter és fordítóprogram
- interpreter: egy utasítás lefordítása után azonnal végrehajtja azt
- fordítóprogram (compiler): átalakítja a programot egy vele ekvivalens formára
- a számítógép által közvetlenül végrehajtható kódra (gépi kódra) vagy
- egy másik, alacsonyabb szintű programozási nyelvre
- a C++ szinte kizárólag fordított nyelv
Előnyök, hátrányok
- interpreter
- közvetlenebb a kapcsolat a programozó és a program között
- gyorsabb, egyszerűbb visszajelzés
- általában kísérletezésre (pl. fejlesztésre) használható
- gyakran pontosabb üzenetek a futási hibákról
- lefordított programok
- hatékonyabban futnak
- egyszer kell fordítani, sokszor lehet futtatni
- az ellenőrzéseket csak egyszer kell megcsinálni
- lehet optimalizálni
Virtuális gép (virtual machine)
- virtuális gép: olyan interpreter, amely ún. bájtkódot értelmez
- a forráskódot előzőleg le kell fordítani bájtkódra
- a bájtkód minden olyan gépen futtatható, ahol a virtuális gép implementálva van
- a bájtkódot tovább lehet fordítani gépi kódra
- futási idejű fordítás (just-in-time compilation): a bájtkód futási időben soron következő részének gépi kódra fordítása
- pl. Java VM, .NET környezet
Előfordító
- egy fordítási egység több fájlból is állhat
- előfordító (preprocessor): a tényleges fordítóprogram futása előtt szövegesen átalakítja a forráskódot
#include
direktíva: fejállomány szöveges beillesztése- sztenderd könyvtárak: kiterjesztés nélkül
- saját fejléc fájlok: elérési úttal, kiterjesztéssel
#include <iostream>
#include "sajat.h"
Előfordító
- fejléc fájl állomány-őrszeme (header guard)
- ugyanazt a fejállományt több
#include
is beillesztheti - a többszörös beillesztés problémát okozhat
- kivédése: szintén az előfordító felhasználásával
#ifndef __SAJAT_H_
#define __SAJAT_H_
#endif
Előfordító
- az előfordító számos más feladatra is használható
- makrók feldolgozása: szöveges helyettesítések
- feltételes fordítás: kódrészletek beillesztése és eltávolítása
- az előfordító nem értelmezi a forrásszöveget
- a nyelv eszközei általában biztonságosabb megoldásokat kínálnak
- célszerű minél kevesebb feladatra az előfordítót használni
A fordítás menete
g++ verem.cpp verem.h -c ⇒ verem.o
g++ verem.o foprogram.cpp ⇒ a.out
A fordítás menete
Fordítási idő
- az az idő, amikor a programkód fordítása folyik
- ez a fordítóprogram futási ideje
- kimenete: tárgykód (object code)
- a program gépi kódjának részleteiből áll
- gépi kód (machine code): a processzor által közvetlenül végrehajtott kód
A fordítás menete
Szerkesztési idő
- a futtatható állomány előállítása a lefordított kódrészletekből
- az összes forrásfájl lefordítása utáni fázis
- eszköz: szerkesztő (linker)
- általában a fordítóprogramba bele van építve
Futási idő (runtime): az az idő, amikor a program utasításainak végrehajtása folyik
Szerkesztés
- statikus szerkesztés (static linking): általában csak a fordítás utolsó szakaszában történik a program összeszerkesztése
- dinamikus szerkesztés (dynamic linking): néha szükség van további szerkesztésre futási időben
- nem feltétlenül futtatható programot állít elő a fordító (Java)
- szükség lehet dinamikus kódbetöltésre (dinamikus könyvtárak, plugin-ek)
Szerkesztés
- statikus
- csak egyszer kell szerkeszteni, nem minden futtatáskor
- dinamikus
- nagy könyvtárak megoszthatók a programok között
- kisebb méretű futtatott programok
- csak az szerkesztődik be, amire szükség van
- a végrehajtási idő terhére történik
- verziókhoz könnyebben alkalmazkodó program
- hot swapping vagy hot plugging: a program komponenseinek futás közbeni cseréje
- futási hibát okoz, ha nem található vagy rossz verziójú a betöltendő
A g++ fordítóprogram
- a
g++
program tartalmazza a fordítás minden fázisának programját- alapesetben megpróbálja futtatható állománnyá fordítani a kódot
- különböző kapcsolókkal meg lehet állítani egy-egy fázis után:
-E
-S
-c
- további fontos kapcsolók
- optimalizálás:
-O
x- x minél nagyobb, annál jobban optimalizál
- figyelmeztetések:
-Wall -Wextra -pedantic
- legalább az első kettő mindig javasolt
man g++
További fejlesztői eszközök
- statikus hibaelemző
- a programszöveget elemzi
- sokfajta hibát képes kiszűrni
- pl. cppcheck
- hibakereső (debugger)
- a program futásának követésére
- pl. gdb
- fejlesztői környezet (IDE)
- syntax highlighting
- kódkiegészítés
- program szerkezetének ábrázolása
- hibakereső
- pl. Code::Blocks
A program futtatása
- a program betöltődik a memóriába
- nem biztos, hogy fordításkor ismert, hová töltődik be
- relatív címek feloldása (relokáció): a programkód betöltési címtől függő részeinek frissítése
- tényleges programvégrehajtás
- virtuális gép: előtte ellenőrzi a betöltött kódot
- a
main
függvény indul el
A program futásának vége
- visszatérés a main függvényből
return
utasítással- a
main
visszatérési értéke a program visszatérési értéke a rendszer felé
- a
main
függvényből tovaterjedő kivétel esetén - az
exit
vagy az abort
függvény meghívásával- a
cstdlib
fejállomány tartalmazza őket - nem minden destruktor fut le, kerülendőek
Szintaxis és szemantika
- nyelv szintaxisa: azoknak a szabályoknak az összessége, amelyek a nyelven írható összes lehetséges, formailag helyes programot (jelsorozatot) definiálják
- a szintaxis befolyásolja a programok olvashatóságát és megbízhatóságát
- nyelv szemantikája: a nyelv programjainak jelentését leíró szabályok összessége
A szabályok ellenőrzése
- a fordítóprogram végzi
- fordítási hibák
- formai
- statikus szemantikai
- futási hibák: dinamikus szemantikai hibák
- ezeket a fordítóprogram nem mindig tudja ellenőrizni
- pl. tömb túlcímzése, nullával való osztás
- a professzionális programfejlesztéshez fontos
- minél előbb derüljön ki (inkább fordításkor)
- szigorú nyelv (pl. erősen típusos)
Lexikai szerkezet
Lexikai szerkezet: a programszöveg alapelemeit írja le
- ábécé
- azonosítók
- számok
- karakterek, literálok
- elválasztó jelek
- operátorok
- tördelés
- megjegyzések
Ábécé
- csak a latin ábécé és néhány grafikus karakter
- a karakterkódolás rögzített
- kis- és nagybetű különbsége mindenhol számít
- Java, C#: minden Unicode karakter
Azonosítók
- latin ábécé betűi, aláhúzás, számjegyek
- számjeggyel nem kezdődhet
- konvenciók
azonosito_neve
Osztaly_neve
- makró, konstans:
CSUPA_NAGYBETU
- aláhúzással kezdődő azonosítókat csak speciális célokra szoktak használni
- speciális elnevezési konvenciók
Azonosítók
- kulcsszó: fenntartott jelentésű név
- előre definiált szó: gyakran használt, előzetes jelentéssel bíró név
- pl. a főprogram neve
main
- könyvtári elemek neveit sem célszerű felhasználni
min
, max
, cout
, endl
, ...
- a fordító mindig a leghosszabb karaktersorozatot ismeri fel névként
abc123
egy azonosító, nem az abc
azonosító és az 123
egész szám
Számok
Egész számok
- tízes:
3241312
- tizenhatos:
1ABCDEFh
, 0xABCDEF
nyolcas: 04512
- utótagok
Lebegőpontos számok
12.
, .34
, 12.34
- utótagok
- kitevő:
e-3
F
: floatU
: unsigned
Karakterek, szövegek
Karakterek
- a karakter kódja aposztrófok között:
'a'
- speciális karakterek: escape szekvenciák
- sorvége:
'\n'
- tabulátor:
'\t'
- perjel:
'\\'
- aposztróf:
'\''
- idézőjel:
'\"'
Literálok
- karakterek idézőjelek között:
"abc\n"
Pontosvessző
- egységek lezárása
- deklarációk
- utasítások
- osztályok
- gyakori hiba ennek a pontosvesszőnek a lehagyása
struct S
{
int f() { return i; }
int i;
};
Tördelés (indentation)
- a tördelésnek nincsen hatása a program jelentésére
- egyes konstrukciók behúzása megtévesztő lehet
if (i > 0)
j = i;
- obfuscation: szándékos olvashatatlanná tétel
- több soros:
/* ... */
- nem ágyazhatóak egymásba, az első
*/
lezárja
- egysoros:
//
- újabb nyelvekben dokumentációs komment speciális szerkezettel
Operátorok
- előre meghatározott szerkezetek
- egyes nyelvekben felvehető új operátor (C++ nyelven nem)
- néha kötelező szóközzel tagolni őket, különben mást jelentenek
int i = *p
int i = *p / *q;
int f(char*=0);
int f(char* = 0);
Adattípus szerepe
- egy fogalom konkrét ábrázolása
- a típusba egyedek vagy objektumok tartoznak
- megadja a típusba tartozó egyedekre alkalmazható műveleteket
2 / "abc"
- a fordítóprogram számára
- méret: mekkora tárhelyet foglal
- ábrázolás (reprezentáció): az adott bitminta hogyan értelmezendő
- összetett típus esetén: szerkezet
- szemantika: a műveletek jelentése
Nyelv típusozása
Nyelvek típusozási lehetőségei
- típusozás erőssége: az azonos reprezentációjú értékek szerepe egyértelmű-e minden kifejezésben
- erős típusozás (strong typing): minden kifejezéshez hozzárendelhető egy típus, és a nyelv szabályai biztosítják, hogy csak az elvárt műveleteket lehessen rá végrehajtani
- garancia: futási időben nincsen típushiba
- gyenge típusozás (weak typing): a kifejezésekben az értékekre nem biztosítható, milyen művelet hajtódik végre
- az automatikus konverziók például gyengítik a nyelvet
- a C++ általában erős típusozású, a gyengeségeit főleg a C öröksége adja
Nyelv típusozása
- statikus típusozás (static typing): fordítási idejű típusbiztosítás
- típusok kiírása alapján
- kötelezően megadott típusokkal
- típuskikövetkeztetéssel (type inference)
- leggyakrabban funkcionális nyelveken
- C++0x: változók auto minősítővel
- biztonság: az érvénytelen konstrukciók fordítási időben kiderülnek
- dinamikus típusozás (dynamic typing): futási idejű típusellenőrzés
- csak az értékeknek vannak típusai, a változóknak nincsenek
- nagyobb rugalmasság
Nyelv típusozása
Példák nyelvekre
erős | C++, Java, Haskell | Erlang |
gyenge | C, PHP | assembly |
Adattípus
Adattípus szerepe
- biztonság növelése: több hiba felderítése fordítási időben
- optimalizációs lehetőség a fordítóprogram számára
- absztrakció: a programozó megszabadítása az implementációs részletektől
- dokumentáció
Adattípusok csoportosítása
- void
- elemi típusok: logikailag felbonthatatlanok
- skalár típusok: egyetlen mennyiséget ábrázolnak
- diszkrét típusok
- felsorolási típusok
- egész
- karakter
- valós
- lebegőpontos
- fixpontos (ilyen nincsen a C++-ban)
- mutató
- C++: a tömbök is ide tartoznak
- referencia
- összetett típusok
- más nyelveken a tömbök ide tartozhatnak
- osztályok
Adattípusok csoportosítása
Felhasználói típusok: a típus értékeinek szerkezetét a felhasználó határozza meg
- felsorolási típusok
- osztályok
Beépített típusok: a nyelv által bevezetett típusok
- a fentieken kívül minden más
Void
- "ismeretlen" típus
- csak összetett típus részeként használható
- leggyakrabban: függvény visszatérési értékeként
Skalár típusok műveletei
- értékadás:
=
- egyenlő:
==
- nem egyenlő:
!=
- tárolási méret:
sizeof
Skalár típusok műveletei
- alapműveletek:
+
, -
, *
, /
- összehasonlítások:
<
, <=
, >
, >=
- diszkrét típusokra
- maradékképzés:
%
- léptetés (szorzás/osztás 2n-nel):
<<
, >>
- bitenkénti és, vagy, kizáró vagy:
&
, |
, ^
- mindegyik fenti művelethez (kivéve összehasonlítások) van társított értékadó operátor
+=
, %=
, >>=
stb.- ezek rövidítések:
x +=y
⇒ x = x + y
- a nyelv nem ellenőrzi a műveletek túlcsordulását
Skalár típusok műveletei
A bitműveletek igazságtáblái
Skalár típusok műveletei
Példák a bonyolultabb műveletekre
100 / 3 ⇒ 33
100 % 3 ⇒ 1
1 << 5 ⇒ 32
100 >> 3 ⇒ 12
12 & 10 ⇒ 8
12 | 10 ⇒ 14
12 ^ 10 ⇒ 6
1100 1100 1100
1010 1010 1010
& ---- | ---- ^ ----
1000 ⇒ 8 1110 ⇒ 14 0110 ⇒ 6
Skalár típusok műveletei
++i
- posztfix növelés/csökkentés (mellékhatásos)
i++
Egész (integer)
- típus neve:
int
- előjel-módosító:
unsigned
- alapértelmezés szerint az
int
előjeles
- hossz-módosítók:
short
, long
, long long
- a módosítók önmagukban leírva is típust jelölnek
int i;
unsigned u;
unsigned int ui;
Logikai típus (Boolean)
- típus neve:
bool
- két érték:
true
, false
- műveletek
- negáció (tagadás):
!x
- konjunkció (és):
x && y
- diszjunkció (vagy):
x || y
- automatikus konverzió egész számra
false
⇆ 0
true
↦ 1
- nem 0 egész ↦
true
1 + (2 && 3)
Karakter (character)
char
- általában egy bájton tárolja a karakter ASCII kódját
- automatikus konverzió egészre, értéke a karakterkód
wchar_t
- "széles karakter", pl. Unicode karakterek tárolására
Lebegőpontos (floating point)
float
: egyszeres pontosságúdouble
: kétszeres pontosságúlong double
: kiterjesztett pontosságú
float f = -1.34f;
- egy rögzített hosszúságú mantissza és egy előjeles egész exponens
- numerikusan: m ⋅ 2e
- a fenti típusokban m és e értékes jegyeinek száma különbözik
- speciális értékek
- NaN (not a number): pl.
0/0
eredménye - pozitív, negatív végtelen
Felsorolási típus (enumeration)
- névvel rendelkező konstansokat vezet be, amelyekhez egy-egy számot rendel
- a típusnak is lehet neve
- alapértelmezés szerint a hozzárendelt számok nullától indulnak
- megadott értéktől is lehet folytatni a számozást (érték előfordulhat újra)
enum { A, B, C, D, E };
enum Abece { A, B = 3, C, D, E };
enum Abece { A, B = 3, C, D = 2, E };
- automatikusan konvertálódik egész számra
int i = D;
Mutató (pointer)
- a memória bájtok sorozataként képzelhető el
- bájt: 8 bit együttese, a memória legkisebb egyszerre elérhető egysége
- memóriacím: a memória egy bájtjának sorszáma
- objektum memóriacíme: az objektumok összefüggő memóriaterületet alkotnak, ennek az első bájtjának a címe
- a mutató egy adott típusú objektum memóriacímét tartalmazza
Mutató (pointer)
int*
0
: speciális, sehová sem mutató mutatóNULL
: általában 0
-ra kifejtődő makró- C++0x: nullptr
- automatikus konverzió logikai típusra
0
↦ false
- érvényes mutató ↦
true
Mutató (pointer)
int i = 3;
int j;
int* pi;
pi = &i;
j = *pi;
Konstans mutató
int i, j;
const int* pi1 = &i;
int*const pi2 = &i;
*pi1 = 3;
*pi2 = 3;
pi1 = &j;
pi2 = &j;
Tömb (array)
- a tömb adott típusú elemek sorozatát tartalmazza
int ai[3] = { 1, 2, 3 };
int bi[] = { 4, 5, 6, 7 };
- az elemek index szerinti elérése hatékony
- index:
int
- a tömb nullától indexelődik
int c = ai[2];
- a tömb méretét nem lehet növelni
Tömb (array)
- bár hasonló kinézetű, értékadás nem megengedett tömbtartalomra
int aa[3];
aa = { 1, 2, 3 };
- a feltöltetlenül maradt pozíciók nullát tartalmaznak
int a1[6] = { -1, -2, -3 };
int a2[6] = { -1, -2, -3, 0, 0, 0 };
Tömb (array)
int ai[3] = { 1, 2, 3 };
int bi[] = { 4, 5, 6, 7 };
- a tömb nem ismeri az elemszámát
- buffer overflow: a program könnyen túlcímezhet a tömbön
- pl. a cppcheck eszközzel lehet vizsgálni
bi[5] = 8;
Tömb (array)
- a tömb konvertálódik az első elemére mutató mutatóra
- az értékadás csak a mutatót másolja, a tartalmat nem
char ai[] = { 'a', 'b', 'c' };
char* b = ai;
- az
==
operátor a mutatók címét hasonlítja össze, a tartalmukat nem- azaz azt adja meg, ugyanott helyezkedik-e el a két objektum
char ai[] = { 'a', 'b', 'c' };
char bi[] = { 'a', 'b', 'c' };
ai == bi ⇒ false
Tömb (array)
- nincs többindexű tömb, csak tömbök tömbje
int ai[3][2] = { { 1, 2 }, {3, 4}, {5, 6} };
- jagged array: mutatók és tömbök kombinációja
int a0[] = {1,2};
int a1[] = {3,4,5};
int* a[2] = { a0, a1 };
Tömb (array)
C sztringek
char s[] = "abc";
- a sztring végét 0 kódú karakter (
'\0'
karakter) jelzi- ez nem a '0' karakter, annak 48 az ASCII-kódja
- a szöveg akkor is az első 0 karakterig tart, ha a tömbben vannak további elemek is
Tömb (array)
char s1[] = "abc";
char s2[] = { 'a', 'b', 'c', 0 };
char s3[] = { 'a', 'b', 'c', '\0' };
char s4[] = { 'a', 'b', 'c', 0, 'd', 'e' };
char* s5 = "abc";
char ures[1] = "";
Tömb (array)
Tömbök és mutatók deklarációjának értelmezése
int **a[2][3][4];
int** (((a[2])[3])[4]);
- a legkülső (sorrendben legelső) tömbnek nem kötelező megadni a dimenzióját, ha inicializáljuk
int b[][3] = { {0,1,2}, {10,11,12} };
Tömb (array)
Mutató-aritmetika
p+1
a következő tömbelem címét adja meg- akkor is, ha ezzel kifutunk a tömb területéről
Tömb (array)
Mutató-aritmetika
- hasonlóan:
p-1
, p++
, ++p
, p--
, --p
- (azonos tömbön dolgozó) mutatók kivonása: a mutatók közötti elemek száma
- általában a mutató-aritmetika veszélyes és kerülendő
Tömb (array)
Hasznos típusok a tömb kiváltására a sztenderd könyvtárból
- szöveg:
string
- tömb:
vector
Tulajdonságaik
- lekérdezhető a hossza/elemszáma
- az értékadás helyesen működik a vektorra
- át lehet méretezni őket
Hivatkozás (referencia)
int i;
int& ri = i;
- referencia: álnév egy objektumra
- konstans mutatóval kiváltható, annál kényelmesebb konstrukció
Hivatkozás (referencia)
- kötelező kezdő értékadás: a nemkonstans hivatkozott objektum
- innentől minden művelet, amit a referencián hajtunk végre, olyan, mintha az eredeti objektumon végeznénk
- ezután az eredeti eléréssel is az új objektumot kapjuk
- konstans referencia
- az objektumot megváltoztató műveletek nem megengedettek
- referenciákból nem készíthető tömb és nem állítható rá mutató
Típus mérete
sizeof
operátor: egy típusról vagy egy elemről megadja, hány bájt hosszan tárolódik- a nyelv nem rögzíti, hány bájton tárolandóak a típusok, csak bizonyos korlátokat ad
1 == sizeof(char)
1 <= sizeof(FelsorolásiTípus) <= sizeof(int)
2 <= sizeof(short) <= sizeof(int) <= sizeof(long)
4 <= sizeof(long)
sizeof(float) <= sizeof(double) <= sizeof(long double)
Áltípus (typedef)
- más néven: típusszinoníma
- új típusnevet vezet be
- az új típus nem különböztethető meg a régitől
- Ada: a km és a kg ábrázolása ugyanaz, de nem keverhetőek össze
typedef int suly;
typedef const char* szovegtomb[100];
- a kód olvashatóságát növeli
Típuskonverzió (cast, type conversion)
- reprezentáció megváltoztatása
- más bitsorozat reprezentálja ugyanazt az értéket
- értelmezés megváltoztatása
- a reprezentáció azonos
- a típusrendszer "megnyugtatására", kijátszására való
- leszármazott osztály konverziója ősosztályra
- itt is megmarad a reprezentáció
- ez biztonságos
Típuskonverzió (cast, type conversion)
- bővítő konverzió: értékvesztés nélküli
double d = 13;
- szűkítő konverzió: előfordulhat értékvesztés
int i = 13.6;
- automatikus konverzió: külön jelölés nem szükséges hozzá
- lehet bővítő vagy szűkítő (pl. a fenti double → int)
- explicit konverzió: konverziós operátorral
- C stílusú
- C++: többfajta konverziós operátor, visszatérünk rájuk
Deklaráció
- deklaráció: egy objektumhoz hozzárendel egy nevet
- változó: a deklaráció egy konkrét memóriaterületet azonosít, amelynek megváltozhat a tartalma
- hatókör vagy láthatósági tartomány (scope): a programszöveg azon összefüggő része, ahol a deklaráció által bevezetett név használatban van
- lokális név: függvényen vagy blokkon belül bevezetett név, hatóköre a deklaráció helyétől a blokk (a függvény blokkja) végéig tart
- globális név: függvényen, osztályon, névtéren kívül bevezetett név, hatóköre a deklaráció helyétől a tartalmazó fájl végéig tart
Deklaráció láthatósága
- közvetlen láthatóság: a deklarációra egyetlen azonosítóval (műveleti jellel) lehet hivatkozni
- láthatóság: a deklaráció közvetlenül vagy minősítéssel (
::
operátor) látható using
: név közvetlenül láthatóvá tétele másik névtérből vagy osztályból- átlapolás vagy elfedés (overlapping): a programszöveg egy részén több, azonos nevet bevezető deklaráció látható
void f(int, int);
void f(double, double);
Deklaráció láthatósága
Névelfedés: azonosító bevezetése vele azonos nevű deklaráció hatókörében
- elfedett globális név használata
::x = 1;
Deklaráció láthatósága
- elfedett lokális név nem használható
- hatóköre azonban itt is tart
{
int x;
{
x = 1;
int x;
x = 2;
}
}
Deklaráció láthatósága
- a függvényparamétereket nem lehet elfedni a függvény törzsében (de a függvény törzsén belüli blokkban már igen)
int f(int x)
{
{
int x = 1;
}
return x;
}
Deklarációk és szerkesztés
Szerkesztési osztály (linkage): meghatározza, hogy melyik fordítási egységekre terjed ki a deklaráció hatóköre
- külső (external linkage): a deklaráció fordítási egységben látható
- nem statikus függvények
- globális objektumok
- extern const objektumok
- osztályok
- felsorolási típusok és értékeik
- sablonok
- névterek
Deklarációk és szerkesztés
Szerkesztési osztály (linkage)
- belső (internal linkage): a deklaráció csak a fordítási egységben látható
- statikus objektumok
- statikus függvények
- névtelen névtér elemei
- typedef-fel megadott áltípus-deklaráció
- nem extern konstansok
- nincsen (no linkage): a deklaráció csak lokálisan látható
- lokális objektumok (amelyek nem tartoznak az előző két kategóriába)
Objektum élettartama
Élettartam (extent, lifetime): az objektum lefoglalása és felszabadítása közötti időtartam
- statikus objektumok
- élettartamuk a program teljes futása
- fajtái
- globális változó
- névtérbe tartozó változó
- lokális statikus változó (static kulcsszó)
- ha nincsen kezdőérték-adás, a típusnak megfelelő 0 értékkel inicializálódnak
Objektum élettartama
Élettartam
- lokális változók (automatikus objektumok): a deklaráció helyétől a hatókör végéig tart
- dinamikusan lefoglalt objektumok: a lefoglalástól a felszabadításig
- mindkét fentire vonatkozó tulajdonságok
- nem inicializálódnak, ha nincsen kezdőérték-adás
- használat előtt inicializálni kell őket, különben definiálatlan a program működése
- tömbök elemei, osztályok adattagjai
- élettartamuk a tömb/osztály élettartamával azonos
Deklaráció szerkezete
- alaptípus
- opcionális minősítő kulcsszavak
- deklarátor
- bevezetett név
- opcionális deklarátor-operátorok
- opcionális kezdőérték-adó rész
- konstans esetén kötelező, egyébként elmaradhat
mutató | * név |
konstans mutató | *const név |
referencia | & név |
tömb | név[] |
függvény | név( paraméterek) |
Deklaráció szerkezete
- opcionális minősítő kulcsszavak
const
, extern
, inline
, static
, virtual
, ...const
: az objektum alaptípusa állandó, a hatókörén belül az értéke nem változik meg- az alaptípus elé és mögé is lehet írni őket
- tetszőleges sorrendben
const int i = 3;
int const j = 6;
const extern int*const bonyolult[3];
Deklaráció szerkezete
- több név bevezetése egy deklarációban
- vesszővel elválasztva
- az operátorok és az értékadás csak egy névre vonatkoznak
int i = 1, j = 2;
int j, *p, **pp;
- célszerű csak egy nevet bevezetni egy deklarációban
int j;
int* p;
int** pp;
Deklaráció szerkezete
- konstans és konstans mutató
const int* pi1 = ...;
int*const pi2;
const int*const pi3 = ...;