Vous êtes sur la page 1sur 1362

Bevezet�s

Ez a bevezet�s �ttekint�st ad a C++ programoz�si nyelv fo fogalmair�l,


tulajdons�gair�l �s
standard (szabv�ny) k�nyvt�r�r�l, valamint bemutatja a k�nyv szerkezet�t �s
elmagyar�zza
azt a megk�zel�t�st, amelyet a nyelv lehetos�geinek �s azok haszn�lat�nak
le�r�s�n�l
alkalmaztunk. Ezenk�v�l a bevezeto fejezetek n�mi h�tt�rinform�ci�t is adnak a C+
+-r�l,
annak fel�p�t�s�rol �s felhaszn�l�s�r�l.
Fejezetek
1. Megjegyz�sek az olvas�hoz
2. Kir�ndul�s a C++-ban
3. Kir�ndul�s a standard k�nyvt�rban
Megjegyz�sek az olvas�hoz
.Sz�lt a Rozm�r:
Van �m el�g, mirol mes�lni j�: ....
(L. Carroll . ford. T�tfalusi Istv�n)
A k�nyv szerkezete . Hogyan tanuljuk a C++-t? . A C++ jellemzoi . Hat�konys�g �s
szerkezet
. Filoz�fiai megjegyz�s . T�rt�neti megjegyz�s . Mire haszn�ljuk a C++-t? . C �s
C++ . Javaslatok C programoz�knak . Gondolatok a C++ programoz�sr�l . Tan�csok .
Hivatkoz�sok
1.1. A k�nyv szerkezete
A k�nyv hat r�szbol �ll:
Bevezet�s: Az 1.3. fejezetek �ttekintik a C++ nyelvet, az �ltala t�mogatott fo
programoz
�si st�lusokat, �s a C++ standard k�nyvt�r�t.
Elso r�sz: A 4.9. fejezetek oktat� jellegu bevezet�st adnak a C++ be�p�tett
t�pusair
�l �s az alapszolg�ltat�sokr�l, melyekkel ezekbol programot �p�thet�nk.
M�sodik r�sz: A 10.15. fejezetek bevezet�st adnak az objektumorient�lt �s az
�ltal�nos�tott programoz�sba a C++ haszn�lat�val.
1
Harmadik r�sz: A 16.22. fejezetek bemutatj�k a C++ standard k�nyvt�r�t.
Negyedik r�sz: A 23.25. fejezetek tervez�si �s szoftverfejleszt�si k�rd�seket
t�rgyalnak.
F�ggel�kek: Az A.E f�ggel�kek a nyelv technikai r�szleteit tartalmazz�k.
Az 1. fejezet �ttekint�st ad a k�nyvrol, n�h�ny �tletet ad, hogyan haszn�ljuk,
valamint
h�tt�rinform�ci�kat szolg�ltat a C++-r�l �s annak haszn�lat�r�l. Az olvas� b�tran
�tfuthat
rajta, elolvashatja, ami �rdekesnek l�tszik, �s visszat�rhet ide, miut�n a k�nyv
m�s r�szeit
elolvasta.
A 2. �s 3. fejezet �ttekinti a C++ programoz�si nyelv �s a standard k�nyvt�r fo
fogalmait �s
nyelvi alaptulajdons�gait, megmutatva, mit lehet kifejezni a teljes C++ nyelvvel.
Ha semmi
m�st nem tesznek, e fejezetek meg kell gyozz�k az olvas�t, hogy a C++ nem (csup�n)
C, �s
hogy a C++ hossz� utat tett meg e k�nyv elso �s m�sodik kiad�sa �ta. A 2. fejezet
magas
szinten ismertet meg a C++-szal. A figyelmet azokra a nyelvi tulajdons�gokra
ir�ny�tja, melyek
t�mogatj�k az elvont adat�br�zol�st, illetve az objektumorient�lt �s az
�ltal�nos�tott
programoz�st. A 3. fejezet a standard k�nyvt�r alapelveibe �s fo szolg�ltat�saiba
vezet be,
ami lehetov� teszi, hogy a szerzo a standard k�nyvt�r szolg�ltat�sait haszn�lhassa
a k�vetkez
o fejezetekben, valamint az olvas�nak is lehetos�get ad, hogy k�nyvt�ri
szolg�ltat�sokat
haszn�ljon a gyakorlatokhoz �s ne kelljen k�zvetlen�l a be�p�tett, alacsony szintu
tulajdons
�gokra hagyatkoznia.
A bevezeto fejezetek egy, a k�nyv folyam�n �ltal�nosan haszn�lt elj�r�s p�ld�j�t
adj�k: ahhoz,
hogy egy m�dszert vagy tulajdons�got m�g k�zvetlenebb �s val�szerubb m�don vizsg
�lhassunk, alkalmank�nt elosz�r r�viden bemutatunk egy fogalmat, majd k�sobb behat
�bban t�rgyaljuk azt. Ez a megk�zel�t�s lehetov� teszi, hogy konkr�t p�ld�kat
mutassunk
be, mielott egy t�m�t �ltal�nosabban t�rgyaln�nk. A k�nyv fel�p�t�se �gy t�kr�zi
azt a megfigyel
�st, hogy rendszerint �gy tanulunk a legjobban, ha a konkr�tt�l haladunk az elvont

fel� . m�g ott is, ahol visszatekintve az elvont egyszerunek �s mag�t�l


�rtetodonek l�tszik.
Az I. r�sz a C++-nak azt a r�szhalmaz�t �rja le, mely a C-ben vagy a Pascalban
k�vetett hagyom
�nyos programoz�si st�lusokat t�mogatja. T�rgyalja a C++ programokban szereplo
alapveto t�pusokat, kifejez�seket, vez�rl�si szerkezeteket. A modularit�st, mint a
n�vterek,
forr�sf�jlok �s a kiv�telkezel�s �ltal t�mogatott tulajdons�got, szint�n
t�rgyalja. Felt�telezz
�k, hogy az olvas�nak m�r ismerosek az I. fejezetben haszn�lt alapveto
programoz�si fogalmak,
�gy p�ld�ul bemutatjuk a C++ lehetos�geit a rekurzi� �s iter�ci� kifejez�s�re, de
nem sok�ig magyar�zzuk, milyen hasznosak ezek.
A II. r�sz a C++ �j t�pusok l�trehoz�s�t �s haszn�lat�t seg�to szolg�ltat�sait
�rja le. Itt (10. �s
12. fejezet) mutatjuk be a konkr�t �s absztrakt oszt�lyokat (fel�leteket), az
oper�tor-t�lterhel
�ssel (11. fejezet), a t�bbalak�s�ggal (polimorfizmussal) �s az oszt�lyhierarchi�k
hasz-
4 Bevezet�s
n�lat�val (12. �s 15. fejezet) egy�tt. A 13. fejezet a sablonokat (template)
mutatja be, vagyis
a C++ lehetos�geit a t�pus- �s f�ggv�nycsal�dok l�trehoz�s�ra, valamint
szeml�lteti a t�rol
�k elo�ll�t�s�ra (pl. list�k), valamint az �ltal�nos�tott (generikus) programoz�s
t�mogat�s�-
ra haszn�lt alapveto elj�r�sokat. A 14. fejezet a kiv�telkezel�st, a hibakezel�si
m�dszereket
t�rgyalja �s a hibatur�s biztos�t�s�hoz ad ir�nyelveket. Felt�telezz�k, hogy az
olvas� az objektumorient
�lt �s az �ltal�nos�tott programoz�st nem ismeri j�l, illetve haszn�t l�tn� egy
magyar�zatnak, hogyan t�mogatja a C++ a fo elvonatkoztat�si (absztrakci�s)
elj�r�sokat.
�gy teh�t nemcsak bemutatjuk az elvonatkoztat�si m�dszereket t�mogat� nyelvi
tulajdons
�gokat, hanem magukat az elj�r�sokat is elmagyar�zzuk. A IV. r�sz ebben az
ir�nyban halad
tov�bb.
A III. r�sz a C++ standard k�nyvt�r�t mutatja be. C�lja: meg�rtetni, hogyan
haszn�ljuk
a k�nyvt�rat; �ltal�nos tervez�si �s programoz�si m�dszereket szeml�ltetni �s
megmutatni,
hogyan bov�ts�k a k�nyvt�rat. A k�nyvt�r gondoskodik t�rol�kr�l (kont�nerek .
list,
vector, map, 18. �s 19. fejezet), szabv�nyos algoritmusokr�l (sort, find, merge,
18. �s 19.
fejezet), karakterl�nc-t�pusokr�l �s -muveletekrol (20. fejezet), a bemenet �s
kimenet kezel
�s�rol (input/output, 21. fejezet), valamint a sz�mokkal v�gzett muveletek
(.numerikus
sz�m�t�s.) t�mogat�s�r�l (22. fejezet).
A IV. r�sz olyan k�rd�seket vizsg�l, melyek akkor mer�lnek fel, amikor nagy
szoftverrendszerek
tervez�s�n�l �s kivitelez�s�n�l a C++-t haszn�ljuk. A 23. fejezet tervez�si �s
vezet�-
si k�rd�sekkel foglalkozik. A 24. fejezet a C++ programoz�si nyelv �s a tervez�si
k�rd�sek
kapcsolat�t vizsg�lja, m�g a 25. fejezet az oszt�lyok haszn�lat�t mutatja be a
tervez�sben.
Az .A. f�ggel�k a C++ nyelvtana, n�h�ny jegyzettel. A .B. f�ggel�k a C �s a C++
k�zti �s
a szabv�nyos C++ (m�s n�ven ISO C++, ANSI C++) illetve az azt megelozo C++-
v�ltozatok
k�zti rokons�got vizsg�lja. A .C. f�ggel�k n�h�ny nyelvtechnikai p�ld�t mutat be,
A .D.
f�ggel�k pedig a kultur�lis elt�r�sek kezel�s�t t�mogat� standard k�nyvt�rbeli
elemeket
mutatja be. Az .E. f�ggel�k a standard k�nyvt�r kiv�telkezel�sel kapcsolatos
garanci�it �s
k�vetelm�nyeit t�rgyalja.
1.1.1. P�ld�k �s hivatkoz�sok
K�nyv�nk az algoritmusok �r�sa helyett a program fel�p�t�s�re fekteti a hangs�lyt.
K�vetkez
�sk�ppen elker�li a ravasz vagy nehezebben �rtheto algoritmusokat. Egy egyszeru
elj�r�s alkalmasabb az egyes fogalmak vagy a programszerkezet egy szempontj�nak
szeml
�ltet�s�re. P�ld�ul Shell rendez�st haszn�l, ahol a val�di k�dban jobb lenne
gyorsrendez
�st (quicksort) haszn�lni. Gyakran j� gyakorlat lehet a k�d �jra�r�sa egy
alkalmasabb algoritmussal.
A val�di k�dban �ltal�ban jobb egy k�nyvt�ri f�ggv�ny h�v�sa, mint a k�nyvben
haszn�lt, a nyelvi tulajdons�gok szeml�ltet�s�re haszn�lt k�d.
1. Megjegyz�sek az olvas�hoz 5
A tank�nyvi p�ld�k sz�ks�gszeruen egyoldal� k�pet adnak a programfejleszt�srol.
Tiszt�zva
�s egyszerus�tve a p�ld�kat a felmer�lt bonyolults�gok eltunnek. Nincs, ami
helyettes�-
ten� a val�di programok �r�s�t, ha benyom�st akarunk kapni, igaz�b�l milyen is a
programoz
�s �s egy programoz�si nyelv. Ez a k�nyv a nyelvi tulajdons�gokra �s az alapveto
elj�r�sokra �sszpontos�t, amelyekbol minden program �sszetevodik, valamint az
�ssze�p�-
t�s szab�lyaira.
A p�ld�k megv�laszt�sa t�kr�zi ford�t�programokkal, alapk�nyvt�rakkal,
szimul�ci�kkal
jellemezheto h�tteremet. A p�ld�k egyszerus�tett v�ltozatai a val�di k�dban
tal�lhat�knak.
Egyszerus�t�sre van sz�ks�g, hogy a programoz�si nyelv �s a tervez�s l�nyeges
szempontjai
el ne vesszenek a r�szletekben. Nincs .�gyes. p�lda, amelynek nincs megfeleloje a
val
�di k�dban. Ahol csak lehets�ges, a .C. f�ggel�kben l�vo nyelvtechnikai p�ld�kat
olyan
alakra hoztam, ahol a v�ltoz�k x �s y, a t�pusok A �s B, a f�ggv�nyek f() �s g()
nevuek.
A k�dp�ld�kban az azonos�t�khoz v�ltoz� sz�less�gu betuket haszn�lunk. P�ld�ul:
#include<iostream>
int main()
{
std::cout << "Hell�, vil�g!\n";
}
Elso l�t�sra ez .term�szetellenesnek. tunhet a programoz�k sz�m�ra, akik
hozz�szoktak,
hogy a k�d �lland� sz�less�gu betukkel jelenik meg. A v�ltoz� sz�less�gu betuket
�ltal�-
ban jobbnak tartj�k sz�veghez, mint az �lland� sz�less�gut. A v�ltoz� sz�less�gu
betuk
haszn�lata azt is lehetov� teszi, hogy a k�dban kevesebb legyen a logik�tlan
sort�r�s. Ezenk
�v�l saj�t k�s�rleteim azt mutatj�k, hogy a legt�bb ember kis ido eltelt�vel
k�nnyebben olvashat
�nak tartja az �j st�lust.
Ahol lehets�ges, a C++ nyelv �s k�nyvt�r tulajdons�gait a k�zik�nyvek sz�raz
bemutat�si
m�dja helyett a felhaszn�l�si k�rnyezetben mutatjuk be. A bemutatott nyelvi
tulajdons�gok
�s le�r�suk r�szletess�ge a szerzo n�zet�t t�kr�zik, aki a legfontosabb k�rd�snek
a k�vetkez
ot tartja: mi sz�ks�ges a C++ hat�kony haszn�lat�hoz? A nyelv teljes le�r�sa . a
k�nnyebb
megk�zel�t�s c�lj�b�l jegyzetekkel ell�tva . a The Annotated C++ Language Standard
c�mu
k�zik�nyvben tal�lhat�, mely Andrew Koenig �s a szerzo muve. Logikusan kellene
hogy legyen
egy m�sik k�zik�nyv is, a The Annotated C++ Standard Library. Mivel azonban mind
az ido, mind �r�si kapacit�som v�ges, nem tudom meg�g�rni, hogy elk�sz�l.
A k�nyv egyes r�szeire val� hivatkoz�sok �2.3.4 (2. fejezet, 3.szakasz, 4.
bekezd�s), �B.5.6
(.B. f�ggel�k, 5.6. bekezd�s �s �6.[10](6. fejezet, 10. gyakorlat) alakban
jelennek meg.
A dolt betuket kiemel�sre haszn�ljuk (pl. .egy karakterl�nc-liter�l nem fogadhat�
el.), fon-
6 Bevezet�s
tos fogalmak elso megjelen�s�n�l (pl. t�bbalak�s�g), a C++ nyelv egyes
szimb�lumain�l
(pl. for utas�t�s), az azonos�t�kn�l �s kulcsszavakn�l, illetve a k�dp�ld�kban
l�vo megjegyz
�sekn�l.
1.1.2. Gyakorlatok
Az egyes fejezetek v�g�n gyakorlatok tal�lhat�k. A gyakorlatok foleg az .�rj egy
programot.
t�pusba sorolhat�k. Mindig annyi k�dot �rjunk, ami el�g ahhoz, hogy a megold�s
ford�that
� �s korl�tozott k�r�lm�nyek k�z�tt futtathat� legyen. A gyakorlatok neh�zs�gben
jelent
osen elt�roek, ez�rt becs�lt neh�zs�gi fokukat megjel�lt�k. A neh�zs�g
hatv�nyozottan
no, teh�t ha egy (*1) gyakorlat 10 percet ig�nyel, egy (*2) gyakorlat egy �r�ba,
m�g egy (*3)
egy napba ker�lhet. Egy program meg�r�sa �s ellenorz�se ink�bb f�gg az ember
tapasztalts
�g�t�l, mint mag�t�l a gyakorlatt�l.
1.1.3. Megjegyz�s az egyes C++-v�ltozatokhoz
A k�nyvben haszn�lt nyelv .tiszta C++., ahogyan a C++ szabv�nyban le�rt�k [C++,
1998].
Ez�rt a p�ld�knak futniuk kell minden C++-v�ltozaton. A k�nyvben szereplo nagyobb
programr�szleteket t�bb k�rnyezetben is kipr�b�ltuk, azok a p�ld�k azonban, melyek

a C++-ba csak nemr�giben be�p�tett tulajdons�gokat haszn�lnak fel, nem mindenhol


ford�that
�k le. (Azt nem �rdemes megeml�teni, mely v�ltozatokon mely p�ld�kat nem siker�lt
leford
�tani. Az ilyen inform�ci�k hamar elavulnak, mert a megval�s�t�son igyekvo
programoz
�k kem�nyen dolgoznak azon, hogy nyelvi v�ltozataik helyesen fogadjanak el minden
C++ tulajdons�got.) A .B. f�ggel�kben javaslatok tal�lhat�k, hogyan birk�zzunk meg
a r�-
gi C++ ford�t�kkal �s a C ford�t�kra �rott k�ddal.
1.2. Hogyan tanuljuk a C++-t?
A C++ tanul�sakor a legfontosabb, hogy a fogalmakra �sszpontos�tsunk �s ne
vessz�nk el
a r�szletekben. A programoz�si nyelvek tanul�s�nak c�lja az, hogy jobb
programoz�v� v�ljunk;
vagyis hat�konyabbak legy�nk �j rendszerek tervez�s�n�l, megval�s�t�s�n�l �s r�gi
rendszerek karbantart�s�n�l. Ehhez sokkal fontosabb a programoz�si �s tervez�si
m�dszerek
felfedez�se, mint a r�szletek meg�rt�se; az ut�bbi idovel �s gyakorlattal
megszerezheto.
1. Megjegyz�sek az olvas�hoz 7
A C++ sokf�le programoz�si st�lust t�mogat. Ezek mind az eros statikus
t�pusellenorz�sen
alapulnak �s legt�bbj�k a magas elvonatkoztat�si szint el�r�s�re �s a programoz�
elk�pzel
�seinek k�zvetlen lek�pez�s�re ir�nyul. Minden st�lus el tudja �rni a c�lj�t,
mik�zben hat
�kony marad fut�si ido �s helyfoglal�s tekintet�ben. Egy m�s nyelvet (mondjuk C,
Fortran,
Smalltalk, Lisp, ML, Ada, Eiffel, Pascal vagy Modula-2) haszn�l� programoz� �szre
kell hogy
vegye, hogy a C++ elonyeinek kiakn�z�s�hoz idot kell sz�nnia a C++ programoz�si
st�lusok
�s m�dszerek megtanul�s�ra �s megem�szt�s�re. Ugyanez �rv�nyes azon programoz
�kra is, akik a C++ egy r�gebbi, kev�sb� kifejezok�pes v�ltozat�t haszn�lt�k.
Ha gondolkod�s n�lk�l alkalmazzuk az egyik nyelvben hat�kony elj�r�st egy m�sik
nyelvben,
rendszerint neh�zkes, gyenge teljes�tm�nyu �s nehezen m�dos�that� k�dot kapunk.
Az ilyen k�d �r�sa is csal�d�st okoz, mivel minden sor k�d �s minden ford�t�si
hiba arra eml
�keztet, hogy a nyelv, amit haszn�lunk, m�s, mint .a r�gi nyelv.. �rhatunk
Fortran, C,
Smalltalk stb. st�lusban b�rmely nyelven, de ez egy m�s filoz�fi�j� nyelvben nem
lesz sem
kellemes, sem gazdas�gos. Minden nyelv gazdag forr�sa lehet az �tleteknek, hogyan
�rjunk
C++ programot. Az �tleteket azonban a C++ �ltal�nos szerkezet�hez �s
t�pusrendszer�hez
kell igaz�tani, hogy hat�kony legyen az elt�ro k�rnyezetben. Egy nyelv alapt�pusai
felett
csak p�rroszi gyozelmet arathatunk.
A C++ t�mogatja a fokozatos tanul�st. Az, hogy hogyan k�zel�ts�nk egy �j nyelv
tanul�s�-
hoz, att�l f�gg, mit tudunk m�r �s mit akarunk m�g megtanulni. Nem l�tezik
egyetlen
megk�zel�t�s sem, amely mindenkinek j� lenne. A szerzo felt�telezi, hogy az olvas�
az�rt
tanulja a C++-t, hogy jobb programoz� �s tervezo legyen. Vagyis nem egyszeruen egy
�j
nyelvtant akar megtanulni, mellyel a r�gi megszokott m�don v�gzi a dolgokat, hanem
�j �s
jobb rendszer�p�t�si m�dszereket akar elsaj�t�tani. Ezt fokozatosan kell csin�lni,
mert minden
�j k�pess�g megszerz�se idot �s gyakorl�st ig�nyel. Gondoljuk meg, mennyi idobe
ker
�lne j�l megtanulni egy �j term�szetes nyelvet vagy megtanulni j�l j�tszani egy
hangszeren.
K�nnyen �s gyorsan lehet�nk jobb rendszertervezok, de nem annyival k�nnyebben �s
gyorsabban, mint ahogy azt a legt�bben szeretn�nk.
K�vetkez�sk�ppen a C++-t . gyakran val�di rendszerek �p�t�s�re . m�r azelott
haszn�lni
fogjuk, mielott meg�rten�nk minden nyelvi tulajdons�got �s elj�r�st. A C++ .
az�ltal, hogy
t�bb programoz�si modellt is t�mogat (2. fejezet) . k�l�nb�zo szintu szak�rtelem
eset�n is
t�mogatja a term�keny programoz�st. Minden �j programoz�si st�lus �jabb eszk�zt ad
eszk
�zt�runkhoz, de mindegyik mag�ban is hat�kony �s mindegyik fokozza a programoz�i
hat�konys�got. A C++-t �gy alkott�k meg, hogy a fogalmakat nagyj�b�l sorban egym�s

ut�n tanulhassuk meg �s ek�zben gyakorlati haszonra tehess�nk szert. Ez fontos,


mert a haszon
a kifejtett erofesz�t�ssel ar�nyos.
8 Bevezet�s
A folytat�d� vita sor�n . kell-e C-t tanulni a C++-szal val� ismerked�s elott .
szil�rd meggy
ozod�semm� v�lt, hogy legjobb k�zvetlen�l a C++-ra �tt�rni. A C++ biztons�gosabb,
kifejez
obb, cs�kkenti annak sz�ks�g�t, hogy a figyelmet alacsonyszintu elj�r�sokra
ir�ny�tsuk.
K�nnyebb a C-ben a magasabb szintu lehetos�gek hi�ny�t p�tl� tr�kk�sebb r�szeket
megtanulni, ha elobb megismert�k a C �s a C++ k�z�s r�szhalmaz�t �s a C++ �ltal
k�zvetlen
�l t�mogatott magasabb szintu elj�r�sokat. A .B. f�ggel�k vez�rfonalat ad azoknak
a programoz�knak, akik a C++ ismeret�ben v�ltanak a C-re, p�ld�ul az�rt, hogy
r�gebbi k�-
dot kezeljenek.
T�bb egym�st�l f�ggetlen�l fejlesztett �s terjesztett C++-v�ltozat l�tezik. Gazdag
v�laszt�k
kaphat� eszk�zt�rakb�l, k�nyvt�rakb�l, programfejleszto k�rnyezetekbol is.
Rengeteg tank
�nyv, k�zik�nyv, foly�irat, elektronikus hirdetot�bla, konferencia, tanfolyam �ll
rendelkez
�s�nkre a C++ legfrissebb fejleszt�seirol, haszn�lat�r�l, seg�deszk�zeirol,
k�nyvt�rair�l,
megval�s�t�sair�l �s �gy tov�bb. Ha az olvas� komolyan akarja a C++-t haszn�lni,
tan�csos
az ilyen forr�sok k�z�tt is b�ng�szni. Mindegyiknek megvan a saj�t n�zopontja,
elfogults�-
ga, ez�rt haszn�ljunk legal�bb kettot k�z�l�k. P�ld�ul l�sd [Barton,1994],
[Booch,1994],
[Henricson, 1997], [Koenig, 1997], [Martin, 1995].
1.3. A C++ jellemzoi
Az egyszerus�g fontos tervez�si felt�tel volt; ahol v�lasztani lehetett, hogy a
nyelvet vagy
a ford�t�t egyszerus�ts�k-e, az elobbit v�lasztottuk. Mindenesetre nagy s�lyt
fektett�nk arra,
hogy megmaradjon a C-vel val� �sszeegyeztethetos�g, ami eleve kiz�rta a C nyelvtan

kis�pr�s�t.
A C++-nak nincsenek be�p�tett magasszintu adatt�pusai, sem magasszintu
alapmuveletei.
A C++-ban p�ld�ul nincs m�trixt�pus inverzi� oper�torral, karakterl�nc-t�pus
�sszefuzo
muvelettel. Ha a felhaszn�l�nak ilyen t�pusra van sz�ks�ge, mag�ban a nyelvben
defin��lhat
ilyet. Alapj�ban v�ve a C++-ban a legelemibb programoz�si tev�kenys�g az �ltal�nos

c�l� vagy alkalmaz�sf�ggo t�pusok l�trehoz�sa. Egy j�l megtervezett felhaszn�l�i


t�pus
a be�p�tett t�pusokt�l csak abban k�l�nb�zik, milyen m�don hat�rozt�k meg, abban
nem,
hogyan haszn�lj�k. A III. r�szben le�rt standard k�nyvt�r sz�mos p�ld�t ad az
ilyen t�pusokra
�s haszn�latukra. A felhaszn�l� szempontj�b�l kev�s a k�l�nbs�g egy be�p�tett �s
egy
standard k�nyvt�rbeli t�pus k�z�tt.
1. Megjegyz�sek az olvas�hoz 9
A C++-ban ker�lt�k az olyan tulajdons�gokat, melyek akkor is a fut�si ido
n�veked�s�t
vagy a t�r t�lterhel�s�t okozn�k, ha nem haszn�ljuk azokat. Nem megengedettek
p�ld�ul
azok a szerkezetek, melyek .h�ztart�si inform�ci�. t�rol�s�t tenn�k sz�ks�gess�
minden
objektumban, �gy ha a felhaszn�l� p�ld�ul k�t 16 bites mennyis�gbol �ll�
szerkezetet ad
meg, az egy 32 bites regiszterbe t�k�letesen belef�r.
A C++-t hagyom�nyos ford�t�si �s fut�si k�rnyezetben val� haszn�latra tervezt�k,
vagyis
a UNIX rendszer C programoz�si k�rnyezet�re. Szerencs�re a C++ sohasem volt a
UNIX-ra
korl�tozva, a UNIX-ot �s a C-t csup�n modellk�nt haszn�ltuk a nyelv, a k�nyvt�rak,
a ford
�t�k, a szerkesztok, a futtat�si k�rnyezetek stb. rokons�ga alapj�n. Ez a
minim�lis modell
seg�tette a C++ sikeres elterjed�s�t l�nyeg�ben minden sz�m�t�g�pes platformon. J�
okai
vannak azonban a C++ haszn�lat�nak olyan k�rnyezetekben, melyek jelentosen nagyobb

t�mogat�sr�l gondoskodnak. Az olyan szolg�ltat�sok, mint a dinamikus bet�lt�s, a


fokozatos
ford�t�s vagy a t�pusmeghat�roz�sok adatb�zisa, an�lk�l is j�l haszn�lhat�k, hogy
befoly
�soln�k a nyelvet.
A C++ t�pusellenorz�si �s adatrejt�si tulajdons�gai a programok ford�t�si ido
alatti elemz�-
s�re t�maszkodnak, hogy elker�lj�k a v�letlen adats�r�l�seket. Nem gondoskodnak
titkos
�t�sr�l vagy az olyan szem�lyek elleni v�delemrol, akik sz�nd�kosan megszegik a
szab�-
lyokat. Viszont szabadon haszn�lhat�k �s nem j�rnak a fut�si ido vagy a sz�ks�ges
t�rhely
n�veked�s�vel. Az alapelv az, hogy ahhoz, hogy egy nyelvi tulajdons�g hasznos
legyen,
nemcsak eleg�nsnak, hanem val�di programon bel�l is elhelyezhetonek kell lennie.
A C++ jellemzoinek rendszerezett �s r�szletes le�r�s�t l�sd [Stroustrup, 1994].
1.3.1. Hat�konys�g �s szerkezet
A C++-t a C programoz�si nyelvbol fejlesztett�k ki �s . n�h�ny kiv�teltol
eltekintve . a C-t,
mint r�szhalmazt, megtartotta. Az alapnyelvet, a C++ C r�szhalmaz�t, �gy
tervezt�k, hogy
nagyon szoros megfelel�s van t�pusai, muveletei, utas�t�sai, �s a sz�m�t�g�pek
�ltal k�zvetlen
�l kezelheto objektumok (sz�mok, karakterek �s c�mek) k�z�tt. A new, delete,
typeid,
dynamic_cast �s throw oper�torok �s . a try blokk . kiv�tel�vel, az egyes C++
kifejez�-
sek �s utas�t�sok nem k�v�nnak fut�si ideju t�mogat�st.
A C++ ugyanolyan f�ggv�nyh�v�si �s visszat�r�si m�dokat haszn�lhat, mint a C .
vagy m�g
hat�konyabbakat. Amikor m�g az ilyen, viszonylag hat�kony elj�r�sok is t�l
k�lts�gesek,
a C++ f�ggv�nyt a ford�t�val kifejtethetj�k helyben (inline k�d), �gy �lvezhetj�k
a f�ggv�-
nyek haszn�lat�nak k�nyelm�t, a fut�si ido n�vel�se n�lk�l.
10 Bevezet�s
A C egyik eredeti c�lja az assembly k�d helyettes�t�se volt a legig�nyesebb
rendszerprogramoz
�si feladatokban. Amikor a C++-t tervezt�k, vigy�ztunk, ne legyen megalkuv�s e t�-

ren. A C �s a C++ k�zti k�l�nbs�g elsosorban a t�pusokra �s adatszerkezetekre


fektetett s�ly
m�rt�k�ben van. A C kifejezo �s eln�zo. A C++ m�g kifejezobb. Ez�rt a jobb
kifejezok�pess
�g�rt cser�be azonban nagyobb figyelmet kell ford�tanunk az objektumok t�pus�ra. A
ford
�t� az objektumok t�pus�nak ismeret�ben helyesen tudja kezelni a kifejez�seket
akkor is,
ha egy�bk�nt k�nos precizit�ssal kellett volna megadni a muveleteket. Az
objektumok t�pus
�nak ismerete arra is k�pess� teszi a ford�t�t, hogy olyan hib�kat fedjen fel,
melyek m�sk
�l�nben eg�szen a tesztel�sig vagy m�g tov�bb megmaradn�nak. Vegy�k �szre, hogy a
t�-
pusrendszer haszn�lata f�ggv�nyparam�terek ellenorz�s�re . az adatok v�letlen
s�r�l�stol
val� megv�d�s�re, �j t�pusok vagy oper�torok elo�ll�t�s�ra �s �gy tov�bb . a C++-
ban nem
n�veli a fut�si idot vagy a sz�ks�ges helyet.
A C++-ban a szerkezetre fektetett hangs�ly t�kr�zi a C megtervez�se �ta meg�rt
programok
.s�lygyarapod�s�t.. Egy kis . mondjuk 1000 soros . programot meg�rhatunk .nyers
erovel.,
m�g akkor is, ha felr�gjuk a j� st�lus minden szab�ly�t. Nagyobb programokn�l ez
egyszeru-
en nincs �gy. Ha egy 100 000 soros programnak rossz a fel�p�t�se, azt fogjuk
tal�lni, hogy
ugyanolyan gyorsan keletkeznek az �jabb hib�k, mint ahogy a r�gieket elt�vol�tjuk.
A C++-t
�gy tervezt�k, hogy lehetov� tegye nagyobb programok �sszeru m�don val�
fel�p�t�s�t, �gy
egyetlen szem�ly is sokkal nagyobb k�dmennyis�ggel k�pes megbirk�zni. Ezenk�v�l
c�lkitu-
z�s volt, hogy egy �tlagos sornyi C++ k�d sokkal t�bbet fejezzen ki, mint egy
�tlagos Pascal
vagy C k�dsor. A C++ mostanra megmutatta, hogy t�l is teljes�ti ezeket a
c�lkituz�seket.
Nem minden k�dr�szlet lehet j�l szerkesztett, hardverf�ggetlen vagy k�nnyen
olvashat�.
A C++-nak vannak tulajdons�gai, melyeket arra sz�ntak, hogy k�zvetlen �s hat�kony
m�-
don kezelhess�k a hardver szolg�ltat�sait, an�lk�l, hogy a biztons�gra vagy az
�rthetos�gre
k�ros hat�ssal lenn�nk. Vannak olyan lehetos�gei is, melyekkel az ilyen k�d
eleg�ns �s
biztons�gos fel�letek m�g� rejtheto.
A C++ nagyobb programokhoz val� haszn�lata term�szetszeruen elvezet a C++ nyelv
programoz�csoportok �ltali haszn�lat�hoz. A C++ �ltal a modularit�sra, az erosen
t�pusos
fel�letekre �s a rugalmass�gra fektetetett hangs�ly itt fizetodik ki. A C++-nak
�ppen olyan
j�l kiegyens�lyozott szolg�ltat�sai vannak nagy programok �r�s�ra, mint b�rmely
nyelvnek.
Ahogy nagyobbak lesznek a programok, a fejleszt�s�kkel �s fenntart�sukkal,
m�dos�t�sukkal
kapcsolatos probl�m�k a .nyelvi probl�ma. jellegtol az eszk�z�k �s a kezel�s
�ltal�nosabb
probl�m�i fel� mozdulnak el. A IV. r�sz ilyen jellegu k�rd�seket is t�rgyal.
1. Megjegyz�sek az olvas�hoz 11
K�nyv�nk kiemeli az �ltal�nos c�l� szolg�ltat�sok, t�pusok �s k�nyvt�rak
k�sz�t�s�nek
m�djait. Ezek �pp�gy szolg�lj�k a kis programok �r�it, mint a nagy programok�it.
Ezen t�lmen
oen, mivel minden bonyolultabb program sok, f�lig-meddig f�ggetlen r�szbol �ll, az

ilyen r�szek �r�s�hoz sz�ks�ges m�dszerek ismerete j� szolg�latot tesz minden


alkalmaz�sprogramoz
�nak.
Az olvas� azt gondolhatja, a r�szletesebb t�pusszerkezetek haszn�lata nagyobb
forr�sprogramhoz
vezet. A C++ eset�ben ez nem �gy van. Egy C++ program, amely f�ggv�nyparam�-
ter-t�pusokat vezet be vagy oszt�lyokat haszn�l, rendszerint kiss� r�videbb, mint
a vele
egyen�rt�ku C program, amely nem haszn�lja e lehetos�geket. Ott, ahol k�nyvt�rakat
haszn
�lnak, egy C++ program sokkal r�videbb lesz, mint a megfelelo C program, felt�ve
term�-
szetesen, hogy k�sz�theto muk�dok�pes C-beli megfelelo.
1.3.2. Filoz�fiai megjegyz�s
A programoz�si nyelvek k�t rokon c�lt szolg�lnak: a programoz�nak r�szben eszk�zt
adnak,
amellyel v�grehajthat� muveleteket adhat meg, ugyanakkor egy sereg fog�dz�t is
rendelkez
�s�re bocs�tanak, amikor arr�l gondolkodik, mit lehet tenni. Az elso c�l ide�lis
esetben
.g�pk�zeli. nyelvet k�v�n, amellyel a sz�m�t�g�p minden fontos oldala egyszeruen
�s
hat�konyan kezelheto, a programoz� sz�m�ra �sszeru, k�zenfekvo m�don. A C nyelvet
els
osorban ebben a szellemben tervezt�k. A m�sodik c�l viszont olyan nyelvet k�vetel
meg,
mely .k�zel van a megoldand� probl�m�hoz., hogy a megold�s k�zvetlen�l �s t�m�ren
kifejezhet
o legyen.
A nyelv, melyben gondolkodunk/programozunk �s a probl�m�k, megold�sok, melyeket el

tudunk k�pzelni, szoros kapcsolatban �llnak egym�ssal. Ez�rt a nyelvi


tulajdons�gok megszor
�t�sa azzal a sz�nd�kkal, hogy kik�sz�b�lj�k a programoz�i hib�kat, a legjobb
esetben
is vesz�lyes. A term�szetes nyelvekhez hasonl�an nagy elonye van annak, ha az
ember legal
�bb k�t nyelvet ismer. A nyelv ell�tja a programoz�t a megfelelo eszk�z�kkel, ha
azonban
ezek nem megfeleloek a feladathoz, egyszeruen figyelmen k�v�l hagyjuk azokat. A j�

tervez�s �s hibamentess�g nem biztos�that� csup�n az egyedi nyelvi tulajdons�gok


jelenl�-
t�vel vagy t�voll�t�vel.
A t�pusrendszer k�l�n�sen �sszetettebb feladatok eset�ben jelent seg�ts�get. A C++
oszt�-
lyai val�ban eros eszk�znek bizonyultak.
12 Bevezet�s
1.4. T�rt�neti megjegyz�s
A szerzo alkotta meg a C++-t, �rta meg elso defin�ci�it, �s k�sz�tette el elso
v�ltozat�t. Megv
�lasztotta �s megfogalmazta a C++ tervez�si felt�teleit, megtervezte fo
szolg�ltat�sait, �s o
volt a felelos a C++ szabv�ny�gyi bizotts�gban a bov�t�si javaslatok
feldolgoz�s��rt.
Vil�gos, hogy a C++ sokat k�sz�nhet a C-nek [Kernighan, 1978]. A C n�h�ny, a
t�pusellen-
orz�s ter�n tapasztalt hi�nyoss�g�t kiv�ve megmaradt, r�szhalmazk�nt (l�sd .B.
f�ggel�k).
Ugyancsak megmaradt az a C-beli sz�nd�k, hogy olyan szolg�ltat�sokra fektessen
hangs
�lyt, melyek el�g alacsony szintuek ahhoz, hogy megbirk�zzanak a legig�nyesebb
rendszerprogramoz
�si feladatokkal is. A C a maga r�sz�rol sokat k�sz�nhet os�nek, a BCPL-nek
[Richards, 1980]; a BCPL // megjegyz�s-form�tuma (�jra) be is ker�lt a C++-ba. A
C++ m�-
sik fontos forr�sa a Simula67 volt [Dahl, 1970] [Dahl, 1972]; az oszt�ly fogalm�t
(a sz�rmaztatott
oszt�lyokkal �s virtu�lis f�ggv�nyekkel) innen vettem �t. A C++ oper�tor-
t�lterhel�si
lehetos�ge �s a deklar�ci�k szabad elhelyez�se az utas�t�sok k�z�tt az Algol68-ra
eml�keztet
[Woodward, 1974].
A k�nyv eredeti kiad�sa �ta a nyelv kiterjedt fel�lvizsg�latokon �s finom�t�sokon
ment
kereszt�l. A fel�lvizsg�latok fo ter�lete a t�lterhel�s felold�sa, az
�sszeszerkeszt�si �s t�rkezel
�si lehetos�gek voltak. Ezenk�v�l sz�mos kisebb v�ltoztat�s t�rt�nt a C-vel val�
kompatibilit
�s n�vel�s�re. Sz�mos �ltal�nos�t�s �s n�h�ny nagy bov�t�s is beleker�lt: ezek
a t�bbsz�r�s �r�kl�s, a static �s const tagf�ggv�nyek, a protected tagok, a
sablonok, a kiv
�telkezel�s, a fut�si ideju t�pusazonos�t�s �s a n�vterek. E bov�t�sek �s
fel�lvizsg�latok
�tfog� feladata a C++ olyan nyelvv� fejleszt�se volt, mellyel jobban lehet
k�nyvt�rakat �rni
�s haszn�lni. A C++ fejlod�s�nek le�r�s�t l�sd [Stroustrup, 1994].
A sablonok (template) bevezet�s�nek elsodleges c�lja a statikus t�pus� t�rol�k
(kont�nerek
. list, vector, map) �s azok hat�kony haszn�lat�nak (�ltal�nos�tott vagy generikus
programoz
�s) t�mogat�sa, valamint a makr�k �s explicit t�pusk�nyszer�t�sek (casting)
sz�ks�g�-
nek cs�kkent�se volt. Inspir�ci�t az Ada �ltal�nos�t� eszk�zei (mind azok
eross�gei, illetve
gyenges�gei), valamint r�szben a Clu param�teres moduljai szolg�ltattak.
Hasonl�an, a C++
kiv�telkezel�si elj�r�sainak elodjei is t�bb�-kev�sb� az Ada [Ichbiah, 1979], a
Clu [Liskov,
1979] �s az ML [Wikstrm, 1987]. Az 1985-1995 k�z�tt bevezetett egy�b
fejleszt�sek . t�bbsz
�r�s �r�kl�s, tiszt�n virtu�lis f�ggv�nyek �s n�vterek . viszont nem annyira m�s
nyelvekb
ol mer�tett �tletek alapj�n sz�lettek, ink�bb a C++ haszn�lat�nak tapasztalataib�l
leszurt
�ltal�nos�t�sok eredm�nyei.
A nyelv kor�bbi v�ltozatait (�sszefoglal� n�ven az oszt�lyokkal bov�tett C-t
[Stroustrup,
1994]) 1980 �ta haszn�lj�k. Kifejleszt�s�ben eredetileg szerepet j�tszott, hogy
olyan esem
�nyvez�relt szimul�ci�kat szerettem volna �rni, melyekhez a Simula67 ide�lis lett
volna,
1. Megjegyz�sek az olvas�hoz 13
ha el�gg� hat�kony. Az .oszt�lyokkal bov�tett C. igazi ter�let�t a nagy programok
jelentett
�k, ahol a leheto leggyorsabbnak kell lenni �s a leheto legkevesebb helyet
foglalni. Az els
o v�ltozatokb�l m�g hi�nyzott az oper�tor-t�lterhel�s, valamint hi�nyoztak a
referenci�k,
a virtu�lis f�ggv�nyek, a sablonok, a kiv�telek �s sok egy�b. A C++-t nem
k�s�rleti k�r�lm
�nyek k�z�tt elosz�r 1983-ban haszn�lt�k.
A C++ nevet Rick Mascitti adta a nyelvnek az eml�tett �v nyar�n. A n�v kifejezi
mindazt
a forradalmi �j�t�st, amit az �j nyelv a C-hez k�pest hozott: a ++ a C n�velo
muveleti jele.
(A .C+.-t is haszn�lj�k, de az egy m�sik, f�ggetlen nyelv.) A C utas�t�sform�it
j�l ismerok
r�mutathatnak, hogy a .C++. kifejez�s nem olyan .eros., mint a .++C..
Mindazon�ltal
a nyelv neve nem is D, hiszen a C-nek csup�n bov�t�s�rol van sz�, amely az ott
felmer�lt
probl�m�k elh�r�t�s�hoz az eredeti nyelv szolg�ltat�sai k�z�l egyet sem vet el. A
C++ n�v
m�s megk�zel�t�su elemz�s�hez l�sd [Orwell, 1949, f�ggel�k].
A C++ megalkot�s�nak fo oka azonban az volt, hogy bar�taimmal egy�tt nem
szerett�nk
volna assembly, C vagy m�s modern, magas szintu nyelven programozni. Csak annyit
akartunk
el�rni, hogy k�nnyebben �s �lvezetesebben �rhassunk j�l haszn�lhat� programokat.
Kezdetben nem vetett�k pap�rra rendszerezetten a fejleszt�si terveket: egyszerre
tervezt
�nk, dokument�ltunk �s alkottunk. Nem volt .C++ projekt. vagy .C++
tervezobizotts�g..
A C++ a felhaszn�l�k tapasztalatai �s a bar�taimmal, munkat�rsaimmal folytatott
vit�k sor
�n fejlod�tt ki.
A C++ k�sobbi robban�sszeru elterjed�se sz�ks�gszeruen v�ltoz�sokat hozott
mag�val. Valamikor
1987-ben nyilv�nval�v� v�lt, hogy a C++ hivatalos szabv�nyos�t�sa imm�r
elker�lhetetlen
�s halad�ktalanul meg kell kezden�nk az ilyen ir�ny� munka elok�sz�t�s�t
[Stroustrup, 1994]. Folyamatosan pr�b�ltuk tartani a kapcsolatot mind hagyom�nyos,
mind
elektronikus lev�lben, illetve szem�lyesen, konferenci�kat tartva a k�l�nb�zo C++
ford�t�k
k�sz�toivel �s a nyelv fo felhaszn�l�ival.
Ebben a munk�ban nagy seg�ts�get ny�jtott az AT&T Bell Laboratories, lehetov�
t�ve, hogy
v�zlataimat �s a C++ hivatkoz�si k�zik�nyv �jabb �s �jabb v�ltozatait
megoszthassam a fejleszt
okkel �s felhaszn�l�kkal. Seg�ts�g�k nem al�becs�lendo, ha tudjuk, hogy az
eml�tettek
nagy r�sze olyan v�llalatokn�l dolgozott, amelyek az AT&T vet�lyt�rsainak
tekinthetok.
Egy kev�sb� .felvil�gosult. c�g komoly probl�m�kat okozhatott volna �s a nyelv
.t�jsz�l�sokra
. t�redez�s�t id�zte volna elo, puszt�n az�ltal, hogy nem tesz semmit. Szerencs�re
a tucatnyi
c�gn�l dolgoz� mintegy sz�z k�zremuk�do elolvasta �s megjegyz�sekkel l�tta el
a v�zlatokat, melyekbol az �ltal�nosan elfogadott hivatkoz�si k�zik�nyv �s a
szabv�nyos
ANSI C++ alapdokumentuma megsz�letett. A munk�t seg�tok neve megtal�lhat� a The
Annotated C++ Reference Manual-ban [Ellis, 1989]. V�g�l az ANSI X3J16 bizotts�ga a
Hewlett-
Packard kezdem�nyez�s�re 1989 december�ben �ssze�lt, 1991 j�nius�ban pedig m�r
14 Bevezet�s
annak �r�lhett�nk, hogy az ANSI (az amerikai nemzeti szabv�ny) C++ az ISO
(nemzetk�-
zi) C++ szabv�nyos�t�si kezdem�nyez�s r�sz�v� v�lt. 1990-tol ezek a szabv�ny�gyi
bizotts
�gok v�ltak a nyelv fejleszt�s�nek �s pontos k�r�lhat�rol�s�nak fo f�rumaiv�.
Magam
mindv�gig r�szt vettem e bizotts�gok munk�j�ban; a bov�tm�nyekkel foglalkoz�
munkacsoport
eln�kek�nt k�zvetlen�l feleltem a C++-t �rinto l�nyegbev�g� m�dos�t�si javaslatok
�s az �j szolg�ltat�sok bevezet�s�t szorgalmaz� k�relmek elb�r�l�s��rt. Az elso
szabv�nyv
�zlat 1995 �prilis�ban ker�lt a nagyk�z�ns�g el�, a v�gleges ISO C++ szabv�nyt
(ISO/IEC
14882) pedig 1998-ban fogadt�k el.
A k�nyvben bemutatott kulcsfontoss�g� oszt�lyok n�melyike a C++-szal p�rhuzamosan
fejl
od�tt. A complex, vector �s stack oszt�lyokat p�ld�ul az oper�tor-t�lterhel�si
elj�r�sokkal
egyidoben dolgoztam ki. A karakterl�nc- �s listaoszt�lyokat (string, list)
Jonathan
Shopironak k�sz�nhetj�k (az�rt �n is k�zremuk�dtem). Jonathan hasonl� oszt�lyai
voltak
az elsok, amelyeket egy k�nyvt�r r�szek�nt sz�les k�rben haszn�ltak; ezekbol a
r�gi k�s�rletekb
ol fejlesztett�k ki a C++ standard k�nyvt�r�nak string oszt�ly�t. A [Stroustrup,
1987]
�s a �12.7[11] �ltal le�rt task k�nyvt�r egyike volt az .oszt�lyokkal bov�tett C.
nyelven elo-
sz�r �rt programoknak. (A k�nyvt�rat �s a kapcsol�d� oszt�lyokat �n �rtam a Simula
st�lus�
szimul�ci�k t�mogat�s�hoz.) A k�nyvt�rat k�sobb Jonathan Shopiro �tdolgozta, �s
m�g ma
is haszn�lj�k. Az elso kiad�sban le�rt stream k�nyvt�rat �n terveztem �s
k�sz�tettem el, Jerry
Schwarz pedig Andrew Koenig form�z� elj�r�sa (�21.4.6) �s m�s �tletek
felhaszn�l�s�val az
e k�nyv 21. fejezet�ben bemutatand� iostreams k�nyvt�rr� alak�totta. A
szabv�nyos�t�s sor
�n a k�nyvt�r tov�bbi finom�t�son esett �t; a munka dand�rj�t Jerry Schwarz,
Nathan Myers
�s Norihiro Kumagai v�gezt�k. A sablonok lehetos�geit az Andrew Koenig, Alex
Stepanov,
szem�lyem �s m�sok �ltal tervezett vector, map, list �s sort sablonok alapj�n
dolgoztuk ki.
Alex Stepanovnak a sablonokkal t�rt�no �ltal�nos�tott programoz�s ter�n v�gzett
munk�ja
emellett elvezetett a t�rol�k bevezet�s�hez �s a C++ standard k�nyvt�r�nak egyes
algoritmusaihoz
is (�16.3, 17. fejezet, 18. fejezet �19.2). A sz�mokkal v�gzett muveletek valarray

k�nyvt�ra (22. fejezet) nagyr�szt Kent Budge munk�ja.


1.5. A C++ haszn�lata
A C++-t programoz�k sz�zezrei haszn�lj�k, l�nyeg�ben minden alkalmaz�si ter�leten.
Ezt
a haszn�latot t�mogatja tucatnyi f�ggetlen megval�s�t�s, t�bbsz�z k�nyvt�r �s
tank�nyv,
sz�mos muszaki foly�irat, konferencia, �s sz�mtalan konzult�ns. Oktat�s �s k�pz�s
minden
szinten, sz�les k�rben el�rheto.
1. Megjegyz�sek az olvas�hoz 15
A r�gebbi alkalmaz�sok erosen a rendszerprogramoz�s fel� hajlottak. T�bb nagy
oper�ci�s
rendszer �r�dott C++-ban: [Campbell, 1987] [Rozier, 1988] [Hamilton, 1993] [Berg,
1995]
[Parrington, 1995] �s sokan m�sok kulcsfontoss�g� r�szeket �rtak. A szerzo
l�nyegesnek tekinti
a C++ engedm�ny n�lk�li g�pk�zelis�g�t, ami lehetov� teszi, hogy C++-ban �rhassunk

eszk�zmeghajt�kat �s m�s olyan programokat, melyek val�sideju, k�zvetlen


hardverkezel�sre
t�maszkodnak. Az ilyen k�dban a muk�d�s kisz�m�that�s�ga legal�bb annyira fontos,
mint
a sebess�g �s gyakran �gy van az eredm�ny�l kapott rendszer t�m�rs�g�vel is. A C+
+-t �gy
tervezt�k, hogy minden nyelvi tulajdons�g haszn�lhat� legyen a komoly idobeli �s
helyfoglal
�sbeli megszor�t�soknak kitett k�dban is. [Stroustrup, 1994, �4.5].
A legt�bb programban vannak k�dr�szletek, melyek l�tfontoss�g�ak az elfogadhat�
teljes
�tm�ny tekintet�ben. A k�d nagyobb r�sz�t azonban nem ilyen r�szek alkotj�k. A
legt�bb
k�dn�l a m�dos�that�s�g, a k�nnyu bov�thetos�g �s tesztelhetos�g a kulcsk�rd�s. A
C++
ilyen t�ren ny�jtott t�mogat�sa vezetett el sz�lesk�ru haszn�lat�hoz ott, ahol
k�telezo
a megb�zhat�s�g, �s ahol az ido haladt�val jelentosen v�ltoznak a k�vetelm�nyek.
P�ldak
�nt a bankok, a kereskedelem, a biztos�t�si szf�ra, a t�vk�zl�s �s a katonai
alkalmaz�sok
szolg�lhatnak. Az USA t�vols�gi telefonrendszere �vek �ta a C++-ra t�maszkodik �s
minden
800-as h�v�st (vagyis olyan h�v�st, ahol a h�vott f�l fizet) C++ program ir�ny�t
[Kamath,
1993]. Sz�mos ilyen program nagy m�retu �s hossz� �letu. Ennek eredm�nyk�ppen a
stabilit
�s, a kompatibilit�s �s a m�retezhetos�g �lland� szempontok a C++ fejleszt�s�ben.
Nem szokatlanok a milli� soros C++ programok.
A C-hez hasonl�an a C++-t sem kifejezetten sz�mokkal v�gzett muveletekhez
tervezt�k.
Mindazon�ltal sok sz�mtani, tudom�nyos �s m�rn�ki sz�m�t�st �rtak C++-ban. Ennek
fo
oka, hogy a sz�mokkal val� hagyom�nyos munk�t gyakran grafik�val �s olyan
sz�m�t�sokkal
kell p�ros�tani, melyek a hagyom�nyos Fortran mint�ba nem illeszkedo
adatszerkezetekre
t�maszkodnak [Budge, 1992] [Barton, 1994]. A grafika �s a felhaszn�l�i fel�let
olyan
ter�letek, ahol erosen haszn�lj�k a C++-t. B�rki, aki ak�r egy Apple Macintosht,
ak�r egy
Windowst futtat� PC-t haszn�lt, k�zvetve a C++-t haszn�lta, mert e rendszerek
elsodleges
felhaszn�l�i fel�leteit C++ programok alkotj�k. Ezenk�v�l a UNIX-ban az X-et
t�mogat� legn
�pszerubb k�nyvt�rak n�melyike is C++-ban �r�dott. Ilyenform�n a C++ k�z�sen
v�lasztott
nyelve annak a hatalmas sz�m� alkalmaz�snak, ahol a felhaszn�l�i fel�let kiemelt
fontoss
�g�.
Mindezen szempontok mellett lehet, hogy a C++ legnagyobb eross�ge az a k�pess�ge,
hogy
hat�konyan haszn�lhat� olyan programokhoz, melyek t�bbf�le alkalmaz�si ter�leten
ig�-
nyelnek munk�t. Egyszeru olyan alkalmaz�st tal�lni, melyben LAN �s WAN h�l�zatot,
sz�mokkal v�gzett muveleteket, grafik�t, felhaszn�l�i k�lcs�nhat�st �s adatb�zis-
hozz�f�r�st
haszn�lunk. Az ilyen alkalmaz�si ter�leteket r�gebben k�l�n�ll�knak tekintett�k �s
�ltal�-
ban k�l�n�ll� fejlesztok�z�ss�gek szolg�lt�k ki, t�bbf�le programoz�si nyelvet
haszn�lva.
16 Bevezet�s
A C++-t sz�les k�rben haszn�lj�k oktat�sra �s kutat�sra. Ez n�h�ny embert
meglepett,
akik . helyesen . r�mutattak, hogy a C++ nem a legkisebb �s legtiszt�bb nyelv,
amelyet valaha
terveztek. Mindazon�ltal a C++
� el�g tiszta ahhoz, hogy az alapfogalmakat sikeresen tan�tsuk,
� el�g val�szeru, hat�kony �s rugalmas az ig�nyes projektekhez is,
� el�rheto olyan szervezetek �s egy�ttmuk�do csoportok sz�m�ra, melyek elt�ro
fejleszt�si �s v�grehajt�si k�rnyezetekre t�maszkodnak,
� el�g �rtheto ahhoz, hogy bonyolult fogalmak �s m�dszerek tan�t�s�nak hordoz
�ja legyen �s
� el�g .kereskedelmi., hogy seg�tse a tanultak gyakorlatban val� felhaszn�l�s�t.
A C++ olyan nyelv, mellyel gyarapodhatunk.
1.6. C �s C++
A C++ alapnyelv�nek a C nyelvet v�lasztottuk, mert
� sokoldal�, t�m�r, �s viszonylag alacsony szintu,
� megfelel a legt�bb rendszerprogramoz�si feladatra,
� minden�tt �s mindenen fut, �s
� illeszkedik a UNIX programoz�si k�rnyezetbe.
A C-nek megvannak a hib�i, de egy �jonnan k�sz�tett nyelvnek is lenn�nek, a C
probl�m�-
it pedig m�r ismerj�k. Nagy jelentos�ge van, hogy C-vel val� munka vezetett el a
hasznos
(b�r neh�zkes) eszk�zz� v�l� .oszt�lyokkal bov�tett C.-hez, amikor elosz�r
gondoltunk a C
bov�t�s�re Simula-szeru oszt�lyokkal.
Ahogy sz�lesebb k�rben kezdt�k haszn�lni a C++-t �s az �ltala ny�jtott, a C
lehetos�geit fel
�lm�l� k�pess�gek jelentosebbek lettek, �jra �s �jra felmer�lt a k�rd�s,
megtartsuk-e a k�t
nyelv �sszeegyeztethetos�g�t. Vil�gos, hogy n�h�ny probl�ma elker�lheto lett
volna, ha
n�melyik C �r�ks�get elutas�tjuk (l�sd pl. [Sethi, 1981]). Ezt nem tett�k meg, a
k�vetkezok
miatt:
1. Megjegyz�sek az olvas�hoz 17
1. T�bb milli� sornyi C k�d van, mely �lvezheti a C++ elonyeit, felt�ve, hogy
sz�ks�gtelen a C-rol C++-ra val� teljes �t�r�s.
2. T�bb milli� sornyi C-ben �rt k�nyvt�ri f�ggv�ny �s eszk�zilleszto k�d van,
melyet
C++ programokb�l/programokban haszn�lni lehet, felt�ve, hogy a C++
program �sszeszerkesztheto �s formailag �sszeegyeztetheto a C programmal.
3. Programoz�k sz�zezrei l�teznek, akik ismerik a C-t �s ez�rt csak a C++ �j
tulajdons
�gait kell megtanulniuk, vagyis nem kell az alapokkal kezdeni�k.
4. A C++-t �s a C-t ugyanazok, ugyanazokon a rendszereken fogj�k �vekig haszn
�lni, teh�t a k�l�nbs�gek vagy nagyon nagyok, vagy nagyon kicsik lesznek,
hogy a hib�k �s a kevered�s lehetos�ge a leheto legkisebbre cs�kkenjen.
A C++-t fel�lvizsg�ltuk, hogy biztos�tsuk, hogy azon szerkezetek, melyek mind a C-
ben,
mind a C++-ban megengedettek, mindk�t nyelvben ugyanazt jelents�k (�B.2).
A C nyelv maga is fejlod�tt, r�szben a C++ fejleszt�s�nek hat�s�ra [Rosler, 1984].
Az ANSI C
szabv�ny [C,1990] a f�ggv�nydeklar�ci�k formai k�vetelm�nyeit az .oszt�lyokkal
bov�tett
C.-bol vette �t. Az �tv�tel mindk�t ir�nyban elofordul: a void* mutat�t�pust
p�ld�ul az ANSI
C-hez tal�lt�k ki, de elosz�r a C++-ban val�s�tott�k meg. Mint ahogy e k�nyv elso
kiad�s�-
ban meg�g�rt�k, a C++-t fel�lvizsg�ltuk, hogy elt�vol�tsuk az indokolatlan
elt�r�seket, �gy
a C++ ma jobban illeszkedik a C-hez, mint eredetileg. Az elk�pzel�s az volt, hogy
a C++
olyan k�zel legyen az ANSI C-hez, amennyire csak lehets�ges . de ne k�zelebb
[Koenig,
1989]. A sz�z sz�zal�kos megfelelos�g soha nem volt c�l, mivel ez megalkuv�st
jelentene
a t�pusbiztons�gban, valamint a felhaszn�l�i �s be�p�tett t�pusok z�kken�smentes
egyeztet
�s�ben.
A C tud�sa nem elofelt�tele a C++ megtanul�s�nak. A C programoz�s sok olyan
m�dszer �s
tr�kk haszn�lat�ra biztat, melyeket a C++ nyelvi tulajdons�gai sz�ks�gtelenn�
tettek. Az
explicit t�pusk�nyszer�t�s p�ld�ul ritk�bban sz�ks�ges a C++-ban, mint a C-ben
(�1.6.1).
A j� C programok azonban hajlanak a C++ programok fel�. A Kernighan �s Ritchie
f�le
A C programoz�si nyelv (Muszaki k�nyvkiad�, m�sodik kiad�s, 1994) [Kernighan,1988]

c�mu k�tetben p�ld�ul minden program C++ program. B�rmilyen statikus t�pusokkal
rendelkez
o nyelvben szerzett tapasztalat seg�ts�get jelent a C++ tanul�s�n�l.
1.6.1. Javaslatok C programoz�knak
Min�l jobban ismeri valaki a C-t, ann�l nehezebbnek l�tja annak elker�l�s�t, hogy
C st�lusban
�rjon C++ programot, lemondva ez�ltal a C++ elonyeirol. K�rj�k, vessen az olvas�
egy
pillant�st a .B. f�ggel�kre, mely le�rja a C �s a C++ k�zti k�l�nbs�geket. �me
n�h�ny ter�-
let, ahol a C++ fejlettebb, mint a C:
18 Bevezet�s
1. A C++-ban a makr�kra majdnem soha sincs sz�ks�g. A n�vvel ell�tott �lland�k
meghat�roz�s�ra haszn�ljunk konstanst (const) (�5.4) vagy felsorol�st (enum)
(�4.8), a f�ggv�nyh�v�s okozta t�bbletterhel�s elker�l�s�re helyben kifejtett
f�ggv�nyeket (�7.1.1), a f�ggv�ny- �s t�puscsal�dok le�r�s�ra sablonokat
(13. fejezet), a n�v�tk�z�sek elker�l�s�re pedig n�vtereket (�8.2).
2. Ne vezess�nk be egy v�ltoz�t, mielott sz�ks�g van r�, �gy annak azonnal
kezdo�rt�ket is adhatunk. Deklar�ci� b�rhol lehet, ahol utas�t�s lehet (�6.3.1),
�gy for utas�t�sok (�6.3.3) �s el�gaz�sok felt�teleiben (�6.3.2.1) is.
3. Ne haszn�ljunk malloc()-ot, a new oper�tor (�6.2.6) ugyanazt jobban elv�gzi.
A realloc() helyett pr�b�ljuk meg a vector-t (�3.8).
4. Pr�b�ljuk elker�lni a void* mutat�kkal val� sz�m�t�sokat, az uni�kat �s
t�puskonverzi
�kat (t�pus�talak�t�sokat), kiv�ve, ha valamely f�ggv�ny vagy oszt�ly
megval�s�t�s�nak m�ly�n tal�lhat�k. A legt�bb esetben a t�puskonverzi� a tervez
�si hiba jele. Ha felt�tlen�l erre van sz�ks�g, az .�j cast-ok. (�6.2.7) egyik�t
pr�b�ljuk haszn�lni sz�nd�kunk pontosabb le�r�s�hoz.
5. Cs�kkents�k a leheto legkevesebbre a t�mb�k �s a C st�lus� karakterl�ncok
haszn�lat�t. A C++ standard k�nyvt�r�nak string (�3.5) �s vector (�3.7.1) oszt�-
lyai a hagyom�nyos C st�lushoz k�pest gyakrabban haszn�lhat�k a programoz�s
egyszerubb� t�tel�re. �ltal�ban ne pr�b�ljunk magunk �p�teni olyat, ami megvan
a standard k�nyvt�rban.
Ahhoz, hogy eleget tegy�nk a C szerkeszt�si szab�lyainak, a C++ f�ggv�nyeket �gy
kell
megadnunk, hogy szerkeszt�s�k C m�d� legyen. (�9.2.4). A legfontosabb, hogy �gy
pr�-
b�ljunk egy programot elk�pzelni, mint egym�ssal k�lcs�nhat�sban l�vo fogalmakat,
melyeket
oszt�lyok �s objektumok k�pviselnek, nem pedig �gy, mint egy halom
adatszerkezetet,
a bitekkel zsonglork�do f�ggv�nyekkel.
1.6.2. Javaslatok C++ programoz�knak
Sokan m�r egy �vtized �ta haszn�lj�k a C++-t. M�g t�bben haszn�lj�k egyetlen
k�rnyezetben
�s tanultak meg egy�tt �lni a korai ford�t�k �s elso gener�ci�s k�nyvt�rak miatti
korl�-
toz�sokkal. Ami a tapasztalt C++ programoz�k figyelm�t gyakran elker�li, nem is
annyira
az �j eszk�z�k megjelen�se, mint ink�bb ezen eszk�z�k kapcsolatainak v�ltoz�sa,
ami
alapjaiban �j programoz�si m�dszereket k�vetel meg. M�s sz�val, amire annak idej�n
nem
gondoltunk vagy haszontalannak tartottunk, ma m�r kiv�l� m�dszerr� v�lhatott, de
ezekre
csak az alapok �jragondol�s�val tal�lunk r�.
1. Megjegyz�sek az olvas�hoz 19
Olvassuk �t a fejezeteket sorban. Ha m�r ismerj�k a fejezet tartalm�t, gondolatban
ism�telj
�k �t. Ha m�g nem ismerj�k, valami olyat is megtanulhatunk, amire eredetileg nem
sz�m�-
tottunk. �n magam el�g sokat tanultam e k�nyv meg�r�s�b�l, �s az a gyan�m, hogy
kev�s
C++ programoz� ismeri az �sszes itt bemutatott �sszes eszk�zt �s elj�r�st. Ahhoz,
hogy helyesen
haszn�ljunk egy nyelvet, behat�an kell ismern�nk annak eszk�zeit, m�dszereit. Fel-

�p�t�se �s p�ld�i alapj�n ez a k�nyv megfelelo r�l�t�st biztos�t.


1.7. Programoz�si megfontol�sok a C++-ban
A programtervez�st ide�lis esetben h�rom fokozatban k�zel�tj�k meg. Elosz�r
tiszt�n �rthet
ov� tessz�k a probl�m�t (elemz�s, anal�zis), ezut�n azonos�tjuk a fo fogalmakat,
melyek
egy megold�sban szerepelnek (tervez�s), v�g�l a megold�st egy programban fejezz�k
ki
(programoz�s). A probl�ma r�szletei �s a megold�s fogalmai azonban gyakran csak
akkor
v�lnak tiszt�n �rthetov�, amikor egy elfogadhat�an futtathat� programban akarjuk
kifejezni
azokat. Ez az, ahol sz�m�t, milyen programoz�si nyelvet v�lasztunk.
A legt�bb alkalmaz�sban vannak fogalmak, melyeket nem k�nnyu a kapcsol�d� adatok
n�lk�l az alapt�pusok egyik�vel vagy f�ggv�nnyel �br�zolni. Ha adott egy ilyen
fogalom,
hozzunk l�tre egy oszt�lyt, amely a programban k�pviselni fogja. A C++ oszt�lyai
t�pusok,
melyek meghat�rozz�k, hogyan viselkednek az oszt�lyba tartoz� objektumok, hogyan
j�nnek
l�tre, hogyan kezelhetok �s hogyan szunnek meg. Az oszt�ly le�rhatja azt is,
hogyan
jelennek meg az objektumok, b�r a programtervez�s korai szakasz�ban ez nem
sz�ks�gszer
uen fo szempont. J� programok �r�s�n�l az a legfontosabb, hogy �gy hozzunk l�tre
oszt
�lyokat, hogy mindegyik�k egyetlen fogalmat, tiszt�n �br�zoljon. Ez �ltal�ban azt
jelenti,
hogy a k�vetkezo k�rd�sekre kell �sszpontos�tani: Hogyan hozzuk l�tre az oszt�ly
objektumait?
M�solhat�k-e �s/vagy megsemmis�thetok-e az oszt�ly objektumai? Milyen muveletek
alkalmazhat�k az objektumokra? Ha nincsenek j� v�laszok e k�rd�sekre, az a
legval�-
sz�nubb, hogy a fogalom nem .tiszta.. Ekkor j� �tlet, ha tov�bb gondolkodunk a
probl�m�n
�s annak javasolt megold�s�n, ahelyett, hogy azonnal elkezden�nk a k�d
kidolgoz�s�t.
A legk�nnyebben kezelheto fogalmak azok, amelyeknek hagyom�nyos matematikai
megfogalmaz
�suk van: mindenfajta sz�mok, halmazok, geometriai alakzatok stb. A sz�vegk�zpont
� bemenet �s kimenet, a karakterl�ncok, az alapt�rol�k, az ezekre a t�rol�kra
alkalmazhat�
alap-algoritmusok, valamint n�h�ny matematikai oszt�ly a C++ standard k�nyvt�r�nak
r�sz�t
k�pezik (3. fejezet, �16.1.2). Ezenk�v�l elk�peszto v�laszt�kban l�teznek
k�nyvt�rak, melyek
�ltal�nos �s r�szter�letekre szakosodott elemeket t�mogatnak.
20 Bevezet�s
Az egyes fogalmak (�s a hozz�juk kapcsol�d� elemek) nem l�g�res t�rben l�teznek,
mindig
rokonfogalmak csoportj�ba tartoznak. Az oszt�lyok k�zti kapcsolatok szervez�se egy

programon bel�l . vagyis az egy megold�sban szereplo k�l�nb�zo elemek k�zti pontos

kapcsolatok meghat�roz�sa . gyakran nehezebb, mint az egyes oszt�lyokat kijel�lni.


Jobb,
ha az eredm�ny nem rendetlens�g, melyben minden oszt�ly f�gg minden m�sikt�l.
Vegy�nk k�t oszt�lyt: A-t �s B-t. Az olyan kapcsolatok, mint az .A h�v B-beli
f�ggv�nyeket.,
.A l�trehoz B-ket. �s .A-nak van egy B tagja. ritk�n okoznak nagy probl�m�t, m�g
az olyanok,
mint az .A haszn�l B-beli adatot. rendszerint kik�sz�b�lhetok.
Az �sszetetts�g kezel�s�nek egyik legerosebb eszk�ze a hierarchikus rendez�s,
vagyis a rokon
elemek faszerkezetbe szervez�se, ahol a fa gy�kere a leg�ltal�nosabb elem. A C++-
ban
a sz�rmaztatott oszt�lyok ilyen fastrukt�r�kat k�pviselnek. Egy program gyakran
�gy szervezhet
o, mint f�k halmaza, vagy mint oszt�lyok ir�ny�tott k�rmentes gr�fja. Vagyis a
programoz
� n�h�ny alaposzt�lyt hoz l�tre, melyekhez saj�t sz�rmaztatott oszt�lyaik halmaza
tartozik. Az elemek leg�ltal�nosabb v�ltozat�nak (a b�zisoszt�lynak) a kezel�s�t
v�gzo mu-
veletek meghat�roz�s�ra a virtu�lis f�ggv�nyeket (�2.5.5, �12.2.6) haszn�lhatjuk.
Sz�ks�g
eset�n ezen muveletek megval�s�t�sa az egyedi esetekben (a sz�rmaztatott
oszt�lyokn�l)
finom�that�.
N�ha m�g az ir�ny�tott k�rmentes gr�f sem l�tszik kiel�g�tonek a programelemek
szervez�-
s�re; egyes elemek k�lcs�n�s �sszef�gg�se �r�kl�ttnek tunik. Ilyen esetben
megpr�b�ljuk
a ciklikus f�ggos�geket behat�rolni, hogy azok ne befoly�solj�k a program �tfog�
rendszer
�t. Ha nem tudjuk kik�sz�b�lni vagy behat�rolni az ilyen k�lcs�n�s f�gg�seket,
val�sz�-
nu, hogy olyan gondban vagyunk, melybol nincs programoz�si nyelv, amely
kiseg�tene.
Hacsak ki nem tudunk eszelni k�nnyen meg�llap�that� kapcsolatokat az alapfogalmak
k�-
z�tt, val�sz�nu, hogy a program kezelhetetlenn� v�lik. A f�ggos�gi gr�fok
kibogoz�s�nak
egyik eszk�ze a fel�let (interf�sz) tiszta elk�l�n�t�se a megval�s�t�st�l
(implement�ci�).
A C++ erre szolg�l� legfontosabb eszk�zei az absztrakt oszt�lyok (�2.5.4, �12.3).
A k�z�s tulajdons�gok kifejez�s�nek m�sik form�ja a sablon (template, �2.7, 13.
fejezet). Az
oszt�lysablonok oszt�lyok csal�dj�t �rj�k le. Egy listasablon p�ld�ul a .T elemek
list�j�t. hat
�rozza meg, ahol .T. b�rmilyen t�pus lehet. A sablon teh�t azt adja meg, hogyan
hozhatunk
l�tre egy t�pust egy m�sik t�pus, mint param�ter �tad�s�val. A legszok�sosabb
sablonok az
olyan t�rol�oszt�lyok, mint a list�k, t�mb�k �s asszociat�v t�mb�k, valamint az
ilyen t�rol
�kat haszn�l� alap-algoritmusok. Rendszerint hiba, ha egy oszt�ly �s a vele
kapcsolatos
f�ggv�nyek param�terez�s�t �r�kl�st haszn�l� t�pussal fejezz�k ki. A legjobb
sablonokat
haszn�lni.
1. Megjegyz�sek az olvas�hoz 21
Eml�keztet�nk arra, hogy sok programoz�si feladat egyszeruen �s tiszt�n
elv�gezheto elemi
t�pusok, adatszerkezetek, vil�gos f�ggv�nyek �s n�h�ny k�nyvt�ri oszt�ly
seg�ts�g�vel.
Az �j t�pusok le�r�s�ban szereplo teljes appar�tust nem szabad haszn�lni, kiv�ve,
ha val�-
ban sz�ks�g van r�.
A .Hogyan �rjunk C++-ban j� programot?. nagyon hasonl�t a .Hogyan �rjunk j�
pr�z�t?. k�rd
�sre. K�t v�lasz van: .Tudnunk kell, mit akarunk mondani. �s .Gyakoroljunk.
Sz�nlelj�k
a j� �r�st.. Mind a ketto �pp�gy helyt�ll� a C++, mint b�rmely term�szetes nyelv
eset�ben .
�s tan�csukat �ppolyan neh�z k�vetni.
1.8. Tan�csok
�me n�h�ny .szab�ly., amelyet figyelembe vehet�nk a C++ tanul�sakor. Ahogy
j�rtasabbak
lesz�nk, tov�bbfejleszthetj�k ezeket saj�t programfajt�inkhoz, programoz�si
st�lusunkhoz
illeszkedoen. A szab�lyok sz�nd�kosan nagyon egyszeruek, �gy n�lk�l�zik a
r�szleteket.
Ne vegy�k oket t�lzottan komolyan: a j� programok �r�s�hoz elsosorban
intelligencia, �zl
�s, t�relem kell. Ezeket nem fogjuk elsore elsaj�t�tani. K�s�rletezz�nk!
[1] Amikor programozunk, valamilyen probl�ma megold�s�ra sz�letett �tleteink konkr
�t megval�s�t�s�t hozzuk l�tre. T�kr�zze a program szerkezete olyan k�zvetlen�l
ezeket az �tleteket, amennyire csak lehets�ges:
a) Ha valamire �gy gondolunk, mint k�l�n �tletre, tegy�k oszt�lly�.
b) Ha k�l�n�ll� egyedk�nt gondolunk r�, tegy�k egy oszt�ly objektum�v�.
c) Ha k�t oszt�lynak van k�z�s fel�lete, tegy�k ezt a fel�letet absztrakt
oszt�lly�.
d) Ha k�t oszt�ly megval�s�t�s�ban van valami k�z�s, tegy�k b�zisoszt�lly� e
k�z�s tulajdons�gokat.
e) Ha egy oszt�ly objektumok t�rol�ja, tegy�k sablonn�.
f) Ha egy f�ggv�ny egy t�rol� sz�m�ra val� algoritmust val�s�t meg, tegy�k
f�ggv�nysablonn�, mely egy t�rol�csal�d algoritmus�t �rja le.
g) Ha oszt�lyok, sablonok stb. egy halmaz�n bel�l logikai rokons�g van, tegy�k
azokat k�z�s n�vt�rbe.
[2] Ha olyan oszt�lyt hozunk l�tre, amely nem matematikai egyedet �r le (mint egy
m�trix vagy komplex sz�m) vagy nem alacsonyszintu t�pust (mint egy l�ncolt lista)
a) ne haszn�ljunk glob�lis adatokat (haszn�ljunk tagokat),
b) ne haszn�ljunk glob�lis f�ggv�nyeket,
22 Bevezet�s
c) ne haszn�ljunk nyilv�nos adattagokat,
d) ne haszn�ljunk .bar�t. (friend) f�ggv�nyeket, kiv�ve a) vagy c) elker�l�s�re,
e) ne tegy�nk egy oszt�lyba t�pusazonos�t� mezoket, haszn�ljunk ink�bb virtu�-
lis f�ggv�nyeket,
f) ne haszn�ljunk helyben kifejtett f�ggv�nyeket, kiv�ve ha jelentos optimaliz�-
l�sr�l van sz�.
Egyedi �s r�szletesebb gyakorlati szab�lyokat az egyes fejezetek .Tan�csok.
r�sz�ben tal�lhatunk.
Eml�keztetj�k az olvas�t, hogy ezek a tan�csok csak �tmutat�sul szolg�lnak, nem
megv�ltoztathatatlan t�rv�nyek. A tan�csokat csak ott k�vess�k, ahol �rtelme van.
Nincs
p�tszere az intelligenci�nak, a tapasztalatnak, a j�zan �sznek �s a j� �zl�snek.
A .soha ne tegy�k ezt. alak� szab�lyokat haszontalannak tekintem. K�vetkez�sk�ppen

a legt�bb tan�csot javaslatk�nt fogalmaztam meg; azt �rtam le, mit tegy�nk. A
.negat�v javaslatokat
. pedig nem �gy kell �rteni, mint tilt�sokat: nem tudok a C++ olyan fo tulajdons
�g�r�l, melyet ne l�ttam volna j�l felhaszn�lni. A .Tan�csok. nem tartalmaznak
magyar�-
zatokat. Helyette minden tan�cs mellett hivatkoz�s tal�lhat� a k�nyv megfelelo
r�sz�re.
Ahol negat�v tan�cs szerepel, a hivatkozott r�sz rendszerint alternat�v javaslatot
tartalmaz.
1.8.1. Hivatkoz�sok
Barton, 1994 John J. Barton and Lee R. Nackman: Scientific and Engineering C++.
Addison-
Wesley. Reading, Mass. 1994. ISBN 1-201-53393-6.
Berg, 1995 William Berg, Marshall Cline, and Mike Girou: Lessons Learned from the
OS/400
OO Project. CACM. Vol. 38 No. 10. October 1995.
Booch, 1994 Grady Booch: Object-Oriented Analysis and Design. Benjamin/Cummings.
Menlo
Park, Calif. 1994. ISBN 0-8053-5340-2.
Budge, 1992 Kent Budge, J. S. Perry, an A. C. Robinson: High-Performance
Scientific
Computation using C++. Proc. USENIX C++Conference. Portland, Oregon. August
1992.
C, 1990 X3 Secretariat: Standard - The C Language. X3J11/90-013. ISO Standard
ISO/IEC
9899. Computer and Business Equipment Manufacturers Association. Washington,
DC, USA.
C++, 1998 X+ Secretariat: International Standard- The C++ Language. X3J16-14882.
Information Technology Council (NSITC). Washington, DC, USA.
Campbell, 1987 Roy Campbell, et al.: The Design of a Multirocessor Operating
System. Proc.
USENIX C++ Conference. Santa Fe, New Mexico. November 1987.
Coplien, 1995 James O. Coplien and Douglas C. Schmidt (editors): Pattern Languages
of
Program Design. Addison-Wesley. Reading, Mass. 1995. ISBN 1-201-60734-4.
1. Megjegyz�sek az olvas�hoz 23
Dahl, 1970 O-J. Dahl, B. Myrhaug, and K. Nygaard: SIMULA Common Base Language.
Norwegian Computing Center S-22. Oslo, Norway. 1970.
Dahl, 1972 O-J. Dahl, and C. A. R. Hoare: Hierarchical Program Consturction in
Structured
Programming. Academic Press, New York. 1972.
Ellis, 1989 Margaret A. Ellis and Bjarne Stroustrup: The Annotated C++ Reference
Manual.
Addison-Wesley. Reading, Mass. 1990. ISBN 0-201-51459-1.
Gamma, 1995 Erich Gamma, et al.: Design Patterns. Addison-Wesley. Reading, Mass.
1995. ISBN
0-201-63361-2.
Goldberg, 1983 A. Goldberg and D. Robson: SMALLTALK- 80 - The Language and Its
Implementation. Addison-Wesley. Reading, Mass. 1983.
Griswold, 1970 R. E. Griswold, et al.: The Snobol4 Programming Language. Prentice-
Hall.
Englewood Cliffs, New Jersey. 1970.
Griswold, 1983 R. E. Grisswold and M. T. Griswold: The ICON Programming Language.
Prentice-
Hall. Englewood Cliffs, New Jersey. 1983.
Hamilton, 1993 G. Hamilton and P. Kougiouris: The Spring Nucleus: A Microkernel
for Objects.
Proc. 1993 Summer USENIX Conference. USENIX.
Henricson, 1997 Mats Henricson and Erik Nyquist: Industrial Strenght C++: Rules
and
Recommendations. Prentice-Hall. Englewood Cliffs, New Jersey. 1997. ISBN 0-13-
120965-5.
Ichbiah, 1979 Jean D. Ichbiah, et al.: Rationale for the Design of the ADA
Programming
Language. SIGPLAN Notices. Vol. 14 No. 6. June 1979.
Kamath, 1993 Yogeesh H. Kamath, Ruth E. Smilan, and Jean G. Smith: Reaping
Benefits with
Object-Oriented Technology. AT&T Technical Journal. Vol. 72 No. 5.
September/October 1993.
Kernighan, 1978 Brian W. Kernighan and Dennis M. Ritchie: The C Programming
Language.
Prentice-Hall. Englewood Cliffs, New Jersey. 1978.
Kernighan, 1988 Brian W. Kernighan and Dennis M. Ritchie: The C Programming
Language
(Second Edition). Prentice-Hall. Enlewood Cliffs, New Jersey. 1988. ISBN 0-13-
110362-8.
Koenig, 1989 Andrew Koenig and Bjarne Stroustrup: C++: As close to C as possible -
but no
closer. The C++ Report. Vol. 1 No. 7. July 1989.
Koenig, 1997 Andrew Koenig and Barbara Moo: Ruminations on C++. Addison Wesley
Longman. Reading, Mass. 1997. ISBN 1-201-42339-1.
Knuth, 1968 Donald Knuth: The Art of Computer Programming. Addison-Wesley.
Reading,
Mass.
Liskowv, 1979 Barbara Liskov et al.: Clu Reference Manual. MIT/LCS/TR-225. MIT
Cambridge.
Mass. 1979.
Martin, 1995 Robert C. Martin: Designing Object-Oriented C++ Applications Using
the Booch
Method. Prentice-Hall. Englewood Cliffs, New Jersey. 1995. ISBN 0-13-203837-4.
Orwell, 1949 George Orwell: 1984. Secker and Warburg. London. 1949.
24 Bevezet�s
Parrington, 1995 Graham Parrington et al.: The Design and Implementation of
Arjuna. Computer
Systems. Vol. 8 No. 3. Summer 1995.
Richards, 1980 Martin Richards and Colin Whitby-Strevens: BCPL - The Language and
Its
Compiler. Cambridge University Press, Cambridge. England. 1980. ISBN 0-521-
21965-5.
Rosler, 1984 L. Rosler: The Evolution of C - Past and Future. AT&T Bell
Laboratories Technical
Journal. Vol. 63 No. 8. Part 2. October 1984.
Rozier, 1988 M. Rozier, et al.: CHORUS Distributed Operating Systems. Computing
Systems.
Vol. 1 no. 4. Fall 1988.
Sethi, 1981 Ravi Sethi: Uniform Syntax for Type Expressions and Declarations.
Software
Practice & Experience. Vol. 11. 1981.
Stepanov, 1994 Alexander Stepanov and Meng Lee: The Standard Template Library. HP
Labs
Technical Report HPL-94-34 (R. 1). August, 1994.
Stroustrup, 1986 Bjarne Stroustrup: The C++ Programming Language. Addison-Wesley.
Reading,
Mass. 1986. ISBN 0-201-12078-X.
Stroustrup, 1987 Bjarne Stroustrup and Jonathan Shopiro: A Set of C Classes for
Co-Routine Style
Programming. Proc. USENIX C++ conference. Santa Fe, New Mexico. November
1987.
Stroustrup, 1991 Bjarne Stroustrup: The C++ Programming Language (Second Edition)
Addison-
Wesley. Reading, Mass. 1991. ISBN 0-201-53992-6.
Strostrup, 1994 Bjarne Stroustrup: The Design and Evolution of C++. Addison-
Wesley. Reading,
Mass. 1994. ISBN 0-201-54330-3.
Tarjan, 1983 Robert E. Tarjan: Data Structures and Network Algorithms. Society for
Industrial
and Applied Mathematics. Philadelphia, Penn. 1983. ISBN 0-898-71187-8.
Unicode, 1996 The Unicode Consortium: The Unicode Standard, Version 2.0. Addison-
Wesley
Developers Press. Reading, Mass. 1996. ISBN 0-201-48345-9.
UNIX, 1985 UNIX Time-Sharing System: Programmer's Manual. Research Version, Tenth
Edition. AT&T Bell Laboratories, Murray Hill, New Jersey. February 1985.
Wilson, 1996 Gregory V. Wilson and Paul Lu (editors): Parallel Progrmming Using C+
+. The
MIT Press. Cambridge. Mass. 1996. ISBN 0-262-73118-5.
Wikstr�m, 1987 Ake Wikstr�m: Functional Programming Using ML. Prentice-Hall.
Englewood
Cliffs, New Jersey. 1987.
Woodward, 1974 P. M. Woodward and S. G. Bond: Algol 68-R Users Guide. Her
Majesty's Stationery
Office. London. England. 1974.
1. Megjegyz�sek az olvas�hoz 25
Kir�ndul�s a C++-ban
.Az elso tennival�nk: �lj�nk
meg minden t�rv�nytud�t.
(Shakespeare: VI. Henrik, II.
r�sz . ford. N�meth L�szl�)
Mi a C++? . Programoz�si megk�zel�t�sek . Elj�r�sk�zpont� programoz�s .
Modularit�s .
K�l�n ford�t�s . Kiv�telkezel�s . Elvont adat�br�zol�s . Felhaszn�l�i t�pusok .
Konkr�t
t�pusok . Absztrakt t�pusok . Virtu�lis f�ggv�nyek . Objektumorient�lt programoz�s
. �ltal
�nos�tott programoz�s . T�rol�k . Algoritmusok . Nyelv �s programoz�s . Tan�csok
2.1. Mi a C++?
A C++ �ltal�nos c�l� programoz�si nyelv, melynek fo alkalmaz�si ter�lete a
rendszerprogramoz
�s �s
� egy jobbfajta C,
� t�mogatja az elvont adat�br�zol�st,
� t�mogatja az objektumorient�lt programoz�st, valamint
� az �ltal�nos�tott programoz�st.
2
Ez a fejezet elmagyar�zza, mit jelentenek a fentiek, an�lk�l, hogy belemenne a
nyelv meghat
�roz�s�nak finomabb r�szleteibe. C�lja �ltal�nos �ttekint�st adni a C++-r�l �s
haszn�lat
�nak fo m�dszereirol, nem pedig a C++ programoz�s elkezd�s�hez sz�ks�ges r�szletes

inform�ci�t adni az olvas�nak.


Ha az olvas� t�l elnagyoltnak tal�lja e fejezet n�melyik r�sz�nek t�rgyal�sm�dj�t,
egyszer
uen ugorja �t �s l�pjen tov�bb. K�sobb mindenre r�szletes magyar�zatot kap.
Mindenesetre,
ha �tugrik r�szeket a fejezetben, tegye meg mag�nak azt a sz�vess�get, hogy k�sobb

visszat�r r�juk.
A nyelvi tulajdons�gok r�szletes meg�rt�se . m�g ha a nyelv �sszes tulajdons�g��
is . nem
ellens�lyozhatja azt, ha hi�nyzik az �tfog� szeml�let�nk a nyelvrol �s
haszn�lat�nak alapvet
o m�dszereirol.
2.2. Programoz�si megk�zel�t�sek
Az objektumorient�lt (objektumk�zpont�) programoz�s egy programoz�si m�d . a .j�.
programok �r�sa k�zben felmer�lo sereg probl�ma megold�s�nak egy megk�zel�t�se
(paradigma).
Ha az .objektumorient�lt programoz�si nyelv. szakkifejez�s egy�ltal�n jelent
valamit, olyan programoz�si nyelvet kell hogy jelentsen, amely az objektumokat
k�z�ppontba
helyezo programoz�si st�lust t�mogat� elj�r�sokr�l gondoskodik.
Itt fontos megk�l�nb�ztetn�nk k�t fogalmat: egy nyelvrol akkor mondjuk, hogy
t�mogat
egy programoz�si st�lust, ha olyan szolg�ltat�sai vannak, melyek �ltal az adott
st�lus haszn
�lata k�nyelmes (k�nnyu, biztons�gos �s hat�kony) lesz. A t�mogat�s hi�nyzik, ha
kiv�-
teles erofesz�t�s vagy �gyess�g kell az ilyen programok �r�s�hoz; ekkor a nyelv
csup�n
megengedi, hogy az adott megk�zel�t�st haszn�ljuk. Lehet struktur�lt programot
�rni
Fortran77-ben �s objektumk�zpont�t C-ben, de sz�ks�gtelen�l nehezen, mivel ezek a
nyelvek
nem t�mogatj�k k�zvetlen�l az eml�tett megk�zel�t�seket.
Az egyes programoz�si m�dok t�mogat�sa nem csak az adott megk�zel�t�s k�zvetlen
haszn
�lat�t lehetov� t�vo nyelvi szolg�ltat�sok mag�t�l �rtetodo form�j�ban rejlik,
hanem a ford
�t�si/fut�si idobeni ellenorz�sek finomabb form�iban, melyek v�delmet adnak a
st�lust�l
val� akaratlan elt�r�s ellen. A t�pusellenorz�s erre a legk�zenfekvobb p�lda, de a
k�t�rtelm
us�g �szlel�se �s a fut�si ideju ellenorz�sek szint�n a programoz�si m�dok nyelvi
t�mogat
�s�hoz tartoznak. A nyelven k�v�li szolg�ltat�sok, mint a k�nyvt�rak �s
programoz�si
k�rnyezetek, tov�bbi t�mogat�st adnak az egyes megk�zel�t�si m�dokhoz.
28 Bevezet�s
Egy nyelv nem sz�ks�gszeruen jobb, mint egy m�sik, csak az�rt, mert olyan
tulajdons�gokkal
rendelkezik, amelyek a m�sikban nem tal�lhat�k meg. Sok p�lda van ennek az
ellenkez
oj�re is. A fontos k�rd�s nem annyira az, milyen tulajdons�gai vannak egy
nyelvnek,
hanem ink�bb az, hogy a megl�vo tulajdons�gok elegendoek-e a k�v�nt programoz�si
st�-
lusok t�mogat�s�ra a k�v�nt alkalmaz�si ter�leteken. Ennek k�v�nalmai a
k�vetkezok:
1. Minden tulajdons�g tiszt�n �s .eleg�nsan. a nyelv szerves r�sze legyen.
2. A tulajdons�gokat egym�ssal p�ros�tva is lehessen haszn�lni, hogy olyan
megold�st adjanak, melyhez egy�bk�nt k�l�n nyelvi tulajdons�gok lenn�nek
sz�ks�gesek.
3. A leheto legkevesebb legyen az �l- �s .speci�lis c�l�. tulajdons�g.
4. Az egyes tulajdons�gok megval�s�t�sa nem okozhat jelentos t�bbletterhel�st
olyan programokn�l, melyek nem ig�nylik azokat.
5. A felhaszn�l�nak csak akkor kell tudnia a nyelv valamely r�szhalmaz�r�l, ha
kifejezetten haszn�lja azt egy program �r�s�hoz.
A fentiek k�z�l az elso elv az eszt�tik�hoz �s a logik�hoz val� folyamod�s. A
k�vetkezo
ketto a minimalizmus gondolat�nak kifejez�se, az utols� ketto pedig �gy
�sszes�theto: .amir
ol nem tudunk, az nem f�j..
A C++-t �gy tervezt�k, hogy az elvont adat�br�zol�st, illetve az objektumorient�lt
�s az �ltal
�nos�tott programoz�st t�mogassa, m�gpedig az e megszor�t�sok mellett t�mogatott
hagyom
�nyos C programoz�si m�dszereken k�v�l. Nem arra szolg�l, hogy minden
felhaszn�l�ra
egyetlen programoz�si st�lust k�nyszer�tsen.
A k�vetkezokben n�h�ny programoz�si st�lust �s az azokat t�mogat� fobb
tulajdons�gokat
vessz�k sz�mba. A bemutat�s egy sor programoz�si elj�r�ssal folytat�dik, melyek az
elj�r�sk
�zpont� (procedur�lis) programoz�st�l elvezetnek az objektumorient�lt
programoz�sban
haszn�lt oszt�lyhierarchi�ig �s a sablonokat haszn�l� �ltal�nos�tott (generikus)
programoz
�sig. Minden megk�zel�t�s az elodj�re �p�l, mindegyik hozz�tesz valamit a C++
programoz
�k eszk�zt�r�hoz, �s mindegyik egy bev�lt tervez�si m�dot t�kr�z.
A nyelvi tulajdons�gok bemutat�sa nem teljes. A hangs�ly a tervez�si
megk�zel�t�seken �s
a programok szerkezeti fel�p�t�s�n van, nem a nyelvi r�szleteken. Ezen a szinten
sokkal
fontosabb, hogy fogalmat kapjunk arr�l, mit lehet megtenni C++-t haszn�lva, mint
hogy
meg�rts�k, hogyan.
2. Kir�ndul�s a C++-ban 29
2.3. Elj�r�sk�zpont� programoz�s
Az eredeti programoz�si alapelv a k�vetkezo:
D�ntsd el, mely elj�r�sokra van sz�ks�ged
�s haszn�ld azokhoz a leheto legjobb algoritmusokat.
A k�z�ppontban az elj�r�s �ll . a k�v�nt sz�m�t�shoz sz�ks�ges algoritmus. A
nyelvek ezt
az alapelvet f�ggv�nyparam�terek �tad�s�val �s a f�ggv�nyek �ltal visszaadott
�rt�kekkel
t�mogatj�k. Az e gondolkod�sm�ddal kapcsolatos irodalom tele van a param�ter�tad�s
�s
a k�l�nb�zo param�terfajt�k megk�l�nb�ztet�si m�djainak (elj�r�sok, rutinok,
makr�k
stb.) t�rgyal�s�val.
A .j� st�lus. jellegzetes p�ld�ja az al�bbi n�gyzetgy�k-f�ggv�ny. �tadva egy
k�tszeres pontoss
�g� lebegopontos param�tert, a f�ggv�ny visszaadja az eredm�nyt. Ezt egy j�l
�rtheto
matematikai sz�m�t�ssal �ri el:
double sqrt(double arg)
{
// a n�gyzetgy�k kisz�m�t�s�nak k�dja
}
void f()
{
double root2 = sqrt(2);
// ...
}
A kapcsos z�r�jelek a C++-ban valamilyen csoportba foglal�st fejeznek ki; itt a
f�ggv�ny t�rzs
�nek kezdet�t �s a v�g�t jelzik. A kettos t�rtvonal // egy megjegyz�s (comment)
kezdete,
mely a sor v�g�ig tart. A void kulcssz� jelzi, hogy az f f�ggv�ny nem ad vissza
�rt�ket.
Programszervez�si szempontb�l a f�ggv�nyeket arra haszn�ljuk, hogy rendet
teremts�nk
az elj�r�sok labirintus�ban. Magukat az algoritmusokat f�ggv�nyh�v�sokkal �s m�s
nyelvi
szolg�ltat�sok haszn�lat�val �rjuk meg. A k�vetkezo alpontok v�zlatos k�pet adnak
a C++
legalapvetobb szolg�ltat�sair�l a sz�m�t�sok kifejez�s�hez.
30 Bevezet�s
2.3.1. V�ltoz�k �s aritmetika
Minden n�vnek �s kifejez�snek t�pusa van, amely meghat�rozza a v�grehajthat�
muveleteket:
int inch;
A fenti deklar�ci� p�ld�ul azt adja meg, hogy inch t�pusa int (vagyis inch egy
eg�sz t�pus�
v�ltoz�).
A deklar�ci� olyan utas�t�s, mely a programba egy nevet vezet be. Ehhez a n�vhez
egy t�-
pust rendel. A t�pus egy n�v vagy kifejez�s megfelelo haszn�lat�t hat�rozza meg.
A C++ t�bb alapt�pussal rendelkezik, melyek k�zvetlen megfeleloi bizonyos
hardverszolg
�ltat�soknak. P�ld�ul:
bool // logikai t�pus, lehets�ges �rt�kei: true (igaz) �s false (hamis)
char // karakter, p�ld�ul 'a', 'z', vagy '9'
int // eg�sz �rt�k, p�ld�ul 1, 42, vagy 1216
double // k�tszeres pontoss�g� lebegopontos sz�m, p�ld�ul 3.14 vagy 299793.0
A char v�ltoz�k term�szetes m�rete egy karakter m�rete az adott g�pen (rendesen
egy
b�jt), az int v�ltoz�k� az adott g�pen muk�do eg�sz t�pus� aritmetik�hoz igazodik
(rendszerint
egy g�pi sz�).
Az aritmetikai muveletek e t�pusok b�rmilyen p�ros�t�s�ra haszn�lhat�k:
+ // �sszead�s vagy elojel, egy- �s k�toperandus� is lehet
- // kivon�s vagy elojel, egy- �s k�toperandus� is lehet
* // szorz�s
/ // oszt�s
% // marad�kk�pz�s
Ugyan�gy az �sszehasonl�t� muveletek is:
== // egyenlo
!= // nem egyenlo
< // kisebb
> // nagyobb
<= // kisebb vagy egyenlo
>= // nagyobb vagy egyenlo
�rt�kad�sokban �s aritmetikai muveletekben a C++ az alapt�pusok k�z�tt elv�gez
minden
�rtelmes �talak�t�st, �gy azokat egym�ssal tetsz�s szerint keverhetj�k:
2. Kir�ndul�s a C++-ban 31
void some_function() // �rt�ket vissza nem ad� f�ggv�ny
{
double d = 2.2; // lebegopontos sz�m kezdeti �rt�kad�sa
int i = 7; // eg�sz kezdeti �rt�kad�sa
d = d+i; // �sszeg �rt�kad�sa
i = d*i; // szorzat �rt�kad�sa
}
Itt = az �rt�kad� muvelet jele �s == az egyenlos�get teszteli, mint a C-ben.
2.3.2. El�gaz�sok �s ciklusok
A C++ az el�gaz�sok �s ciklusok kifejez�s�re rendelkezik a hagyom�nyos
utas�t�sk�szlettel.
�me egy egyszeru f�ggv�ny, mely a felhaszn�l�t�l v�laszt k�r �s a v�laszt�l f�ggo
logikai
�rt�ket ad vissza:
bool accept()
{
cout << "Do you want to proceed (y or n)?\n"; // k�rd�s ki�r�sa
char answer = 0;
cin >> answer; // v�lasz beolvas�sa
if (answer == 'y') return true;
return false;
}
A << (.tedd bele.) muveleti jelet kimeneti oper�tork�nt haszn�ltuk; a cout a
szabv�nyos kimeneti
adatfolyam. A >> (.olvasd be.) a bemenet muveleti jele, a cin a szabv�nyos bemen
o adatfolyam. A >> jobb oldal�n �ll� kifejez�s hat�rozza meg, milyen bemenet
fogadhat�
el �s ez a beolvas�s c�lpontja. A \n karakter a ki�rt karakterl�nc v�g�n �j sort
jelent.
A p�lda kiss� jav�that�, ha egy 'n' v�laszt is sz�m�t�sba vesz�nk:
bool accept2()
{
cout << "Do you want to proceed (y or n)?\n"; // k�rd�s ki�r�sa
char answer = 0;
cin >> answer; // v�lasz beolvas�sa
32 Bevezet�s
switch (answer) {
case 'y':
return true;
case 'n':
return false;
default:
cout << "I'll take that for a no.\n"; // nemleges v�lasznak veszi
return false;
}
}
A switch utas�t�s egy �rt�ket ellenoriz, �lland�k halmaz�t alapul v�ve. A case
konstansoknak
k�l�n�ll�knak kell lenni�k, �s ha az �rt�k egyikkel sem egyezik, a vez�rl�s a
default
c�mk�re ker�l. A programoz�nak nem kell alap�rtelmez�srol (default) gondoskodnia.
Kev�s programot �rnak ciklusok n�lk�l. Eset�nkben szeretn�nk lehetos�get adni a
felhaszn
�l�nak n�h�ny pr�b�lkoz�sra:
bool accept3()
{
int tries = 1;
while (tries < 4) {
cout << "Do you want to proceed (y or n)?\n"; // k�rd�s ki�r�sa
char answer = 0;
cin >> answer; // v�lasz beolvas�sa
switch (answer) {
case 'y':
return true;
case 'n':
return false;
default:
cout << "Sorry, I don't understand that.\n" ; // nem �rti a v�laszt
tries = tries + 1;
}
}
cout << "I'll take that for a no.\n"; // nemleges v�lasznak veszi
return false;
}
A while utas�t�s addig hajt�dik v�gre, am�g a felt�tele hamis nem lesz.
2. Kir�ndul�s a C++-ban 33
2.3.3. Mutat�k �s t�mb�k
Egy t�mb�t �gy hat�rozhatunk meg:
char v[10]; // 10 karakterbol �ll� t�mb
Egy mutat�t �gy:
char* p; // mutat� karakterre
A deklar�ci�kban a [ ] jelent�se .t�mbje. (array of), m�g a * jelent�se .mutat�ja.
(pointer to).
Minden t�mbnek 0 az als� hat�ra, teh�t v-nek t�z eleme van, v[0].v[9]. A mutat�
v�ltoz�
a megfelelo t�pus� objektum c�m�t tartalmazhatja:
p = &v[3]; // p a v negyedik elem�re mutat
A .c�me. jelent�ssel b�r� oper�tor az egyoperandus� &. L�ssuk, hogyan m�solhatjuk
�t egy
t�mb t�z elem�t egy m�sik t�mbbe:
void another_function()
{
int v1[10];
int v2[10];
// ...
for (int i=0; i<10; ++i) v1[i]=v2[i];
}
A for utas�t�s �gy olvashat�: .�ll�tsuk i-t 0-ra, am�g i kisebb, mint 10, az i-
edik elemet m�-
soljuk �t, �s n�velj�k meg i-t.. Ha eg�sz t�pus� v�ltoz�ra alkalmazzuk, a ++
n�velo muveleti
jel az �rt�ket egyszeruen eggyel n�veli.
2.4. Modul�ris programoz�s
Az �vek sor�n a programtervez�s s�lypontja az elj�r�sok felol az adatszervez�s
ir�ny�ba tol
�dott el. Egyebek mellett ez a programok nagyobb m�ret�ben t�kr�zodik. Az
egym�ssal
rokon elj�r�sokat az �ltaluk kezelt adatokkal egy�tt gyakran modul-nak nevezz�k. A
megk
�zel�t�s alapelve ez lesz:
34 Bevezet�s
D�ntsd el, mely modulokra van sz�ks�g �s oszd fel
a programot �gy, hogy az adatokat modulokba helyezed.
Ez az adatrejt�s elve. Ahol az elj�r�sok nincsenek az adatokkal egy csoportban, az
elj�r�sk
�zpont� programoz�s megfelel a c�lnak. Az egyes modulokon bel�li elj�r�sokra a .j�
elj
�r�sok. tervez�s�nek m�dja is alkalmazhat�. A modulra a legk�z�ns�gesebb p�lda egy

verem (stack) l�trehoz�sa. A megoldand� fo probl�m�k:


1. Gondoskodni kell a verem felhaszn�l�i fel�let�rol (pl. push() �s pop()
f�ggv�nyek).
2. Biztos�tani kell, hogy a verem megjelen�t�se (pl. az elemek t�mbje) csak ezen
a felhaszn�l�i fel�leten kereszt�l legyen hozz�f�rheto.
3. Biztos�tani kell a verem elso haszn�lat elotti elok�sz�t�s�t (inicializ�l�s�t).

A C++ egym�ssal rokon adatok, f�ggv�nyek stb. k�l�n�ll� n�vterekbe val�


csoportos�t�s�-
ra ad lehetos�get. Egy Stack modul felhaszn�l�i fel�lete p�ld�ul �gy adhat� meg �s
haszn�lhat
�:
namespace Stack { // fel�let
void push(char);
char pop();
}
void f()
{
Stack::push('c');
if (Stack::pop() != 'c') error("lehetetlen");
}
A Stack:: minos�t�s azt jelzi, hogy a push() �s a pop() a Stack n�vt�rhez
tartoznak. E nevek
m�shol t�rt�no haszn�lata nem lesz befoly�ssal erre a programr�szre �s nem fog
zavart
okozni.
A Stack kifejt�se lehet a program k�l�n ford�that� r�sze:
namespace Stack { // megval�s�t�s
const int max_size = 200;
char v[max_size];
int top = 0;
2. Kir�ndul�s a C++-ban 35
void push(char c) { /* t�lcsordul�s ellenorz�se �s c behelyez�se */ }
char pop() { /* alulcsordul�s ellenorz�se �s a legfelso elem kiemel�se */ }
}
A Stack modul fontos jellemzoje, hogy a felhaszn�l�i k�dot a Stack::push()-t �s
a Stack::pop()-ot megval�s�t� k�d elszigeteli a Stack adat�br�zol�s�t�l. A
felhaszn�l�nak
nem kell tudnia, hogy a verem egy t�mbbel van megval�s�tva, a megval�s�t�s pedig
an�lk
�l m�dos�that�, hogy hat�ssal lenne a felhaszn�l�i k�dra.
Mivel az adat csak egyike az .elrejtendo. dolgoknak, az adatrejt�s elve az
inform�ci�rejt�s
elv�v� terjesztheto ki; vagyis a f�ggv�nyek, t�pusok stb. nevei szint�n modulba
helyezhet
ok. K�vetkez�sk�ppen a C++ b�rmilyen deklar�ci� elhelyez�s�t megengedi egy
n�vt�rben
(�8.2.).
A fenti Stack modul a verem egy �br�zol�sm�dja. A k�vetkezokben t�bbf�le vermet
haszn
�lunk a k�l�nb�zo programoz�i st�lusok szeml�ltet�s�re.
2.4.1. K�l�n ford�t�s
A C++ t�mogatja a C k�l�n ford�t�si elv�t. Ezt arra haszn�lhatjuk, hogy egy
programot r�szben
f�ggetlen r�szekre bontsunk.
Azokat a deklar�ci�kat, melyek egy modul fel�let�t �rj�k le, jellemzoen egy f�jlba
�rjuk,
melynek neve a haszn�latot t�kr�zi. Ennek k�vetkezt�ben a
namespace Stack { // fel�let
void push(char);
char pop();
}
a stack.h nevu f�jlba ker�l, a felhaszn�l�k pedig ezt az �gynevezett fej�llom�nyt
(header)
be�p�tik (#include):
#include "stack.h" // a fel�let be�p�t�se
void f()
{
Stack::push('c');
if (Stack::pop() != 'c') error("impossible");
}
36 Bevezet�s
Ahhoz, hogy a ford�t�nak seg�ts�nk az egys�gess�g �s k�vetkezetess�g
biztos�t�s�ban,
a Stack modult megval�s�t� f�jl szint�n tartalmazza a fel�letet:
#include "stack.h" // a fel�let be�p�t�se
namespace Stack { // �br�zol�s
const int max_size = 200;
char v[max_size];
int top = 0;
}
void Stack::push(char c) { /* t�lcsordul�s ellenorz�se �s c behelyez�se */ }
char Stack::pop() { /* alulcsordul�s ellenorz�se �s a legfelso elem kiemel�se */ }

A felhaszn�l�i k�d egy harmadik f�jlba ker�l (user.c). A user.c �s a stack.c


f�jlokban l�vo
k�d k�z�sen haszn�lja a stack.h-ban megadott veremfel�letet, de a k�t f�jl
egy�bk�nt f�ggetlen
�s k�l�n-k�l�n leford�that�. A program r�szei a k�vetkezok�ppen �br�zolhat�k:
A k�l�n ford�t�s k�vetelm�ny minden val�di (t�nyleges haszn�latra sz�nt) program
eset�-
ben, nem csak a modul�ris fel�p�t�suekn�l (mint pl. a Stack). Pontosabban, a k�l�n
ford�-
t�s haszn�lata nem nyelvi k�vetelm�ny; ink�bb annak m�dja, hogyan lehet egy adott
nyelvi
megval�s�t�s elonyeit a legjobban kihaszn�lni. A legjobb, ha a modularit�st a
leheto legnagyobb
m�rt�kig fokozzuk, nyelvi tulajdons�gok �ltal �br�zoljuk, majd k�l�n-k�l�n
hat�konyan
ford�that� f�jlokon kereszt�l val�s�tjuk meg (8. �s 9. fejezet).
2. Kir�ndul�s a C++-ban 37
veremfel�let
#include "stack.h"
verem megval�s�t�sa
#include "stack.h"
verem haszn�lata
stack.h:
user.c: stack.c:
2.4.2. Kiv�telkezel�s
Ha egy programot modulokra bontunk, a hibakezel�st a modulok szintj�n kell
elv�gezn
�nk. A k�rd�s, melyik modul felelos az adott hiba kezel�s��rt? A hib�t �szlelo
modul
gyakran nem tudja, mit kell tennie. A helyre�ll�t�si tev�kenys�g a muveletet
kezdem�nyez
o modult�l f�gg, nem att�l, amelyik �szlelte a hib�t, mik�zben megk�s�relte a
muvelet
v�grehajt�s�t. A programok n�veked�s�vel . k�l�n�sen kiterjedt k�nyvt�rhaszn�lat
eset
�n . a hib�k (vagy �ltal�nosabban: a .kiv�teles esem�nyek.) kezel�si szabv�nyai
egyre
fontosabb� v�lnak.
Vegy�k megint a Stack p�ld�t. Mit kell tenn�nk, amikor t�l sok karaktert pr�b�lunk
push()-
sal egy verembe rakni? A verem modul �r�ja nem tudja, hogy a felhaszn�l� mit akar
tenni
ilyen esetben, a felhaszn�l� pedig nem mindig �szleli a hib�t (ha �gy lenne, a
t�lcsordul�s
nem t�rt�nne meg). A megold�s: a Stack �r�ja kell, hogy tudat�ban legyen a
t�lcsordul�s
vesz�ly�nek �s ezut�n az (ismeretlen) felhaszn�l�val tudatnia kell ezt. A
felhaszn�l� majd
megteszi a megfelelo l�p�st:
namespace Stack { // fel�let
void push(char);
char pop();
class Overflow { }; // t�lcsordul�st �br�zol� t�pus
}
T�lcsordul�s �szlel�sekor a Stack::Push() megh�vhat egy kiv�telkezelo k�dot;
vagyis .egy
Overflow kiv�telt dobhat.:
void Stack::push(char c)
{
if (top == max_size) throw Overflow();
// c behelyez�se
}
A throw a vez�rl�st a Stack::Overflow t�pus� kiv�telkezelonek adja �t, valamilyen
f�ggv�nyben,
mely k�zvetve vagy k�zvetlen�l megh�vta a Stack::Push()-t. Ehhez .visszatekerj�k.
a f�ggv�nyh�v�si vermet, ami ahhoz sz�ks�ges, hogy visszajussunk a h�v� f�ggv�ny
k�rnyezet
�hez. �gy a throw �gy muk�dik, mint egy t�bbszintu return. P�ld�ul:
void f()
{
// ...
try { // a kiv�telekkel az al�bb meghat�rozott kezelo foglalkozik
38 Bevezet�s
while (true) Stack::push('c');
}
catch (Stack::Overflow) {
// hopp�: verem-t�lcsordul�s; a megfelelo muvelet v�grehajt�sa
}
// ...
}
A while ciklus �r�kk� ism�tlodne, ez�rt ha valamelyik Stack::push() h�v�s egy
throw-t v�lt
ki, a vez�rl�s a Stack::Overflow-t kezelo catch r�szhez ker�l.
A kiv�telkezelo elj�r�sok haszn�lata szab�lyosabb� �s olvashat�bb� teheti a
hibakezelo k�-
dot. Tov�bbi t�rgyal�s, r�szletek �s p�ld�k: �8.3, 14. fejezet, .E. f�ggel�k.
2.5. Elvont adat�br�zol�s
A modularit�s alapveto szempont minden sikeres nagy programn�l. E k�nyv minden
tervez
�si vizsg�lat�ban ez marad a k�z�ppontban. Az elozoekben le�rt alak� modulok
azonban
nem elegendoek ahhoz, hogy tiszt�n kifejezz�nk �sszetett rendszereket. Az
al�bbiakban
a modulok haszn�lat�nak egyik m�dj�val foglalkozunk (felhaszn�l�i t�pusok
l�trehoz�sa),
majd megmutatjuk, hogyan k�zdj�nk le probl�m�kat a felhaszn�l�i t�pusok k�zvetlen
l�trehoz
�sa r�v�n.
2.5.1. T�pusokat le�r� modulok
A modulokkal val� programoz�s elvezet az �sszes azonos t�pus� adatnak egyetlen
t�puskezel
o modul �ltali k�zpontos�tott kezel�s�hez. Ha p�ld�ul sok vermet akarunk . az
elobbi
Stack modulban tal�lhat� egyetlen helyett . megadhatunk egy veremkezelot, az
al�bbi fel
�lettel:
namespace Stack {
struct Rep; // a verem szerkezet�nek meghat�roz�sa m�shol tal�lhat�
typedef Rep& stack;
stack create(); // �j verem l�trehoz�sa
void destroy(stack s); // s t�rl�se
2. Kir�ndul�s a C++-ban 39
void push(stack s, char c); // c behelyez�se az s verembe
char pop(stack s); // s legfelso elem�nek kiemel�se
}
A k�vetkezo deklar�ci� azt mondja, hogy Rep egy t�pus neve, de k�sobbre hagyja a
t�pus
meghat�roz�s�t (�5.7).
struct Rep;
Az al�bbi deklar�ci� a stack nevet adja egy .Rep referenci�nak. (r�szletek �5.5-
ben).
typedef Rep& stack;
Az �tlet az, hogy a vermet saj�t Stack::stack-j�vel azonos�tjuk �s a tov�bbi
r�szleteket a felhaszn
�l� elol elrejtj�k. A Stack::stack muk�d�se nagyon hasonl�t egy be�p�tett
t�pus�hoz:
struct Bad_pop { };
void f()
{
Stack::stack s1 = Stack::create(); // �j verem l�trehoz�sa
Stack::stack s2 = Stack::create(); // m�g egy verem l�trehoz�sa
Stack::push(s1,'c');
Stack::push(s2,'k');
if (Stack::pop(s1) != 'c') throw Bad_pop();
if (Stack::pop(s2) != 'k') throw Bad_pop();
Stack::destroy(s1);
Stack::destroy(s2);
}
Ezt a Stack-et t�bbf�lek�ppen megval�s�thatn�nk. Fontos, hogy a felhaszn�l�nak nem

sz�ks�ges tudnia, hogyan tessz�k ezt. Am�g a fel�letet v�ltozatlanul hagyjuk, a


felhaszn�l�
nem fogja �szrevenni, ha �gy d�nt�nk, hogy �t�rjuk a Stack-et. Egy megval�s�t�s
p�ld�ul
elore lefoglalhatna n�h�ny veremp�ld�nyt �s a Stack::create() egy nem haszn�lt
p�ld�nyra
val� hivatkoz�st adna �t. Ezut�n a Stack::destroy() egy �br�zol�st .nem haszn�lt.-
k�nt jel�lhet
meg, �gy a Stack::create() �jra haszn�lhatja azt:
namespace Stack { // �br�zol�s
const int max_size = 200;
40 Bevezet�s
struct Rep {
char v[max_size];
int top;
};
const int max = 16; // vermek maxim�lis sz�ma
Rep stacks[max]; // elore lefoglalt veremp�ld�nyok
bool used[max]; // used[i] igaz, ha stacks[i] haszn�latban van
typedef Rep& stack;
}
void Stack::push(stack s, char c) { /* s t�lcsordul�s�nak ellenorz�se �s c
behelyez�se */ }
char Stack::pop(stack s) { /* s alulcsordul�s�nak ellenorz�se �s a legfelso elem
kiemel�se */ }
Stack::stack Stack::create()
{
// haszn�laton k�v�li Rep kiv�laszt�sa, haszn�ltk�nt
// megjel�l�se, elok�sz�t�se, r� mutat� hivatkoz�s visszaad�sa
}
void Stack::destroy(stack s) { /* s megjel�l�se nem haszn�ltk�nt */ }
Amit tett�nk, az �br�zol� t�pus becsomagol�sa fel�leti f�ggv�nyek k�szlet�be. Az,
hogy az
eredm�ny�l kapott .stack t�pus. hogyan viselkedik, r�szben att�l f�gg, hogyan
adtuk meg
ezeket a fel�leti f�ggv�nyeket, r�szben att�l, hogyan mutattuk be a Stack-et
�br�zol� t�pust
a verem felhaszn�l�inak, r�szben pedig mag�t�l az �br�zol� t�pust�l.
Ez gyakran kevesebb az ide�lisn�l. Jelentos probl�ma, hogy az ilyen .mut�pusoknak.
a felhaszn
�l�k r�sz�re val� bemutat�sa az �br�zol� t�pus r�szleteitol f�ggoen nagyon v�ltoz�
lehet
. a felhaszn�l�kat viszont el kell szigetelni az �br�zol� t�pus ismeret�tol. Ha
p�ld�ul egy
jobban kidolgozott adatszerkezetet v�lasztottunk volna a verem azonos�t�s�ra,
a Stack::stack-ek �rt�kad�si �s elok�sz�t�si (inicializ�l�si) szab�lyai dr�mai
m�don megv�ltoztak
volna (ami n�ha val�ban k�v�natos lehet). Ez azonban azt mutatja, hogy a k�nyelmes

vermek szolg�ltat�s�nak probl�m�j�t egyszeruen �ttett�k a Stack modulb�l


a Stack::stack �br�zol� t�pusba.
M�g l�nyegesebb, hogy azok a felhaszn�l�i t�pusok, melyeket az adott megval�s�t�
t�pushoz
hozz�f�r�st ad� modul hat�rozott meg, nem �gy viselkednek, mint a be�p�tett
t�pusok,
�s kisebb vagy m�s t�mogat�st �lveznek, mint azok. Azt p�ld�ul, hogy mikor
haszn�lhat�
egy Stack::Rep, a Stack::create() �s a Stack::destroy() f�ggv�ny ellenorzi, nem a
szok�sos
nyelvi szab�lyok.
2. Kir�ndul�s a C++-ban 41
2.5.2. Felhaszn�l�i t�pusok
A C++ ezt a probl�m�t �gy k�zdi le, hogy engedi, hogy a felhaszn�l� k�zvetlen�l
adjon
meg t�pusokat, melyek k�zel �gy viselkednek, mint a be�p�tett t�pusok. Az ilyen
t�pusokat
gyakran elvont vagy absztrakt adatt�pusoknak (abstract data type, ADT) nevezz�k. A
szerz
o ink�bb a felhaszn�l�i t�pus (user-defined type) megnevez�st kedveli. Az elvont
adatt�-
pus kifejezobb meghat�roz�s�hoz .absztrakt. matematikai le�r�s kellene. Ha adva
volna
ilyen, azok, amiket itt t�pusoknak nevez�nk, az ilyen val�ban elvont egyedek
konkr�t p�ld
�nyai lenn�nek. A programoz�si megk�zel�t�s most ez lesz:
D�ntsd el, mely t�pusokra van sz�ks�g
�s mindegyikhez biztos�ts teljes muveletk�szletet.
Ott, ahol egy t�pusb�l egy p�ld�nyn�l t�bbre nincs sz�ks�g, elegendo a modulokat
haszn�-
l� adatrejt�si st�lus. Az olyan aritmetikai t�pusok, mint a racion�lis �s komplex
sz�mok, k�-
z�ns�ges p�ld�i a felhaszn�l�i t�pusnak. Vegy�k az al�bbi k�dot:
class complex {
double re, im;
public:
complex(double r, double i) { re=r; im=i; } // complex l�trehoz�sa k�t skal�rb�l
complex(double r) { re=r; im=0; } // complex l�trehoz�sa egy skal�rb�l
complex() { re = im = 0; } // alap�rtelmezett complex: (0,0)
friend complex operator+(complex, complex);
friend complex operator-(complex, complex); // k�toperandus�
friend complex operator-(complex); // egyoperandus�
friend complex operator*(complex, complex);
friend complex operator/(complex, complex);
friend bool operator==(complex, complex); // egyenlo
friend bool operator!=(complex, complex); // nem egyenlo
// ...
};
A complex oszt�ly (vagyis felhaszn�l�i t�pus) deklar�ci�ja egy komplex sz�mot �s a
rajta
v�grehajthat� muveletek halmaz�t �br�zolja. Az �br�zol�s priv�t (private); vagyis
a re �s az
im csak a complex oszt�ly bevezet�sekor megadott f�ggv�nyek �ltal hozz�f�rheto.
Ezeket
az al�bbi m�don adhatjuk meg:
42 Bevezet�s
complex operator+(complex a1, complex a2)
{
return complex(a1.re+a2.re,a1.im+a2.im);
}
Az a tagf�ggv�ny, melynek neve megegyezik az oszt�ly�val, a konstruktor. A
konstruktor
�rja le az oszt�ly egy objektum�nak elok�sz�t�si-l�trehoz�si m�dj�t. A complex
oszt�ly
h�rom konstruktort tartalmaz. Egyik�k egy double-b�l csin�l complex-et, egy m�sik
egy
double p�rb�l, a harmadik alap�rtelmezett �rt�k alapj�n. A complex oszt�ly �gy
haszn
�lhat�:
void f(complex z)
{
complex a = 2.3;
complex b = 1/a;
complex c = a+b*complex(1,2.3);
// ...
if (c != b) c = -(b/a)+2*b;
}
A ford�t� a komplex sz�mokhoz kapcsolt muveleti jeleket megfelelo
f�ggv�nyh�v�sokk�
alak�tja. A c!=b jelent�se p�ld�ul operator!=(c,b), az 1/a jelent�se operator/
(complex(1),a).
A legt�bb . de nem minden . modul jobban kifejezheto felhaszn�l�i t�pusk�nt.
2.5.3. Konkr�t t�pusok
Felhaszn�l�i t�pusok v�ltozatos ig�nyek kiel�g�t�s�re k�sz�thetok. Vegy�nk egy
felhaszn�-
l�i veremt�pust a complex t�pus soraival egy�tt. Ahhoz, hogy kiss� val�s�ghubb�
tegy�k
a p�ld�t, ez a Stack t�pus param�terk�nt elemei sz�m�t kapja meg:
class Stack {
char* v;
int top;
int max_size;
public:
class Underflow { }; // kiv�tel
class Overflow { }; // kiv�tel
class Bad_size { }; // kiv�tel
Stack(int s); // konstruktor
~Stack(); // destruktor
2. Kir�ndul�s a C++-ban 43
void push(char c);
char pop();
};
A Stack(int) konstruktor megh�v�dik, valah�nyszor l�trehozzuk az oszt�ly egy
p�ld�ny�t.
Ez a f�ggv�ny gondoskodik a kezdeti �rt�kad�sr�l. Ha b�rmilyen .takar�t�sra. van
sz�ks�g,
amikor az oszt�ly egy objektuma kiker�l a hat�k�rbol, megadhatjuk a konstruktor
ellent�-
t�t, a destruktort:
Stack::Stack(int s) // konstruktor
{
top = 0;
if (s<0 || 10000<s) throw Bad_size(); // "||" jelent�se "vagy"
max_size = s;
v = new char[s]; // az elemek szabad t�rba helyez�se
}
Stack::~Stack() // destruktor
{
delete[ ] v; // elemek t�rl�se, hely felszabad�t�sa �jrafelhaszn�l�s c�lj�ra
(�6.2.6)
}
A konstruktor egy �j Stack v�ltoz�t hoz l�tre. Ehhez lefoglal n�mi helyet a szabad
t�rb�l
(heap . halom, kupac . vagy dinamikus t�r) a new oper�tor haszn�lat�val. A
destruktor takar
�t, felszabad�tva a t�rat. Az eg�sz a Stack-ek felhaszn�l�inak beavatkoz�sa n�lk�l
t�rt�-
nik. A felhaszn�l�k a vermeket ugyan�gy hozz�k l�tre �s haszn�lj�k, ahogy a
be�p�tett t�-
pus� v�ltoz�kat szokt�k. P�ld�ul:
Stack s_var1(10); // 10 elemet t�rolni k�pes glob�lis verem
void f(Stack& s_ref, int i) // hivatkoz�s a Stack veremre
{
Stack s_var2(i); // lok�lis verem i sz�m� elemmel
Stack* s_ptr = new Stack(20); // mutat� a szabad t�rban levo Stack-re
s_var1.push('a');
s_var2.push('b');
s_ref.push('c');
s_ptr->push('d');
// ...
}
Ez a Stack t�pus ugyanolyan n�vad�sra, hat�k�rre, �lettartamra, m�sol�sra stb.
vonatkoz�
szab�lyoknak engedelmeskedik, mint az int vagy a char be�p�tett t�pusok.
44 Bevezet�s
Term�szetszeruen a push() �s pop() tagf�ggv�nyeket valahol szint�n meg kell adni:
void Stack::push(char c)
{
if (top == max_size) throw Overflow();
v[top] = c;
top = top + 1;
}
char Stack::pop()
{
if (top == 0) throw Underflow();
top = top - 1;
return v[top];
}
A complex �s Stack t�pusokat konkr�t t�pusnak nevezz�k, ellent�tben az absztrakt
t�pusokkal,
ahol a fel�let t�k�letesebben elszigeteli a felhaszn�l�t a megval�s�t�s
r�szleteitol.
2.5.4. Absztrakt t�pusok
Amikor a Stackrol, mint egy modul (�2.5.1) �ltal megval�s�tott .mut�pusr�l.
�tt�rt�nk egy saj
�t t�pusra (�2.5.3), egy tulajdons�got elvesztett�nk. Az �br�zol�s nem v�lik el a
felhaszn�-
l�i fel�lettol, hanem r�sze annak, amit be kellene �p�teni (#include) a vermeket
haszn�l�
programr�szbe. Az �br�zol�s priv�t, ez�rt csak a tagf�ggv�nyeken kereszt�l
hozz�f�rheto,
de jelen van. Ha b�rmilyen jelentos v�ltoz�st szenved, a felhaszn�l� �jra le kell,
hogy ford
�tsa. Ezt az �rat kell fizetni, hogy a konkr�t t�pusok pontosan ugyan�gy
viselkedjenek,
mint a be�p�tettek. Nevezetesen egy t�pusb�l nem lehetnek val�di lok�lis (helyi)
v�ltoz�-
ink, ha nem tudjuk a t�pus �br�zol�s�nak m�ret�t.
Azon t�pusokn�l, melyek nem v�ltoznak gyakran, �s ahol lok�lis v�ltoz�k
gondoskodnak
a sz�ks�ges tisztas�gr�l �s hat�konys�gr�l, ez elfogadhat� �s gyakran ide�lis. Ha
azonban
teljesen el akarjuk szigetelni az adott verem felhaszn�l�j�t a megval�s�t�s
v�ltoz�sait�l,
a legutols� Stack nem elegendo. Ekkor a megold�s lev�lasztani a fel�letet az
�br�zol�sr�l
�s lemondani a val�di lok�lis v�ltoz�kr�l.
Elosz�r hat�rozzuk meg a fel�letet:
class Stack {
public:
class Underflow { }; // kiv�tel
class Overflow { }; // kiv�tel
2. Kir�ndul�s a C++-ban 45
virtual void push(char c) = 0;
virtual char pop() = 0;
};
A virtual sz� a Simul�ban �s a C++-ban azt jelenti, hogy .az adott oszt�lyb�l
sz�rmaztatott
oszt�lyban k�sobb fel�l�rhat�.. Egy Stack-bol sz�rmaztatott oszt�ly a Stack
fel�letet val�s�tja
meg. A furcsa =0 kifejez�s azt mondja, hogy a verembol sz�rmaztatott oszt�lynak
meg
kell hat�roznia a f�ggv�nyt. Ilyenform�n a Stack fel�letk�nt szolg�l b�rmilyen
oszt�ly r�sz�-
re, mely tartalmazza a push() �s pop() f�ggv�nyeket.Ezt a Stack-et �gy
haszn�lhatn�nk:
void f(Stack& s_ref)
{
s_ref.push('c');
if (s_ref.pop() != 'c') throw Bad_pop();
}
Vegy�k �szre, hogyan haszn�lja f() a Stack fel�letet, a megval�s�t�s mik�ntj�rol
mit sem
tudva. Az olyan oszt�lyt, mely m�s oszt�lyoknak fel�letet ad, gyakran t�bbalak�
(polimorf)
t�pusnak nevezz�k.
Nem meglepo, hogy a megval�s�t�s a konkr�t Stack oszt�lyb�l mindent tartalmazhat,
amit
kihagytunk a Stack fel�letbol:
class Array_stack : public Stack { // Array_stack megval�s�tja Stack-et
char* p;
int max_size;
int top;
public:
Array_stack(int s);
~Array_stack();
void push(char c);
char pop();
};
A .:public. olvashat� �gy, mint .sz�rmaztatva .-b�l., .megval�s�tja .-t., vagy
..alt�pusa
.-nak..
Az f() f�ggv�ny r�sz�re, mely a megval�s�t�s ismeret�nek teljes hi�ny�ban egy
Stacket akar
haszn�lni, valamilyen m�sik f�ggv�ny kell l�trehozzon egy objektumot, amelyen az
f() mu-
veletet hajthat v�gre:
void g()
{
46 Bevezet�s
Array_stack as(200);
f(as);
}
Mivel f() nem tud az Array_stack-ekrol, csak a Stack fel�letet ismeri, ugyanolyan
j�l fog mu-
k�dni a Stack egy m�sik megval�s�t�s�val is:
class List_stack : public Stack { // List_stack megval�s�tja Stack-et
list<char> lc; // (standard k�nyvt�rbeli) karakterlista (�3.7.3)
public:
List_stack() { }
void push(char c) { lc.push_front(c); }
char pop();
};
char List_stack::pop()
{
char x = lc.front(); // az elso elem lek�r�se
lc.pop_front(); // az elso elem elt�vol�t�sa
return x;
}
Itt az �br�zol�s egy karakterlista. Az lc.push_front(c) beteszi c-t, mint lc elso
elem�t, az
lc.pop_front h�v�s elt�vol�tja az elso elemet, az lc.front() pedig lc elso elem�re
utal.
Egy f�ggv�ny l�tre tud hozni egy List_stack-et �s f() haszn�lhatja azt:
void h()
{
List_stack ls;
f(ls);
}
2.5.5. Virtu�lis f�ggv�nyek
Hogyan t�rt�nik az f()-en bel�li s_ref.pop() h�v�s felold�sa a megfelelo
f�ggv�nydefin�ci�
h�v�s�ra? Amikor h()-b�l h�vjuk f()-et, a List_stack::pop()-ot kell megh�vni,
amikor g()-bol,
az Array_stack::pop()-ot. Ahhoz, hogy ezt feloldhassuk, a Stack objektumnak
inform�ci�t
kell tartalmaznia arr�l, hogy fut�si idoben mely f�ggv�nyt kell megh�vni. A
ford�t�kn�l szok
�sos elj�r�s egy virtu�lis f�ggv�ny nev�nek egy t�bl�zat valamely sorsz�m�rt�k�v�
alak�-
t�sa, amely t�bl�zat f�ggv�nyekre hivatkoz� mutat�kat tartalmaz. A t�bl�zatot
.virtu�lis
2. Kir�ndul�s a C++-ban 47
f�ggv�nyt�bl�nak. vagy egyszeruen vtbl-nek szok�s nevezni. Minden virtu�lis
f�ggv�nyeket
tartalmaz� oszt�lynak saj�t vtbl-je van, mely azonos�tja az oszt�ly virtu�lis
f�ggv�nyeit.
Ez grafikusan �gy �br�zolhat�:
A vtbl-ben l�vo f�ggv�nyek lehetov� teszik, hogy az objektumot akkor is helyesen
haszn�ljuk,
ha a h�v� nem ismeri annak m�ret�t �s adatainak elrendez�s�t. A h�v�nak mind�ssze
a vtbl hely�t kell tudnia a Stack-en bel�l, illetve a virtu�lis f�ggv�nyek
sorsz�m�t. Ez a virtu
�lis h�v�si elj�r�s l�nyeg�ben ugyanolyan hat�konny� teheto, mint a .norm�lis
f�ggv�nyh
�v�s.. T�bblet helysz�ks�glete: a virtu�lis f�ggv�nyeket tartalmaz� oszt�ly minden
objektum
�ban egy-egy mutat�, valamint egy-egy vtbl minden oszt�lyhoz.
2.6. Objektumorient�lt programoz�s
Az elvont adat�br�zol�s a j� tervez�shez alapfontoss�g�, a k�nyvben pedig a
tervez�s v�gig
k�zponti k�rd�s marad. A felhaszn�l�i t�pusok azonban �nmagukban nem el�g
rugalmasak
ahhoz, hogy kiszolg�lj�k ig�nyeinket. E r�szben elosz�r egyszeru felhaszn�l�i
t�pusokkal
mutatunk be egy probl�m�t, majd megmutatjuk, hogyan lehet azt megoldani
oszt�lyhierarchi
�k haszn�lat�val.
2.6.1. Probl�m�k a konkr�t t�pusokkal
A konkr�t t�pusok . a modulokban megadott .mut�pusokhoz. hasonl�an . egyfajta
.fekete
dobozt. �rnak le. Ha egy fekete dobozt l�trehozunk, az nem l�p igazi
k�lcs�nhat�sba
a program t�bbi r�sz�vel. Nincs m�d arra, hogy �j felhaszn�l�shoz igaz�tsuk,
kiv�ve, ha de-
48 Bevezet�s
p
max_size
top
lc
Array_stack::push()
Array_stack::pop()
List_stack::push()
List_stack::pop()
Array_stack objektum:
List_stack objektum: vtbl:
vtbl:
fin�ci�j�t m�dos�tjuk. Ez a helyzet ide�lis is lehet, de komoly rugalmatlans�ghoz
is vezethet.
Vegy�k p�ld�ul egy grafikus rendszerben haszn�lni k�v�nt Shape (Alakzat) t�pus
meghat�-
roz�s�t. Tegy�k fel, hogy pillanatnyilag a rendszernek k�r�ket, h�romsz�geket �s
n�gyzeteket
kell t�mogatnia. Tegy�k fel azt is, hogy l�teznek az al�bbiak:
class Point { /* ... */ };
class Color { /* ... */ };
A /* �s */ egy megjegyz�s kezdet�t, illetve v�g�t jel�li. A jel�l�s t�bbsoros
megjegyz�sekhez
is haszn�lhat�.
Egy alakzatot az al�bbi m�don adhatunk meg:
enum Kind { circle, triangle, square }; // felsorol�s (�4.8)
class Shape {
Kind k; // t�pusmezo
Point center;
Color col;
// ...
public:
void draw();
void rotate(int);
// ...
};
A k t�pusazonos�t� mezo az�rt sz�ks�ges, hogy az olyan muveletek sz�m�ra, mint a
draw()
(rajzol�s) vagy a rotate() (forgat�s) meghat�rozhat�v� tegy�k, milyen fajta
alakzattal van
dolguk. (A Pascal-szeru nyelvekben egy v�ltoz� rekordt�pust haszn�lhatn�nk, k
c�mk�vel).
A draw() f�ggv�nyt �gy adhatn�nk meg:
void Shape::draw()
{
switch (k) {
case circle:
// k�r rajzol�sa
break;
case triangle:
// h�romsz�g rajzol�sa
break;
2. Kir�ndul�s a C++-ban 49
case square:
// n�gyzet rajzol�sa
break;
}
}
Ez azonban .rendetlens�g.. A f�ggv�nyeknek . mint a draw() . tudniuk kell arr�l,
milyen
alakzatfajt�k l�teznek. Ez�rt az ilyen f�ggv�nyn�l mindig n�vekszik a k�d,
valah�nyszor
a rendszerhez egy �j alakzatot adunk. Ha �j alakzatot hozunk l�tre, minden
muveletet meg
kell vizsg�lni �s (lehetos�g szerint) m�dos�tani kell azokat. A rendszerhez nem
adhatunk �j
alakzatot, hacsak hozz� nem f�r�nk minden muvelet forr�sk�dj�hoz. Mivel egy �j
alakzat
hozz�ad�sa mag�val vonja minden fontos alakzat-muvelet k�dj�nak m�dos�t�s�t, az
ilyen
munka nagy �gyess�get k�v�n �s hib�kat vihet be a m�s (r�gebbi) alakzatokat kezelo
k�dba.
Az egyes alakzat-�br�zol�sok kiv�laszt�s�t komolyan megb�n�thatja az a
k�vetelm�ny,
hogy az �br�zol�soknak (legal�bb is n�h�nynak) illeszkednie kell abba a .
jellemzoen r�gz
�tett m�retu . keretbe, melyet az �ltal�nos Shape t�pus le�r�sa k�pvisel.
2.6.2. Oszt�lyhierarchi�k
A probl�ma az, hogy nincs megk�l�nb�ztet�s az egyes alakzatok �ltal�nos
tulajdons�gai
(sz�n, rajzolhat�s�g stb.) �s egy adott alakzatfajta tulajdons�gai k�zt. (A k�r
p�ld�ul olyan
alakzat, melynek sugara van, egy k�rrajzol� f�ggv�nnyel lehet megrajzolni stb.). E
megk�-
l�nb�ztet�s kifejez�se �s elonyeinek kihaszn�l�sa az objektumorient�lt programoz�s
l�nyege.
Azok a nyelvek, melyek e megk�l�nb�ztet�s kifejez�s�t �s haszn�lat�t lehetov� t�vo

szerkezetekkel rendelkeznek, t�mogatj�k az objektumk�zpont�s�got, m�s nyelvek nem.

A megold�sr�l a Simul�b�l k�lcs�nz�tt �r�kl�s gondoskodik. Elosz�r l�trehozunk egy


oszt
�lyt, mely minden alakzat �ltal�nos tulajdons�gait le�rja:
class Shape {
Point center;
Color col;
// ...
public:
Point where() { return center; }
void move(Point to) { center = to; /* ... */ draw(); }
virtual void draw() = 0;
virtual void rotate(int angle) = 0;
// ...
};
50 Bevezet�s
Ak�rcsak a �2.5.4 absztrakt Stack t�pus�ban, azokat a f�ggv�nyeket, melyekn�l a
h�v�si
fel�let meghat�rozhat�, de a konkr�t megval�s�t�s m�g nem ismert, virtu�lisk�nt
(virtual) vezetj�k be.
A fenti meghat�roz�s alapj�n m�r �rhatunk �ltal�nos f�ggv�nyeket, melyek
alakzatokra hivatkoz
� mutat�kb�l �ll� vektorokat kezelnek:
void rotate_all(vector<Shape*>& v, int angle) // v elemeinek elforgat�sa angle
sz�ggel
{
for (int i = 0; i<v.size(); ++i) v[i]->rotate(angle);
}
Egy konkr�t alakzat meghat�roz�s�hoz meg kell mondanunk, hogy alakzatr�l van sz�
�s
meg kell hat�roznunk konkr�t tulajdons�gait (bele�rtve a virtu�lis f�ggv�nyeket
is):
class Circle : public Shape {
int radius;
public:
void draw() { /* ... */ }
void rotate(int) {} // igen, �res f�ggv�ny
};
A C++-ban a Circle oszt�lyr�l azt mondjuk, hogy a Shape oszt�lyb�l sz�rmazik
(derived),
a Shape oszt�lyr�l pedig azt, hogy a Circle oszt�ly ose ill. b�zisoszt�lya
(alaposzt�lya, base).
M�s sz�haszn�lat szerint a Circle �s a Shape aloszt�ly (subclass), illetve
fooszt�ly (superclass).
A sz�rmaztatott oszt�lyr�l azt mondjuk, hogy �r�kli (inherit) a b�zisoszt�ly
tagjait, ez�rt
a b�zis- �s sz�rmaztatott oszt�lyok haszn�lat�t �ltal�ban �r�kl�sk�nt eml�tj�k.A
programoz�si
megk�zel�t�s itt a k�vetkezo:
D�ntsd el, mely oszt�lyokra van sz�ks�ged,
biztos�ts mindegyikhez teljes muveletk�szletet,
az �r�kl�s seg�ts�g�vel pedig hat�rold k�r�l pontosan
a k�z�s tulajdons�gokat.
Ahol nincs ilyen k�z�s tulajdons�g, elegendo az elvont adat�br�zol�s. A t�pusok
k�zti,
�r�kl�s �s virtu�lis f�ggv�nyek haszn�lat�val kiakn�zhat� k�z�ss�g m�rt�ke
mutatja,
mennyire alkalmazhat� egy probl�m�ra az objektumorient�lt megk�zel�t�s. N�mely
ter�leten,
p�ld�ul az interakt�v grafik�ban, vil�gos, hogy az objektumk�zpont�s�gnak �ri�si
le-
2. Kir�ndul�s a C++-ban 51
hetos�gei vannak. M�s ter�leteken, mint a klasszikus aritmetikai t�pusokn�l �s az
azokon
alapul� sz�m�t�sokn�l, alig l�tszik t�bb lehetos�g, mint az elvont adat�br�zol�s,
�gy az objektumk
�zpont�s�g t�mogat�s�hoz sz�ks�ges szolg�ltat�sok feleslegesnek tunnek.
Az egyes t�pusok k�z�s tulajdons�gait megtal�lni nem egyszeru. A kihaszn�lhat�
k�z�ss�g
m�rt�k�t befoly�solja a rendszer tervez�si m�dja. Amikor egy rendszert tervez�nk .
�s akkor
is, amikor a rendszerk�vetelm�nyeket le�rjuk . akt�van kell keresn�nk a k�z�s
tulajdons
�gokat. Oszt�lyokat lehet kifejezetten m�s t�pusok �p�tokock�ik�nt tervezni, a
l�tezo oszt
�lyokat pedig meg lehet vizsg�lni, mutatnak-e olyan hasonl�s�gokat, amelyeket egy
k�z�s
b�zisoszt�lyban kihaszn�lhatn�nk. Az objektumorient�lt programoz�s konkr�t
programoz
�si nyelvi szerkezetek n�lk�l val� elemz�s�re ir�nyul� k�s�rleteket l�sd
[Kerr,1987] �s
[Booch, 1994] a �23.6-ban.
Az oszt�lyhierarchi�k �s az absztrakt oszt�lyok (�2.5.4) nem k�lcs�n�sen kiz�rj�k,
hanem
kieg�sz�tik egym�st (�12.5), �gy az itt felsorolt ir�nyelvek is ink�bb egym�st
kieg�sz�to, k�lcs
�n�sen t�mogat� jelleguek. Az oszt�lyok �s modulok p�ld�ul f�ggv�nyeket
tartalmaznak,
m�g a modulok oszt�lyokat �s f�ggv�nyeket. A tapasztalt tervezo sokf�le megk�zel�-

t�st haszn�l . ahogy a sz�ks�g parancsolja.


2.7. �ltal�nos�tott programoz�s
Ha valakinek egy verem kell, nem felt�tlen�l karaktereket tartalmaz� veremre van
sz�ks�-
ge. A verem �ltal�nos fogalom, f�ggetlen a karakter fogalm�t�l. K�vetkez�sk�ppen
f�ggetlen
�l kell �br�zolni is.
M�g �ltal�nosabban, ha egy algoritmus az �br�zol�st�l f�ggetlen�l �s logikai
torzul�s n�lk
�l kifejezheto, akkor �gy is kell tenni. A programoz�si ir�nyelv a k�vetkezo:
D�ntsd el, mely algoritmusokra van sz�ks�g,
�s �gy l�sd el azokat param�terekkel, hogy min�l t�bb t�pussal
�s adatszerkezettel muk�djenek.
2.7.1. T�rol�k
Egy karakterverem-t�pust �ltal�nos�thatunk, ha sablont (template) hozunk l�tre
belole �s
a konkr�t char t�pus helyett sablonparam�tert haszn�lunk. P�ld�ul:
52 Bevezet�s
template<class T> class Stack {
T* v;
int max_size;
int top;
public:
class Underflow { };
class Overflow { };
Stack(int s); // konstruktor
~Stack(); // destruktor
void push(T);
T pop();
};
A template<class T> elotag T-t az ut�na k�vetkezo deklar�ci� param�ter�v� teszi.
Hasonl�k�ppen adhatjuk meg a tagf�ggv�nyeket is:
template<class T> void Stack<T>::push(T c)
{
if (top == max_size) throw Overflow();
v[top] = c;
top = top + 1;
}
template<class T> T Stack<T>::pop()
{
if (top == 0) throw Underflow();
top = top - 1;
return v[top];
}
Ha a defin�ci�k adottak, a vermet az al�bbi m�don haszn�lhatjuk:
Stack<char> sc(200); // verem 200 karakter sz�m�ra
Stack<complex> scplx(30); // verem 30 komplex sz�m r�sz�re
Stack< list<int> > sli(45); // verem 45, eg�szekbol �ll� lista sz�m�ra
void f()
{
sc.push('c');
if (sc.pop() != 'c') throw Bad_pop();
scplx.push(complex(1,2));
if (scplx.pop() != complex(1,2)) throw Bad_pop();
}
2. Kir�ndul�s a C++-ban 53
Hasonl� m�don, sablonokk�nt adhatunk meg list�kat, vektorokat, asszociat�v
t�mb�ket
(map) �s �gy tov�bb. Az olyan oszt�lyt, amely valamilyen t�pus� elemek
gyujtem�ny�t tartalmazza,
�ltal�ban container class-nak vagy egyszeruen t�rol�nak (kont�nernek) h�vjuk.
A sablonoknak ford�t�si idoben van jelentos�g�k, teh�t haszn�latuk a .k�zzel
�rott. k�dhoz
k�pest nem n�veli a fut�si idot.
2.7.2. �ltal�nos�tott algoritmusok
A C++ standard k�nyvt�ra t�bbf�le t�rol�r�l gondoskodik, de a felhaszn�l�k
saj�tokat is
�rhatnak (3., 17. �s 18. fejezetek). Ism�t haszn�lhatjuk teh�t az �ltal�nos�tott
(generikus)
programoz�s ir�nyelveit algoritmusok t�rol�k �ltali param�terez�s�re. Tegy�k fel,
hogy
vektorokat, list�kat �s t�mb�ket akarunk rendezni, m�solni �s �tkutatni, an�lk�l,
hogy minden
egyes t�rol�ra meg�rn�nk a sort(), copy() �s search() f�ggv�nyeket. Konvert�lni
nem
akarunk egyetlen adott adatszerkezetre sem, melyet egy konkr�t sort f�ggv�ny
elfogad,
ez�rt tal�lnunk kell egy �ltal�nos m�dot a t�rol�k le�r�s�ra, m�gpedig olyat,
amely megengedi,
hogy egy t�rol�t an�lk�l haszn�ljunk, hogy pontosan tudn�nk, milyen fajta
t�rol�r�l
van sz�.
Az egyik megold�s, amelyet a C++ standard k�nyvt�r�ban a t�rol�k �s nem numerikus
algoritmusok
megk�zel�t�s�bol (18. fej. �3.8) vett�nk �t, a sorozatokra �sszpontos�t �s azokat
bej�r�kkal ( iterator) kezeli.
�me a sorozat fogalm�nak grafikus �br�zol�sa:
A sorozatnak van egy kezdete �s egy v�ge. A bej�r� (iterator) valamely elemre
hivatkozik
�s gondoskodik arr�l a muveletrol, melynek hat�s�ra legk�zelebb a sorozat soron
k�vetkez
o elem�re fog hivatkozni. A sorozat v�ge ugyancsak egy bej�r�, mely a sorozat
utols� elem
�n t�lra hivatkozik. A .v�ge. fizikai �br�zol�sa lehet egy .or. (sentinel) elem,
de elk�pzelhet
o m�s is. A l�nyeg, hogy a sorozat sz�mos m�don �br�zolhat�, �gy list�kkal �s t�mb
�kkel is.
54 Bevezet�s
Kezdet
elemek:
V�g
...
Az olyan muveletekhez, mint .egy bej�r� �ltal f�rj�nk hozz� egy elemhez. �s. a
bej�r� hivatkozzon
a k�vetkezo elemre. sz�ks�g�nk van valamilyen szabv�nyos jel�l�sre. Ha az
alap�tletet meg�rtett�k, az elso hely�n k�zenfekvo v�laszt�s a * dereferencia
(hivatkoz�
vagy mutat�) oper�tort haszn�lni, a m�sodikn�l pedig a ++ n�velo muveleti jelet.
A fentieket adottnak tekintve, az al�bbi m�don �rhatunk k�dot:
template<class In, class Out> void copy(In from, In too_far, Out to)
{
while (from != too_far) {
*to = *from; // hivatkozott elemek m�sol�sa
++to; // k�vetkezo c�l
++from; // k�vetkezo forr�s
}
}
Ez �tm�sol b�rmilyen t�rol�t, amelyre a formai k�vetelm�nyek betart�s�val bej�r�t
adhatunk
meg. A C++ be�p�tett, alacsonyszintu t�mb �s mutat� t�pusai rendelkeznek a
megfelelo mu-
veletekkel:
char vc1[200]; // 200 karakter t�mbje
char vc2[500]; // 500 karakter t�mbje
void f()
{
copy(&vc1[0],&vc1[200],&vc2[0]);
}
Ez vc1-et elso elem�tol az utols�ig vc2-be m�solja, vc2 elso elem�tol kezdodoen.
Minden standard k�nyvt�rbeli t�rol� (17. Fej., �16.3) t�mogatja ezt a bej�r�-
(iterator) �s sorozatjel
�l�st. A forr�s �s a c�l t�pusait egyetlen param�ter helyett k�t sablonparam�ter,
az In
�s Out jel�li. Ezt az�rt tessz�k, mert gyakran akarunk m�solni egy fajta t�rol�b�l
egy m�sik
fajt�ba. P�ld�ul:
complex ac[200];
void g(vector<complex>& vc, list<complex>& lc)
{
copy(&ac[0],&ac[200],lc.begin());
copy(lc.begin(),lc.end(),vc.begin());
}
2. Kir�ndul�s a C++-ban 55
Itt a t�mb�t a list-be m�soljuk, a list-et pedig a vector-ba. Egy szabv�nyos
t�rol�n�l a begin()
a bej�r� (iterator), amely az elso elemre mutat.
2.8. Ut�irat
Egyetlen programoz�si nyelv sem t�k�letes. Szerencs�re egy programoz�si nyelvnek
nem
kell t�k�letesnek lennie ahhoz, hogy j� eszk�zk�nt szolg�ljon nagyszeru rendszerek
�p�t�-
s�hez. Val�j�ban egy �ltal�nos c�l� programoz�si nyelv nem is lehet minden
feladatra t�-
k�letes, amire csak haszn�lj�k. Ami egy feladatra t�k�letes, gyakran komoly
fogyat�koss�-
gokat mutathat egy m�sikn�l, mivel az egy ter�leten val� t�k�letess�g mag�val
vonja
a szakosod�st. A C++-t ez�rt �gy tervezt�k, hogy j� �p�toeszk�z legyen a
rendszerek sz�les
v�laszt�k�hoz �s a fogalmak sz�les k�r�t k�zvetlen�l kifejezhess�k vele.
Nem mindent lehet k�zvetlen�l kifejezni egy nyelv be�p�tett tulajdons�gait
felhaszn�lva.
Val�j�ban ez nem is lenne ide�lis. A nyelvi tulajdons�gok egy sereg programoz�si
st�lus �s
m�dszer t�mogat�s�ra val�k. K�vetkez�sk�ppen egy nyelv megtanul�s�n�l a feladat
a nyelv saj�tos �s term�szetes st�lusainak elsaj�t�t�s�ra val� �sszpontos�t�s, nem
az �sszes
nyelvi tulajdons�g minden r�szletre kiterjedo meg�rt�se.
A gyakorlati programoz�sn�l kev�s az elonye, ha ismerj�k a legrejtettebb nyelvi
tulajdons
�gokat vagy ha a legt�bb tulajdons�got kihaszn�ljuk. Egyetlen nyelvi tulajdons�g
�nmag�-
ban nem t�l �rdekes. Csak akkor lesz jelent�keny, ha az egyes programoz�si
m�dszerek �s
m�s tulajdons�gok k�rnyezet�ben tekintj�k. Amikor teh�t az Olvas� a k�vetkezo
fejezeteket
olvassa, k�rj�k, eml�kezzen arra, hogy a C++ r�szletekbe meno vizsg�lat�nak igazi
c�lja
az, hogy k�pesek legy�nk egy�ttesen haszn�lni a nyelv szolg�ltat�sait, j�
programoz�si
st�lusban, eg�szs�ges tervez�si k�rnyezetben.
2.9. Tan�csok
[1] Ne ess�nk k�ts�gbe! Idovel minden kitisztul. �2.1.
[2] J� programok �r�s�hoz nem kell ismern�nk a C++ minden r�szlet�t. �1.7.
[3] A programoz�si m�dszerekre �sszpontos�tsunk, ne a nyelvi tulajdons�gokra.
�2.1.
56 Bevezet�s
Kir�ndul�s a standard k�nyvt�rban
.Minek vesztegess�k az idot tanul�sra,
mikor a tudatlans�g azonnali?.
(Hobbes)
Szabv�nyos k�nyvt�rak . Kimenet . Karakterl�ncok . Bemenet . Vektorok .
Tartom�nyellen
orz�s . List�k . Asszociat�v t�mb�k . T�rol�k (�ttekint�s) . Algoritmusok .
Bej�r�k
. Bemeneti/kimeneti bej�r�k . Bej�r�sok �s predik�tumok . Tagf�ggv�nyeket haszn�l�

algoritmusok . Algoritmusok (�ttekint�s) . Komplex sz�mok . Vektoraritmetika . A


standard
k�nyvt�r (�ttekint�s) . Tan�csok
3.1. Bevezet�s
Nincs olyan jelentos program, mely csak a puszta programnyelven �r�dik. Elosz�r a
nyelvet
t�mogat� k�nyvt�rakat fejlesztik ki, ezek k�pezik a tov�bbi munka alapj�t.
A 2. fejezet folytat�sak�nt ez a fejezet gyors k�rutaz�st tesz a fo k�nyvt�ri
szolg�ltat�sokban,
hogy fogalmat adjon, mit lehet a C++ �s standard k�nyvt�r�nak seg�ts�g�vel
megtenni.
Bemutat olyan hasznos k�nyvt�ri t�pusokat, mint a string, vector, list �s map,
valamint
haszn�latuk leg�ltal�nosabb m�djait. Ez lehetov� teszi, hogy a k�vetkezo
fejezetekben jobb
3
p�ld�kat �s gyakorlatokat adjak az olvas�nak. A 2. fejezethez hasonl�an b�tor�tani
akarom
az olvas�t, ne zavarja, ne kedvetlen�tse el, ha a r�szleteket nem �rti
t�k�letesen. E fejezet
c�lja, hogy meg�zlelj�k, mi k�vetkezik, �s meg�rts�k a leghasznosabb k�nyvt�ri
szolg�ltat
�sok legegyszerubb haszn�lat�t. A standard k�nyvt�rat r�szletesebben a �16.1.2
mutatja be.
Az e k�nyvben le�rt standard k�nyvt�rbeli szolg�ltat�sok minden teljes C++-
v�ltozat r�sz�t
k�pezik. A C++ standard k�nyvt�r�n k�v�l a legt�bb megval�s�t�s a felhaszn�l� �s a
program
k�zti p�rbesz�dre grafikus felhaszn�l�i fel�leteket is k�n�l, melyeket gyakran
GUI-knak
vagy ablakoz� rendszernek neveznek. Hasonl�k�ppen, a legt�bb programfejleszto
k�rnyezetet alapk�nyvt�rakkal (foundation library) is ell�tt�k, amelyek a
szabv�nyos fejleszt
�si �s/vagy futtat�si k�rnyezeteket t�mogatj�k. Ilyeneket nem fogunk le�rni. A
sz�nd�-
kunk a C++ �n�ll� le�r�s�t adni, �gy, ahogy a szabv�nyban szerepel, �s megorizni a
p�ld�k
.hordozhat�s�g�t. (m�s rendszerekre val� �t�ltet�s�nek lehetos�g�t), kiv�ve a
k�l�n megjel
�lteket. Term�szetesen biztatjuk az olvas�t, fedezze fel a legt�bb rendszerben
megl�vo,
kiterjedt lehetos�geket . ezt azonban a gyakorlatokra hagytuk.
3.2. Hell�, vil�g!
A legkisebb C++ program:
int main() { }
A program megadja a main nevu f�ggv�nyt, melynek nincsenek param�terei �s nem tesz

semmit. Minden C++ programban kell, hogy legyen egy main() nevu f�ggv�ny. A
program
e f�ggv�ny v�grehajt�s�val indul. A main() �ltal visszaadott int �rt�k, ha van
ilyen, a program
visszat�r�si �rt�ke .a rendszerhez.. Ha nincs visszat�r�si �rt�k, a rendszer a
sikeres befejez
�st jelzo �rt�ket kap vissza. Ha a main() nem nulla �rt�ket ad vissza, az hib�t
jelent.
A programok jellemzoen valamilyen kimenetet �ll�tanak elo. �me egy program, amely
ki-
�rja: Hell�, vil�g!:
#include <iostream>
int main()
{
std::cout << "Hell�, vil�g!\n";
}
58 Bevezet�s
Az #include <iostream> utas�tja a ford�t�t, hogy illessze be az iostream-ben
tal�lhat� adatfolyam-
bemeneti �s -kimeneti szolg�ltat�sok deklar�ci�j�t a forr�sk�dba. E deklar�ci�k
n�lk
�l az al�bbi kifejez�s
std::cout << "Hell�, vil�g!\n"
�rtelmetlen volna. A << (.tedd bele.) kimeneti oper�tor m�sodik operandus�t be�rja
az els
obe. Ebben az esetben a .Hell�, vil�g!\n. karakterliter�l a szabv�nyos kimeneti
adatfolyamba,
az std::cout-ba �r�dik. A karakterliter�l egy " " jelek k�z� z�rt karaktersorozat.

A benne szereplo \ (backslash, ford�tott perjel) az ut�na k�vetkezo karakterrel


valamilyen
egyedi karaktert jel�l. Eset�nkben az \n az �j sor jele, teh�t a ki�rt .Hell�,
vil�g!. sz�veget
sort�r�s k�veti.
3.3. A standard k�nyvt�r n�vtere
A standard k�nyvt�r az std n�vt�rhez (�2.4, �8.2) tartozik. Ez�rt �rtunk
std::cout-ot cout helyett.
Ez egy�rtelmuen a standard cout haszn�lat�t �rja elo, nem valamilyen m�s cout-�t.
A standard k�nyvt�r minden szolg�ltat�s�nak be�p�t�s�rol valamilyen, az
<iostream>-hez
hasonl� szabv�nyos fej�llom�ny �ltal gondoskodhatunk:
#include<string>
#include<list>
Ez rendelkez�sre bocs�tja a szabv�nyos string-et �s list-et. Haszn�latukhoz az
std:: elotagot
alkalmazhatjuk:
std::string s = "N�gy l�b j�, k�t l�b rossz!";
std::list<std::string> slogans;
Az egyszerus�g kedv��rt a p�ld�kban ritk�n �rjuk ki az std:: elotagot, illetve a
sz�ks�ges
#include <fej�llom�ny>-okat. Az itt k�z�lt programr�szletek ford�t�s�hoz �s
futtat�s�hoz
a megfelelo fej�llom�nyokat be kell �p�teni (#include, amint a �3.7.5, �8.6 �s a
16. fejezetben
szereplo felsorol�sokban szerepelnek). Ezenk�v�l vagy az std:: elotagot kell
haszn�lni,
vagy glob�liss� kell tenni minden nevet az std n�vt�rbol (�8.2.3):
3. Kir�ndul�s a standard k�nyvt�rban 59
#include<string> // a szabv�nyos karakterl�nc-szolg�ltat�sok el�rhetov� t�tele
using namespace std; // std nevek el�rhetov� t�tele az std:: elotag n�lk�l
string s = "A tudatlans�g er�ny!"; // rendben: a string jelent�se std::string
�ltal�ban szeg�nyes �zl�sre vall egy n�vt�rbol minden nevet a glob�lis n�vt�rbe
helyezni.
Mindazon�ltal, a nyelvi �s k�nyvt�ri tulajdons�gokat illusztr�l� programr�szletek
r�vidre
fog�sa �rdek�ben elhagytuk az ism�tlodo #include-okat �s std:: minos�t�seket. E
k�nyvben
majdnem kiz�r�lag a standard k�nyvt�rat haszn�ljuk, ha teh�t egy nevet haszn�lunk
onnan,
azt vagy a szabv�ny aj�nlja, vagy egy magyar�zat r�sze (hogyan hat�rozhat� meg az
adott
szabv�nyos szolg�ltat�s).
3.4. Kimenet
Az iostream k�nyvt�r minden be�p�tett t�pusra meghat�roz kimenetet, de
felhaszn�l�i t�-
pushoz is k�nnyen megadhatjuk. Alap�rtelmez�sben a cout-ra ker�lo kimeneti �rt�kek

karaktersorozatra alak�t�dnak �t. A k�vetkezo k�d p�ld�ul az 1 karaktert a 0


karakterrel
k�vetve a szabv�nyos kimeneti adatfolyamba helyezi.
void f()
{
cout << 10;
}
Ugyanezt teszi az al�bbi k�d is:
void g()
{
int i = 10;
cout << i;
}
A k�l�nb�zo t�pus� kimenetek term�szetesen p�ros�that�k:
void h(int i)
{
cout << "i �rt�ke ";
cout << i;
cout << '\n';
}
60 Bevezet�s
Ha i �rt�ke 10, a kimenet a k�vetkezo lesz:
i �rt�ke 10
A karakterkonstans egy karakter, egyszeres id�zojelek k�z� z�rva. Vegy�k �szre,
hogy
a karakterkonstansok nem sz�m�rt�kk�nt, hanem karakterk�nt �r�dnak ki:
void k()
{
cout << 'a';
cout << 'b';
cout << 'c';
}
A fenti k�d kimenete p�ld�ul abc lesz.Az ember hamar belef�rad a kimeneti
adatfolyam nev
�nek ism�tl�s�be, amikor t�bb rokon t�telt kell ki�rni. Szerencs�re maguk a
kimeneti kifejez
�sek eredm�nyei felhaszn�lhat�k tov�bbi kimenetekhez:
void h2(int i)
{
cout << "i �rt�ke " << i << '\n';
}
Ez egyen�rt�ku h()-val. Az adatfolyamok r�szletes magyar�zata a 21. fejezetben
tal�lhat�.
3.5. Karakterl�ncok
A standard k�nyvt�r gondoskodik a string (karakterl�nc) t�pusr�l, hogy kieg�sz�tse
a kor�bban
haszn�lt karakterliter�lokat. A string t�pus egy sereg hasznos karakterl�nc-
muveletet
biztos�t, ilyen p�ld�ul az �sszefuz�s :
string s1 = "Hell�";
string s2 = "vil�g";
void m1()
{
string s3 = s1 + ", " + s2 + "!\n";
cout << s3;
}
3. Kir�ndul�s a standard k�nyvt�rban 61
Az s3 kezdeti �rt�ke itt a k�vetkezo karaktersorozat (�j sorral k�vetve):
Hell�, vil�g!
A karakterl�ncok �sszead�sa �sszefuz�st jelent. A karakterl�ncokhoz
karakterliter�lokat �s
karaktereket adhatunk. Sok alkalmaz�sban az �sszefuz�s leg�ltal�nosabb form�ja
valamit
egy karakterl�nc v�g�hez fuzni. Ezt a += muvelet k�zvetlen�l t�mogatja:
void m2(string& s1, string& s2)
{
s1 = s1 + '\n'; // sort�r�s
s2 += '\n'; // sort�r�s
}
A l�nc v�g�hez val� hozz�ad�s k�t m�dja egyen�rt�ku, de az ut�bbit elonyben
r�szes�tj�k,
mert t�m�rebb �s val�sz�nuleg hat�konyabban val�s�that� meg.Term�szetesen a
karakterl
�ncok �sszehasonl�that�k egym�ssal �s liter�lokkal is:
string incantation; //var�zssz�
void respond(const string& answer)
{
if (answer == incantation) {
// var�zsl�s megkezd�se
}
else if (answer == "yes") {
// ...
}
// ...
}
A standard k�nyvt�r string oszt�ly�t a 20. fejezet �rja le. Ez m�s hasznos
tulajdons�gai mellett
lehetov� teszi a r�szl�ncok (substring) kezel�s�t is. P�ld�ul:
string name = "Niels Stroustrup";
void m3()
{
string s = name.substr(6,10); // s = "Stroustrup"
name.replace(0,5,"Nicholas"); // a n�v �j �rt�ke "Nicholas Stroustrup" lesz
}
A substr() muvelet egy olyan karakterl�ncot ad vissza, mely a param�tereivel
megadott
r�szl�nc m�solata. Az elso param�ter egy, a karakterl�nc egy adott hely�re mutat�
sorsz�m,
62 Bevezet�s
a m�sodik a k�v�nt r�szl�nc hossza. Mivel a sorsz�moz�s (az index) 0-t�l indul, s
a Stroustrup
�rt�ket kapja.A replace() muvelet a karakterl�nc egy r�sz�t helyettes�ti egy m�sik
karakterl
�nccal. Ebben az esetben a 0-val indul�, 5 hossz�s�g� r�szl�nc a Niels; ez
helyettes
�todik a Nicholas-szal. A name v�gso �rt�ke teh�t Nicholas Stroustrup. Vegy�k
�szre, hogy
a helyettes�to karakterl�ncnak nem kell ugyanolyan m�retunek lennie, mint az a
r�szl�nc,
amelyet helyettes�t.
3.5.1.C st�lus� karakterl�ncok
A C st�lus� karakterl�nc egy nulla karakterrel v�gzodo karaktert�mb (�5.5.2). Meg
fogjuk mutatni,
hogy egy C st�lus� karakterl�ncot k�nnyen bevihet�nk egy string-be. A C st�lus�
karakterl
�ncokat kezelo f�ggv�nyek megh�v�s�hoz k�pesnek kell lenn�nk egy string �rt�k�-
nek C st�lus� karakterl�nc form�ban val� kinyer�s�re. A c_str() f�ggv�ny ezt teszi
(�20.3.7).
A name-et a printf() ki�r� C-f�ggv�nnyel (�21.8) p�ld�ul az al�bbi m�don
�rathatjuk ki:
void f()
{
printf("name: %s\n",name.c_str());
}
3.6. Bemenet
A standard k�nyvt�r bemenetre az istreams-et aj�nlja. Az ostreams-hez hasonl�an az

istreams is a be�p�tett t�pusok karaktersorozatk�nt t�rt�no �br�zol�s�val dolgozik


�s
k�nnyen bov�theto, hogy felhaszn�l�i t�pusokkal is meg tudjon birk�zni. A >>
(.olvasd be.)
muveleti jelet bemeneti oper�tork�nt haszn�ljuk; a cin a szabv�nyos bemeneti
adatfolyam.
A >> jobb oldal�n �ll� t�pus hat�rozza meg, milyen bemenet fogadhat� el �s mi a
beolvas�
muvelet c�lpontja. Az al�bbi k�d egy sz�mot, p�ld�ul 1234-et olvas be a szabv�nyos
bemenetr
ol az i eg�sz v�ltoz�ba �s egy lebegopontos sz�mot, mondjuk 12.34e5-�t �r a
k�tszeres
pontoss�g�, lebegopontos d v�ltoz�ba:
void f()
{
int i;
cin >> i; // eg�sz sz�m beolvas�sa i-be
double d;
cin >> d; // k�tszeres pontoss�g� lebegopontos sz�m beolvas�sa d-be
}
3. Kir�ndul�s a standard k�nyvt�rban 63
A k�vetkezo p�lda h�velykrol centim�terre �s centim�terrol h�velykre alak�t.
Bemenetk�nt
egy sz�mot kap, melynek v�g�n egy karakter jelzi az egys�get (centim�ter vagy
h�velyk).
A program v�laszul kiadja a m�sik egys�gnek megfelelo �rt�ket:
int main()
{
const float factor = 2.54; // 1 h�velyk 2.54 cm-rel egyenlo
float x, in, cm;
char ch = 0;
cout << "�rja be a hossz�s�got: ";
cin >> x; // lebegopontos sz�m beolvas�sa
cin >> ch; // m�rt�kegys�g beolvas�sa
switch (ch) {
case 'i': // inch (h�velyk)
in = x;
cm = x*factor;
break;
case 'c': // cm
in = x/factor;
cm = x;
break;
default:
in = cm = 0;
break;
}
cout << in << " in = " << cm << " cm\n";
}
A switch utas�t�s egy �rt�ket hasonl�t �ssze �lland�kkal. A break utas�t�sok a
switch utas�-
t�sb�l val� kil�p�sre val�k. A case konstansoknak egym�st�l k�l�nb�zni�k kell. Ha
az ellen
orz�tt �rt�k egyikkel sem egyezik, a vez�rl�s a default-ot v�lasztja. A
programoz�nak
nem kell sz�ks�gszeruen errol az alap�rtelmezett lehetos�grol gondoskodnia.
Gyakran akarunk karaktersorozatot olvasni. Ennek k�nyelmes m�dja egy string -be
val�
helyez�s:
int main()
{
string str;
64 Bevezet�s
cout << "�rja be a nev�t!\n";
cin >> str;
cout << "Hell�, " << str << "!\n";
}
Ha beg�pelj�k a k�vetkezot
Erik
a v�lasz az al�bbi lesz:
Hell�, Erik!
Alap�rtelmez�s szerint az olvas�st egy .�reshely. (whitespace) karakter (�5.5.2),
p�ld�ul
egy sz�k�z fejezi be, teh�t ha be�rjuk a h�rhedt kir�ly nev�t
Erik a V�reskezu
a v�lasz marad
Hell�, Erik!
A getline() f�ggv�ny seg�ts�g�vel eg�sz sort is beolvashatunk:
int main()
{
string str;
cout << "�rja be a nev�t!\n";
getline(cin,str);
cout << "Hell�, " << str << "!\n";
}
E programmal az al�bbi bemenet
Erik a V�reskezu
a k�v�nt kimenetet eredm�nyezi:
Hell�, Erik a V�reskezu!
3. Kir�ndul�s a standard k�nyvt�rban 65
A szabv�nyos karakterl�ncoknak megvan az a sz�p tulajdons�guk, hogy rugalmasan
bov�-
tik a tartalmukat azzal, amit bevisz�nk, teh�t ha n�h�ny megab�jtnyi pontosvesszot
adunk
meg, a program val�ban t�bb oldalnyi pontosvesszot ad vissza . hacsak g�p�nk vagy
az
oper�ci�s rendszer valamilyen kritikus eroforr�sa elobb el nem fogy.
3.7. T�rol�k
Sok sz�m�t�s j�r k�l�nb�zo objektumform�kb�l �ll� gyujtem�nyek (collection)
l�trehoz�-
s�val �s kezel�s�vel. Egy egyszeru p�lda karakterek karakterl�ncba helyez�se, majd
a karakterl
�nc ki�rat�sa. Az olyan oszt�lyt, melynek fo c�lja objektumok t�rol�sa,
�ltal�nosan
t�rol�nak (container, kont�ner) nevezz�k. Adott feladathoz megfelelo t�rol�kr�l
gondoskodni
�s ezeket t�mogatni b�rmilyen program �p�t�s�n�l nagy fontoss�ggal b�r.
A standard k�nyvt�r leghasznosabb t�rol�inak bemutat�s�ra n�zz�nk meg egy egyszeru

programot, amely neveket �s telefonsz�mokat t�rol. Ez az a fajta program, amelynek


v�ltozatai
az elt�ro h�tteru emberek sz�m�ra is .egyszerunek �s magukt�l �rtetodonek. tunnek.

3.7.1. Vektor
Sok C programoz� sz�m�ra alkalmas kiindul�snak l�tszana egy be�p�tett (n�v- vagy
sz�m-)
p�rokb�l �ll� t�mb:
struct Entry {
string name;
int number;
};
Entry phone_book[1000];
void print_entry(int i) // egyszeru haszn�lat
{
cout << phone_book[i].name << ' ' << phone_book[i].number << '\n';
}
A be�p�tett t�mb�k m�rete azonban r�gz�tett. Ha nagy m�retet v�lasztunk, helyet
pazarolunk;
ha kisebbet, a t�mb t�l fog csordulni. Mindk�t esetben alacsonyszintu t�rkezelo
k�-
dot kell �rnunk. A standard k�nyvt�r a vector t�pust (�16.3) bocs�tja
rendelkez�sre, amely
megoldja a fentieket:
66 Bevezet�s
vector<Entry> phone_book(1000);
void print_entry(int i) // egyszeru haszn�lat, mint a t�mbn�l
{
cout << phone_book[i].name << ' ' << phone_book[i].number << '\n';
}
void add_entries(int n) // m�ret n�vel�se n-nel
{
phone_book.resize(phone_book.size()+n);
}
A vector size() tagf�ggv�nye megadja az elemek sz�m�t. Vegy�k �szre a () z�r�jelek
haszn
�lat�t a phone_book defin�ci�j�ban. Egyetlen vector<Entry> t�pus� objektumot
hoztunk
l�tre, melynek megadtuk a kezdeti m�ret�t. Ez nagyon k�l�nb�zik a be�p�tett t�mb�k

bevezet�s�tol:
vector<Entry> book(1000); // vektor 1000 elemmel
vector<Entry> books[1000]; // 1000 �res vektor
Ha hib�san [ ] .t (sz�gletes z�r�jelet) haszn�ln�nk ott, ahol egy vector
deklar�l�s�ban ()-t
�rtett�nk, a ford�t� majdnem biztos, hogy hiba�zenetet ad, amikor a vector-t
haszn�lni
pr�b�ljuk.
A vector egy p�ld�nya objektum, melynek �rt�ket adhatunk:
void f(vector<Entry>& v)
{
vector<Entry> v2 = phone_book;
v = v2;
// ...
}
A vector-ral val� �rt�kad�s az elemek m�sol�s�val j�r. Teh�t f()-ben az
elok�sz�t�s (inicializ
�l�s) �s �rt�kad�s ut�n v �s v2 is egy-egy k�l�n m�solatot tartalmaz a phone_book-
ban l�-
vo minden egyes Entry-rol. Ha egy vektor sok elemet tartalmaz, az ilyen
�rtatlannak l�tsz�
�rt�kad�sok megengedhetetlen�l .k�lts�gesek.. Ahol a m�sol�s nem k�v�natos,
referenci�-
kat (hivatkoz�sokat) vagy mutat�kat kell haszn�lni.
3. Kir�ndul�s a standard k�nyvt�rban 67
3.7.2. Tartom�nyellenorz�s
A standard k�nyvt�rbeli vector alap�rtelmez�s szerint nem gondoskodik
tartom�nyellenorz
�srol (�16.3.3). P�ld�ul:
void f()
{
int i = phone_book[1001].number; // az 1001 k�v�l esik a tartom�nyon
// ...
}
A kezdeti �rt�kad�s val�sz�nuleg ink�bb valamilyen v�letlenszeru �rt�ket tesz i-
be, mint
hogy hib�t okoz. Ez nem k�v�natos, ez�rt a soron k�vetkezo fejezetekben a vector
egy egyszer
u tartom�nyellenorzo �talak�t�s�t fogjuk haszn�lni, Vec n�ven. A Vec olyan, mint
a vector, azzal a k�l�nbs�ggel, hogy out_of_range t�pus� kiv�telt v�lt ki, ha egy
index kifut
a tartom�ny�b�l.
A Vec-hez hasonl� t�pusok megval�s�t�si m�djait �s a kiv�telek hat�kony
haszn�lat�t �11.12,
�8.3 �s a 14. fejezet t�rgyalja. Az itteni defin�ci� azonban elegendo a k�nyv
p�ld�ihoz:
template<class T> class Vec : public vector<T> {
public:
Vec() : vector<T>() { }
Vec(int s) : vector<T>(s) { }
T& operator[ ](int i) { return at(i); } // tartom�nyellenorz�s
const T& operator[ ](int i) const { return at(i); } // tartom�nyellenorz�s
};
Az at(i) egy vector indexmuvelet, mely out_of_range t�pus� kiv�telt v�lt ki, ha
param�tere
kifut a vector tartom�ny�b�l (�16.3.3).
Visszat�rve a nevek �s telefonsz�mok t�rol�s�nak probl�m�j�hoz, most m�r
haszn�lhatjuk
a Vec-et, biztos�tva, hogy a tartom�nyon k�v�li hozz�f�r�seket elkapjuk:
Vec<Entry> phone_book(1000);
void print_entry(int i) // egyszeru haszn�lat, mint a vektorn�l
{
cout << phone_book[i].name << ' ' << phone_book[i].number << '\n';
}
68 Bevezet�s
A tartom�nyon k�v�li hozz�f�r�s kiv�telt fog kiv�ltani, melyet a felhaszn�l�
elkaphat:
void f()
{
try {
for (int i = 0; i<10000; i++) print_entry(i);
}
catch (out_of_range) {
cout << "tartom�nyhiba\n";
}
}
A kiv�tel .dob�sa. majd elkap�sa akkor t�rt�nik, amikor a phone_book[i]-re i==1000
�rt�kkel
t�rt�nik hozz�f�r�si k�s�rlet. Ha a felhaszn�l� nem kapja el ezt a fajta kiv�telt,
a program
meghat�rozott m�don befejezodik; nem folytatja fut�s�t �s nem v�lt ki
meghat�rozatlan
hib�t. A kiv�telek okozta meglepet�sek cs�kkent�s�nek egyik m�dja, ha a main()
t�rzs�ben egy try blokkot hozunk l�tre:
int main()
try {
// saj�t k�d
}
catch (out_of_range) {
cerr << "tartom�nyhiba\n";
}
catch (...) {
cerr << "ismeretlen kiv�tel\n";
}
Ez gondoskodik az alap�rtelmezett kiv�telkezelokrol, teh�t ha elmulasztunk elkapni
egy kiv
�telt, a cerr szabv�nyos hibakimeneti adatfolyamon hibajelz�s jelenik meg
(�21.2.1).
3.7.3. Lista
A telefonk�nyv-bejegyz�sek besz�r�sa �s t�rl�se �ltal�nosabb lehet, ez�rt egy
egyszeru telefonk
�nyv �br�zol�s�ra egy lista jobban megfelelne, mint egy vektor:
list<Entry> phone_book;
Amikor list�t haszn�lunk, az elemekhez nem sorsz�m alapj�n szeretn�nk hozz�f�rni,
ahogy
a vektorok eset�ben �ltal�ban tessz�k. Ehelyett �tkutathatjuk a list�t, adott
�rt�ku elemet
keresve.
3. Kir�ndul�s a standard k�nyvt�rban 69
Ehhez kihaszn�ljuk azt a t�nyt, hogy a list egy sorozat (�3.8):
void print_entry(const string& s)
{
typedef list<Entry>::const_iterator LI;
for (LI i = phone_book.begin(); i != phone_book.end(); ++i) {
Entry& e = *i; // r�vid�t�s referenci�val
if (s == e.name) {
cout << e.name << ' ' << e.number << '\n';
return;
}
}
}
Az s keres�se a lista elej�n�l kezdodik, �s addig folytat�dik, m�g az s-t
megtal�ljuk vagy el-
�r�nk a lista v�g�hez. Minden standard k�nyvt�rbeli t�rol� tartalmazza a begin()
�s end()
f�ggv�nyeket, melyek egy bej�r�t (iter�tort) adnak vissza az elso, illetve az
utols� ut�ni
elemre (�16.3.2). Ha adott egy i bej�r�, a k�vetkezo elem ++i lesz. Az i v�ltoz� a
*i elemre
hivatkozik. A felhaszn�l�nak nem kell tudnia, pontosan milyen t�pus� egy
szabv�nyos t�-
rol� bej�r�ja. A t�pus a t�rol� le�r�s�nak r�sze �s n�v szerint lehet hivatkozni
r�. Ha nincs
sz�ks�g�nk egy t�rol�elem m�dos�t�s�ra, a const_iterator az a t�pus, ami nek�nk
kell. K�-
l�nben a sima iterator t�pust (�16.3.1) haszn�ljuk.
Elemek hozz�ad�sa egy list-hez igen k�nnyu:
void add_entry(const Entry& e, list<Entry>::iterator i)
{
phone_book.push_front(e); // hozz�ad�s a lista elej�hez
phone_book.push_back(e); // hozz�ad�s a lista v�g�hez
phone_book.insert(i,e); // hozz�ad�s az .i' �ltal mutatott elem el�
}
3.7.4. Asszociat�v t�mb�k
Egy n�v- vagy sz�mp�rokb�l �ll� list�hoz kereso k�dot �rni val�j�ban igen
f�rads�gos munka.
Ezenk�v�l a sorban t�rt�no keres�s . a legr�videbb list�k kiv�tel�vel . nagyon
rossz hat
�konys�g�. M�s adatszerkezetek k�zvetlen�l t�mogatj�k a besz�r�st, a t�rl�st �s az
�rt�k
szerinti keres�st. A standard k�nyvt�r nevezetesen a map t�pust biztos�tja erre a
feladatra
(�17.4.1). A map egy �rt�kp�r-t�rol�. P�ld�ul:
map<string,int> phone_book;
70 Bevezet�s
M�s k�rnyezetekben a map mint asszociat�v t�mb vagy sz�t�r szerepel. Ha elso
t�pus�val
(a kulccsal, key) indexelj�k, a map a m�sodik t�pus (az �rt�k, vagyis a
hozz�rendelt t�pus,
mapped type) megfelelo �rt�k�t adja vissza:
void print_entry(const string& s)
{
if (int i = phone_book[s]) cout << s << ' ' << i << '\n';
}
Ha nem tal�l illeszked�st az s kulcsra, a phone_book egy alap�rt�ket ad vissza. A
map alap-
�rt�ke int t�pusra 0. Itt felt�telezz�k, hogy a 0 nem �rv�nyes telefonsz�m.
3.7.5. Szabv�nyos t�rol�k
Az asszociat�v t�mb, a lista �s a vektor mind haszn�lhat� telefonk�nyv
�br�zol�s�ra. Mindegyiknek
megvannak az eros �s gyenge oldalai. A vektorokat indexelni .olcs�. �s k�nnyu.
M�sr�szt k�t eleme k�z� egyet besz�rni k�lts�gesebb lehet. A lista tulajdons�gai
ezzel pontosan
ellent�tesek. A map eml�keztet egy (kulcs.�rt�k) p�rokb�l �ll� list�ra, azzal a
kiv�-
tellel, hogy �rt�kei a kulcs szerinti keres�shez a legmegfelelobbek.
A standard k�nyvt�r rendelkezik a leg�ltal�nosabb �s leghaszn�lhat�bb
t�rol�t�pusokkal,
ami lehetov� teszi, hogy a programoz�k olyan t�rol�t v�lasszanak, mely az adott
alkalmaz
�s ig�nyeit a legjobban kiszolg�lja:
3. Kir�ndul�s a standard k�nyvt�rban 71
Szabv�nyos t�rol�k �sszefoglal�sa
Vector<T> V�ltoz� hossz�s�g� vektor (�16.3)
list<T> K�tir�ny� l�ncolt lista (�17.2.2)
Queue<T> Sor (�17.3.2)
Stack<T> Verem (�17.3.1)
Deque<T> K�tv�gu sor (�17.2.3)
Priority_queue<T> �rt�k szerint rendezett sor (�17.3.3)
set<T> Halmaz (�17.4.3)
Multiset<T> Halmaz, melyben egy �rt�k t�bbsz�r
is elofordulhat (�17.4.4)
Map<kulcs,�rt�k> Asszociat�v t�mb (�17.4.1)
Multimap<kulcs,�rt�k> Asszociat�v t�mb, melyben egy kulcs t�bbsz�r
elofordulhat (�17.4.2)
A szabv�nyos t�rol�kat �16.2, �16.3 �s a 17. fejezet mutatja be. A t�rol�k az std
n�vt�rhez
tartoznak, le�r�suk a <vector>, <list>, <map> stb. fej�llom�nyokban szerepel. A
szabv�nyos
t�rol�k �s alapmuveleteik jel�l�s szempontj�b�l hasonl�ak, tov�bb� a muveletek
jelent�se
a k�l�nb�zo t�rol�kra n�zve egyforma. Az alapmuveletek �ltal�ban mindenfajta
t�rol�ra alkalmazhat
�k. A push_back() p�ld�ul . meglehetosen hat�kony m�don . egyar�nt haszn�lhat
� elemeknek egy vektor vagy lista v�g�hez fuz�s�re, �s minden t�rol�nak van size()
tagf
�ggv�nye, mely visszaadja az elemek a sz�m�t.Ez a jel�l�sbeli �s jelent�sbeli
egys�gess�g
lehetov� teszi, hogy a programoz�k �j t�rol�t�pusokat k�sz�tsenek, melyek a
szabv�nyos t�-
pusokhoz nagyon hasonl� m�don haszn�lhat�k. A Vec tartom�nyellenorz�ssel ell�tott
vektor
(�3.7.6) ennek egy p�ld�ja. A 17. fejezet bemutatja, hogyan lehet egy hash_map-et
a szerkezethez hozz�tenni. A t�rol�fel�letek egys�ges volta emellett lehetov�
teszi azt is,
hogy az egyes t�rol�t�pusokt�l f�ggetlen�l adjunk meg algoritmusokat.
3.8. Algoritmusok
Az adatszerkezetek, mint a list vagy a vector, �nmagukban nem t�l hasznosak.
Haszn�latukhoz
olyan alapveto hozz�f�r�si muveletekre van sz�ks�g, mint az elemek hozz�ad�sa �s
elt�vol�t�sa. Emellett ritk�n haszn�lunk egy t�rol�t puszt�n t�rol�sra. Rendezz�k,
ki�ratjuk,
r�szhalmazokat vonunk ki belol�k, elemeket t�vol�tunk el, objektumokat keres�nk
benn�k
�s �gy tov�bb. Emiatt a standard k�nyvt�r az �ltal�nos t�rol�t�pusokon k�v�l
biztos�tja a t�-
rol�k leg�ltal�nosabb elj�r�sait is. A k�vetkezo k�dr�szlet p�ld�ul egy vector-t
rendez �s
minden egyedi vector elem m�solat�t egy list-be teszi:
void f(vector<Entry>& ve, list<Entry>& le)
{
sort(ve.begin(),ve.end());
unique_copy(ve.begin(),ve.end(),le.begin());
}
A szabv�nyos algoritmusok le�r�s�t a 18. fejezetben tal�ljuk. Az algoritmusok
elemek sorozat
�val muk�dnek (�2.7.2). Az ilyen sorozatok bej�r�-p�rokkal �br�zolhat�k, melyek az
els
o, illetve az utols� ut�ni elemet adj�k meg. A p�ld�ban a sort() rendezi a
sorozatot,
ve.begin()-tol ve.end()-ig, ami �ppen a vector �sszes elem�t jelenti. �r�shoz csak
az elso
�rand� elemet sz�ks�ges megadni. Ha t�bb mint egy elemet �runk, a kezdo elemet
k�veto
elemek fel�l�r�dnak. Ha az �j elemeket egy t�rol� v�g�hez k�v�nn�nk adni, az
al�bbit �rhatn
�nk:
72 Bevezet�s
void f(vector<Entry>& ve, list<Entry>& le)
{
sort(ve.begin(),ve.end());
unique_copy(ve.begin(),ve.end(),back_inserter(le)); // hozz�fuz�s le-hez
}
A back_inserter() elemeket ad egy t�rol� v�g�hez, bov�tve a t�rol�t, hogy helyet
csin�ljon
r�sz�kre (�19.2.4). A szabv�nyos t�rol�k �s a back_inserter()-ek kik�sz�b�lik a
hibaleheto-
s�get jelento, C st�lus� realloc()-ot haszn�l� t�rkezel�st (�16.3.5). Ha a
hozz�fuz�skor elfelejtj
�k a back_inserter()-t haszn�lni, az hib�khoz vezethet:
void f(vector<Entry>& ve, list<Entry>& le)
{
copy(ve.begin(),ve.end(),le); // hiba: le nem bej�r�
copy(ve.begin(),ve.end(),le.end()); // rossz: t�l�r a v�g�n
copy(ve.begin(),ve.end(),le.begin()); // elemek fel�l�r�sa
}
3.8.1. Bej�r�k haszn�lata
Amikor elosz�r tal�lkozunk egy t�rol�val, megkaphatjuk n�h�ny hasznos elem�re
hivatkoz
� bej�r�j�t (iter�tor�t); a legjobb p�lda a begin() �s az end(). Ezenk�v�l sok
algoritmus ad
vissza bej�r�kat. A find szabv�nyos algoritmus p�ld�ul egy sorozatban keres egy
�rt�ket �s
azt a bej�r�t adja vissza, amely a megtal�lt elemre mutat. Ha a find-ot
haszn�ljuk, megsz�ml
�lhatjuk valamely karakter elofordul�sait egy karakterl�ncban:
int count(const string& s, char c) // c elofordul�sainak megsz�ml�l�sa s-ben
{
int n = 0;
string::const_iterator i = find(s.begin(),s.end(),c);
while (i != s.end()) {
++n;
i = find(i+1,s.end(),c);
}
return n;
}
A find algoritmus valamely �rt�k egy sorozatban val� elso elofordul�s�ra vagy a
sorozat
utols� ut�ni elem�re mutat� bej�r�t ad vissza. L�ssuk, mi t�rt�nik a count
egyszeru megh�-
v�sakor:
3. Kir�ndul�s a standard k�nyvt�rban 73
void f()
{
string m = "Mary had a little lamb";
int a_count = count(m,'a');
}
A find() elso h�v�sa megtal�lja 'a'-t a Mary-ben. A bej�r� teh�t e karakterre
mutat �s nem az
s.end()-re, �gy bel�pt�nk a ciklusba. A ciklusban i+1-gyel kezdj�k a keres�st;
vagyis eggyel
a megtal�lt 'a' ut�n. Ezut�n folytatjuk a ciklust �s megtal�ljuk a m�sik h�rom
'a'-t. A find()
ekkor el�r a sorozat v�g�hez �s az s.end()-et adja vissza, �gy nem teljes�l az i!
=s.end() felt�-
tel �s kil�p�nk a ciklusb�l. Ezt a count() h�v�st grafikusan �gy �br�zolhatn�nk:
A nyilak az i kezdeti, k�zbenso �s v�gso �rt�keit mutatj�k.
Term�szetesen a find algoritmus minden szabv�nyos t�rol�n egyform�n fog muk�dni.
K�-
vetkez�sk�ppen ugyanilyen m�don �ltal�nos�thatn�nk a count() f�ggv�nyt:
template<class C, class T> int count(const C& v, T val)
{
typename C::const_iterator i = find(v.begin(),v.end(),val); // typename, l�sd
�C.13.5
int n = 0;
while (i != v.end()) {
++n;
++i; // az elobb megtal�lt elem �tugr�sa
i = find(i,v.end(),val);
}
return n;
}
Ez muk�dik, �gy mondhatjuk:
void f(list<complex>& lc, vector<string>& vc, string s)
{
int i1 = count(lc,complex(1,3));
int i2 = count(vc,"Diogen�sz");
int i3 = count(s,'x');
}
74 Bevezet�s
M a r y h a d a l i t t l e l a m b
A count sablont azonban nem kell defini�lnunk. Az elemek elofordul�sainak
megsz�ml�l�-
sa annyira �ltal�nos �s hasznos, hogy a standard k�nyvt�r tartalmazza ezt a
muveletet. Hogy
teljesen �ltal�nos legyen a megold�s, a standard k�nyvt�ri count param�terk�nt
t�rol� helyett
egy sorozatot kap:
void f(list<complex>& lc, vector<string>& vs, string s)
{
int i1 = count(lc.begin(),lc.end(),complex(1,3));
int i2 = count(vs.begin(),vs.end(),"Diogen�sz");
int i3 = count(s.begin(),s.end(),'x');
}
A sorozat haszn�lata megengedi, hogy a sz�ml�l�st be�p�tett t�mbre haszn�ljuk �s
azt is,
hogy egy t�rol� valamely r�sz�t sz�ml�ljuk:
void g(char cs[ ], int sz)
{
int i1 = count(&cs[0],&cs[sz],'z'); // 'z'-k a t�mbben
int i2 = count(&cs[0],&cs[sz/2],'z'); // 'z'-k a t�mb elso fel�ben
}
3.8.2. Bej�r�t�pusok
Val�j�ban mik is azok a bej�r�k (iter�torok)? Minden bej�r� valamilyen t�pus�
objektum.
Azonban sok k�l�nb�zo t�pusuk l�tezik, mert a bej�r�nak azt az inform�ci�t kell
t�rolnia,
melyre az adott t�rol�t�pusn�l feladata ell�t�s�hoz sz�ks�ge van. Ezek a
bej�r�t�pusok
olyan k�l�nb�zok lehetnek, mint a t�rol�k �s azok az egyedi ig�nyek, melyeket
kiszolg�lnak.
Egy vector bej�r�ja p�ld�ul minden bizonnyal egy k�z�ns�ges mutat�, mivel az
nagyon
�sszeru hivatkoz�si m�d a vector elemeire:
3. Kir�ndul�s a standard k�nyvt�rban 75
P i e t H e i n
bej�r�:
vektor:
p
Egy vector-bej�r� megval�s�that� �gy is, mint a vector-ra hivatkoz� mutat�, meg
egy sorsz
�m:
Az ilyen bej�r�k haszn�lata tartom�nyellenorz�sre is lehetos�get ad (�19.3).
A list�k bej�r�inak valamivel bonyolultabbnak kell lenni�k, mint egy egyszeru
mutat� a list
�ban t�rolt elemre, mivel egy ilyen elem �ltal�ban nem tudja, hol van a lista
k�vetkezo tagja.
A lista-bej�r� teh�t ink�bb a lista valamely csom�pontj�ra hivatkoz� mutat�:
Ami k�z�s minden bej�r�n�l, az a jelent�s�k �s a muveleteik elnevez�se. A ++
alkalmaz�-
sa b�rmely bej�r�ra p�ld�ul olyan bej�r�t ad, mely a k�vetkezo elemre hivatkozik.
Hasonl
�k�ppen * azt az elemet adja meg, melyre a bej�r� hivatkozik. Val�j�ban bej�r�
lehet b�rmely
objektum, amely n�h�ny, az elozoekhez hasonl� egyszeru szab�lynak eleget tesz
(�19.2.1). Tov�bb�, a felhaszn�l� ritk�n kell, hogy ismerje egy adott
bej�r�t�pus�t. Saj�t
bej�r�-t�pusait minden t�rol� ismeri �s azokat az egyezm�nyes iterator �s
const_iterator neveken
rendelkez�sre bocs�tja. P�ld�ul a list<Entry>::iterator a list<Entry> �ltal�nos
bej�r�-
t�pusa. Ritk�n kell agg�dnunk az adott t�pus meghat�roz�sa miatt.
76 Bevezet�s
P i e t H e i n
bej�r�: (kezdet == p, pozici� == 3)
vektor:
csom�pont cs. cs. cs. ...
P i e t
bej�r�: p
lista:
elemek:
3.8.3. Bemeneti �s kimeneti bej�r�k
A bej�r�k fogalma �ltal�nos �s hasznos a t�rol�k elemeibol �ll� sorozatok
kezel�s�n�l. A t�-
rol�k azonban nem az egyetlen helyet jelentik, ahol elemek sorozat�t tal�ljuk. A
bemeneti
adatfolyamok is �rt�kek sorozat�b�l �llnak, �s �rt�kek sorozat�t �rjuk a kimeneti
adatfolyamba
is. K�vetkez�sk�ppen a bej�r�k hasznosan alkalmazhat�k a bemenetn�l �s kimenetn
�l is.
Egy ostream_iterator l�trehoz�s�hoz meg kell hat�roznunk, melyik adatfolyamot
haszn�ljuk
�s milyen t�pus� objektumokat �runk bele. Megadhatunk p�ld�ul egy bej�r�t, mely
a cout szabv�nyos kimeneti adatfolyamra hivatkozik:
ostream_iterator<string> oo(cout);
Az �rt�kad�s *oo-nak azt jelenti, hogy az �rt�kad� adatot a cout-ra �rjuk ki.
P�ld�ul:
int main()
{
*oo = "Hell�, "; // jelent�se cout << "Hell�, "
++oo;
*oo = "vil�g!\n"; // jelent�se cout << "vil�g!\n"
}
Ez egy �jabb m�d szabv�nyos �zenetek ki�r�s�ra a szabv�nyos kimenetre. A ++oo
c�lja:
ut�nozni egy t�mbbe mutat�n kereszt�l t�rt�no �r�st. A szerzo elsonek nem ezt a
m�dot v�-
lasztan� erre az egyszeru feladatra, de ez az eszk�z alkalmas arra, hogy a
kimenetet �gy kezelj
�k, mint egy csak �rhat� t�rol�t, ami hamarosan mag�t�l �rtetodo lesz . ha eddig
m�g
nem lenne az.
Hasonl�k�ppen az istream_iterator olyasvalami, ami lehetov� teszi, hogy a bemeneti
adatfolyamot
�gy kezelj�k, mint egy csak olvashat� t�rol�t. Itt is meg kell adnunk a haszn�lni
k�v�nt adatfolyamot �s a v�rt �rt�kek t�pus�t:
istream_iterator<string> ii(cin);
Mivel a bej�r�k mindig p�rokban �br�zolnak egy sorozatot, a bemenet v�g�nek
jelz�s�hez
egy istream_iterator-r�l kell gondoskodni. Az alap�rtelmezett istream_iterator a
k�vetkezo:
istream_iterator<string> eos;
3. Kir�ndul�s a standard k�nyvt�rban 77
Most �jra beolvashatn�nk a .Hell�, vil�got!.-ot a bemenetrol �s ki�rathatn�nk az
al�bbi
m�don:
int main()
{
string s1 = *ii;
++ii;
string s2 = *ii;
cout << s1 << ' ' << s2 << '\n';
}
Val�j�ban az istream_iterator-okat �s ostream_ iterator-okat nem k�zvetlen
haszn�latra tal
�lt�k ki. Jellemzoen algoritmusok param�tereik�nt szolg�lnak. �rjunk p�ld�ul egy
egyszer
u programot, mely egy f�jlb�l olvas, az olvasott adatokat rendezi, a k�tszer
szereplo elemeket
elt�vol�tja, majd az eredm�nyt egy m�sik f�jlba �rja:
int main()
{
string from, to;
cin >> from >> to; // a forr�s- �s c�lf�jl nev�nek beolvas�sa
ifstream is(from.c_str()); // bemeneti adatfolyam (c_str(), l�sd �3.5.1 �s
�20.3.7)
istream_iterator<string> ii(is); // bemeneti bej�r� az adatfolyam sz�m�ra
istream_iterator<string> eos; // bemenet-ellenorz�s
vector<string> b(ii,eos); // b egy vektor, melynek a bemenetrol adunk kezdo�rt�ket

sort(b.begin(),b.end()); // az �tmeneti t�r (b) rendez�se


ofstream os(to.c_str()); // kimeneti adatfolyam
ostream_iterator<string> oo(os,"\n"); // kimeneti bej�r� az adatfolyam sz�m�ra
unique_copy(b.begin(),b.end(),oo); // b tartalm�nak a kimenetre m�sol�sa,
// a kettoz�tt �rt�kek elvet�se
return !is.eof() || !os; // hiba�llapot visszaad�sa (�3.2, �21.3.3)
}
Az ifstream egy istream, mely egy f�jlhoz kapcsolhat�, az ofstream pedig egy
ostream,
mely szint�n egy f�jlhoz kapcsolhat�. Az ostream_iterator m�sodik param�tere a
kimeneti
�rt�keket elv�laszt� jel.
78 Bevezet�s
3.8.4. Bej�r�sok �s predik�tumok
A bej�r�k lehetov� teszik, hogy ciklusokat �rjunk egy sorozat bej�r�s�ra. A
ciklusok meg-
�r�sa azonban f�rads�gos lehet, ez�rt a standard k�nyvt�r m�dot ad arra, hogy egy
adott
f�ggv�nyt a sorozat minden egyes elem�re megh�vjunk. Tegy�k fel, hogy �runk egy
programot,
mely a bemenetrol szavakat olvas �s feljegyzi elofordul�suk gyakoris�g�t. A
karakterl
�ncok �s a hozz�juk tartoz� gyakoris�gok k�zenfekvo �br�zol�sa egy map-pel
t�rt�nhet:
map<string,int> histogram;
Az egyes karakterl�ncok gyakoris�g�nak feljegyz�s�re term�szetes muvelet a
k�vetkezo:
void record(const string& s)
{
histogram[s]++; // "s'' gyakoris�g�nak r�gz�t�se
}
Ha beolvastuk a bemenetet, szeretn�nk az �sszegyujt�tt adatokat a kimenetre
k�ldeni.
A map (string,int) p�rokb�l �ll� sorozat. K�vetkez�sk�ppen szeretn�nk megh�vni az
al�bbi
f�ggv�nyt
void print(const pair<const string,int>& r)
{
cout << r.first << ' ' << r.second << '\n';
}
a map minden elem�re (a p�rok (pair) elso elem�t first-nek, m�sodik elem�t second-
nak
nevezz�k). A pair elso eleme const string, nem sima string, mert minden map kulcs
konstans.
A foprogram teh�t a k�vetkezo:
int main()
{
istream_iterator<string> ii(cin);
istream_iterator<string> eos;
for_each(ii,eos,record);
for_each(histogram.begin(),histogram.end(),print);
}
3. Kir�ndul�s a standard k�nyvt�rban 79
Vegy�k �szre, hogy nem kell rendezn�nk a map-et ahhoz, hogy a kimenet rendezett
legyen.
A map rendezve t�rolja az elemeket �s a ciklus is (n�vekvo) sorrendben j�rja v�gig

a map-et.
Sok programoz�si feladat sz�l arr�l, hogy meg kell keresni valamit egy t�rol�ban,
ahelyett,
hogy minden elemen v�grehajtan�nk egy feladatot. A find algoritmus (�18.5.2)
k�nyelmes
m�dot ad egy adott �rt�k megkeres�s�re. Ennek az �tletnek egy �ltal�nosabb
v�ltozata
olyan elemet keres, mely egy bizonyos k�vetelm�nynek felel meg. P�ld�ul meg
akarjuk keresni
egy map elso 42-n�l nagyobb �rt�k�t:
bool gt_42(const pair<const string,int>& r)
{
return r.second>42;
}
void f(map<string,int>& m)
{
typedef map<string,int>::const_iterator MI;
MI i = find_if(m.begin(),m.end(),gt_42);
// ...
}
M�skor megsz�ml�lhatn�nk azon szavakat, melyek gyakoris�ga nagyobb, mint 42:
void g(const map<string,int>& m)
{
int c42 = count_if(m.begin(),m.end(),gt_42);
// ...
}
Az olyan f�ggv�nyeket, mint a gt_42(), melyet az algoritmus vez�rl�s�re
haszn�lunk, predik
�tumnak (.�ll�tm�ny., vez�rlof�ggv�ny, predicate) nevezz�k. Ezek minden elemre
megh�v�dnak �s logikai �rt�ket adnak vissza, melyet az algoritmus sz�nd�kolt
tev�kenys�-
g�nek elv�gz�s�hez felhaszn�l. A find_if() p�ld�ul addig keres, am�g a predik�tuma
true-t
nem ad vissza, jelezv�n, hogy a k�rt elemet megtal�lta. Hasonl� m�don a count_if()
annyit
sz�ml�l, ah�nyszor a predik�tuma true.
A standard k�nyvt�r n�h�ny hasznos predik�tumot is biztos�t, valamint olyan
sablonokat,
melyek tov�bbiak alkot�s�ra haszn�lhat�k (�18.4.2).
80 Bevezet�s
3.8.5. Tagf�ggv�nyeket haszn�l� algoritmusok
Sok algoritmus alkalmaz f�ggv�nyt egy sorozat elemeire. P�ld�ul �3.8.4-ben a
for_each(ii,eos,record);
megh�vja a record()-ot minden egyes, a bemenetrol beolvasott karakterl�ncra.
Gyakran mutat�k t�rol�ival van dolgunk, �s sokkal ink�bb a hivatkozott objektum
egy tagf
�ggv�ny�t szeretn�nk megh�vni, nem pedig egy glob�lis f�ggv�nyt, a mutat�t
param�terk
�nt �tadva. Tegy�k fel, hogy a Shape::draw() tagf�ggv�nyt akarjuk megh�vni egy
list<Shape>* elemeire. A p�lda kezel�s�re egyszeruen egy nem tag f�ggv�nyt �runk,
mely
megh�vja a tagf�ggv�nyt:
void draw(Shape* p)
{
p->draw();
}
void f(list<Shape*>& sh)
{
for_each(sh.begin(),sh.end(),draw);
}
A m�dszert �gy �ltal�nos�thatjuk:
void g(list<Shape*>& sh)
{
for_each(sh.begin(),sh.end(),mem_fun(&Shape::draw));
}
A standard k�nyvt�ri mem_fun() sablon (�18.4.4.2) param�terk�nt egy tagf�ggv�ny
mutat
�j�t kapja (�15.5) �s valami olyasmit hoz l�tre, amit a tag oszt�ly�ra hivatkoz�
mutat�n kereszt
�l h�vhatunk meg. A mem_fun(&Shape::draw) eredm�nye egy Shape* param�tert kap
�s visszaadja, amit a Shape::draw() visszaad.
A mem_fun() az�rt fontos, mert megengedi, hogy a szabv�nyos algoritmusokat
t�bbalak�
(polimorf) objektumok t�rol�ira haszn�ljuk.
3. Kir�ndul�s a standard k�nyvt�rban 81
3.8.6. A standard k�nyvt�r algoritmusai
Mi az algoritmus? �ltal�nos meghat�roz�sa szerint .szab�lyok v�ges halmaza, mely
adott
probl�mahalmaz megold�s�hoz muveletek sorozat�t hat�rozza meg �s �t fontos
jellemzoje
van: v�gess�g, meghat�rozotts�g, bemenet, kimenet, hat�konys�g. [Knuth,1968,
�1.1].
A C++ standard k�nyvt�r�nak viszonylat�ban az algoritmus elemek sorozat�n
muveleteket
v�gzo sablonok (template-ek) halmaza.
A standard k�nyvt�r t�bb tucat algoritmust tartalmaz. Az algoritmusok az std
n�vt�rhez tartoznak,
le�r�suk az <algorithm> fej�llom�nyban szerepel. �me n�h�ny, melyeket k�l�n�sen
hasznosnak tal�ltam:
3.9. Matematika
A C-hez hasonl�an a C++ nyelvet sem elsosorban sz�mokkal v�gzett muveletekre
tervezt
�k. Mindemellett rengeteg numerikus munk�t v�geztek C++-ban �s ez t�kr�zodik a
standard
k�nyvt�rban is.
82 Bevezet�s
V�logatott szabv�nyos algoritmusok
for_each() H�vd meg a f�ggv�nyt minden elemre (�18.5.1)
find() Keresd meg a param�terek elso elofordul�s�t
(�18.5.2)
find_if() Keresd meg a predik�tumra az elso illeszked�st
(�18.5.2)
count() Sz�ml�ld meg az elem elofordul�sait (�18.5.3)
count_if() Sz�ml�ld meg az illeszked�seket a predik�tumra
(�18.5.3)
replace() Helyettes�tsd be az elemet �j �rt�kkel (�18.6.4)
replace_if() Helyettes�tsd be a predik�tumra illeszkedo elemet
�j �rt�kkel (�18.6.4)
copy() M�sold az elemeket (�18.6.1)
unique_copy() M�sold a csak egyszer szereplo elemeket (�18.6.1)
sort() Rendezd az elemeket (�18.7.1)
equal_range() Keresd meg az �sszes egyezo �rt�ku elemet
(�18.7.2)
merge() F�s�ld �ssze a rendezett sorozatokat (�18.7.3)
3.9.1. Komplex sz�mok
A standard k�nyvt�r a komplex sz�mok egy t�puscsal�dj�t tartalmazza, a �2.5.2-ben
le�rt
complex oszt�ly alakj�ban. Az egyszeres pontoss�g� lebegopontos (float), a
k�tszeres pontoss
�g� (double) stb. skal�rokat tartalmaz� komplex sz�mok t�mogat�s�ra a standard
k�nyvt�rbeli complex egy sablon:
template<class scalar> class complex {
public:
complex(scalar re, scalar im);
// ...
};
A szok�sos aritmetikai muveletek �s a leggyakrabban haszn�lt matematikai
f�ggv�nyek
komplex sz�mokkal is muk�dnek:
// szabv�nyos exponenci�lis f�ggv�ny a <complex> sablonb�l:
template<class C> complex<C> pow(const complex<C>&, int);
void f(complex<float> fl, complex<double> db)
{
complex<long double> ld = fl+sqrt(db);
db += fl*3;
fl = pow(1/fl,2);
// ...
}
R�szletesebben l�sd �22.5.
3.9.2. Vektoraritmetika
A �3.7.1-ben le�rt vector-t �ltal�nos �rt�kt�rol�sra tervezt�k; kelloen rugalmas
�s illeszkedik
a t�rol�k, bej�r�k �s algoritmusok szerkezet�be, ugyanakkor nem t�mogatja a
matematikai
vektormuveleteket. Ilyen muveleteket k�nnyen be lehetett volna �p�teni a vector-
ba, de az
�ltal�noss�g �s rugalmass�g eleve kiz�r olyan optimaliz�l�sokat, melyeket
komolyabb, sz�-
mokkal v�gzett munk�n�l gyakran l�nyegesnek tekint�nk. Emiatt a standard
k�nyvt�rban
megtal�ljuk a valarray nevu vektort is, mely kev�sb� �ltal�nos �s a
sz�mmuveletekhez jobban
megfelel:
template<class T> class valarray {
// ...
T& operator[ ](size_t);
// ...
};
3. Kir�ndul�s a standard k�nyvt�rban 83
A size_t elojel n�lk�li eg�sz t�pus, melyet a nyelv t�mb�k indexel�s�re haszn�l. A
szok�sos aritmetikai
muveleteket �s a leggyakoribb matematikai f�ggv�nyeket meg�rt�k a valarray-kre is:

// szabv�nyos abszol�t�rt�k-f�ggv�ny a <valarray> sablonb�l:


template<class T> valarray<T> abs(const valarray<T>&);
void f(valarray<double>& a1, valarray<double>& a2)
{
valarray<double> a = a1*3.14+a2/a1;
a2 += a1*3.14;
a = abs(a);
double d = a2[7];
// ...
}
R�szletesebben l�sd: �22.4
3.9.3. Alapszintu numerikus t�mogat�s
A standard k�nyvt�r a lebegopontos t�pusokhoz term�szetesen tartalmazza a
leggyakoribb
matematikai f�ggv�nyeket (log(), pow() �s cos(), l�sd �2.2.3). Ezenk�v�l azonban
tartalmaz
olyan oszt�lyokat is, melyek be�p�tett t�pusok tulajdons�gait . p�ld�ul egy float
kitevoj�nek
lehets�ges legnagyobb �rt�k�t .�rj�k le (l�sd �22.2).
3.10. A standard k�nyvt�r szolg�ltat�sai
A standard k�nyvt�r szolg�ltat�sait az al�bbi m�don oszt�lyozhatjuk:
1. Alapveto fut�si ideju t�mogat�s (pl. t�rlefoglal�s �s fut�si ideju
t�pusinform�ci�),
l�sd �16.1.3.
2. A szabv�nyos C k�nyvt�r (nagyon csek�ly m�dos�t�sokkal, a t�pusrendszer
megs�rt�s�nek elker�l�s�re), l�sd �16.1.2.
3. Karakterl�ncok �s bemeneti/kimeneti adatfolyamok (nemzetk�zi karakterk�szlet
�s nyelvi t�mogat�ssal), l�sd 20. �s 21. fejezet.
4. T�rol�k (vector, list �s map) �s t�rol�kat haszn�l� algoritmusok (�ltal�nos
bej�-
r�sok, rendez�sek �s �sszef�s�l�sek) rendszere, l�sd 16., 17., 18. �s 19.fejezet.
84 Bevezet�s
5. Sz�mokkal v�gzett muveletek t�mogat�sa (komplex sz�mok �s vektorok aritmetikai
muveletekkel), BLAS-szeru �s �ltal�nos�tott szeletek, valamint az optimaliz
�l�st megk�nny�to szerkezetek, l�sd 22. fejezet.
Annak fo felt�tele, hogy egy oszt�ly beker�lhet-e a k�nyvt�rba, az volt, hogy
valamilyen
m�don haszn�lta-e m�r majdnem minden C++ programoz� (kezdok �s szak�rtok egyar
�nt), hogy �ltal�nos alakban megadhat�-e, hogy nem jelent-e jelentos
t�bbletterhel�st
ugyanennek a szolg�ltat�snak valamely egyszerubb v�ltozat�hoz viszony�tva, �s hogy

k�nnyen megtanulhat�-e a haszn�lata. A C++ standard k�nyvt�ra teh�t az alapveto


adatszerkezeteket
�s az azokon alkalmazhat� alapveto algoritmusokat tartalmazza.
Minden algoritmus �talak�t�s n�lk�l muk�dik minden t�rol�ra. Ez az egyezm�nyesen
STLnek
(Standard Template Library, szabv�nyos sablonk�nyvt�r) [Stepanov, 1994] nevezett
v�z
bov�theto, abban az �rtelemben, hogy a felhaszn�l�k a k�nyvt�r r�szek�nt
megadottakon
k�v�l k�nnyen k�sz�thetnek saj�t t�rol�kat �s algoritmusokat, �s ezeket azonnal
muk�dtethetik
is a szabv�nyos t�rol�kkal �s algoritmusokkal egy�tt.
3.11. Tan�csok
[1] Ne tal�ljunk fel a melegvizet . haszn�ljunk k�nyvt�rakat.
[2] Ne higgy�nk a csod�kban. �rts�k meg, mit tesznek k�nyvt�raink, hogyan
teszik, �s milyen �ron teszik.
[3] Amikor v�laszthatunk, r�szes�ts�k elonyben a standard k�nyvt�rat m�s k�nyvt�-
rakkal szemben.
[4] Ne gondoljuk, hogy a standard k�nyvt�r mindenre ide�lis.
[5] Ne felejts�k el be�p�teni (#include) a felhaszn�lt szolg�ltat�sok
fej�llom�nyait.
�3.3.
[6] Ne felejts�k el, hogy a standard k�nyvt�r szolg�ltat�sai az std n�vt�rhez
tartoznak.
�3.3.
[7] Haszn�ljunk string-et char* helyett. �3.5, �3.6.
[8] Ha k�ts�geink vannak, haszn�ljunk tartom�nyellenorzo vektort (mint a Vec).
�3.7.2.
[9] R�szes�ts�k elonyben a vector<T>-t, a list<T>-t �s a map<key,value>-t a T[ ]-
vel
szemben. �3.7.1, �3.7.3, �3.7.4.
3. Kir�ndul�s a standard k�nyvt�rban 85
[10] Amikor elemeket tesz�nk egy t�rol�ba, haszn�ljunk push_back()-et vagy
back_inserter()-t. �3.7.3, �3.8.
[11] Haszn�ljunk vektoron push_back()-et a realloc() t�mbre val� alkalmaz�sa
helyett. �3.8.
[12] Az �ltal�nos kiv�teleket a main()-ben kapjuk el. �3.7.2.
86 Bevezet�s
Elso r�sz
Alapok
Ez a r�sz a C++ be�p�tett t�pusait �s azokat az alapveto lehetos�geket �rja le,
amelyekkel
programokat hozhatunk l�tre. A C++-nak a C nyelvre visszautal� r�sze a hagyom�nyos

programoz�si st�lusok t�mogat�s�val egy�tt ker�l bemutat�sra, valamint ez a r�sz


t�rgyalja
azokat az alapveto eszk�z�ket is, amelyekkel C++ programot hozhatunk l�tre logikai
�s fizikai
elemekbol.
Fejezetek
4. T�pusok �s deklar�ci�k
5. Mutat�k, t�mb�k �s strukt�r�k
6. Kifejez�sek �s utas�t�sok
7. F�ggv�nyek
8. N�vterek �s kiv�telek
9. Forr�sf�jlok �s programok
T�pusok �s deklar�ci�k
.Ne fogadj el semmit, ami
nem t�k�letes!.
(ismeretlen szerzo)
.A t�k�letess�g csak az �sszeoml
�s pontj�n �rheto el..
(C.N. Parkinson)
T�pusok . Alapt�pusok . Logikai t�pusok . Karakterek . Karakterliter�lok . Eg�szek
.
Eg�sz liter�lok . Lebegopontos t�pusok . Lebegopontos liter�lok . M�retek . void .
Felsorol
� t�pusok . Deklar�ci�k . Nevek . Hat�k�r�k . Kezdeti �rt�kad�s . Objektumok .
typedef-ek . Tan�csok . Gyakorlatok
4
4.1. T�pusok
Vegy�k az
x = y+f(2);
kifejez�st. Hogy ez �rtelmes legyen valamely C++ programban, az x, y �s f neveket
megfelel
oen defini�lni kell, azaz a programoz�nak meg kell adnia, hogy ezek az x, y, �s f
nevu
egyedek l�teznek �s olyan t�pus�ak, amelyekre az = (�rt�kad�s), a + (�sszead�s) �s
a ()
(f�ggv�nyh�v�s) rendre �rtelmezettek.
A C++ programokban minden n�vnek (azonos�t�nak) van t�pusa. Ez a t�pus hat�rozza
meg,
milyen muveleteket lehet v�grehajtani a n�ven (azaz az egyeden, amelyre a n�v
hivatkozik)
�s ezek a muveletek mit jelentenek. P�ld�ul a
float x; // x lebegopontos v�ltoz�
int y = 7; // y eg�sz t�pus� v�ltoz�, kezdo�rt�ke 7
float f(int); // f eg�sz param�tert v�r� �s lebegopontos sz�mot visszaad� f�ggv�ny

deklar�ci�k m�r �rtelmess� teszik a fenti p�ld�t. Mivel y-t int-k�nt adtuk meg,
�rt�k�l lehet
adni, haszn�lni lehet aritmetikai kifejez�sekben stb. M�sfelol f-et olyan
f�ggv�nyk�nt hat�roztuk
meg, amelynek egy int param�tere van, �gy meg lehet h�vni a megfelelo
param�terrel.
Ez a fejezet az alapveto t�pusokat (�4.1.1) �s deklar�ci�kat (�4.9) mutatja be. A
p�ld�k csak
a nyelv tulajdons�gait szeml�ltetik, nem felt�tlen�l v�geznek hasznos dolgokat. A
terjedelmesebb
�s val�s�ghubb p�ld�k a k�sobbi fejezetekben ker�lnek sorra, amikor m�r t�bbet
ismertett�nk a C++-b�l. Ez a fejezet egyszeruen csak azokat az alapelemeket �rja
le, amelyekb
ol a C++ programok l�trehozhat�k. Ismern�nk kell ezeket az elemeket, a vel�k j�r�
elnevez�seket �s formai k�vetelm�nyeket, ahhoz is, hogy val�di C++ programot
k�sz�thess
�nk, de foleg az�rt, hogy el tudjuk olvasni a m�sok �ltal �rt k�dot. A t�bbi
fejezet meg�rt
�s�hez azonban nem sz�ks�ges teljesen �tl�tni ennek a fejezetnek minden apr�
r�szlet�t.
K�vetkez�sk�pp az olvas� jobban teszi, ha csak �tn�zi, hogy meg�rtse a fontosabb
fogalmakat,
�s k�sobb visszat�r, hogy meg�rtse a r�szleteket, amint sz�ks�ges.
90 Alapok
4.1.1. Alapt�pusok
A C++ rendelkezik azokkal az alapt�pusokkal, amelyek megfelelnek a sz�m�t�g�p
leggyakoribb
t�rol�si egys�geinek �s adatt�rol�si m�dszereinek:
�4.2 Logikai t�pus (bool)
�4.3 Karaktert�pusok (mint a char)
�4.4 Eg�sz t�pusok (mint az int)
�4.5 Lebegopontos t�pusok (mint a double)
Tov�bb� a felhaszn�l� megadhat:
�4.8 felsorol� t�pusokat adott �rt�khalmazok jel�l�s�re (enum)
�s l�tezik a
�4.7 void t�pus is, melyet az inform�ci� hi�ny�nak jelz�s�re haszn�lunk.
Ezekbol a t�pusokb�l m�s t�pusokat is l�trehozhatunk. Ezek a k�vetkezok:
�5.1 Mutat�t�pusok (mint az int*)
�5.2 T�mbt�pusok (mint a char[ ])
�5.5 Referencia-t�pusok (mint a double&)
�5.7 Adatszerkezetek �s oszt�lyok (10. fejezet)
A logikai, karakter- �s eg�sz t�pusokat egy�tt integr�lis t�pusoknak nevezz�k, az
integr�lis
�s lebegopontos t�pusokat pedig k�z�sen aritmetikai t�pusoknak. A felsorol�
t�pusokat �s
az oszt�lyokat (10. fejezet) felhaszn�l�i adatt�pusokk�nt emlegetj�k, mert a
felhaszn�l�nak
kell azokat meghat�roznia; elozetes bevezet�s n�lk�l nem �llnak rendelkez�sre,
mint az
alapt�pusok. A t�bbi t�pust be�p�tett t�pusnak nevezz�k.
Az integr�lis �s lebegopontos t�pusok t�bbfajta m�rettel adottak, lehetov� t�ve a
programoz
�nak, hogy kiv�laszthassa a felhaszn�lt t�r nagys�g�t, a pontoss�got, �s a
sz�m�t�si �rt�ktartom
�nyt (�4.6). Azt felt�telezz�k, hogy a sz�m�t�g�p b�jtokat biztos�t a karakterek
t�rol
�s�hoz, g�pi sz�t az eg�szek t�rol�s�ra �s az azokkal val� sz�mol�sra, l�teznek
alkalmas
egyedek lebegopontos sz�m�t�sokhoz �s c�mek sz�m�ra, hogy hivatkozhassunk ezekre
az
egyedekre. A C++ alapt�pusai a mutat�kkal �s t�mb�kkel egy�tt az adott nyelvi
megval�s�-
t�st�l f�ggetlen�l biztos�tj�k ezeket a g�pszintu fogalmakat a programoz� sz�m�ra.

4. T�pusok �s deklar�ci�k 91
A legt�bb programban a logikai �rt�kekhez egyszeruen bool-t haszn�lhatunk,
karakterekhez
char-t, eg�szekhez int-et, lebegopontos �rt�kekhez pedig double-t. A t�bbi
alapt�pus
hat�konys�gi �s m�s egyedi c�lokra haszn�latos, �gy legjobb azokat elker�lni
addig, am�g
ilyen ig�nyek fel nem mer�lnek, de a r�gi C �s C++ k�dok olvas�s�hoz ismern�nk
kell oket.
4.2. Logikai t�pusok
A logikai t�pusoknak (bool), k�t �rt�ke lehet: true vagy false (igaz, illetve
hamis). A logikai
t�pusokat logikai muveletek eredm�ny�nek kifejez�s�re haszn�ljuk:
void f(int a, int b)
{
bool b1 = a==b; // = �rt�kad�s, == egyenlos�gvizsg�lat
// ...
}
Ha a �s b �rt�ke ugyanaz, akkor b1 igaz lesz, m�sk�l�nben hamis.
A bool gyakran haszn�latos olyan f�ggv�ny visszat�r�si �rt�kek�nt, amely
valamilyen felt�-
telt ellenoriz (predik�tum):
bool is_open(File*);
bool greater(int a, int b) { return a>b; }
Eg�sz sz�mra alak�tva a true �rt�ke 1 lesz, a false-� pedig 0. Ugyan�gy az eg�szek
is logikai
t�pus�v� alak�that�k: a nem nulla eg�szek true, a 0 false logikai �rt�kk�
alakulnak:
bool b = 7; // bool(7) igaz, �gy b igaz
int i = true; // int(true) �rt�ke 1, �gy i �rt�ke 1
Aritmetikai �s logikai kifejez�sekben a logikai t�pusok eg�ssz� alakulnak; az
aritmetikai �s
logikai eg�sz-muveletek az �talak�tott �rt�keken hajt�dnak v�gre. Ha az eredm�ny
visszaalakul
logikai t�pus�v�, a 0 false lesz, a nem nulla eg�szek pedig true �rt�ket kapnak.
92 Alapok
void g()
{
bool a = true;
bool b = true;
bool x = a+b; // a+b �rt�ke 2, �gy x igaz
bool y = a|b; // a|b �rt�ke 1, �gy y igaz
}
Logikai t�pus�v� mutat�kat is alak�thatunk (�C.6.2.5). A nem nulla mutat�k true, a
.nulla
mutat�k. false �rt�kuek lesznek.
4.3. Karaktert�pusok
A char t�pus� v�ltoz�k egy karaktert t�rolhatnak az adott nyelvi megval�s�t�s
karakterk�szlet
�bol:
char ch = 'a';
A char t�pus �ltal�ban 8 bites, �gy 256 k�l�nb�zo �rt�ket t�rolhat. A
karakterk�szlet jellemz
oen az ISO-646 egy v�ltozata, p�ld�ul ASCII, �gy a billentyuzeten megjeleno
karaktereket
tartalmazza. Sok probl�ma sz�rmazik abb�l, hogy ezeket a karakterk�szleteket csak
r�szben
szabv�nyos�tott�k (�C.3).
Jelentosen elt�rnek azok a karakterk�szletek, amelyek term�szetes nyelveket
t�mogatnak,
�s azok is, amelyek m�sf�lek�ppen t�mogatj�k ugyanazt a term�szetes nyelvet. Itt
azonban
csak az �rdekel minket, hogy ezek a k�l�nbs�gek hogyan befoly�solj�k a C++
szab�lyait.
Enn�l fontosabb k�rd�s, hogyan programozzunk t�bbnyelvu, t�bb karakterk�szletes
k�rnyezetben,
ez azonban a k�nyv keretein t�lmutat, b�r sz�mos helyen eml�t�sre ker�l (�20.2,
�21.7, �C3.3, �D).
Biztosan felteheto, hogy az adott C++-v�ltozat karakterk�szlete tartalmazza a
decim�lis
sz�mjegyeket, az angol �b�c� 26 betuj�t �s n�h�ny �ltal�nos �r�sjelet. Nem biztos,
hogy egy
8 bites karakterk�szletben nincs 127-n�l t�bb karakter (n�h�ny karakterk�szlet 255
karaktert
biztos�t), hogy nincs t�bb alfabetikus karakter, mint az angolban (a legt�bb
eur�pai
nyelvben t�bb van), hogy az �b�c� betui �sszef�ggoek (az EBCDIC lyukat hagy az .i.
�s
a .j. k�z�tt), vagy hogy minden karakter rendelkez�sre �ll, ami a C++ k�d �r�s�hoz
sz�ks�-
4. T�pusok �s deklar�ci�k 93
ges (n�h�ny nemzeti karakterk�szlet nem biztos�tja a { } [ ] | \ karaktereket,
�C.3.1). Amikor
csak lehets�ges, nem szabad semmit felt�telezn�nk az objektumok �br�zol�s�r�l �s
ez
az �ltal�nos szab�ly a karakterekre is vonatkozik.
Minden karakternek van egy eg�sz �rt�ke, a .b.-� p�ld�ul az ASCII
karakterk�szletben 98.
�me egy kis program, amely a beg�pelt karakter eg�sz �rt�k�t mutatja meg:
#include <iostream>
int main()
{
char c;
std::cin >> c;
std::cout << "A(z) ' " << c << " ' �rt�ke " << int(c) << '\n';
}
Az int(c) jel�l�s a c karakter eg�sz �rt�k�t adja. Az a lehetos�g, hogy karaktert
eg�ssz� lehet
alak�tani, felvet egy k�rd�st: a char elojeles vagy elojel n�lk�li? A 8 bites
b�jton �br�zolt
256 �rt�ket �gy lehet �rtelmezni, mint 0-t�l 255-ig vagy -127-tol 127-ig terjedo
�rt�keket.
Sajnos az adott ford�t�program d�nti el, melyiket v�lasztja egy sima char eset�ben
(�C.1,
�C.3.4). A C++ azonban ad k�t olyan t�pust, amelyekre a k�rd�s biztosan
megv�laszolhat�:
a signed char-t (elojeles karakter), amely legal�bb a -127 �s127 k�zti �rt�keket
k�pes t�-
rolni �s az unsigned char (elojel n�lk�li karakter) t�pust, amely legal�bb 0-t�l
255-ig tud �rt
�keket t�rolni. Szerencs�re csak a 0-127 tartom�nyon k�v�li �rt�kekben lehet
k�l�nbs�g
�s a leggyakoribb karakterek a tartom�nyon bel�l vannak.
Azok a 0-127 tartom�nyon t�li �rt�kek, amelyeket egy sima char t�rol, nehezen
felder�thet
o .hordozhat�s�gi. probl�m�kat okozhatnak. L�sd m�g a �C.3.4-et arra az esetre, ha
t�bbf
�le char t�pus sz�ks�ges, vagy ha char t�pus� v�ltoz�kban szeretn�nk eg�szeket
t�rolni.
A nagyobb karakterk�szletek . p�ld�ul a Unicode . karaktereinek t�rol�s�ra a
wchar_t �ll
rendelkez�s�nkre, amely �n�ll� t�pus. M�rete az adott C++-v�ltozatt�l f�gg, de
el�g nagy
ahhoz, hogy a sz�ks�ges legnagyobb karakterk�szletet t�rolhassa (l�sd �21.7 �s
�C.3.3).
A k�l�n�s n�v m�g a C-bol maradt meg. A C-ben a wchar_t egy typedef (�4.9.7),
vagyis t�-
pus-�ln�v, nem pedig be�p�tett t�pus. Az _t toldal�k a szabv�nyos typedef-ektol
val� megk
�l�nb�ztet�st seg�ti.
Jegyezz�k meg, hogy a karaktert�pusok integr�lis t�pusok (�4.1.1), �gy
alkalmazhat�ak r�juk
az aritmetikai �s logikai muveletek (�6.2) is.
94 Alapok
4.3.1. Karakterliter�lok
A karakterliter�l, melyet gyakran karakterkonstansnak is h�vnak, egy egyszeres
id�zojelek
k�z� z�rt karakter, p�ld�ul 'a' �s '0'. A karakterliter�lok t�pusa char. Val�j�ban
szimbolikus
konstansok (jelk�pes �lland�k), melyek �rt�ke annak a sz�m�t�g�pnek a
karakterk�szlet�-
ben l�vo karakter eg�sz �rt�ke, amin a C++ program fut. Ha p�ld�ul ASCII
karakterk�szlettel
rendelkezo sz�m�t�g�pet haszn�lunk, a '0' �rt�ke 48 lesz. A program
hordozhat�s�g�t
jav�tja, ha decim�lis jel�l�s helyett karakterliter�lokat haszn�lunk. N�h�ny
karakternek szint
�n van szabv�nyos neve, ezek a \ ford�tott perjelt haszn�lj�k �n. escape
karakterk�nt. P�ld
�ul a \n az �j sort, a \t pedig a v�zszintes tabul�tort (beh�z�st) jelenti. Az
escape karakterekr
ol r�szletesebben l�sd �C.3.2-t.
A .sz�les. karakterliter�lok L.ab. alak�ak, ahol az egyszeres id�zojelek k�z�tt
l�vo karakterek
sz�m�t �s jelent�s�t az adott C++-megval�s�t�s a wchar_t t�pushoz igaz�tja, mivel
a sz�-
les karakterliter�lok t�pusa wchar_t.
4.4. Eg�sz t�pusok
A char-hoz hasonl�an az eg�sz t�pusok is h�romf�l�k: .sima. int, signed int, �s
unsigned
int. Az eg�szek h�rom m�retben adottak: short int, .sima. int , illetve long int.
Egy long intre
lehet sima long-k�nt hivatkozni. Hasonl�an, a short a short int, az unsigned az
unsigned
int, a signed pedig a signed int szinonim�ja.
Az elojel n�lk�li (unsigned) eg�sz t�pusok olyan felhaszn�l�sra ide�lisak, amely
�gy kezeli
a t�rat, mint egy bitt�mb�t. Szinte soha nem j� �tlet az elojel n�lk�li t�pust
haszn�lni int helyett,
hogy egy vagy t�bb bitet nyerj�nk pozit�v eg�szek t�rol�s�hoz. Azok a pr�b�lkoz�-
sok, amelyek �gy k�s�rlik meg biztos�tani valamilyen �rt�k nem negat�v volt�t,
hogy a v�ltoz
�t unsigned-k�nt adj�k meg, �ltal�ban meghi�sulnak a m�g�ttes konverzi�s szab�lyok

miatt (�C.6.1, �C.6.2.1).


A sima char-ral ellent�tben a sima int-ek mindig elojelesek. A signed int t�pusok
csak vil�-
gosabban kifejezett szinonim�i a nekik megfelelo sima int t�pusoknak.
4. T�pusok �s deklar�ci�k 95
4.4.1. Eg�sz liter�lok
Az eg�sz liter�lok n�gyf�le alakban fordulnak elo: decim�lis, okt�lis,
hexadecim�lis �s
karakterliter�lk�nt. A decim�lis liter�lok a legink�bb haszn�latosak �s �gy n�znek
ki, ahogy
elv�rjuk tol�k:
7 1234 976 12345678901234567890
A ford�t�programnak figyelmeztetnie kell olyan liter�lok eset�ben, amelyek t�l
hossz�ak az
�br�zol�shoz. A null�val kezdodo �s x-szel folytat�d� (0x) liter�lok hexadecim�lis
(16-os
sz�mrendszerbeli) sz�mok. Ha a liter�l null�val kezdodik �s sz�mjeggyel
folytat�dik, okt�-
lis (8-as sz�mrendszerbeli) sz�mr�l van sz�:
decim�lis: 2 63 83
okt�lis: 0 02 077 0123
hexadecim�lis: 0x0 0x2 0x3f 0x53
Az a, b, c, d, e �s f betuk, illetve nagybetus megfeleloik rendre 10-et, 11-et,
12-t, 13-at, 14-
et �s 15-�t jelentenek. Az okt�lis �s hexadecim�lis jel�l�s legink�bb bitmint�k
kifejez�s�n�l
hasznos. Meglepet�seket okozhat, ha ezekkel a jel�l�sekkel val�di sz�mokat
fejez�nk ki.
Egy olyan g�pen p�ld�ul, ahol az int egy kettes komplemensu 16 bites eg�szk�nt van
�br
�zolva, 0xffff a -1 negat�v decim�lis sz�m lesz. Ha t�bb bitet haszn�ltunk volna
az eg�sz
�br�zol�s�ra, akkor ez 65 535 lett volna.
Az U ut�tag haszn�lat�val elojel n�lk�li (unsigned) liter�lokat adhatunk meg.
Hasonl�an, az
L ut�tag haszn�latos a long liter�lokhoz. P�ld�ul 3 egy int, 3U egy unsigned int
�s 3L egy
long int. Ha nincs megadva ut�tag, a ford�t� egy olyan eg�sz liter�lt ad, amelynek
t�pusa
megfelel az �rt�knek �s a megval�s�t�s eg�sz-m�reteinek (�C.4).
J� �tlet korl�tozni a nem magukt�l �rtetodo �lland�k haszn�lat�t n�h�ny,
megjegyz�sekkel
megfeleloen ell�tott const (�5.4) vagy felsorol� t�pus� (�4.8) kezdeti
�rt�kad�s�ra.
4.5. Lebegopontos t�pusok
A lebegopontos t�pusok lebegopontos (val�s) sz�mokat �br�zolnak. Az eg�szekhez
hasonl
�an ezek is h�romfajta m�retuek lehetnek: float (egyszeres pontoss�g�), double
(k�tszeres
pontoss�g�), �s long double (kiterjesztett pontoss�g�).
96 Alapok
Az egyszeres, k�tszeres �s kiterjesztett pontoss�g pontos jelent�se az adott C++-
v�ltozatt�l
f�gg. A megfelelo pontoss�g kiv�laszt�sa egy olyan probl�m�n�l, ahol fontos a
v�laszt�s,
a lebegopontos sz�m�t�sok m�ly meg�rt�s�t k�veteli meg. Ha nem �rt�nk a
lebegopontos
aritmetik�hoz, k�rj�nk tan�csot, sz�njunk idot a megtanul�s�ra, vagy haszn�ljunk
double-t
�s rem�lj�k a legjobbakat.
4.5.1. Lebegopontos liter�lok
Alap�rtelmez�s szerint a lebegopontos liter�lok double t�pus�ak. A ford�t�nak itt
is figyelmeztetnie
kell, ha a lebegopontos liter�lok az �br�zol�shoz k�pest t�l nagyok. �me n�h�ny
lebegopontos liter�l:
1.23 .23 0.23 1. 1.0 1.2e10 1.23e-15
Jegyezz�k meg, hogy sz�k�z nem fordulhat elo egy lebegopontos liter�l k�zep�n.
A 65.43 e-21 p�ld�ul nem lebegopontos liter�l, hanem n�gy k�l�n�ll� nyelvi egys�g
(ami
formai hib�t okoz):
65.43 e - 21
Ha float t�pus� lebegopontos liter�lt akarunk megadni, akkor azt az f vagy F
ut�tag haszn�-
lat�val tehetj�k meg:
3.14159265f 2.0f 2.997925F 2.9e-3f
Ha long double t�pus� lebegopontos liter�lt szeretn�nk megadni, haszn�ljuk az l
vagy L ut�-
tagot:
3.14159265L 2.0L 2.997925L 2.9e-3L
4.6. M�retek
A C++ alapt�pusainak n�h�ny jellemzoje, mint p�ld�ul az int m�rete, a C++ adott
megval�-
s�t�s�t�l f�gg (�C.2). R�mutatok ezekre a f�ggos�gekre �s gyakran aj�nlom, hogy
ker�lj�k
oket vagy tegy�nk l�p�seket annak �rdek�ben, hogy hat�sukat cs�kkents�k. Mi�rt
kellene
ezzel foglalkozni? Azok, akik k�l�nb�zo rendszereken programoznak vagy t�bbf�le
ford�-
4. T�pusok �s deklar�ci�k 97
t�t haszn�lnak, k�nytelenek t�rodni ezzel, mert ha nem tenn�k, r�k�nyszer�ln�nek
arra,
hogy idot pazaroljanak nehezen megfoghat� programhib�k megtal�l�s�ra �s
kijav�t�s�ra.
Azok, akik azt �ll�tj�k, hogy nem �rdekli oket a hordozhat�s�g, �ltal�ban az�rt
teszik ezt,
mert csak egy rendszert haszn�lnak �s �gy �rzik, megengedhetik maguknak azt a
hozz��ll
�st, miszerint .a nyelv az, amit a ford�t�m megval�s�t.. Ez beszuk�lt l�t�sm�d. Ha
egy program
sikeres, akkor val�sz�nu, hogy �tviszik m�s rendszerre, �s valakinek meg kell
tal�lnia
�s ki kell jav�tania a megval�s�t�s saj�toss�gaib�l ad�d� probl�m�kat. A
programokat tov
�bb� gyakran �jra kell ford�tani m�s ford�t�kkal ugyanarra a rendszerre �s m�g a
kedvenc
ford�t�nk k�sobbi v�ltozata is m�sk�ppen csin�lhat n�h�ny dolgot, mint a mostani.
Sokkal
egyszerubb ismerni �s korl�tozni az adott ford�t� haszn�lat�nak hat�s�t, amikor
egy programot
meg�rnunk, mint megpr�b�lni k�sobb kibogozni a probl�m�t.
A megval�s�t�sb�l eredo nyelvi saj�toss�gok hat�s�t viszonylag k�nnyu korl�tozni,
a rendszerf
�ggo k�nyvt�rak�t azonban sokkal nehezebb. Az egyik m�dszer az lehet, hogy lehet
oleg csak a standard k�nyvt�r elemeit haszn�ljuk.
Annak, hogy t�bb eg�sz, t�bb elojel n�lk�li, �s t�bb lebegopontos t�pus van, az az
oka,
hogy ez lehetos�get ad a programoz�nak, hogy a hardver jellemzoit megfeleloen
kihaszn
�lhassa. Sok g�pen jelentos k�l�nbs�gek vannak a mem�riaig�nyben, a mem�ria hozz�-

f�r�si idej�ben, �s a t�bbfajta alapt�pussal val� sz�mol�si sebess�gben. Ha


ismerj�k a g�-
pet, �ltal�ban k�nnyen kiv�laszthatjuk p�ld�ul a megfelelo eg�sz t�pust egy adott
v�ltoz�
sz�m�ra, igaz�n hordozhat� k�dot �rni azonban sokkal nehezebb.
A C++ objektumainak m�rete mindig a char m�ret�nek t�bbsz�r�se, �gy a char m�rete
1.
Egy objektum m�ret�t a sizeof oper�torral kaphatjuk meg (�6.2). Az alapt�pusok
m�ret�re
vonatkoz�an a k�vetkezok garant�ltak:
1 o sizeof(char) L sizeof(short) L sizeof(int) L sizeof(long)
1 L sizeof(bool) L sizeof(long)
sizeof(char) L sizeof(wchar_t) L sizeof(long)
sizeof(float) L sizeof(double) L sizeof(long double)
sizeof(N) o sizeof(signed N) o sizeof(unsigned N)
A fentiekben N lehet char, short int, int vagy long int, tov�bb� biztos�tott, hogy
a char legal
�bb 8, a short legal�bb 16, a long pedig legal�bb 32 bites. A char a g�p
karakterk�szlet�-
bol egy karaktert t�rolhat. Az al�bbi �bra az alapt�pusok egy lehets�ges halmaz�t
�s egy
minta-karakterl�ncot mutat:
98 Alapok
Ugyanilyen m�retar�nyban (0,5 cm egy b�jt) egy megab�jt mem�ria k�r�lbel�l �t
kilom�-
ternyire l�gna ki a jobb oldalon.
A char t�pust az adott nyelvi v�ltozatnak �gy kell megv�lasztania, hogy a
karakterek t�rol�-
s�ra �s kezel�s�re egy adott sz�m�t�g�pen a legmegfelelobb legyen; ez jellemzoen
egy 8 bites
b�jt. Hasonl�an, az int t�pusnak a legmegfelelobbnek kell lennie az eg�szek
t�rol�s�ra �s
kezel�s�re; ez �ltal�ban egy 4 b�jtos (32 bites) g�pi sz�. Nem b�lcs dolog t�bbet
felt�telezni.
P�ld�ul vannak olyan g�pek, ahol a char 32 bites. Ha sz�ks�g�nk van r�, az adott
C++-
v�ltozat egyedi tulajdons�gait megtal�lhatjuk a <limits> fej�llom�nyban (�22.2).
P�ld�ul:
#include <limits>
#include <iostream>
int main()
{
std::cout << "A legnagyobb lebegopontos sz�m == " <<
std::numeric_limits<float>::max()
<< ", a char elojeles == " << std::numeric_limits<char>::is_signed << '\n';
}
Az alapt�pusok �rt�kad�sokban �s kifejez�sekben szabadon p�ros�that�k. Ahol
lehets�ges,
az �rt�kek �gy alak�t�dnak �t, hogy ne legyen adatveszt�s (�C.6).
Ha v �rt�k pontosan �br�zolhat� egy T t�pus� v�ltoz�ban, akkor v �rt�k T t�pus�v�
alak�t�-
sa megorzi az �rt�ket �s nincs probl�ma. Legjobb, ha elker�lj�k azokat az
eseteket, amikor
a konverzi�k nem �rt�korzok (�C.6.2.6).
Nagyobb programok k�sz�t�s�hez az automatikus konverzi�kat r�szletesebben meg kell
�rten
�nk, foleg az�rt, hogy k�pesek legy�nk �rtelmezni a m�sok �ltal �rt k�dot, a
k�vetkezo
fejezetek olvas�s�hoz ugyanakkor ez nem sz�ks�ges.
4. T�pusok �s deklar�ci�k 99
char:
bool:
short:
int:
int*:
double:
char[14]:
'a'
1
756
100000000
&c1
1234567e34
Hello, world!\0
4.7. Void
A void form�ja alapj�n alapt�pus, de csak egy bonyolultabb t�pus r�szek�nt lehet
haszn�lni;
nincsenek void t�pus� objektumok. Vagy arra haszn�ljuk, hogy meghat�rozzuk, hogy
egy
f�ggv�ny nem ad vissza �rt�ket, vagy akkor, amikor egy mutat� ismeretlen t�pus�
objektumra
mutat:
void x; // hiba: nincsenek void objektumok
void f(); // az f f�ggv�ny nem ad vissza �rt�ket (�7.3)
void* pv; // ismeretlen t�pus� objektumra hivatkoz� mutat� (�5.6)
Amikor egy f�ggv�nyt bevezet�nk, meg kell hat�rozni visszat�r�si �rt�k�nek t�pus�t
is. Logikailag
elv�rhat� lenne, hogy a visszat�r�si t�pus elhagy�s�val jelezz�k, a f�ggv�ny nem
ad vissza �rt�ket. Ez viszont a nyelvtant (.A. f�ggel�k) kev�sb� szab�lyoss� tenn�
�s �tk�zne
a C-beli gyakorlattal. K�vetkez�sk�ppen a void .l�tsz�lagos visszat�r�si t�pus.-
k�nt
haszn�latos, annak jel�l�s�re, hogy a f�ggv�ny nem ad vissza �rt�ket.
4.8. Felsorol� t�pusok
A felsorol� t�pus (enumeration) olyan t�pus, amely felhaszn�l� �ltal meghat�rozott
�rt�keket
tartalmaz. Meghat�roz�sa ut�n az eg�sz t�pushoz hasonl�an haszn�lhat�. A felsorol�
t�-
pusok tagjaik�nt n�vvel rendelkezo eg�sz konstansokat adhatunk meg. Az al�bbi k�d
p�ld
�ul h�rom eg�sz �lland�t ad meg . ezeket felsorol� konstansoknak nevezz�k . �s
�rt�keket
rendel hozz�juk:
enum { ASM, AUTO, BREAK };
Alap�rtelmez�s szerint az �lland�k 0-t�l n�vekvoen kapnak �rt�keket, �gy ASM==0,
AUTO==1, BREAK==2. A felsorol� t�pusnak lehet neve is:
enum keyword { ASM, AUTO, BREAK };
Minden felsorol�s �n�ll� t�pus. A felsorol� konstansok t�pusa a felsorol�si t�pus
lesz.
Az AUTO p�ld�ul keyword t�pus�.
100 Alapok
Ha keyword t�pus� v�ltoz�t adunk meg sima int helyett, mind a felhaszn�l�nak, mind
a ford
�t�nak utalunk a v�ltoz� tervezett haszn�lat�ra:
void f(keyword key)
{
switch (key) {
case ASM:
// valamit csin�lunk
break;
case BREAK:
// valamit csin�lunk
break;
}
}
A ford�t� figyelmeztet�st adhat, mert a h�rom keyword t�pus� �rt�kbol csak kettot
kezelt�nk.
A felsorol� konstans a kezdeti �rt�kad�skor integr�lis t�pus� (�4.1.1) konstans
kifejez�ssel
(�C.5.) is megadhat�. A felsorol� t�pus �rt�khalmaza �sszes tagj�nak �rt�k�t
tartalmazza,
felkerek�tve a 2 legk�zelebbi, azokn�l nagyobb hatv�ny�n�l eggyel kisebb �rt�kig.
Ha
a legkisebb felsorol� konstans nem negat�v, az �rt�khalmaz 0-val kezdodik, ha
negat�v, a 2
legk�zelebbi, a tagokn�l kisebb negat�v hatv�ny�val. Ez a szab�ly azt a legkisebb
bitmezot
adja meg, amely tartalmazhatja a felsorol� konstansok �rt�k�t. P�ld�ul:
enum e1 { dark, light }; // tartom�ny: 0:1
enum e2 { a = 3, b = 9 }; // tartom�ny: 0:15
enum e3 { min = -10, max = 1000000 }; // tartom�ny: -1048576:1048575
Egy integr�lis t�pus �rt�k�t meghat�rozott m�don felsorol� t�pus�v� alak�thatjuk.
Ha az �rt
�k nem esik a felsorol� t�pus �rt�khalmaz�ba, a konverzi� eredm�nye nem
meghat�rozott:
enum flag { x=1, y=2, z=4, e=8 }; // tartom�ny: 0:15
flag f1 = 5; // t�pushiba: 5 nem flag t�pus�
flag f2 = flag(5); // rendben: flag(5) flag t�pus� �s annak tartom�ny�n bel�li
flag f3 = flag(z|e); // rendben: flag(12) flag t�pus� �s annak tartom�ny�n bel�li
flag f4 = flag(99); // meghat�rozatlan: 99 nem esik a flag tartom�ny�n bel�lre
Az utols� �rt�kad�s mutatja, mi�rt nincs automatikus konverzi� eg�szrol felsorol�
t�pusra;
a legt�bb eg�sz �rt�k ugyanis nem �br�zolhat� egy adott felsorol� t�pusban.
4. T�pusok �s deklar�ci�k 101
A felsorol� t�pusok �rt�khalmaz�nak fogalma k�l�nb�zik a Pascal nyelvcsal�dba
tartoz�
nyelvek felsorol� t�pusainak fogalm�t�l. A C-ben �s a C++-ban azonban hossz�
hagyom�-
nya van azoknak a bitkezelo muveleteknek, amelyek arra �p�tenek, hogy a felsorol�
t�pusok
tagjain k�v�li �rt�kek j�l k�r�lhat�roltak.
A felsorol� t�pusok sizeof-ja egy olyan integr�lis t�pus sizeof-ja, amely k�pes a
felsorol� t�-
pus �rt�khalmaz�t t�rolni �s nem nagyobb sizeof(int)-n�l, hiszen akkor nem lehetne
intk
�nt vagy unsigned int-k�nt �br�zolni. P�ld�ul sizeof(e1) lehet 1 vagy tal�n 4, de
nem lehet
8 egy olyan g�pen, ahol sizeof(int)==4.
Alap�rtelmez�s szerint a felsorol� t�pusok aritmetikai muveletek eset�ben eg�ssz�
alak�t�dnak
(�6.2). A felsorol� t�pus felhaszn�l�i t�pus, �gy a felhaszn�l�k a felsorol�sra
saj�t muveleteket
adhatnak meg, p�ld�ul a ++ �s << oper�torokkal (�11.2.3).
4.9. Deklar�ci�k
A C++ programokban a neveket (azonos�t�kat) haszn�lat elott be kell vezetn�nk,
azaz meg
kell hat�roznunk t�pusukat, hogy megmondjuk a ford�t�nak, a n�v mif�le egyedre
hivatkozik.
A deklar�ci�k sokf�les�g�t a k�vetkezo p�ld�k szeml�ltetik:
char ch;
string s;
int count = 1;
const double pi = 3.1415926535897932385;
extern int error_number;
char* name = "Natasa";
char* season[ ] = { "tavasz", "ny�r", "osz", "t�l" };
struct Date { int d, m, y; };
int day(Date* p) { return p->d; }
double sqrt(double);
template<class T> T abs(T a) { return a<0 ? -a : a; }
typedef complex<short> Point;
struct User;
enum Beer { Carlsberg, Tuborg, Thor };
namespace NS { int a; }
102 Alapok
Amint a p�ld�kb�l l�that�, a deklar�ci� t�bbet is jelenthet ann�l, mint hogy
egyszeruen
egy nevet kapcsol �ssze a n�v t�pus�val. A fenti deklar�ci�k t�bbs�ge defin�ci�
is, azaz
meg is hat�rozza azt az egyedet, amelyre a n�v hivatkozik. A ch eset�ben p�ld�ul
ez az
egyed a megfelelo mem�riater�let, amelyet v�ltoz�k�nt haszn�lunk (vagyis ezt a
mem�-
riater�letet fogjuk lefoglalni), a day-n�l a meghat�rozott f�ggv�ny, a pi
�lland�n�l
a 3.1415926535897932385 �rt�k, a Date-n�l egy �j t�pus. A Point eset�ben az egyed
a complex<short> t�pus, �gy a Point a complex<short> szinonim�ja lesz. A fenti
deklar�ci-
�k k�z�l csak a
double sqrt(double);
extern int error_number;
struct User;
deklar�ci�k nem defin�ci�k is egyben: azaz m�shol kell defini�lni (meghat�rozni)
azokat az
egyedeket, amelyekre hivatkoznak. Az sqrt f�ggv�ny k�dj�t (t�rzs�t) m�s
deklar�ci�kkal
kell meghat�rozni, az int t�pus� error_number v�ltoz� sz�m�ra az error_number egy
m�-
sik deklar�ci�j�nak kell lefoglalnia a mem�ri�t, �s a User t�pus egy m�sik
deklar�ci�j�nak
kell megadnia, hogy a t�pus hogy n�zzen ki. P�ld�ul:
double sqrt(double d) { /* ... */ }
int error_number = 1;
struct User { /* ... */ };
A C++ programokban minden n�v sz�m�ra mindig pontosan egy defin�ci� (meghat�roz�s)

l�tezhet (az #include hat�sait l�sd �9.2.3-ban). Ugyanakkor a nevet t�bbsz�r is


deklar�lhatunk (bevezethetj�k). Egy egyed minden deklar�ci�ja meg kell, hogy
egyezzen
a hivatkozott egyed t�pus�ban. �gy a k�vetkezo r�szletben k�t hiba van:
int count;
int count; // hiba: �jb�li defin�ci�
extern int error_number;
extern short error_number; // hiba: nem megfelelo t�pus
A k�vetkezoben viszont egy sincs (az extern haszn�lat�r�l l�sd �9.2):
extern int error_number;
extern int error_number;
4. T�pusok �s deklar�ci�k 103
N�h�ny defin�ci� valamilyen .�rt�ket. is meghat�roz a megadott egyedeknek:
struct Date { int d, m, y; };
typedef complex<short> Point;
int day(Date* p) { return p->d; }
const double pi = 3.1415926535897932385;
T�pusok, sablonok, f�ggv�nyek �s �lland�k eset�ben ez az .�rt�k. nem v�ltozik. Nem

konstans adatt�pusok eset�ben a kezdeti �rt�ket k�sobb m�dos�thatjuk:


void f()
{
int count = 1;
char* name = "Bjarne";
// ...
count = 2;
name = "Marian";
}
A defin�ci�k k�z�l csak az al�bbi nem hat�roz meg �rt�ket:
char ch;
string s;
(Arr�l, hogy hogyan �s mikor kap egy v�ltoz� alap�rtelmezett �rt�ket, l�sd �4.9.5-
�t �s
�10.4.2-t.) Minden deklar�ci�, amely �rt�ket hat�roz meg, egyben defin�ci�nak is
minos�l.
4.9.1. A deklar�ci�k szerkezete
A deklar�ci�k n�gy r�szbol �llnak: egy nem k�telezo minos�tobol, egy alapt�pusb�l,
egy
deklar�torb�l, �s egy . szint�n nem k�telezo . kezdo�rt�k-ad� kifejez�sbol. A
f�ggv�ny- �s
n�vt�r-meghat�roz�sokat kiv�ve a deklar�ci� pontosvesszore v�gzodik:
char* kings[ ] = { "Antig�nusz", "Szeleukusz", "Ptolemaiosz" };
Itt az alapt�pus char, a deklar�tor a *kings[ ], a kezdo�rt�k-ad� r�sz pedig az
={.}.
A minos�to (specifier) egy kulcssz�, mint a virtual (�2.5.5, �12.2.6) �s az extern
(�9.2), �s
a bevezetett elem n�h�ny, nem a t�pusra jellemzo tulajdons�g�t hat�rozza meg. A
deklar�-
tor (declarator) egy n�vbol �s n�h�ny nem k�telezo oper�torb�l �ll. A leggyakoribb
deklar
�tor-oper�torok a k�vetkezok (�A.7.1):
104 Alapok
* mutat� elotag
*const konstans mutat� elotag
& referencia elotag
[ ] t�mb ut�tag
() f�ggv�ny ut�tag
Haszn�latuk egyszeru lenne, ha mindegyik�k elotagk�nt (prefix) vagy mindegyik�k
ut�tagk
�nt (postfix) haszn�lt oper�tor volna. A *, a [ ] �s a () oper�torokat azonban
arra tervezt
�k, hogy kifejez�sekben is haszn�lhat�k legyenek (�6.2), �gy a * elotag-, a [ ] �s
a () pedig
ut�tag oper�torok. Az ut�tagk�nt haszn�lt oper�torok t�bb megk�t�ssel j�rnak, mint
az elo-
tagk�nt haszn�ltak. K�vetkez�sk�ppen a *kings[ ] egy valamire hivatkoz� mutat�kb�l
�ll�
vektor, �s z�r�jeleket kell haszn�lnunk, ha olyasmit akarunk kifejezni, mint ..
f�ggv�nyre
hivatkoz� mutat�. (l�sd az �5.1 p�ld�it). Teljes r�szletess�ggel l�sd a nyelvtant
az .A. f�ggel
�kben.
Jegyezz�k meg, hogy a t�pus nem hagyhat� el a deklar�ci�b�l:
const c = 7; // hiba: nincs t�pus
gt(int a, int b) { return (a>b) ? a : b; } // hiba: nincs visszat�r�si t�pus
unsigned ui; // rendben: 'unsigned' jelent�se 'unsigned int'
long li; // rendben: 'long' jelent�se 'long int'
A szabv�nyos C++ ebben elt�r a C �s a C++ r�gebbi v�ltozatait�l, amelyek
megengedt�k az
elso k�t p�ld�t, azt felt�telezve, hogy a t�pus int, ha nincs t�pus megadva
(�B.2). Ez az .implicit
int. szab�ly sok f�lre�rt�s �s nehezen megfoghat� hiba forr�sa volt.
4.9.2. T�bb n�v bevezet�se
Egyetlen deklar�ci�ban t�bb nevet is megadhatunk. A deklar�ci� ekkor vesszovel
elv�lasztott
deklar�ci�k list�j�t tartalmazza. K�t eg�szet p�ld�ul �gy vezethet�nk be:
int x, y; // int x �s int y;
Jegyezz�k meg, hogy az oper�torok csak egyes nevekre vonatkoznak, az ugyanabban
a deklar�ci�ban szereplo tov�bbi nevekre nem:
int* p, y; // int* p �s int y, NEM int* y
int x, *q; // int x �s int* q
int v[10], *pv; // int v[10] �s int* pv
A fentihez hasonl� szerkezetek rontj�k a program olvashat�s�g�t, ez�rt ker�lendok.

4. T�pusok �s deklar�ci�k 105


4.9.3. Nevek
A n�v (azonos�t�) betuk �s sz�mok sorozat�b�l �ll. Az elso karakternek betunek
kell lennie.
Az _ (al�h�z�s) karaktert betunek tekintj�k. A C++ nem korl�tozza a n�vben
haszn�lhat
� karakterek sz�m�t. A ford�t�program �r�ja azonban a megval�s�t�s egyes r�szeire
nincs
befoly�ssal (konkr�tan a szerkesztoprogramra, a linker-re), ez pedig hat�rokat
szab.
N�h�ny fut�si ideju k�rnyezet ugyancsak sz�ks�gess� teszi, hogy kibov�ts�k vagy
megszor
�tsuk az azonos�t�ban elfogadhat� karakterk�szletet. A bov�t�sek (p�ld�ul a $
enged�lyez
�se egy n�vben) nem hordozhat� programokat eredm�nyeznek. A C++ kulcsszavai (.A.
f�ggel�k), mint a new �s az int, nem haszn�lhat�k felhaszn�l�i egyedek nevek�nt.
P�ld�k
a nevekre:
hello ez_egy_szokatlanul_hossz�_n�v
DEFINED foO bAr u_name LoPatko
var0 var1 CLASS _class ___
�s n�h�ny p�lda olyan karaktersorozatokra, amelyek nem haszn�lhat�k azonos�t�k�nt:

012 egy bolond $sys class 3var


fizetes.esedekes foo~bar .name if
Az al�h�z�ssal kezdodo nevek a nyelvi megval�s�t�s �s a fut�si ideju k�rnyezet
egyedi eszk
�zei sz�m�ra vannak fenntartva, �gy ezeket nem szabadna haszn�lni alkalmaz�i
programokban.
Amikor a ford�t� olvassa a programot, mindig a leghosszabb olyan sorozatot keresi,
amely
kiadhat egy nevet. �gy a var10 �s nem a var n�v (amit a 10-es sz�m k�vet).
Hasonl�an, az
elseif is egy n�v, nem pedig az else, amit az if kulcssz� k�vet.
A kis- �s nagybetuket a nyelv megk�l�nb�zteti, �gy a Count �s a count k�l�nb�zo
nevek,
de nem b�lcs dolog olyan neveket v�lasztani, amelyek csak a kezdobetuben t�rnek
el.
A legjobb elker�lni azokat a neveket, amelyek csak kicsit k�l�nb�znek. P�ld�ul a
nagybet
us o (O) �s a nulla (0) nehezen megk�l�nb�ztetheto, a kis L (l) �s az egyes (1)
szint�n. K�-
vetkez�sk�ppen azonos�t�nak a l0, lO, l1 �s ll nem szerencs�s v�laszt�s.
A nagy hat�k�ru nevek lehetoleg hossz�ak �s �rthetoek legyenek, mint vector,
Window_with_border, �s Department_number. A k�d viszont �rthetobb lesz, ha a kis
hat�-
k�rben haszn�lt neveknek r�vid, hagyom�nyos st�lus� nev�k van, mint x, i �s p. Az
oszt�lyok
(10. fejezet) �s a n�vterek (�8.2) haszn�lhat�k arra, hogy a hat�k�r�k kicsik
maradjanak.
Hasznos dolog viszonylag r�vidnek hagyni a gyakran haszn�lt neveket, az igaz�n
hossz�akat
106 Alapok
pedig megtartani a kev�sb� gyakran haszn�latos egyedeknek. V�lasszuk meg �gy a
neveket,
hogy az egyed jelent�s�re �s ne annak megval�s�t�s�ra utaljanak. A phone_book
(telefonk
�nyv) p�ld�ul jobb, mint a number_list (sz�mok list�ja), m�g akkor is, ha a
telefonsz�mokat
list�ban (�3.7) t�roljuk. A j� nevek megv�laszt�sa is egyfajta muv�szet.
Pr�b�ljunk k�vetkezetes elnevez�si st�lust fenntartani. P�ld�ul �rjuk nagy
kezdobetuvel
a nem standard k�nyvt�rbeli felhaszn�l�i t�pusokat �s kisbetuvel azokat a neveket,
amelyek
nem t�pusnevek (p�ld�ul Shape �s current_token). Tov�bb� haszn�ljunk csupa
nagybetut
makr�k eset�ben (ha makr�kat kell haszn�lnunk, p�ld�ul HACK) �s haszn�ljunk
al�h�z�st,
ha az azonos�t�ban sz�t akarjuk v�lasztani a szavakat. Ak�rhogy is, neh�z el�rni a
k�vetkezetess
�get, mivel a programokat �ltal�ban k�l�nb�zo forr�sokb�l vett r�szletek alkotj�k
�s
sz�mos k�l�nb�zo �sszeru st�lus haszn�latos benn�k. Legy�nk k�vetkezetesek a
r�vid�t�-
sek �s betuszavak haszn�lat�ban is.
4.9.4. Hat�k�r�k
A deklar�ci� a megadott nevet egy hat�k�rbe (scope) vezeti be, azaz a nevet csak a
programsz
�veg meghat�rozott r�sz�ben lehet haszn�lni. A f�ggv�nyeken bel�l megadott nevek
eset�ben (ezeket gyakran lok�lis vagy helyi n�vnek h�vjuk) ez a hat�k�r a
deklar�ci� hely�-
tol annak a blokknak a v�g�ig tart, amelyben a deklar�ci� szerepel. A blokk olyan
k�dr�sz,
amelyet a { } kapcsos z�r�jelek hat�rolnak.
Egy nevet glob�lisnak nevez�nk, ha f�ggv�nyen, oszt�lyon (10. fejezet) vagy
n�vt�ren
(�8.2) k�v�l bevezetett. A glob�lis nevek hat�k�re a bevezet�s pontj�t�l annak a
f�jlnak
a v�g�ig terjed, amelyben a deklar�ci� szerepel. A blokkokban szereplo
n�vdeklar�ci�k
a k�r�lvevo blokkban l�vo deklar�ci�kat �s a glob�lis neveket elfedhetik, azaz egy
nevet
�jra meg lehet adni �gy, hogy egy m�sik egyedre hivatkozzon egy blokkon bel�l. A
blokkb
�l val� kil�p�s ut�n a n�v visszanyeri elozo jelent�s�t:
int x; // glob�lis x
void f()
{
int x; // a lok�lis x elfedi a glob�lis x-et
x = 1; // �rt�kad�s a lok�lis x-nek
{
int x; // elfedi az elso lok�lis x-et
x = 2; // �rt�kad�s a m�sodik lok�lis x-nek
}
4. T�pusok �s deklar�ci�k 107
x = 3; // �rt�kad�s az elso lok�lis x-nek
}
int* p = &x; // a glob�lis x c�m�nek felhaszn�l�sa
A nevek elfed�se elker�lhetetlen nagy programok �r�sakor. A k�dot olvas�nak
azonban
k�nnyen elker�li a figyelm�t, hogy egy n�v t�bbsz�r szerepel. Mivel az ilyen hib�k
viszonylag
ritk�n fordulnak elo, nagyon nehezen lehet azokat megtal�lni. K�vetkez�sk�ppen
a n�velfed�sek sz�m�t a leheto legkisebbre kell cs�kkenteni. Ha valaki olyan
neveket haszn
�l glob�lis v�ltoz�k�nt vagy egy hosszabb f�ggv�ny lok�lis v�ltoz�jak�nt, mint i
�s x, akkor
maga keresi a bajt.
Az elfedett glob�lis nevekre a :: hat�k�rjelzo haszn�lat�val hivatkozhatunk:
int x;
void f2()
{
int x = 1; // a glob�lis x elfed�se
::x = 2; // �rt�kad�s a glob�lis x-nek
x = 2; // �rt�kad�s a lok�lis x-nek
// ...
}
Elfedett lok�lis n�v haszn�lat�ra nincs m�d.
A n�v hat�k�re a n�v deklar�ci�j�nak pontj�t�l kezdodik; azaz a teljes deklar�tor
ut�n �s
a kezdeti �rt�k(ek)et megad� r�sz elott. Ez azt jelenti, hogy egy nevet saj�t
kezdo�rt�k�nek
meghat�roz�s�ra is haszn�lhatunk:
int x;
void f3()
{
int x = x; // perverz: kezdeti �rt�kad�s x-nek saj�t maga (nem meghat�rozott)
�rt�k�vel
}
Ez nem tiltott, csak butas�g. Egy j� ford�t�program figyelmeztet�st ad, ha egy
v�ltoz�t azel
ott haszn�lunk, mielott �rt�k�t be�ll�tottuk volna (l�sd �5.9[9]).
108 Alapok
Egy n�vvel egy blokkban k�t k�l�nb�zo objektumra a :: oper�tor haszn�lata n�lk�l
is hivatkozhatunk:
int x = 11;
void f4() // perverz:
{
int y = x; // a glob�lis x felhaszn�l�sa, y = 11
int x = 22;
y = x; // a lok�lis x felhaszn�l�sa, y = 22
}
A f�ggv�nyparam�terek neveit �gy tekintj�k, mint ha a f�ggv�ny legk�lso blokkj�ban
lenn
�nek megadva, �gy az al�bbi hib�s, mert x-et ugyanabban a hat�k�rben k�tszer adtuk

meg:
void f5(int x)
{
int x; // hiba
}
Ilyen hiba gyakran elofordul, �rdemes figyeln�nk r�.
4.9.5. Kezdeti �rt�kad�s
Ha egy objektumhoz kezdo�rt�k-ad� kifejez�st adunk meg, akkor ez hat�rozza meg az
objektum
kezdeti �rt�k�t. Ha nincs megadva ilyen, a glob�lis (�4.9.4), n�vt�r (�8.2), vagy
helyi
statikus objektumok (�7.1.2, �10.2.4) (melyeket egy�ttesen statikus objektumoknak
nevez
�nk) a megfelelo t�pus 0 �rt�k�t kapj�k kezdo�rt�k�l:
int a; // jelent�se "int a = 0;''
double d; // jelent�se "double d = 0.0;''
A lok�lis v�ltoz�knak (ezeket n�ha automatikus objektumoknak nevezz�k) �s a szabad
t�rban
l�trehozott objektumoknak (dinamikus vagy .heap. objektumok) alap�rtelmez�s
szerint
nincs kezdo�rt�k�k:
void f()
{
int x; // x �rt�ke nem meghat�rozott
// ...
}
4. T�pusok �s deklar�ci�k 109
A t�mb�k �s strukt�r�k tagjai alap�rtelmez�s szerint kapnak kezdo�rt�ket,
f�ggetlen�l att
�l, hogy az adott szerkezet statikus-e vagy sem. A felhaszn�l�i t�pusokhoz magunk
is megadhatunk
alap�rtelmezett kezdo�rt�ket (�10.4.2).
A bonyolultabb objektumoknak egyn�l t�bb �rt�kre van sz�ks�g�k a kezdeti
�rt�kad�shoz.
A t�mb�k �s strukt�r�k C t�pus� felt�lt�sekor (�5.2.1, �5.7) ezt egy { } z�r�jelek
�ltal hat�-
rolt list�val �rhetj�k el. A konstruktorral rendelkezo felhaszn�l�i t�pusokn�l a
f�ggv�ny st�-
lus� param�terlist�k haszn�latosak (�2.5.2, �10.2.3). Jegyezz�k meg, hogy a
deklar�ci�kban
szereplo () �res z�r�jelek jelent�se mindig .f�ggv�ny.:
int a[ ] = { 1, 2 }; // t�mb kezdeti �rt�kad�sa
Point z(1,2); // f�ggv�ny st�lus� kezdeti �rt�kad�s (konstruktorral)
int f(); // f�ggv�ny-deklar�ci�
4.9.6. Objektumok �s bal�rt�kek
N�vvel nem rendelkezo .v�ltoz�kat. is lefoglalhatunk �s haszn�lhatunk, �s �rt�ket
is adhatunk
nekik furcsa kifejez�sekkel (pl. *p[a+10]=7). K�vetkez�sk�pp el kellene nevezn�nk
azt, hogy .valami a mem�ri�ban.. Ez az objektum legegyszerubb �s legalapvetobb
fogalma.
Azaz, az objektum egy folytonos t�rter�let; a bal oldali �rt�k (.bal�rt�k.) pedig
egy olyan
kifejez�s, amely egy objektumra hivatkozik. A bal�rt�k (lvalue) sz�t eredetileg
arra alkott
�k, hogy a k�vetkezot jelentse: .valami, ami egy �rt�kad�s bal oldal�n
szerepelhet.. Nem
minden bal�rt�k lehet azonban az �rt�kad�s bal oldal�n, egy bal�rt�k hivatkozhat
�lland�ra
(const) is (�5.5). A nem const-k�nt megadott bal�rt�ket szok�s m�dos�that�
bal�rt�knek
(modifiable lvalue) is nevezni. Az objektumnak ezt az egyszeru �s alacsony szintu
fogalm�t
nem szabad �sszet�veszteni az oszt�lyobjektumok �s t�bbalak� (polimorf t�pus�)
objektumok
(�15.4.3) fogalm�val.
Hacsak a programoz� m�sk�pp nem rendelkezik (�7.1.2, �10.4.8), egy f�ggv�nyben
bevezetett
v�ltoz� akkor j�n l�tre, amikor defin�ci�j�hoz �rkez�nk, �s akkor szunik meg,
amikor
a neve a hat�k�r�n k�v�lre ker�l (�10.4.4). Az ilyen objektumokat automatikus
objektumoknak
nevezz�k. A glob�lis �s n�vt�r-hat�k�rben bevezetett objektumok �s a f�ggv�-
nyekben vagy oszt�lyokban megadott static objektumok (csak) egyszer j�nnek l�tre
�s
kapnak kezdeti �rt�ket, �s a program befejezt�ig .�lnek.(10.4.9). Az ilyen
objektumokat
statikus objektumoknak nevezz�k. A t�mbelemeknek �s a nem statikus strukt�r�k vagy

oszt�lyok tagjainak az �lettartam�t az az objektum hat�rozza meg, amelynek r�szei.


A new
�s delete oper�torokkal olyan objektumok hozhat�k l�tre, amelyek �lettartama
k�zvetlen�l
szab�lyozhat� (�6.2.6).
110 Alapok
4.9.7. Typedef
Az a deklar�ci�, amit a typedef kulcssz� eloz meg, a t�pus sz�m�ra �j nevet hoz
l�tre, nem
egy adott t�pus� v�ltoz�t:
typedef char* Pchar;
Pchar p1, p2; // p1 �s p2 t�pusa char*
char* p3 = p1;
Az �gy megadott, gyakran typedef-nek (�lt�pus) nevezett n�v k�nyelmes r�vid�t�s
lehet egy
nehezen haszn�lhat� n�v helyett. P�ld�ul az unsigned char t�ls�gosan hossz� az
igaz�n
gyakori haszn�latra, ez�rt megadhatjuk a szinonim�j�t, az uchar-t:
typedef unsigned char uchar;
A typedef m�sik haszn�lata az, hogy egy t�pushoz val� k�zvetlen hozz�f�r�st egy
helyre
korl�tozunk:
typedef int int32;
typedef short int16;
Ha most az int32-t haszn�ljuk, amikor egy viszonylag nagy eg�szre van sz�ks�g�nk,
programunkat
�tvihetj�k egy olyan g�pre, ahol a sizeof(int) 2-vel egyenlo, �gy, hogy a k�dban
egyszer szereplo int32-t most m�sk�pp hat�rozzuk meg:
typedef long int32;
V�gezet�l, a typedef-ek ink�bb m�s t�pusok szinonim�i, mint �n�ll� t�pusok.
K�vetkez�sk
�ppen a typedef-ek szabadon felcser�lhetok azokkal a t�pusokkal, melyeknek
szinonim�i.
Azok, akik ugyanolyan jelent�ssel vagy �br�zol�ssal rendelkezo �n�ll� t�pusokat
szeretn�-
nek, haszn�lj�k a felsorol� t�pusokat (�4.8) vagy az oszt�lyokat (10. fejezet).
4. T�pusok �s deklar�ci�k 111
4.10. Tan�csok
[1] A hat�k�r�k legyenek kicsik. �4.9.4.
[2] Ne haszn�ljuk ugyanazt a nevet egy hat�k�rben �s az azt k�r�lvevo hat�k�rben
is. �4.9.2.
[3] Deklar�ci�nk�nt (csak) egy nevet adjunk meg. �4.9.3.
[4] A gyakori �s helyi nevek legyenek r�videk, a nem helyi �s ritk�n haszn�lt
nevek
hosszabbak. �4.9.3.
[5] Ker�lj�k a hasonl�nak l�tsz� neveket. �4.9.3.
[6] Elnevez�si st�lusunk legyen k�vetkezetes. �4.9.3.
[7] Figyelj�nk arra, hogy a n�vv�laszt�s ink�bb a jelent�sre, mintsem a megval�s�-

t�sra utaljon. �4.9.3.


[8] Ha a be�p�tett t�pus, amelyet egy �rt�k �br�zol�s�ra haszn�lunk, megv�ltozhat,

haszn�ljunk typedef-et, �gy a t�pus sz�m�ra besz�des nevet adhatunk. �4.9.7


[9] A typedef-ekkel t�pusok szinonim�it adjuk meg; �j t�pusok defini�l�s�ra
haszn�ljunk
felsorol� t�pusokat �s oszt�lyokat. �4.9.7.
[10] Eml�kezz�nk arra, hogy minden deklar�ci�ban sz�ks�ges a t�pus megad�sa
(nincs .implicit int.). �4.9.1.
[11] Ker�lj�k a karakterek sz�m�rt�k�vel kapcsolatos sz�ks�gtelen
felt�telez�seket.
�4.3.1, �C.6.2.1.
[12] Ker�lj�k az eg�szek m�ret�vel kapcsolatos sz�ks�gtelen felt�telez�seket.
�4.6.
[13] Ker�lj�k a sz�ks�gtelen felt�telez�seket a lebegopontos t�pusok
�rt�kk�szlet�-
vel kapcsolatban is. � 4.6.
[14] R�szes�ts�k elonyben a sima int-et a short int-tel vagy a long int-tel
szemben.
�4.6.
[15] R�szes�ts�k elonyben a double-t a float-tal vagy a long double-lal szemben.
�4.5.
[16] R�szes�ts�k elonyben a sima char-t a signed char-ral �s az unsigned char-ral
szemben. �C.3.4.
[17] Ker�lj�k az objektumok m�ret�vel kapcsolatos sz�ks�gtelen felt�telez�seket.
�4.6.
[18] Ker�lj�k az elojel n�lk�li aritmetik�t. �4.4.
[19] Legy�nk �vatosak az elojelesrol elojel n�lk�lire �s unsigned-r�l signed-ra
val�
�talak�t�ssal. �C.6.2.6.
[20] Legy�nk �vatosak a lebegopontos t�pusr�l eg�szre val� �talak�t�ssal. �
C.6.2.6.
[21] Legy�nk �vatosak a kisebb t�pusokra val� �talak�t�sokkal (p�ld�ul int-rol
char-ra).
� C.6.2.6.
112 Alapok
4.11. Gyakorlatok
1. (*2) Futtassuk le a .Hell�, vil�g!. programot (�3.2). Ha a program ford�t�sa
nem
�gy siker�l, ahogy kellene, olvassuk el �B.3.1-et.
2. (*1) �4.9 minden deklar�ci�j�ra v�gezz�k el a k�vetkezoket: ha a deklar�ci�
nem defin�ci�, �rjunk hozz� defin�ci�t. Ha a deklar�ci� defin�ci� is, �rjunk olyan

deklar�ci�t, ami nem az.


3. (*1.5) �rjunk programot, amely ki�rja az alapt�pusok, n�h�ny szabadon
v�lasztott
mutat�t�pus �s n�h�ny szabadon v�lasztott felsorol� t�pus m�ret�t. Haszn�ljuk
a sizeof oper�tort.
4. (*1.5) �rjunk programot, amely ki�rja az 'a'.'z' betuket �s a '0'.'9'
sz�mjegyeket,
valamint a hozz�juk tartoz� eg�sz �rt�keket. V�gezz�k el ugyanezt a t�bbi
ki�rhat� karakterre is. Csin�ljuk meg ugyanezt hexadecim�lis jel�l�ssel.
5. (*2) Mi a rendszer�nk�n a legnagyobb �s legkisebb �rt�ke a k�vetkezo
t�pusoknak:
char, short, int, long, float, double, long double �s unsigned?
6. (*1) Mi a leghosszabb lok�lis n�v, amit a C++ programokban haszn�lhatunk
a rendszer�nkben? Mi a leghosszabb k�lso n�v, amit a C++ programokban
haszn�lhatunk a rendszer�nkben? Van-e megszor�t�s a nevekben haszn�lhat�
karakterekre?
7. (*2) Rajzoljunk �br�t az eg�sz �s alapt�pusokr�l, ahol egy t�pus egy m�sik
t�pusra
mutat, ha az elso minden �rt�ke minden szabv�nyos megval�s�t�sban �br�-
zolhat� a m�sik t�pus �rt�kek�nt. Rajzoljuk meg az �br�t kedvenc C++-
v�ltozatunk t�pusaira is.
4. T�pusok �s deklar�ci�k 113
Mutat�k, t�mb�k �s strukt�r�k
.A fens�ges �s a nevets�ges
gyakran annyira �sszef�ggnek,
hogy neh�z oket sz�tv�lasztani..
(Tom Paine)
Mutat�k . Nulla . T�mb�k . Karakterliter�lok . T�mbre hivatkoz� mutat�k .
Konstansok
. Mutat�k �s konstansok . Referenci�k . void* . Strukt�r�k . Tan�csok .
Gyakorlatok
5.1. Mutat�k
Ha T egy t�pus, T* a .T-re hivatkoz� mutat�. t�pus lesz, azaz egy T* t�pus�
v�ltoz� egy T t�-
pus� objektum c�m�t tartalmazhatja. P�ld�ul:
char c = 'a';
char* p = &c; // a p a c c�m�t t�rolja
5
�br�val:
Sajnos a t�mb�kre �s f�ggv�nyekre hivatkoz� mutat�k eset�ben bonyolultabb jel�l�s
sz�ks�ges:
int* pi; // mutat� eg�szre
char** ppc; // mutat� char-ra hivatkoz� mutat�ra
int* ap[15]; // eg�szre hivatkoz� mutat�k 15 elemu t�mbje
int (*fp)(char*); // char* param�teru f�ggv�nyre hivatkoz� mutat�; eg�szet ad
vissza
int* f(char*); // char* param�teru f�ggv�ny; eg�szre hivatkoz� mutat�t ad vissza
L�sd �4.9.1-et a deklar�ci�k formai k�vetelm�nyeire vonatkoz�an, �s az .A.
f�ggel�ket
a teljes nyelvtannal kapcsolatban.
A mutat�n v�gezheto alapveto muvelet a .dereferencia., azaz a mutat� �ltal
mutatott objektumra
val� hivatkoz�s. E muveletet indirekci�nak (k�zvetett haszn�latnak, hivatkoz�snak)

is h�vj�k. Az indirekci� jele az elotagk�nt haszn�lt egyoperandus� * :


char c = 'a';
char* p = &c; // a p a c c�m�t t�rolja
char c2 = *p; // c2 == 'a'
A p �ltal mutatott v�ltoz� c, a c-ben t�rolt �rt�k 'a', �gy c2 �rt�ke 'a' lesz.A
t�mbelemekre hivatkoz
� mutat�kon aritmetikai muveleteket is v�gezhet�nk (�5.3), a f�ggv�nyekre hivatkoz
� mutat�k pedig v�gtelen�l hasznosak, ezeket a �7.7 pontban t�rgyaljuk.
A mutat�k c�lja, hogy k�zvetlen kapcsolatot teremtsenek annak a g�pnek a c�mz�si
elj�-
r�saival, amin a program fut. A legt�bb g�p b�jtokat c�mez meg. Azok, amelyek erre
nem
k�pesek, olyan hardverrel rendelkeznek, amellyel a b�jtokat g�pi szavakb�l nyerik
ki. M�sr
�szrol kev�s g�p tud k�zvetlen�l egy bitet megc�mezni, k�vetkez�sk�pp a legkisebb
objektum,
amely sz�m�ra �n�ll�an mem�ri�t foglalhatunk �s amelyre be�p�tett t�pus� mutat
�val hivatkozhatunk, a char. Jegyezz�k meg, hogy a bool legal�bb annyi helyet
foglal, mint
a char (�4.6). Ahhoz, hogy a kisebb �rt�keket t�m�rebben lehessen t�rolni, logikai
oper�-
torokat (�6.2.4) vagy strukt�r�kban levo bitmezoket (�C.8.1) haszn�lhatunk.
116 Alapok
&c
'a'
p:
c:
5.1.1. Nulla
A nulla (0) az int t�pusba tartozik. A szabv�nyos konverzi�knak (�C.6.2.3)
k�sz�nhetoen a 0
integr�lis (�4.1.1), lebegopontos, mutat�, vagy .tagra hivatkoz� mutat�. t�pus�
konstansk
�nt is haszn�lhat�. A t�pust a k�rnyezet d�nti el. A null�t �ltal�ban (de nem
sz�ks�gszeru-
en) a megfelelo m�retu .csupa nulla. bitminta jel�li.Nincs olyan objektum, amely
sz�m�ra
a 0 c�mmel foglaln�nk helyet. K�vetkez�sk�ppen a 0 mutat�-liter�lk�nt viselkedik,
azt jel
�lve, hogy a mutat� nem hivatkozik objektumra.A C-ben a nulla mutat�t
(nullpointer) szok
�s a NULL makr�val jel�lni. A C++ szigor�bb t�pusellenorz�se miatt az ilyen NULL
makr�k
helyett haszn�ljuk a sima 0-t, ez kevesebb probl�m�hoz vezet. Ha �gy �rezz�k,
musz�j
a NULL-t megadnunk, tegy�k azt az al�bbi m�don:
const int NULL = 0 ;
A const minos�to megakad�lyozza, hogy a NULL-t v�letlen�l �jra defini�ljuk �s
biztos�tja,
hogy a NULL.t ott is haszn�lni lehessen, ahol �lland�ra van sz�ks�g.
5.2. T�mb�k
Ha T egy t�pus, a T[size] a .size darab T t�pus� elembol �ll� t�mb. t�pus lesz. Az
elemek sorsz
�moz�sa 0-t�l size-1-ig terjed:
float v[3]; // h�rom lebegopontos sz�mb�l �ll� t�mb: v[0], v[1], v[2]
char* a[32]; // karakterre hivatkoz� mutat�k 32 elemu t�mbje: a[0] .. a[31]
A t�mb elemeinek sz�ma, m�rete vagy dimenzi�ja, konstans kifejez�s kell, hogy
legyen
(�C.5). Ha v�ltoz� m�retre van sz�ks�g�nk, haszn�ljunk vektort (�3.7.1, �16.3):
void f(int i)
{
int v1[i]; // hiba: a t�mb m�rete nem konstans kifejez�s
vector<int> v2(i); // rendben
}
A t�bbdimenzi�s t�mb�k �gy �br�zol�dnak, mint t�mb�kbol �ll� t�mb�k:
int d2[10][20]; // d2 olyan t�mb, amely 10 darab, 20 eg�szbol �ll� t�mb�t
tartalmaz
5. Mutat�k, t�mb�k �s strukt�r�k 117
A m�s nyelvekben t�mb�k m�ret�nek meghat�roz�s�ra haszn�lt vesszo jel�l�s
ford�t�si
hib�kat eredm�nyez, mert a , (vesszo) muveletsorozatot jelzo oper�tor (�6.2.2) �s
nem megengedett
konstans kifejez�sekben (�C.5). P�ld�ul pr�b�ljuk ki ezt:
int bad[5,2]; // hiba: konstans kifejez�sben nem lehet vesszo
A t�bbdimenzi�s t�mb�ket a �C.7 pontban t�rgyaljuk. Alacsonyszintu k�don k�v�l a
legjobb,
ha ker�lj�k oket.
5.2.1. T�mb�k felt�lt�se
A t�mb�knek �rt�kekbol �ll� list�kkal adhatunk kezdo�rt�ket:
int v1[ ] = { 1, 2, 3, 4 };
char v2[ ] = { 'a', 'b', 'c', 0 };
Amikor egy t�mb�t �gy adunk meg, hogy a m�ret�t nem hat�rozzuk meg, de
kezdo�rt�keket
biztos�tunk, a ford�t�program a t�mb m�ret�t a kezdo�rt�k-lista elemeinek
megsz�ml�-
l�s�val sz�m�tja ki. K�vetkez�sk�pp v1 �s v2 t�pusa rendre int[4] �s char[4] lesz.
Ha a m�-
retet megadjuk, a kezdo�rt�k-list�ban nem szerepelhet ann�l t�bb elem, mert ez
hib�nak
sz�m�t:
char v3[2] = { 'a', 'b', 0 }; // hiba: t�l sok kezdo�rt�k
char v4[3] = { 'a', 'b', 0 }; // rendben
Ha a kezdo�rt�k t�l kev�s elemet ad meg, a t�mb marad�k elemeire 0 lesz
felt�telezve:
int v5[8] = { 1, 2, 3, 4 };
Az elozo k�d egyen�rt�ku a k�vetkezovel:
int v5[ ] = { 1, 2, 3, 4 , 0, 0, 0, 0 };
Jegyezz�k meg, hogy a kezdo�rt�k-lista nem helyettes�theto �s nem b�r�lhat� fel�l
t�mb-
�rt�kad�ssal:
void f()
{
v4 = { 'c', 'd', 0 }; // hiba: t�mb�t nem lehet �rt�k�l adni
}
118 Alapok
Ha ilyen �rt�kad�sra van sz�ks�g�nk, t�mb helyett haszn�ljunk vector-t (�16.3)
vagy
valarray-t (�22.4).
A karaktert�mb�ket k�nyelmi okokb�l karakterliter�lokkal (�5.2.2) is
felt�lthetj�k.
5.2.2. Karakterliter�lok
A karakterliter�l egy macskak�rm�kkel hat�rolt karaktersorozat:
"Ez egy karakterl�nc"
Egy karakterliter�l a l�tsz�lagosn�l eggyel t�bb karaktert tartalmaz; a '\0' null
karakterre
v�gzodik, melynek �rt�ke 0:
sizeof("Bohr")==5
A karakterliter�lok t�pusa .megfelelo sz�m� const (�lland�) karakterbol �ll�
t�mb., �gy
a "Bohr" t�pusa const char[5] lesz.
A karakterliter�lokat egy char*-nak is �rt�k�l adhatjuk. Ez az�rt megengedett,
mert
a karakterliter�l t�pusa a C �s a C++ kor�bbi v�ltozataiban char* volt, �gy ez
sz�ks�ges ahhoz,
hogy milli� sornyi C �s C++ k�d �rv�nyes maradjon. Az ilyen karakterliter�lokat
azonban
hiba ilyen mutat�n kereszt�l m�dos�tani.
void f()
{
char* p = "Plat�n";
p[4] = 'e'; // hiba: �rt�kad�s konstansnak; az eredm�ny nem meghat�rozott
}
Az effajta hib�t �ltal�ban nem lehet a fut�si idoig kider�teni, �s a nyelv egyes
megval�s�t�-
sai is k�l�nb�znek abban, hogy mennyire szereznek �rv�nyt ennek a szab�lynak.
(L�sd
m�g �B.2.3-at.) Az, hogy a karakterliter�lok �lland�k, nemcsak mag�t�l �rtetodo,
hanem azt
is lehetov� teszi, hogy a nyelv adott v�ltozata jelentosen optimaliz�lhassa a
karakterliter�lok
t�rol�s�nak �s hozz�f�r�s�nek m�dj�t.
5. Mutat�k, t�mb�k �s strukt�r�k 119
Ha olyan karakterl�ncot szeretn�nk, amit biztosan m�dos�thatunk, karaktereit egy
t�mbbe
kell m�solnunk:
void f()
{
char p[ ] = "Z�n�n"; // p egy 6 karakterbol �ll� t�mb
p[0] = 'R'; // rendben
}
A karakterliter�l t�rol�si helye nem v�ltozik (statikus), �gy egy f�ggv�ny
visszat�r�si �rt�kek
�nt biztons�gosan megadhat�:
const char* error_message(int i)
{
// ...
return "tartom�nyhiba";
}
A range_error-t tartalmaz� mem�riater�let tartalma nem t�rlodik az error_message()
megh
�v�sa ut�n.
Az, hogy k�t egyforma karakterliter�l egyetlen mem�riater�leten t�rol�dik-e, az
adott nyelvi
v�ltozatt�l f�gg (�C.1):
const char* p = "Herakleitosz";
const char* q = "Herakleitosz";
void g()
{
if (p == q) cout << "Egyezik!\n"; // az eredm�ny az adott C++-v�ltozatt�l f�gg
// ...
}
Jegyezz�k meg, hogy a mutat�kra alkalmazott == a c�meket (a mutat� �rt�keket)
hasonl�tja
�ssze, nem azokat az �rt�keket, melyekre a mutat�k hivatkoznak.
�res karakterl�ncot a "" szomsz�dos macskak�r�m-p�rral �rhatunk le (t�pusa const
char[1]).
A nem grafikus karakterek jel�l�s�re haszn�lt ford�tott perjel (�C.3.2) szint�n
haszn�lhat�
egy karakterl�nc belsej�ben. Ez lehetov� teszi az id�zojel (" ) �s a ford�tott
perjel .escape.
karakter (\) karakterl�ncon bel�li �br�zol�s�t is. Az '\n' (�j sor) karakter ezek
k�z�l messze
a leggyakrabban haszn�lt:
cout<<"csengo az �zenet v�g�n\a\n";
120 Alapok
Az '\a' karakter az ASCII BEL (csengo), amely alert-k�nt is ismert, ki�r�sa pedig
valamilyen
hangjelz�st eredm�nyez.
A karakterl�ncokban .igazi. sort�r�s nem szerepelhet:
"Ez nem karakterl�nc
hanem formai hiba"
A hossz� l�ncok .�reshely. (whitespace) karakterekkel sz�tt�rdelhetok, hogy a
programsz
�veg szebb legyen:
char alpha[ ] = "abcdefghijklmnopqrstuvwxyz"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ";
A ford�t�program �sszefuzi a szomsz�dos l�ncokat, �gy az alpha egyetlen
karakterl�nccal is
megadhat� lett volna:
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
A null karaktert elvileg a karakterl�ncok belsej�ben is haszn�lhatn�nk, de a
legt�bb program
nem felt�telezi, hogy ut�na is vannak karakterek. A "Jens\000Munk" karakterl�ncot
p�ld�ul az olyan standard k�nyvt�rbeli f�ggv�nyek, mint a strcpy() �s a strlen(),
"Jens"-k�nt
fogj�k kezelni (�20.4.1).
Az L elotag� karakterl�ncok . mint amilyen az L"angst" . .sz�les. karakterekbol
(wide char)
�llnak (�4.3, �C3.3), t�pusuk const wchar_t[ ].
5.3. T�mb�kre hivatkoz� mutat�k
A C++-ban a t�mb�k �s mutat�k k�z�tt szoros kapcsolat �ll fenn. Egy t�mb nev�t �gy
is
haszn�lhatjuk, mint egy mutat�t, amely a t�mb elso elem�re mutat:
int v[ ] = { 1, 2, 3, 4 };
int* p1 = v; // mutat� a kezdoelemre (automatikus konverzi�)
int* p2 = &v[0]; // mutat� a kezdoelemre
int* p3 = &v[4]; // mutat� az "utols� ut�ni" elemre
5. Mutat�k, t�mb�k �s strukt�r�k 121
�br�val:
Az biztosan muk�dik, ha a mutat�t eggyel a t�mb v�ge ut�ni elemre �ll�tjuk. Ez sok
algoritmus
sz�m�ra fontos (�2.7.2, �18.3). Mivel azonban egy ilyen mutat� t�nylegesen m�r nem

mutat egy t�mb elem�re, nem szabad �r�sra vagy olvas�sra haszn�lni. Nem
meghat�rozott,
hogy mi t�rt�nik, amikor egy t�mb kezdoeleme elott levo elem c�m�t vessz�k, ez�rt
az
ilyesmi ker�lendo. Egyes sz�m�t�g�peken a t�mb�k gyakran a g�p c�mz�si hat�rain
ker�lnek
lefoglal�sra, �gy az .eggyel a kezdoelem elotti elem. egyszeruen �rtelmetlen lesz.

A t�mbnevek automatikus (implicit) �talak�t�sa mutat�v� sz�lesk�ruen haszn�latos a


C st�-
lus� k�dokban szereplo f�ggv�nyh�v�sokn�l:
extern "C" int strlen(const char*); // a <string.h> fej�llom�nyb�l
void f()
{
char v[ ] = "Annemarie";
char* p = v; // char[ ] automatikus �talak�t�sa char*-g�
strlen(p);
strlen(v); // char[ ] automatikus �talak�t�sa char*-g�
v = p; // hiba: a t�mbnek nem adhat� �rt�k
}
A standard k�nyvt�r strlen() f�ggv�ny�nek mindk�t h�v�skor ugyanaz az �rt�k ad�dik
�t. Az
a b�kkeno, hogy az automatikus konverzi�t lehetetlen elker�lni, vagyis nincs m�d
olyan
f�ggv�ny bevezet�sre, amelynek megh�v�sakor a v t�mb �tm�sol�dik. Szerencs�re
mutat�-
r�l t�mbre val� �talak�t�s nem v�gezheto sem automatikusan, sem defini�lt m�don.
A t�mbparam�ter automatikus mutat�v� alak�t�sa azt jelenti, hogy a t�mb m�rete
elv�sz
a f�ggv�ny sz�m�ra. A f�ggv�nynek azonban valahogy meg kell hat�roznia a t�mb
m�ret
�t, hogy �rtelmes muveleteket hajthasson v�gre rajta. A C standard k�nyvt�r�ban
levo m�s
f�ggv�nyekhez hasonl�an . amelyek karakterre hivatkoz� mutat�kat kapnak param�terk
�nt . az strlen() is arra sz�m�t, hogy a null karakter jelzi a karakterl�nc v�g�t,
�gy a strlen(p)
122 Alapok
p1 p2 p3
v: 1 2 3 4
a p karaktereinek a 0 null karakter v�gzod�sig sz�molt mennyis�g�t jelenti, nem
bele�rtve
a null karakter v�gzod�st . Ez meglehetosen alacsony szintu megold�s. A standard
k�nyvt
�rban l�vo vector (�16.3.) �s string (20. fejezet) eset�ben nincs ilyen probl�ma.
5.3.1. T�mb�k bej�r�sa
Sok algoritmus l�nyege a t�mb�kh�z �s m�s hasonl� adatt�pusokhoz val� hat�kony
�s .eleg
�ns. hozz�f�r�s (l�sd �3.8, 18. fejezet). A hozz�f�r�s egy t�mbre hivatkoz�
mutat�val, illetve
egy indexszel vagy egy elemre hivatkoz� mutat�val val�s�that� meg. �me egy p�lda
egy karakterl�nc bej�r�s�ra index haszn�lat�val:
void fi(char v[ ])
{
for (int i = 0; v[i]!=0; i++) use(v[i]);
}
Ez egyen�rt�ku a mutat�val t�rt�no bej�r�ssal:
void fp(char v[ ])
{
for (char* p = v; *p!=0; p++) use(*p);
}
Az elotagk�nt haszn�lt * indirekci� oper�tor egy mutat�-hivatkoz�st old fel, �gy
*p a p �ltal
mutatott karakter lesz, a ++ pedig �gy n�veli a mutat�t, hogy az a t�mb k�vetkezo
elem�-
re hivatkozzon. Nincs olyan eredendo ok, ami�rt az egyik v�ltozat gyorsabb lenne a
m�sikn
�l. A modern ford�t�programoknak ugyanazt a k�dot kell l�trehozniuk mindk�t p�lda
eset�ben (l�sd �5.9[8]-at). A programoz�k logikai �s eszt�tikai alapon
v�laszthatnak a v�ltozatok
k�z�tt.
Ha a +, -, ++ vagy -- aritmetikai muveleti jeleket mutat�kra alkalmazzuk, az
eredm�ny a mutat
�k �ltal hivatkozott objektumok t�pus�t�l f�gg. Amikor egy T* t�pus� p mutat�ra
alkalmazunk
egy aritmetikai oper�tort, akkor p-rol felt�telezz�k, hogy egy T t�pus�
objektumokb
�l �ll� t�mb elem�re mutat, �gy p+1 a t�mb k�vetkezo elem�t jelzi, p-1 pedig az
elozo
elemre mutat. Ez arra utal, hogy p+1 eg�sz �rt�ke sizeof(T)-vel nagyobb lesz, mint
p eg�sz
�rt�ke. Hajtsuk v�gre a k�vetkezot:
#include <iostream>
int main ()
{
int vi[10];
short vs[10];
5. Mutat�k, t�mb�k �s strukt�r�k 123
std::cout << &vi[0] << ' ' << &vi[1] << '\n';
std::cout << &vs[0] << ' ' << &vs[1] << '\n';
}
Ekkor a k�vetkezot kapjuk (a mutat�k �rt�k�nek alap�rtelmez�s szerinti,
hexadecim�lis jel
�l�s�t haszn�lva):
0x7fffaef0 0x7fffaef4
0x7fffaedc 0x7fffaede
Ez azt mutatja, hogy sizeof(short) az adott megval�s�t�sban 2, sizeof(int) pedig
4.
Mutat�kat csak akkor vonhatunk ki egym�sb�l defini�lt m�don, ha mindk�t mutat�
ugyanannak
a t�mbnek az elemeire mutat (b�r a nyelvben nincs gyors m�d annak ellenorz�s�re,
hogy val�ban arra mutatnak). Amikor kivonunk egy mutat�t egy m�sikb�l, az eredm�ny

a k�t mutat� k�z�tt l�vo t�mbelemek sz�ma (egy eg�sz t�pus� �rt�k) lesz. A
mutat�khoz
eg�sz �rt�ket is adhatunk �s ki is vonhatunk belole eg�szet, az eredm�ny mindk�t
esetben
egy mutat� �rt�k lesz. Ha ez az �rt�k nem ugyanannak a t�mbnek egy elem�re mutat,
amelyre az eredeti mutat�, vagy nem eggyel a t�mb m�g�, az eredm�ny�l kapott
mutat�
�rt�k felhaszn�l�sa kisz�m�thatatlan eredm�nyhez vezethet:
void f()
{
int v1[10];
int v2[10];
int i1 = &v1[5]-&v1[3]; // i1 = 2
int i2 = &v1[5]-&v2[3]; // meghat�rozhatatlan eredm�ny
int* p1 = v2+2; // p1 = &v2[2]
int* p2 = v2-2; // *p2 nem meghat�rozott
}
A bonyolult mutat�aritmetika rendszerint sz�ks�gtelen, ez�rt legjobb elker�lni.
Nincs �rtelme
mutat�kat �sszeadni, �s ez nem is megengedett.
A t�mb�k nem �nle�r�k, mert nem biztos, hogy a t�mb elemeinek sz�ma is t�rol�dik
a t�mbbel egy�tt. Ez azt jelenti, hogy ahhoz, hogy bej�rjunk egy t�mb�t, amely nem
tartalmaz
a karakterl�ncok�hoz hasonl� v�gzod�st, valahogy meg kell adnunk a t�mb elemeinek
sz�m�t:
124 Alapok
void fp(char v[ ], unsigned int size)
{
for (int i=0; i<size; i++) use(v[i]);
const int N = 7;
char v2[N];
for (int i=0; i<N; i++) use(v2[i]);
}
Jegyezz�k meg, hogy a legt�bb C++-v�ltozat a t�mb�k eset�ben nem v�gez
indexhat�rellen
orz�st. A t�mb ezen fogalma eredendoen alacsony szintu. Fejlettebb t�mbfogalmat
oszt�lyok haszn�lat�val val�s�thatunk meg (�3.7.1).
5.4. Konstansok
A C++ felk�n�lja a const, azaz a felhaszn�l�i �lland� fogalm�t, hogy lehetos�g�nk
legyen
annak kifejez�s�re, hogy egy �rt�k nem v�ltozik meg k�zvetlen�l. Ez sz�mos esetben
hasznos
lehet. Sok objektumnak a l�trehoz�s ut�n m�r nem v�ltozik meg az �rt�ke. A
szimbolikus
konstansok (jelk�pes �lland�k) k�nnyebben m�dos�that� k�dhoz vezetnek, mint
a k�dban k�zvetlen�l elhelyezett liter�lok. Gyakori, hogy egy �rt�ket mutat�n
kereszt�l
�r�nk el, de az �rt�ket nem v�ltoztatjuk meg. A legt�bb f�ggv�nyparam�tert csak
olvassuk,
nem �rjuk.
A const kulcssz� hozz�adhat� egy objektum deklar�ci�j�hoz, jelezve, hogy az
objektumot
�lland�k�nt hat�rozzuk meg. Mivel egy �lland�nak k�sobb nem lehet �rt�ket adni,
kezdeti
�rt�kad�st kell v�gezn�nk:
const int model = 90; // a model �lland�
const int v[ ] = { 1, 2, 3, 4 }; // a v[i] �lland�
const int x; // hiba: nincs kezdeti �rt�kad�s
Ha valamit const-k�nt hat�rozunk meg, az biztos�t�k arra, hogy hat�k�r�n bel�l
�rt�ke nem
fog megv�ltozni:
void f()
{
model = 200; // hiba
v[2]++; // hiba
}
5. Mutat�k, t�mb�k �s strukt�r�k 125
Jegyezz�k meg, hogy a const kulcssz� m�dos�tja a t�pust �s megszor�t�st ad arra,
hogyan
haszn�lhatunk egy objektumot, de nem hat�rozza meg, hogyan kell az �lland� sz�m�ra
helyet
foglalni:
void g(const X* p)
{
// itt *p nem m�dos�that�
}
void h()
{
X val; // a val m�dos�that�
g(&val);
// ...
}
Att�l f�ggoen, hogy a ford�t�program mennyire okos, sz�mos m�don kihaszn�lhatja
egy
objektum �lland� mivolt�t. Az �lland�k kezdeti �rt�ke p�ld�ul gyakran (de nem
mindig)
egy konstans kifejez�s (�C.5), ami ford�t�si idoben ki�rt�kelheto. Tov�bb�, ha a
ford�t�-
program tud az �lland� minden haszn�lat�r�l, nem kell t�rhelyet sem lefoglalnia
sz�m�ra:
const int c1 = 1;
const int c2 = 2;
const int c3 = my_f(3); // c3 �rt�ke ford�t�skor nem ismert
extern const int c4; // c4 �rt�ke ford�t�skor nem ismert
const int* p = &c2; // c2 sz�m�ra t�rter�letet kell foglalni
Ekkor a ford�t�program ismeri c1 �s c2 �rt�k�t, �gy azokat konstans kifejez�sekben
felhaszn
�lhatjuk. Mivel a c3 �s c4 �rt�kek ford�t�si idoben nem ismertek (ha csak ebben a
ford�t�-
si egys�gben levo inform�ci�kat haszn�ljuk fel, l�sd �9.1), c3-nak �s c4-nek
t�rhelyet kell
foglalni. Mivel c2 c�m�t haszn�ljuk, c2-nek is helyet kell foglalni. A c1 konstans
p�lda arra
az egyszeru �s gyakori esetre, amikor az �lland� �rt�ke ford�t�si idoben ismert �s
sz�m�ra
nem sz�ks�ges t�rat foglalni. Az extern kulcssz� azt jel�li, hogy a c4-et m�shol
defini�ltuk
(�9.2).
A konstansokb�l �ll� t�mb�knek �ltal�ban sz�ks�ges helyet foglalni, mert a
ford�t�program
nem tudja eld�nteni, mely t�mbelemekre hivatkoznak a kifejez�sek. Sok g�pen
azonban
m�g ebben az esetben is n�velhetj�k a hat�konys�got, �gy, hogy a konstansokb�l
�ll�
t�mb�t csak olvashat� mem�ri�ba tessz�k.
126 Alapok
A const-okat gyakran haszn�ljuk t�mb�k indexhat�rak�nt �s case c�mk�kn�l is:
const int a = 42;
const int b = 99;
const int max = 128;
int v[max];
void f(int i)
{
switch (i) {
case a:
// ...
case b:
// ...
}
}
Ilyen esetekben gyakori, hogy const helyett felsorol� konstansokat (�4.8)
haszn�lunk. Azt,
hogy a const milyen m�don haszn�lhat� oszt�lyok tagf�ggv�nyeivel, a �10.2.6 �s
�10.2.7
pontokban t�rgyaljuk.
A szimbolikus konstansokat rendszeresen haszn�lnunk kellene arra, hogy elker�lj�k
a k�dban
a .m�gikus sz�mokat.. Ha egy numerikus �lland�, p�ld�ul egy t�mb m�rete, a k�dban
ism�tlodik, a programot neh�z lesz �tn�zni, hogy a megfelelo m�dos�t�skor az
�lland� minden
egyes elofordul�s�t kicser�lj�k. A szimbolikus konstansok haszn�lata viszont
lok�liss�
teszi az inform�ci�t. A numerikus konstansok rendszerint valamilyen, a programmal
kapcsolatos
felt�telez�st jel�lnek. A 4 p�ld�ul egy eg�szben l�vo b�jtok sz�m�t, a 128 a
bemenet
�tmeneti t�rba helyez�s�hez (pufferel�s�hez) sz�ks�ges karakterek sz�m�t, a 6.24
pedig a d�n korona �s az amerikai doll�r k�z�tti kereszt�rfolyamot jel�lheti. Ha
ezeket az
�rt�keket numerikus �lland�k�nt hagyjuk a k�dban, akkor az, aki a programot
karbantartja,
nagyon nehezen tudja megtal�lni �s meg�rteni azokat. Ezeket az �lland�kat gyakran
nem veszik �szre, �s �rv�nytelenn� v�lnak, amikor a programot �tviszik m�s
rendszerre
vagy ha m�s v�ltoz�sok al��ss�k az �ltaluk kifejezett felt�telez�seket. Ha a
feltev�seket
megjegyz�sekkel megfeleloen ell�tott szimbolikus konstansokk�nt val�s�tjuk meg,
minim�-
lisra cs�kkenthetj�k az ilyen jellegu karbantart�si probl�m�kat.
5. Mutat�k, t�mb�k �s strukt�r�k 127
5.4.1. Mutat�k �s konstansok
A mutat�k haszn�latakor k�t objektummal kapcsolatos dologr�l van sz�: mag�r�l a
mutat
�r�l �s az �ltala mutatott objektumr�l. Ha a mutat� deklar�ci�j�t a const sz�
elozi meg, akkor
az az objektumot, �s nem a mutat�t hat�rozza meg �lland�k�nt. Ahhoz, hogy �lland�-

k�nt egy mutat�t, �s ne az �ltala mutatott objektumot vezess�k be, a *const


deklar�tort kell
haszn�lnunk a sima * helyett:
void f1(char* p)
{
char s[ ] = "Gorm";
const char* pc = s; // mutat� �lland�ra
pc[3] = 'g'; // hiba: pc �lland�ra mutat
pc = p; // rendben
char *const cp = s; // konstans mutat�
cp[3] = 'a'; // rendben
cp = p; // hiba: cp konstans
const char *const cpc = s; // konstans mutat� �lland�ra
cpc[3] = 'a'; // hiba: cpc �lland�ra mutat
cpc = p; // hiba: cpc konstans
}
A *const deklar�torjelzo teszi �lland�v� a mutat�t. Nincs azonban const*
deklar�tor-oper�-
tor, �gy a * elott szereplo const kulcssz�t az alapt�pus r�sz�nek tekintj�k:
char *const cp; // konstans mutat� karakterre
char const* pc; // mutat� kostans karakterre
const char* pc2; // mutat� kostans karakterre
�ltal�ban seg�ts�get jelent, ha az ilyen deklar�ci�kat jobbr�l balra olvassuk ki.
P�ld�ul: .cp
egy konstans (const) mutat�, amely egy karakterre (char) mutat. �s .pc2 egy
mutat�, amely
egy karakter-konstansra (char const) mutat..
Egy objektum, amely �lland� akkor, amikor mutat�n kereszt�l f�r�nk hozz�, lehet,
hogy
m�dos�that� lesz akkor, ha m�s m�don f�r�nk hozz�. Ez k�l�n�sen hasznos a
f�ggv�nyparam
�terek eset�ben. Azzal, hogy egy mutat�-param�tert const-k�nt adunk meg, a f�ggv
�nynek megtiltjuk, hogy m�dos�tsa a mutat� �ltal mutatott objektumot:
char* strcpy(char* p, const char* q); // *q nem m�dos�that�
128 Alapok
Egy v�ltoz� c�m�t �rt�k�l adhatjuk egy konstansra hivatkoz� mutat�nak, mert ebbol
m�g
semmi rossz nem k�vetkezik. Konstans c�m�t azonban nem lehet �rt�k�l adni egy nem
konstans mutat�nak, mert ezzel megengedn�nk, hogy az objektum �rt�ke megv�ltozzon:

void f4()
{
int a = 1;
const int c = 2;
const int* p1 = &c; // rendben
const int* p2 = &a; // rendben
int* p3 = &c; // hiba: kezdeti �rt�kad�s int*-nak const int*-gal
*p3 = 7; // k�s�rlet c �rt�k�nek m�dos�t�s�ra
}
A const-ra hivatkoz� mutat�kkal kapcsolatos megszor�t�sokat meghat�rozott
(explicit)
t�puskonverzi�val k�sz�b�lhetj�k ki (�10.2.7.1 �s �15.4.2.1).
5.5. Referenci�k
A referencia (hivatkoz�s) egy objektum .�lneve. (alias). Az ilyen hivatkoz�sokat
�ltal�ban
f�ggv�nyek �s k�l�n�sen t�lterhelt oper�torok (11. fejezet) param�tereinek �s
visszat�r�si
�rt�keinek megad�s�ra haszn�ljuk. Az X& jel�l�s jelent�se .referencia X-re..
L�ssunk egy
p�ld�t:
void f()
{
int i = 1;
int& r = i; // r �s i itt ugyanarra az int-re hivatkoznak
int x = r; // x = 1
r = 2; // i = 2
}
Azt biztos�tand�, hogy a referencia valaminek a neve legyen (azaz tartozzon hozz�
objektum),
a hivatkoz�s c�lpontj�t m�r l�trehoz�skor meg kell hat�roznunk:
int i = 1;
int& r1 = i; // rendben: r1 kapott kezdo�rt�ket
int& r2; // hiba: kezdeti �rt�kad�s hi�nyzik
extern int& r3; // rendben: r3 m�shol kap kezdo�rt�ket
5. Mutat�k, t�mb�k �s strukt�r�k 129
A referencia kezdeti �rt�kad�sa nagyban k�l�nb�zik a k�sobbi �rt�kad�st�l. A
l�tszat ellen
�re a referenci�n nem hajt�dik v�gre egyetlen muvelet sem. P�ld�ul:
void g()
{
int ii = 0;
int& rr = ii;
rr++; // ii n�vel�se eggyel
int* pp = &rr; // pp az ii-re mutat
}
Ez nem helytelen, de rr++ nem az rr �rt�k�t n�veli; a ++ egy int-re hajt�dik v�gre
(ami itt
ii). K�vetkez�sk�ppen a referenci�k �rt�ke m�r nem m�dos�that� a kezdeti �rt�kad�s
ut�n;
mindig arra az objektumra fognak hivatkozni, amelyre kezdetben be�ll�tottuk
azokat. Az rr
�ltal jel�lt objektumra hivatkoz� mutat�t &rr-rel kaphatjuk meg.
A referencia mag�t�l �rtetodo m�don megval�s�that� (konstans) mutat�k�nt is, amely
minden
egyes haszn�latakor automatikusan feloldja a mutat�-hivatkoz�st. Nem sz�rmazhat
baj
abb�l, ha �gy gondolunk a referenci�kra, mindaddig, m�g el nem felejtj�k, hogy nem
olyan
objektumok, amelyet mutat�k�nt kezelhetn�nk:
Egyes ford�t�programok olyan optimaliz�ci�t alkalmazhatnak, amely a referencia
sz�m�ra
fut�si idoben sz�ks�gtelenn� teszi t�rter�let lefoglal�s�t.
A referencia kezdeti �rt�kad�sa mag�t�l �rtetodo, ha a kezdo�rt�k egy bal�rt�k
(vagyis egy
olyan objektum, amelynek c�m�re hivatkozhatunk, l�sd 4.9.6). Egy .sima. T&
kezdo�rt�ke
T t�pus� bal�rt�k kell, hogy legyen. Egy const T& eset�ben ez nem sz�ks�ges (sem
bal�rt
�knek, sem T t�pus�nak nem kell lennie), helyette az al�bbiak t�rt�nnek:
130 Alapok
&ii
ii: 1
rr:
pp:
1. Elosz�r T-re t�rt�no automatikus t�puskonverzi� megy v�gbe, ha sz�ks�ges
(l�sd �C.6-ot),
2. azt�n a kapott �rt�k egy T t�pus� ideiglenes v�ltoz�ba ker�l,
3. v�g�l ez az ideiglenes v�ltoz� lesz a kezdo�rt�k.
Vegy�k a k�vetkezo p�ld�t:
double& dr = 1; // hiba: bal�rt�kre van sz�ks�g
const double& cdr = 1; // rendben
A m�sodik a k�vetkezok�ppen �rtelmezheto:
double temp = double(1); // elosz�r l�trehozunk egy ideiglenes v�ltoz�t a jobb
oldali
// �rt�kkel
const double& cdr = temp; // majd ezt haszn�ljuk a cdr kezdeti �rt�kad�s�ra
A referencia kezdo�rt�k�t t�rol� ideiglenes v�ltoz� a referencia hat�k�r�nek
v�g�ig marad
fenn. A konstansok �s v�ltoz�k hivatkoz�sait az�rt k�l�nb�ztetj�k meg, mert a
v�ltoz�k
eset�ben nagy hibalehetos�geket rejt mag�ban egy ideiglenes v�ltoz� bevezet�se, a
v�ltoz
�nak val� �rt�kad�s ugyanis a . nemsok�ra megszuno . ideiglenes t�rter�letnek adna
�rt
�ket. A konstansok hivatkoz�saival nincs ilyen probl�ma, ami szerencs�s, mert ezek
gyakran
f�ggv�nyparam�terk�nt j�tszanak fontos szerepet (�11.6).
A referenci�kat olyan f�ggv�nyparam�terek megad�s�ra is haszn�lhatjuk, melyeken
kereszt
�l a f�ggv�ny m�dos�thatja a neki �tadott objektum �rt�k�t:
void increment(int& aa) { aa++; }
void f()
{
int x = 1;
increment(x); // x = 2
}
A param�ter�tad�s a kezdeti �rt�kad�shoz hasonl�, �gy az increment megh�v�sakor az
aa
param�ter az x m�sik neve lesz. Ha azt szeretn�nk, hogy a program olvashat�
maradjon,
legjobb, ha elker�lj�k az olyan f�ggv�nyeket, amelyek m�dos�tj�k param�tereiket.
Ehelyett
meghat�rozhatjuk a f�ggv�ny �ltal visszaadand� �rt�ket vagy mutat� param�tert
adhatunk
neki:
int next(int p) { return p+1; }
void incr(int* p) { (*p)++; }
5. Mutat�k, t�mb�k �s strukt�r�k 131
void g()
{
int x = 1;
increment(x); // x = 2
x = next(x); // x = 3
incr(&x); // x = 4
}
Az increment(x) jel�l�s az olvas�nak semmit sem �rul el arr�l, hogy az x �rt�ke
m�dosul,
ellent�tben az x=next(x) �s incr(&x) jel�l�sekkel. K�vetkez�sk�ppen a .sima.
referenciaparam
�tereket csak olyan esetekben haszn�ljuk, amikor a f�ggv�ny neve hat�rozottan utal

arra, hogy ezek m�dosulnak.


A referenci�kat olyan f�ggv�nyek megad�s�ra is haszn�lhatjuk, amelyek egy
�rt�kad�s bal
�s jobb oldal�n egyar�nt szerepelhetnek. Ez a bonyolultabb felhaszn�l�i t�pusok
tervez�sekor
lehet igaz�n hasznos. Adjunk meg p�ld�ul egy egyszeru asszociat�v t�mb�t. Elosz�r
hat
�rozzuk meg a Pair adatszerkezetet:
struct Pair {
string name;
double val;
};
Az alap�tlet az, hogy a string-hez tartozik egy lebegopontos �rt�k. K�nnyu
elk�sz�teni
a value() f�ggv�nyt, amely egy Pair-bol �ll� adatszerkezetet vet �ssze k�l�nb�zo
karakterl
�ncokkal. R�vid�ts�k le a p�ld�t �s haszn�ljunk egy nagyon egyszeru (persze nem
t�l hat
�kony) megval�s�t�st:
vector<Pair> pairs;
double& value(const string& s)
/*
Vessz�k Pair-ek egy halmaz�t,
megkeress�k s-t, ha megtal�ltuk, visszaadjuk az �rt�k�t; ha nem, �j Pair-t
k�sz�t�nk �s
visszaadjuk az alap�rtelmezett 0-�t.
*/
{
for (int i = 0; i < pairs.size(); i++)
if (s == pairs[i].name) return pairs[i].val;
Pair p = { s, 0 };
pairs.push_back(p); // Pair hozz�ad�sa a v�g�hez (�3.7.3)
return pairs[pairs.size()-1].val;
}
132 Alapok
Ezt a f�ggv�nyt �gy foghatjuk fel, mint egy lebegopontos �rt�kekbol �ll� t�mb�t,
amit karakterl
�ncok indexelnek. Adott karakterl�nccal �sszevetve, a value() a megfelelo lebego-
pontos objektumot (nem pedig annak �rt�k�t) tal�lja meg, �s az erre vonatkoz�
referenci�t
adja vissza:
int main() // az egyes szavak elofordul�s�nak megsz�ml�l�sa a bemeneten
{
string buf;
while (cin>>buf) value(buf)++;
for (vector<Pair>::const_iterator p = pairs.begin(); p!=pairs.end(); ++p)
cout << p->name << ": " << p->val << '\n';
}
A while ciklus minden esetben beolvas egy sz�t a cin szabv�nyos bemenetrol �s a
buf
karakterl�ncba helyezi (�3.6.), azt�n n�veli a hozz� tartoz� sz�ml�l�t. V�g�l
ki�rja az eredm
�ny�l kapott t�bl�zatot, amelyben a bemenetrol kapott karakterl�ncok �s azok
elofordul
�s�nak sz�ma szerepel. Ha a bemenet p�ld�ul a k�vetkezo:
aa bb bb aa aa bb aa aa
akkor a program eredm�nye az al�bbi:
aa: 5
bb: 3
Ezt m�r k�nnyu �gy tov�bb finom�tani, hogy val�di asszociat�v t�mb�t kapjunk;
ehhez egy
sablon oszt�lyt kell haszn�lnunk a t�lterhelt (�11.8.) [ ] indexelo oper�torral.
M�g k�nnyebb
a dolgunk, ha a standard k�nyvt�r map (�17.4.1.) t�pus�t haszn�ljuk.
5.6. Void-ra hivatkoz� mutat�k
B�rmilyen t�pus� objektumra hivatkoz� mutat�t �rt�k�l lehet adni egy void* t�pus�
v�ltoz
�nak, egy void* t�pus� v�ltoz�t �rt�k�l lehet adni egy m�sik void* t�pus�nak, a
void* t�-
pus� v�ltoz�kat �ssze lehet hasonl�tani, hogy egyenloek-e vagy sem, egy void*
t�pus� v�ltoz
�t pedig meghat�rozott m�don m�s t�pus�v� lehet alak�tani. A t�bbi muvelet nem
lenne
5. Mutat�k, t�mb�k �s strukt�r�k 133
biztons�gos, mert a ford�t�program nem tudja, hogy val�j�ban mif�le objektumra
hivatkozik
egy ilyen mutat�, ez�rt a t�bbi muvelet ford�t�si ideju hib�t eredm�nyez. Ahhoz,
hogy
egy void* t�pus� v�ltoz�t haszn�lhassunk, �t kell konvert�lnunk azt adott t�pus�
mutat�v�:
void f(int* pi)
{
void* pv = pi; // rendben: int* automatikus konvert�l�sa void*-g�
*pv; // hiba: nem lehet void*-ra hivatkozni
pv++; // hiba: void* nem n�velheto (a mutatott objektum m�rete ismeretlen)
int* pi2 = static_cast<int*>(pv); // explicit visszaalak�t�s int*-ra
double* pd1 = pv; // hiba
double* pd2 = pi; // hiba
double* pd3 = static_cast<double*>(pv); // nem biztons�gos
}
�ltal�ban nem biztons�gos olyan mutat�t haszn�lni, amely olyan t�pusra
konvert�l�dik
(cast), amely k�l�nb�zik a mutat� �ltal elozoleg hivatkozott t�pust�l. A g�p
p�ld�ul felt�telezheti,
hogy minden double 8 b�jtos mem�riahat�ron j�n l�tre. Ha �gy van, akkor furcsa mu-

k�d�s sz�rmazhat abb�l, ha a pi egy olyan int-re mutatott, amely nem �gy
helyezkedett el
a mem�ri�ban. Az ilyen jellegu explicit t�pusk�nyszer�t�s eredendoen cs�nya �s nem
biztons
�gos, k�vetkez�sk�pp a haszn�lt static_cast jel�l�st is sz�nd�kosan cs�ny�nak
tervezt�k.
A void* elsodlegesen arra haszn�latos, hogy mutat�kat adjunk �t olyan
f�ggv�nyeknek,
amelyek nem felt�teleznek semmit az objektumok t�pus�r�l, valamint arra, hogy
f�ggv�-
nyek nem t�pusos objektumokat adjanak vissza. Ahhoz, hogy ilyen objektumokat
haszn�ljunk,
explicit t�puskonverzi�t kell alkalmaznunk. Azok a f�ggv�nyek, amelyek void* t�pus
� mutat�kat haszn�lnak, jellemzoen a rendszer legals� szintj�n helyezkednek el,
ahol az
igazi hardver-eroforr�sokat kezelik. P�ld�ul:
void* my_alloc(size_t n); // n b�jt lefoglal�sa saj�t t�rter�leten
A rendszer magasabb szintjein l�vo void* t�pus� mutat�kat gyanakv�ssal kell
figyeln�nk,
mert tervez�si hib�t jelezhetnek. Ha a void*-ot optimaliz�l�sra haszn�ljuk,
rejts�k t�pusbiztos
fel�let m�g� (�13.5, �24.4.2).
A f�ggv�nyekre hivatkoz� mutat�kat (�7.7.) �s a tagokra hivatkoz� mutat�kat
(�15.5) nem
adhatjuk �rt�k�l void* t�pus� v�ltoz�nak.
134 Alapok
5.7. Strukt�r�k
A t�mb�k azonos t�pus� elemekbol �llnak, a struct-ok (adatszerkezetek, strukt�r�k)
majdnem
tetszoleges t�pus�akb�l:
struct address {
char* name; // "Jim Dandy"
long int number; // 61
char* street; // "South St"
char* town; // "New Providence"
char state[2]; // 'N' 'J'
long zip; // 7974
};
A fenti k�d egy address (c�m) nevu �j t�pust hoz l�tre, amely levelek k�ld�s�hez
sz�ks�ges
c�mz�si adatokat tartalmaz. Vegy�k �szre a pontosvesszot a defin�ci� v�g�n. Ez
egyike azon
kev�s helyeknek a C++-ban, ahol pontosvesszot kell tenni a kapcsos z�r�jel ut�n,
ez�rt sokan
hajlamosak elfelejteni.
Az address t�pus� v�ltoz�kat pontosan �gy adhatjuk meg, mint m�s v�ltoz�kat, �s az
egyes
tagokra a . (pont, tagkiv�laszt�) oper�torral hivatkozhatunk:
void f()
{
address jd;
jd.name = "Jim Dandy";
jd.number = 61;
}
A t�mb�k kezdeti �rt�kad�s�ra haszn�lt jel�l�s a strukt�ra-t�pus� v�ltoz�k
felt�lt�s�re is
haszn�lhat�:
address jd = {
"Jim Dandy",
61, "South St",
"New Providence", {'N','J'}, 7974
};
Enn�l azonban rendszerint jobb megold�s konstruktorokat (�10.2.3) haszn�lni.
Vegy�k �szre,
hogy a jd.state-et nem lehetett volna az "NJ" karakterl�nccal felt�lteni. Mivel a
karakterl
�ncok a '\0' karakterre v�gzodnek, az "NJ" h�rom karakterbol �ll, ami eggyel t�bb,
mint
ami a jd.state-be belef�r.
5. Mutat�k, t�mb�k �s strukt�r�k 135
A strukt�r�k objektumaira gyakran hivatkozunk mutat�kon kereszt�l a -> (strukt�ra-
mutat
�) oper�torral:
void print_addr(address* p)
{
cout << p->name << '\n'
<< p->number << ' ' << p->street << '\n'
<< p->town << '\n'
<< p->state[0] << p->state[1] << ' ' << p->zip << '\n';
}
Ha p egy mutat�, akkor p->m egyen�rt�ku (*p).m-mel.
A strukt�ra-t�pus� objektumokat �rt�k�l adhatjuk, �tadhatjuk
f�ggv�nyparam�terk�nt, �s
visszaadhatjuk f�ggv�nyek visszat�r�si �rt�kek�nt is:
address current;
address set_current(address next)
{
address prev = current;
current = next;
return prev;
}
M�s lehets�ges muveletek, mint az �sszehasonl�t�s (== �s !=), nem meghat�rozottak,
de
a felhaszn�l� megadhat ilyeneket (11. fejezet).
A strukt�ra-t�pus� objektumok m�rete nem felt�tlen�l a tagok m�ret�nek �sszege.
Ennek
az az oka, hogy sok g�p ig�nyli bizonyos t�pus� objektumok elhelyez�s�t a
fel�p�t�stol f�gg
o mem�riahat�rokra, vagy eleve hat�konyabban kezeli az �gy l�trehozott
objektumokat.
Az eg�szek p�ld�ul gyakran g�pi sz�hat�rokon j�nnek l�tre. Ezt �gy mondjuk, hogy
az
ilyen g�peken az objektumok j�l illesztettek. Ez a strukt�r�kon bel�l .lyukakat.
eredm�-
nyez. Sz�mos g�pen a sizeof(address) p�ld�ul 24, nem pedig 22, ahogy az elv�rhat�
lenne.
Az elpazarolt helyet a leheto legkevesebbre cs�kkenthetj�k, ha egyszeruen m�ret
szerint
rendezz�k a strukt�ra tagjait (a legnagyobb tag lesz az elso). A legjobb azonban
az, ha
olvashat�s�g szerint rendezz�k sorba a tagokat, �s csak akkor m�ret szerint, ha
bizony�tottan
sz�ks�g van optimaliz�l�sra.
136 Alapok
Egy t�pus neve r�gt�n felhaszn�lhat� att�l a pontt�l, ahol elosz�r megjelenik, nem
csak
a teljes deklar�ci� ut�n:
struct Link {
Link* previous;
Link* successor;
};
A strukt�ra teljes deklar�ci�j�nak v�g�ig viszont nem adhatunk meg �jabb ilyen
t�pus� objektumokat:
struct No_good {
No_good member; // hiba: rekurz�v defin�ci�
};
Ez az�rt hib�s, mert a ford�t�program nem k�pes eld�nteni a No_good m�ret�t. K�t
(vagy
t�bb) strukt�ra-t�pus k�lcs�n�s hivatkoz�s�hoz adjunk meg p�ld�ul egy nevet, amely
a t�-
pus neve:
struct List; // k�sobb meghat�rozand�
struct Link {
Link* pre;
Link* suc;
Link* member_of;
};
struct List {
Link* head;
};
A List elso deklar�ci�ja n�lk�l a List haszn�lata a Link deklar�ci�j�ban formai
hib�t okozott
volna. A strukt�ra-t�pus neve a t�pus meghat�roz�sa elott is felhaszn�lhat�,
felt�ve, hogy ez
a haszn�lat nem ig�nyli egy tag nev�nek vagy a strukt�ra m�ret�nek ismeret�t:
class S; // 'S' valamilyen t�pus neve
extern S a;
S f();
void g(S);
S* h(S*);
5. Mutat�k, t�mb�k �s strukt�r�k 137
A fenti deklar�ci�k k�z�l azonban sok nem haszn�lhat�, hacsak meg nem adjuk az S
t�pus�t:
void k(S* p)
{
S a; // hiba: S nem defini�lt; a helyfoglal�shoz m�ret kell
f(); // hiba: S nem defini�lt; �rt�k visszaad�s�hoz m�ret kell
g(a); // hiba: S nem defini�lt; param�ter �tad�s�hoz m�ret kell
p->m = 7; // hiba: S nem defini�lt; a tag neve nem ismert
S* q = h(p); // rendben: a mutat�k sz�m�ra foglalhat� hely �s �t is adhat�k
q->m = 7; // hiba: S nem defini�lt; a tag neve nem ismert
}
A struct az oszt�ly (10. fejezet) egyszeru form�ja.
A C t�rt�net�re visszany�l� okok miatt ugyanazzal a n�vvel �s ugyanabban a
hat�k�rben
megadhatunk egy struct-ot �s egy nem strukt�ra jellegu t�pust is:
struct stat { /* ... */ };
int stat(char* name, struct stat* buf);
Ebben az esetben a .sima. stat n�v a nem-strukt�ra neve, az adatszerkezetre pedig
a struct
elotaggal kell hivatkoznunk. Elotagk�nt a class, union (�C.8.2) �s enum (�4.8)
kulcsszavak
is haszn�lhat�k, ezekkel elker�lhetj�k a k�t�rtelmus�get. A legjobb azonban, ha
nem terhelj
�k t�l a neveket.
5.7.1. Egyen�rt�ku t�pusok
K�t strukt�ra mindig k�l�nb�zo t�pus�, akkor is, ha tagjaik ugyanazok:
struct S1 { int a; };
struct S2 { int a; };
A fenti k�t t�pus k�l�nb�zo, �gy
S1 x;
S2 y = x; // hiba: nem megfelelo t�pus
138 Alapok
A strukt�ra-t�pusok az alapt�pusokt�l is k�l�nb�znek, ez�rt
S1 x;
int i = x; // hiba: nem megfelelo t�pus
Minden struct-nak egy�rtelmu meghat�roz�sa kell, hogy legyen a programban
(�9.2.3.).
5.8. Tan�csok
[1] Ker�lj�k a nem mag�t�l �rtetodo mutat�-aritmetik�t. �5.3.
[2] �gyelj�nk arra, hogy ne �rjunk egy t�mb indexhat�r�n t�lra. �5.3.1.
[3] Haszn�ljunk 0-�t NULL helyett. �5.1.1.
[4] Haszn�ljuk a vector-t �s a valarray-t a be�p�tett (C st�lus�) t�mb�k helyett.
�5.3.1.
[5] Haszn�ljunk string-et nulla v�gzod�su karaktert�mb�k helyett. �5.3.
[6] Haszn�ljunk a leheto legkevesebb egyszeru referencia-param�tert. �5.5.
[7] Az alacsonyszintu k�dot kiv�ve ker�lj�k a void*-ot. �5.6.
[8] Ker�lj�k a k�dban a nem mag�t�l �rtetodo liter�lokat (.m�gikus sz�mokat.).
Haszn�ljunk helyett�k jelk�pes �lland�kat. �4.8, �5.4.
5.9. Gyakorlatok
1. (*1) Vezess�k be a k�vetkezoket: karakterre hivatkoz� mutat�, 10 eg�szbol �ll�
t�mb, 10 eg�szbol �ll� t�mb referenci�ja, karakterl�ncokb�l �ll� t�mbre hivatkoz
� mutat�, karakterre hivatkoz� mutat�ra hivatkoz� mutat�, konstans eg�sz,
konstans eg�szre hivatkoz� mutat�, eg�szre hivatkoz� konstans mutat�. Mindegyiknek

adjunk kezdeti �rt�ket.


2. (*1,5) Mik a char*, int*, �s void* mutat�t�pusokra vonatkoz� megszor�t�sok
a mi rendszer�nk�n? Lehetne-e p�ld�ul egy int*-nak furcsa �rt�ke? Seg�ts�g:
illeszt�s.
5. Mutat�k, t�mb�k �s strukt�r�k 139
3. (*1) Haszn�ljunk typedef-et a k�vetkezok meghat�roz�s�ra: unsigned char,
const unsigned char, eg�szre hivatkoz� mutat�, karakterre hivatkoz� mutat�ra
hivatkoz� mutat�, karaktert�mb�kre hivatkoz� mutat�; 7 elemu, eg�szre hivatkoz
� mutat�kb�l �ll� t�mb; 7 elemu, eg�szre hivatkoz� mutat�kb�l �ll� t�mbre
hivatkoz� mutat�; eg�szre hivatkoz� mutat�kat tartalmaz� 7 elemu t�mb�kbol
�ll� 8 elemu t�mb.
4. (*1) �rjunk egy swap nevu f�ggv�nyt, amely k�t eg�szt cser�l fel. Haszn�ljunk
int* t�pust a param�terek t�pusak�nt. �rjunk egy m�sik swap-et is, melynek param
�terei int& t�pus�ak.
5. (*1,5) Mi az str t�mb m�rete a k�vetkezo p�ld�ban?
char str[ ] = "r�vid karakterl�nc";
Mi a "r�vid karakterl�nc" hossza?
6. (*1) K�sz�ts�k el az f(char), g(char&) �s h(const char&) f�ggv�nyeket. H�vjuk
meg oket az 'a', 49, 3300, c, uc �s sc param�terekkel, ahol c char, uc unsigned
char �s sc signed char t�pus�. Mely h�v�sok megengedettek? Mely h�v�sokn�l
vezet be a ford�t�program ideiglenes v�ltoz�t?
7. (*1,5) K�sz�ts�nk egy t�bl�zatot, amely a h�napok neveibol �s napjaik sz�m�-
b�l �ll. �rjuk ki a t�bl�zatot. Csin�ljuk meg mindezt k�tszer: egyszer haszn�ljunk

karaktert�mb�t a nevek �s egy t�mb�t a napok sz�m�ra, m�sodszor haszn�ljunk


strukt�r�kb�l �ll� t�mb�t, ahol az egyes adatszerkezetek a h�nap nev�t �s
a benne levo napok sz�m�t t�rolj�k.
8. (*2) Futtassunk le n�h�ny tesztet, hogy megn�zz�k, a ford�t�program t�nyleg
egyen�rt�ku k�dot hoz-e l�tre a mutat�k haszn�lat�val �s az indexel�ssel val�
t�mbbej�r�shoz (�5.3.1). Ha k�l�nb�zo m�rt�ku optimaliz�l�st lehet haszn�lni,
n�zz�k meg, hat-e �s hogyan hat ez a l�trehozott k�d minos�g�re.
9. (*1,5) Tal�ljunk p�ld�t, hol lenne �rtelme egy nevet a saj�t kezdo�rt�k�ben
haszn�lni.
10. (*1) Adjunk meg egy karakterl�ncokb�l �ll� t�mb�t, ahol a karakterl�ncok
a h�napok neveit tartalmazz�k. �rjuk ki ezeket. Adjuk �t a t�mb�t egy f�ggv
�nynek, amely ki�rja a karakterl�ncokat.
11. (*2) Olvassuk be a bemenetrol szavak egy sorozat�t. A bemenetet lez�r� sz�-
k�nt haszn�ljuk a Quit-et. �rjuk ki a beolvasott szavakat. Ne �rjuk ki k�tszer
ugyanazt a sz�t. M�dos�tsuk a programot, hogy rendezze a szavakat, mielott
ki�rn� azokat.
12. (*2) �rjunk olyan f�ggv�nyt, amely megsz�molja egy betup�r elofordul�sait egy
karakterl�ncban, �s egy m�sikat, ami ugyanezt csin�lja egy nulla v�gu karaktert
�mbben (vagyis egy C st�lus� karakterl�ncban). Az "ab" p�r p�ld�ul k�tszer
szerepel az "xabaacbaxabb"-ben.
13. (*1,5) Adjunk meg egy Date strukt�r�t d�tumok �br�zol�s�hoz. �rjunk olyan
f�ggv�nyt, ami Date-eket olvas be a bemenetrol, olyat, ami Date-eket
�r a kimenetre, �s olyat, ami egy d�tummal ad kezdo�rt�ket a Date-nek.
140 Alapok
Kifejez�sek �s utas�t�sok
.Az ido elotti optimaliz�l�s
minden rossz gy�kere..
(D. Knuth)
.M�sr�szrol, nem hagyhatjuk
figyelmen k�v�l
a hat�konys�got..
(John Bentley)
.Asztali sz�mol�g�p. p�lda . Bemenet . Parancssori param�terek . Kifejez�sek
(�ttekint
�s) . Logikai �s �sszehasonl�t� oper�torok . N�vel�s �s cs�kkent�s . Szabad t�r .
Meghat
�rozott t�puskonverzi�k . Utas�t�sok (�ttekint�s) . Deklar�ci�k . El�gaz�
utas�t�sok .
Deklar�ci�k a felt�telekben . Ciklusutas�t�sok . A h�rhedt goto . Megjegyz�sek �s
beh�-
z�s . Tan�csok . Gyakorlatok
6
6.1. Egy asztali sz�mol�g�p
A kifejez�seket �s utas�t�sokat egy asztali sz�mol�g�p p�ld�j�n kereszt�l mutatjuk
be.
A sz�mol�g�p a n�gy aritmetikai alapmuveletet hajtja v�gre lebegopontos �rt�keken.
A mu-
veleti jeleket a sz�mok k�z�tt (infix oper�tork�nt) kell megadni. A felhaszn�l�
v�ltoz�kat is
megadhat. A bemenet legyen a k�vetkezo:
r = 2.5
area = pi * r * r
A sz�mol�g�p program az al�bbiakat fogja ki�rni (pi elore meghat�rozott):
2.5
19.635
A 2.5 a bemenet elso sor�nak, a 19.635 a bemenet m�sodik sor�nak eredm�nye.
A sz�mol�g�p n�gy fo r�szbol �ll: egy elemzobol (parser), egy adatbeviteli
f�ggv�nybol,
egy szimb�lumt�bl�b�l �s egy vez�rlobol. Val�j�ban ez egy miniatur ford�t�program,

amelyben az elemzo v�gzi a szintaktikai elemz�st (vagyis a nyelvi utas�t�sok


formai elemz
�s�t), az adatbeviteli f�ggv�ny kezeli a bemenetet �s v�gzi a lexikai elemz�st
(vagyis
a nyelvi elemek �rtelmez�s�t), a szimb�lumt�bla tartalmazza a nem v�ltoz� adatokat
�s
a vez�rlo kezeli a kezdeti �rt�kad�st, a kimenetet �s a hib�kat. A sz�mol�g�pet
sz�mos szolg
�ltat�ssal bov�thetj�k, hogy m�g hasznosabb� tegy�k (�6.6[20]), de a k�d �gy is
el�g hossz�
lesz, �s a legt�bb szolg�ltat�s csak a k�dot n�veln�, an�lk�l, hogy tov�bbi
betekint�st ny�jtana
a C++ haszn�lat�ba.
6.1.1. Az elemzo
�me a sz�mol�g�p �ltal elfogadott nyelvtan:
program:
END // END a bevitel v�ge
expr_list END
expr_list:
expression PRINT // PRINT a pontosvesszo
expression PRINT expr_list
142 Alapok
expression:
expression + term
expression - term
term
term:
term / primary
term * primary
primary
primary:
NUMBER
NAME
NAME = expression
- primary
( expression )
M�s sz�val, a program kifejez�sek sorozata, amelyeket pontosvesszok v�lasztanak el
egym
�st�l. A kifejez�sek alapelemei a sz�mok, nevek �s a *, /, +, - (ak�r egy, ak�r
k�t
operandus�) oper�torok, �s az = . A neveket nem kell haszn�lat elott defini�lni.
Az �ltalunk haszn�lt szintaktikai elemz�s m�dszer�t rendszerint rekurz�v
lesz�ll�snak
(recursive descent) nevezik; n�pszeru �s l�nyegret�ro, fel�lrol lefel� halad�
elj�r�s. Egy
olyan nyelvben, mint a C++, amelyben a f�ggv�nyh�v�sok viszonylag .kis
k�lts�guek",
a m�dszer hat�kony is. A nyelvtan minden szab�ly�ra adunk egy f�ggv�nyt, amely m�s

f�ggv�nyeket h�v meg. A lez�r� szimb�lumokat (p�ld�ul az END, NUMBER, + �s -)


a get_token() lexikai elemzo, a nem lez�r� szimb�lumokat pedig az expr(), term()
�s prim()
szintaktikai elemzo f�ggv�nyek ismerik fel. Ha egy (r�sz)kifejez�s mink�t
operandusa ismert,
a kifejez�s ki�rt�kelodik . egy igazi ford�t�program eset�ben ezen a ponton
t�rt�nhetne
a k�d l�trehoz�sa. Az elemzo a get_token() f�ggv�nyt haszn�lja arra, hogy
bemenetet
kapjon. Az utols� get_token() h�v�s eredm�nye a curr_tok glob�lis v�ltoz�ban
tal�lhat�.
A curr_tok v�ltoz� t�pusa Token_value felsorol� t�pus:
enum Token_value {
NAME, NUMBER, END,
PLUS='+', MINUS='-', MUL='*', DIV='/',
PRINT=';', ASSIGN='=', LP='(', RP=')'
};
Token_value curr_tok = PRINT;
6. Kifejez�sek �s utas�t�sok 143
Az, hogy minden szimb�lumot (token) a karakter�nek megfelelo eg�sz �rt�kkel
jel�l�nk,
k�nyelmes �s hat�kony megold�s, �s seg�theti azokat, akik hibakeresot (debugger)
haszn
�lnak. Ez a m�dszer addig muk�dik, am�g bemenetk�nt olyan karaktert nem adunk meg,

melynek �rt�k�t felsorol� konstansk�nt m�r haszn�ljuk. �n pedig nem tudok olyan
karakterk
�szletrol, amelyben van olyan ki�rhat� karakter, melynek eg�sz �rt�ke egy
sz�mjegyu.
Az�rt v�lasztottam a curr_tok kezdeti �rt�kek�nt a PRINT-et, mert a curr_tok ezt
az �rt�ket
fogja felvenni, miut�n a sz�mol�g�p ki�rt�kelt egy kifejez�st �s ki�rta annak
�rt�k�t. �gy
alap�llapotban .ind�tjuk el a rendszert., a leheto legkisebbre cs�kkentj�k annak
az es�ly�t,
hogy hib�k forduljanak elo �s egyedi ind�t�k�dra sincs sz�ks�g�nk.
Minden elemzo f�ggv�nynek van egy logikai (bool) (�4.2) param�tere, amely jelzi,
hogy
meg kell-e h�vnia a get_token()-t a k�vetkezo szimb�lum beolvas�s�hoz. A f�ggv�ny
ki�rt
�keli a .saj�t. kifejez�s�t �s visszaadja az �rt�k�t. Az expr() f�ggv�ny kezeli az
�sszead�st
�s kivon�st. A f�ggv�ny egyetlen ciklusb�l �ll, amely elemeket (term) keres az
�sszead�shoz
vagy kivon�shoz:
double expr(bool get) // �sszead�s �s kivon�s
{
double left = term(get);
for (;;) // "�r�kk�" (v�gtelen ciklus)
switch (curr_tok) {
case PLUS:
left += term(true);
break;
case MINUS:
left -= term(true);
break;
default:
return left;
}
}
Ez a f�ggv�ny �nmag�ban nem csin�l t�l sokat. Egy nagyobb program magasabb szintu
f�ggv�nyeihez hasonl� m�don m�s f�ggv�nyeket h�v meg a feladat elv�gz�s�hez.
A switch utas�t�s azt vizsg�lja meg, hogy a switch kulcssz� ut�n z�r�jelben
megadott felt�tel
�rt�ke megegyezik-e a konstansok valamelyik�vel. A break-kel a switch utas�t�sb�l
l�phet
�nk ki. A case c�mk�ket k�veto konstansoknak k�l�nb�zni�k kell egym�st�l. Ha a
vizsg�lt
�rt�k nem egyezik egyik case c�mk�vel sem, a default c�mke v�laszt�dik ki. A
programoz�-
nak nem k�telezo megadnia a default r�szt.
144 Alapok
Figyelj�k meg, hogy a 2-3+4-hez hasonl� kifejez�sek (2-3)+4-k�nt �rt�kelodnek ki,
ahogy
azt a nyelvtanban meghat�roztuk.
A furcsa for( ; ; ) jel�l�s megszokott m�dja annak, hogy v�gtelen ciklust �rjunk;
�gy mondhatjuk
ki, hogy .�r�kk�. (forever). Ez a for utas�t�s (�6.3.3) v�gletes form�ja; helyette
haszn
�lhatjuk a while(true) szerkezetet is. A switch utas�t�s v�grehajt�sa addig
ism�tlodik, am�g
nem tal�l a +-t�l �s - -t�l k�l�nb�zo jelet, amikor is a default c�mke ut�ni
return utas�t�s
hajt�dik v�gre.
Az �sszead�s �s kivon�s kezel�s�re a += �s -= oper�torokat haszn�ljuk.
Haszn�lhatn�nk
a left=left+term(true) �s left=left-term(true) form�t is, a program jelent�se nem
v�ltozna.
A left+=term(true) �s a left-=term(true) azonban nemcsak r�videbbek, hanem
k�zvetlenebb
�l is fejezik ki a k�v�nt muveletet. Minden �rt�kad� oper�tor �n�ll� nyelvi
egys�g, �gy a +
= 1 nyelvtanilag hib�s a + �s az = k�z�tti sz�k�z miatt.
A k�vetkezo k�toperandus� muveletekhez l�teznek �rt�kad� oper�torok:
+ - * / % & | ^ << >>
�gy a k�vetkezo �rt�kad� oper�torok lehets�gesek:
= += -= *= /= %= &= |= ^= <<= >>=
A % a modul� vagy marad�kk�pzo oper�tor; &, |, �s ^ a bitenk�nti �S, VAGY, illetve
kiz�-
r� VAGY oper�torok; << �s >> pedig a balra �s jobbra l�pteto oper�torok. A
muveleti jeleket
�s jelent�s�ket �6.2 foglalja �ssze. Ha @ egy bin�ris (k�toperandus�) oper�tor,
akkor
x@=y jelent�se x=x@y, azzal a k�l�nbs�ggel, hogy x csak egyszer �rt�kelodik ki.
A 8. �s a 9. fejezet t�rgyalja, hogyan �p�ts�nk fel programot modulokb�l. A
sz�mol�g�p p�lda
deklar�ci�it . egy kiv�tellel . �gy rendezhetj�k sorba, hogy mindent csak egyszer
�s
haszn�lat elott adunk meg. A kiv�tel az expr(), ami megh�vja a term()-et, ami
megh�vja
a prim()-et, ami pedig ism�t megh�vja az expr()-et. Ezt a k�rt valahol meg kell
szak�tanunk.
A prim() meghat�roz�sa elotti deklar�ci� erre val�.
double expr(bool);
A term() f�ggv�ny ugyanolyan m�don kezeli a szorz�st �s oszt�st, mint ahogy az
expr() kezeli
az �sszead�st �s kivon�st:
6. Kifejez�sek �s utas�t�sok 145
double term(bool get) // szorz�s �s oszt�s
{
double left = prim(get);
for (;;)
switch (curr_tok) {
case MUL:
left *= prim(true);
break;
case DIV:
if (double d = prim(true)) {
left /= d;
break;
}
return error("Null�val nem lehet osztani");
default:
return left;
}
}
A null�val val� oszt�s nem meghat�rozott �s rendszerint v�gzetes hib�t okoz. Ez�rt
oszt�s
elott megn�zz�k, hogy a nevezo 0 -e, �s ha igen, megh�vjuk az error()-t. Az
error() f�ggv
�nyt a �6.1.4-ben ismertetj�k. A d v�ltoz�t pontosan azon a ponton vezetj�k be a
programba,
ahol az sz�ks�ges, �s r�gt�n kezdeti �rt�ket is adunk neki. Egy felt�telben
bevezetett
n�v hat�k�re a felt�tel �ltal vez�relt utas�t�s, az eredm�nyezett �rt�k pedig a
felt�tel �rt�ke
(�6.3.2.1). K�vetkez�sk�ppen a left/=d oszt�s �s �rt�kad�s csak akkor megy v�gbe,
ha d
nem nulla.
A prim() f�ggv�ny, amely az elemi szimb�lumokat kezeli, nagyban hasonl�t az
expr()-re �s
a term()-re, kiv�ve azt, hogy mivel m�r lejjebb �rt�nk a h�v�si hierarchi�ban,
n�mi val�di
munk�t kell v�gezni �s nincs sz�ks�g ciklusra:
double number_value;
string string_value;
double prim(bool get) // elemi szimb�lumok kezel�se
{
if (get) get_token();
switch (curr_tok) {
case NUMBER: // lebegopontos konstans
{ double v = number_value;
get_token();
return v;
}
146 Alapok
case NAME:
{ double& v = table[string_value];
if (get_token() == ASSIGN) v = expr(true);
return v;
}
case MINUS: // egyoperandus� m�nusz
return -prim(true);
case LP:
{ double e = expr(true);
if (curr_tok != RP) return error(") sz�ks�ges");
get_token(); // ')' lenyel�se
return e;
}
default:
return error("elemi szimb�lum sz�ks�ges");
}
}
Amikor egy NUMBER-t (azaz egy eg�sz vagy lebegopontos liter�lt) tal�lunk,
visszaadjuk az
�rt�k�t. A get_token() bemeneti elj�r�s elhelyezi az �rt�ket a number_value
glob�lis v�ltoz
�ban. Glob�lis v�ltoz� haszn�lata a k�dban gyakran jelenti, hogy a program
szerkezete
nem krist�lytiszta . valamif�le optimaliz�ci�t alkalmaztak r�. Itt is ez t�rt�nt.
Ide�lis esetben
egy nyelvi egys�g (lexikai szimb�lum) k�t r�szbol �ll: egy �rt�kbol, amely
meghat�rozza
a szimb�lum fajt�j�t (ebben a programban ez a Token_value) �s (ha sz�ks�ges) a
token �rt
�k�bol. Itt csak egy egyszeru curr_tok v�ltoz� szerepel, �gy a number_value
glob�lis v�ltoz
� sz�ks�ges ahhoz, hogy az utols� beolvasott NUMBER �rt�k�t t�rolja. E k�tes
szerepu
glob�lis v�ltoz� kik�sz�b�l�s�t is a feladatok k�z� tuzz�k ki (�6.6[21]). A
number_value �rt
�k�t nem felt�tlen�l sz�ks�ges a v lok�lis v�ltoz�ba menteni a get_token()
megh�v�sa elott.
A sz�mol�g�p a sz�m�t�shoz minden helyes bemenetn�l haszn�latba veszi az elso
sz�mot,
mielott egy m�sikat olvasna be, hiba eset�n viszont seg�theti a felhaszn�l�t, ha
mentj�k az
�rt�ket �s helyesen ki�rjuk. Hasonl�an ahhoz, ahogy az utols� beolvasott NUMBER-t
a number_value t�rolja, az utols� beolvasott NAME karakterl�ncot a string_value
tartalmazza.
Mielott a sz�mol�g�p b�rmit kezdene egy n�vvel, meg kell n�znie, hogy a nevet
�rt�-
k�l kell-e adnia vagy csak egyszeruen be kell olvasnia. Mindk�t esetben a
szimb�lumt�bl�-
hoz fordul. A szimb�lumt�bla egy map (�3.7.4, �17.4.1):
map<string,double> table;
Azaz, amikor a table-t egy karakterl�nccal indexelj�k, az eredm�ny�l kapott �rt�k
az
a double lesz, ami a karakterl�nchoz tartozik. Tegy�k fel, hogy a felhaszn�l� a
k�vetkezo-
ket �rja be:
radius = 6378.388;
6. Kifejez�sek �s utas�t�sok 147
Ekkor a sz�mol�g�p az al�bbiakat hajtja v�gre:
double& v = table["radius"];
// ... expr() kisz�molja az �tadand� �rt�ket
v = 6378.388;
A v referenci�t haszn�ljuk arra, hogy a radius-hoz tartoz� double �rt�kre
hivatkozzunk,
am�g az expr() a bemeneti karakterekbol kisz�m�tja a 6378.388 �rt�ket.
6.1.2. A bemeneti f�ggv�ny
A bemenet beolvas�sa gyakran a program legrendezetlenebb r�sze. Ez az�rt van �gy,
mert
a programnak egy emberrel kell t�rsalognia �s meg kell birk�znia annak
szesz�lyeivel, szok
�saival �s viszonylag v�letlenszeru hib�ival. Kellemetlen dolog (jogosan), ha
megpr�b�ljuk
a felhaszn�l�t r�k�nyszer�teni, hogy �gy viselkedjen, hogy az a g�p sz�m�ra
megfelel
obb legyen. Egy alacsonyszintu beolvas� elj�r�s feladata az, hogy karaktereket
olvasson be
�s magasabb szintu szimb�lumokat hozzon l�tre belol�k. Ezek a szimb�lumok k�sobb
a magasabb szintu elj�r�sok bemeneti egys�gei lesznek. Itt az alacsonyszintu
beolvas�st
a get_token() v�gzi. Nem felt�tlen�l mindennapi feladat alacsonyszintu bemeneti
elj�r�sokat
�rni. Sok rendszer erre a c�lra szabv�nyos f�ggv�nyeket ny�jt.
K�t l�p�sben �p�tem fel a get_token()-t. Elosz�r egy megt�vesztoen egyszeru
v�ltozatot k�-
sz�tek, amely komoly terhet r� a felhaszn�l�ra. Ezut�n ezt m�dos�tom egy kev�sb�
eleg�ns,
de j�val haszn�lhat�bb v�ltozatra.
Az �tlet az, hogy beolvasunk egy karaktert, felhaszn�ljuk arra, hogy eld�nts�k,
milyen
szimb�lumot kell l�trehozni, majd visszaadjuk a beolvasott token-t �br�zol�
Token_value
�rt�ket. A kezdeti utas�t�sok beolvass�k az elso nem .�reshely. (whitespace, azaz
sz�k�z,
tabul�tor, �j sor stb.) karaktert ch-ba, �s ellenorzik, hogy az olvas�si muvelet
siker�lt-e:
Token_value get_token()
{
char ch = 0;
cin>>ch;
switch (ch) {
case 0:
return curr_tok=END; // �rt�kad�s �s visszat�r�s
148 Alapok
Alap�rtelmez�s szerint a >> oper�tor �tugorja az �reshely karaktereket �s ch
�rt�k�t v�ltozatlanul
hagyja, ha a bemeneti muvelet nem siker�l. K�vetkez�sk�ppen ch==0 a bemenet
v�g�t jelzi.
Az �rt�kad�s egy oper�tor, az �rt�kad�s eredm�nye pedig annak a v�ltoz�nak az
�rt�ke,
melynek �rt�ket adunk. Ez megengedi, hogy a curr_tok v�ltoz�nak az END-et adjam
�rt�-
k�l, majd a v�ltoz�t ugyanabban az utas�t�sban adjam vissza. Az, hogy egy
utas�t�st haszn
�lunk ketto helyett, megk�nny�ti a k�d k�sobbi m�dos�t�s�t. Ha az �rt�kad�st �s a
visszaadott
�rt�ket k�l�nv�lasztan�nk a k�dban, lehet, hogy a programoz� megv�ltoztatn� az
egyiket, de elfelejten� m�dos�tani a m�sikat.
N�zz�nk meg n�h�ny esetet k�l�n-k�l�n, mielott a teljes f�ggv�nnyel foglalkozn�nk.
A kifejez
�sek ; v�gzod�s�t, a z�r�jeleket �s az oper�torokat �gy kezelj�k, hogy egyszeruen
visszaadjuk az �rt�k�ket:
case ';':
case '*':
case '/':
case '+':
case '-':
case '(':
case ')':
case '=':
return curr_tok=Token_value(ch);
A sz�mokat �gy kezelj�k:
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
case '.':
cin.putback(ch);
cin >> number_value;
return curr_tok=NUMBER;
A case c�mk�ket f�ggoleges helyett v�zszintesen egy kupacba tenni �ltal�ban nem j�
�tlet,
mert ez az elrendez�s nehezebben olvashat�. F�raszt� lenne azonban minden
sz�mjegyet
k�l�n sorba �rni. Mivel a >> muveleti jel a lebegopontos konstansokat
szab�lyszeruen egy
double t�pus� v�ltoz�ba olvassa, a k�d mag�t�l �rtetodo. Elosz�r a kezdo karaktert
(sz�mjegyet
vagy pontot) visszatessz�k a cin-be, majd a konstanst a number_value v�ltoz�ba
helyezz�k.
6. Kifejez�sek �s utas�t�sok 149
A neveket hasonl�an kezelj�k:
default: // NAME, NAME =, vagy hiba
if (isalpha(ch)) {
cin.putback(ch);
cin>>string_value;
return curr_tok=NAME;
}
error("rossz szimb�lum");
return curr_tok=PRINT;
A standard k�nyvt�rban levo isalpha() f�ggv�nyt (�20.4.2) haszn�ljuk arra, hogy ne
kelljen
minden karaktert felsorolnunk, mint k�l�nb�zo case c�mk�ket. A karakterl�ncok
(ebben az
esetben a string_value) >> muvelete addig olvassa a l�ncot, am�g �reshelyet nem
tal�l. K�-
vetkez�sk�ppen a felhaszn�l�nak sz�k�zzel kell befejeznie az adott nevet azon
oper�torok
elott, melyek a nevet operandusk�nt haszn�lj�k. Ez nem ide�lis megold�s, ez�rt
erre
a probl�m�ra m�g visszat�r�nk �6.1.3-ban.
�me a teljes bemeneti f�ggv�ny:
Token_value get_token()
{
char ch = 0;
cin>>ch;
switch (ch) {
case 0:
return curr_tok=END;
case ';':
case '*':
case '/':
case '+':
case '-':
case '(':
case ')':
case '=':
return curr_tok=Token_value(ch);
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
case '.':
cin.putback(ch);
cin >> number_value;
return curr_tok=NUMBER;
150 Alapok
default: // NAME, NAME =, vagy hiba
if (isalpha(ch)) {
cin.putback(ch);
cin>>string_value;
return curr_tok=NAME;
}
error("rossz szimb�lum");
return curr_tok=PRINT;
}
}
Egy oper�tor �talak�t�sa az oper�tornak megfelelo szimb�lumra mag�t�l �rtetodo,
mivel az
oper�torok token_value �rt�k�t az oper�tor eg�sz �rt�kek�nt hat�roztuk meg (�4.8).

6.1.3. Alacsonyszintu bemenet


Ha a sz�mol�g�pet �gy haszn�ljuk, ahogy az eddigiekben le�rtuk, f�ny der�l n�h�ny
k�-
nyelmetlen dologra. F�raszt� eml�kezni arra, hogy pontosvesszot kell tenn�nk egy
kifejez
�s ut�n, ha ki akarjuk �ratni az �rt�k�t, �s nagyon bosszant� tud lenni, hogy csak

�reshellyel lehet egy nevet befejezni. P�ld�ul x=7 egy azonos�t�, �s nem x, amit
az = oper
�tor �s a 7-es sz�m k�vet. Mindk�t probl�m�t �gy oldjuk meg, hogy a get_token()-
ben a t�-
pussal kapcsolatos alap�rtelmezett bemeneti muveleteket olyan k�dra cser�lj�k,
amely
egyenk�nt olvassa be a karaktereket. Elosz�r is, az .�j sor. karaktert azonosk�nt
kezelj�k
a kifejez�s v�g�t jelzo pontosvesszovel:
Token_value get_token()
{
char ch;
do { // �reshelyek �tugr�sa az '\n' kiv�tel�vel
if(!cin.get(ch)) return curr_tok = END;
} while (ch!='\n' && isspace(ch));
switch (ch) {
case ';':
case '\n':
return curr_tok=PRINT;
A do utas�t�st haszn�ljuk, amely egyen�rt�ku a while utas�t�ssal, kiv�ve, hogy a
ciklusmag
mindig legal�bb egyszer v�grehajt�dik. A cin.get(ch) beolvas egy karaktert a
szabv�nyos bemeneti
adatfolyamb�l ch-ba. Alap�rtelmez�s szerint a get() nem ugorja �t az �reshelyeket
6. Kifejez�sek �s utas�t�sok 151
�gy, ahogy a >> muvelet teszi. Az if(!cin.get(ch)) ellenorz�s sikertelen, ha nem
olvashat� be
karakter a cin-bol; ebben az esetben END-et adunk vissza, hogy befejezz�k a
sz�mol�g�p
muk�d�s�t. A ! (NEM) oper�tort az�rt haszn�ljuk, mert a get() igazat ad vissza, ha
sikeres.
A standard k�nyvt�r isspace() f�ggv�nye v�gzi az �reshelyek (�20.4.2) szabv�nyos
vizsg�-
lat�t. Ha c �reshely, az isspace(c) nem nulla �rt�ket ad vissza, m�s esetben
null�t. A vizsg�-
latot t�bl�zatban val� keres�sk�nt val�s�tjuk meg, �gy az isspace() haszn�lata
sokkal gyorsabb,
mint az egyes �reshely karakterek vizsg�lata. Hasonl� f�ggv�nyekkel n�zhetj�k meg,

hogy egy karakter sz�mjegy (isdigit()), betu (isalpha()), esetleg betu vagy sz�m-e

(isalnum()).
Miut�n �tugrottuk az �reshelyeket, a k�vetkezo karaktert arra haszn�ljuk, hogy
eld�nts�k,
mif�le nyelvi egys�g j�n. A probl�m�t, amit az okoz, hogy a >> addig olvassa a
karakterl
�ncot, am�g �reshelyeket nem tal�l, �gy oldjuk meg, hogy egyszerre egy karaktert
olvasunk
be, am�g olyan karaktert nem tal�lunk, ami nem sz�m �s nem betu:
default: // NAME, NAME=, vagy hiba
if (isalpha(ch)) {
string_value = ch;
while (cin.get(ch) && isalnum(ch)) string_value.push_back(ch);
cin.putback(ch);
return curr_tok=NAME;
}
error("rossz szimb�lum");
return curr_tok=PRINT;
Szerencs�re mindk�t jav�t�s elv�gezheto �gy, hogy a k�dnak csak egyes helyi
�rv�nyess�-
gu r�szeit m�dos�tjuk. Fontos tervez�si c�l, hogy olyan programokat hozzunk l�tre,
melyek
jav�t�s�t, fejleszt�s�t helyi m�dos�t�sokkal int�zhetj�k.
6.1.4. Hibakezel�s
Mivel a program ennyire egyszeru, a hibakezel�ssel nem kell komolyabban t�rodn�nk.

Az error f�ggv�ny egyszeruen megsz�molja a hib�kat, ki�r egy hiba�zenetet, �s


visszat�r:
int no_of_errors;
double error(const string& s)
{
no_of_errors++;
cerr << "hiba: " << s << '\n';
return 1;
}
152 Alapok
A cerr egy �tmeneti t�rba nem helyezett (.nem pufferelt.) kimeneti adatfolyam,
amely rendszerint
hibajelz�sre haszn�latos (�21.2.1).
Az�rt adunk vissza �rt�ket, mert a hib�k jellemzoen valamilyen kifejez�s
ki�rt�kel�se k�zben
t�rt�nnek, �gy vagy teljesen abba kellene hagynunk a ki�rt�kel�st, vagy olyan
�rt�ket
kellene visszaadnunk, amely nem val�sz�nu, hogy tov�bbi hib�kat okozna. Ezen
egyszeru
sz�mol�g�p eset�ben az ut�bbi megold�s megfelelo. Ha a get_token() nyomon k�vette
volna
a sorok sz�m�t, az error() t�j�koztathatta volna a felhaszn�l�t a hiba pontos
hely�rol,
ami akkor lenne hasznos, ha a sz�mol�g�pet nem interakt�van haszn�ln�nk (�6.6.
[19]).
A program fut�s�nak gyakran be kell fejezodne, miut�n hiba t�rt�nt, mert nincs
megadva,
milyen �sszeru m�don folytathatn� muk�d�s�t. Ezt tehetj�k meg az exit()
megh�v�s�val,
amely elosz�r rendbe rakja az adatfolyamokat �s hasonl� dolgokat, majd befejezi a
programot,
melynek visszat�r�si �rt�ke az exit() param�tere lesz (�9.4.1.1).
Kiv�telek haszn�lat�val eleg�nsabb hibakezelo elj�r�sok k�sz�thetok (l�sd �8.3 �s
14. fejezet),
de amit most csin�ltunk, egy 150 soros sz�mol�g�pnek �ppen megfelel.
6.1.5. A vez�rlo
Miut�n a program minden r�szlete a hely�re ker�lt, m�r csak a vez�rlo k�dra van
sz�ks�g�nk
ahhoz, hogy elind�tsuk a muk�d�st. Ebben az egyszeru p�ld�ban ezt a main() v�gzi
el:
int main()
{
table["pi"] = 3.1415926535897932385; // elore megadott nevek beilleszt�se
table["e"] = 2.7182818284590452354;
while (cin) {
get_token();
if (curr_tok == END) break;
if (curr_tok == PRINT) continue;
cout << expr(false) << '\n';
}
return no_of_errors;
}
Hagyom�ny szerint a main() 0-�t kell, hogy visszaadjon, ha a program hiba n�lk�l
�r v�-
get, m�s esetben nem null�t (�3.2). A hib�k sz�m�nak visszaad�s�val ezt sz�pen
megold-
6. Kifejez�sek �s utas�t�sok 153
juk. Ebben az esetben az egyetlen sz�ks�ges elok�sz�t�s az, hogy a
szimb�lumt�bl�ba bele
kell tenn�nk az elore megadott neveket. A fo ciklus feladata, hogy beolvassa a
kifejez�-
seket �s ki�rja a v�laszt. Ezt a k�vetkezo sor oldja meg:
cout << expr(false) << '\n';
A false param�ter mondja meg az expr()-nek, hogy nem kell megh�vnia a get_token()-
t ahhoz,
hogy egy �jabb szimb�lumot kapjon, amellyel dolgozhat.
A cin ciklusonk�nt egyszeri ellenorz�se biztos�tja, hogy a program befejezodik, ha
hiba t�rt
�nik a bemeneti adatfolyammal, az END vizsg�lata pedig arr�l gondoskodik, hogy a
ciklusb
�l megfeleloen l�pj�nk ki, ha a get_token() a f�jl v�g�hez �r. A break utas�t�s a
legk�zelebbi
k�r�lvevo switch utas�t�sb�l vagy ciklusb�l (azaz for, while vagy do utas�t�sb�l)
l�p
ki. A PRINT (azaz '\n' �s ';') vizsg�lata megk�nny�ti az expr() dolg�t az �res
kifejez�sek kezel
�s�ben. A continue utas�t�s egyen�rt�ku azzal, hogy a ciklus legv�g�re ugrunk, �gy
ebben
az esetben
while (cin) {
// ...
if (curr_tok == PRINT) continue;
cout << expr(false) << '\n';
}
megegyezik a k�vetkezovel:
while (cin) {
// ...
if (curr_tok != PRINT)
cout << expr(false) << '\n';
}
6.1.6. Fej�llom�nyok
A sz�mol�g�p a standard k�nyvt�r eszk�zeit haszn�lja. Ez�rt a megfelelo
fej�llom�nyokat
(header) be kell �p�ten�nk (#include), hogy befejezz�k a programot:
#include<iostream> // bemenet/kimenet
#include<string> // karakterl�ncok
#include<map> // asszociat�v t�mb
#include<cctype> // isalpha(), stb.
154 Alapok
Ezen fej�llom�nyok mindegyike az std n�vt�rben ny�jt szolg�ltat�sokat, �gy ahhoz,
hogy az
�ltaluk ny�jtott neveket felhaszn�lhassuk, vagy az std:: minos�tot kell
haszn�lnunk, vagy
a glob�lis n�vt�rbe kell helyezn�nk a neveket a k�vetkezok�ppen:
using namespace std;
�n az ut�bbit v�lasztottam, hogy ne keverjem �ssze a kifejez�sek t�rgyal�s�t a
modularit�s
k�rd�sk�r�vel. A 8. �s a 9. fejezet t�rgyalja, milyen m�don lehet ezt a
sz�mol�g�pet a n�vterek
haszn�lat�val modulokba szervezni �s hogyan lehet forr�sf�jlokra bontani. A
szabv�-
nyos fej�llom�nyoknak sz�mos rendszeren .h kiterjeszt�su f�jl megfeleloj�k van,
melyek le-
�rj�k az oszt�lyokat, f�ggv�nyeket stb. �s a glob�lis n�vt�rbe is behelyezik
azokat (�9.2.1,
�9.2.4, �B.3.1).
6.1.7. Parancssori param�terek
Miut�n a programot meg�rtam �s kipr�b�ltam, k�nyelmetlennek tal�ltam, hogy elosz�r
el
kell ind�tani a programot, azt�n be kell g�pelni a kifejez�seket, v�g�l ki kell
l�pni. A leggyakrabban
egyetlen kifejez�s ki�rt�kel�s�re haszn�ltam a programot. Ha egy kifejez�st
meg lehetne adni parancssori param�terk�nt, j�n�h�ny billentyule�t�st
megtakar�thatn�nk.
A program a main() (�3.2., �9.4.) megh�v�s�val kezdodik, amely k�t param�tert kap:
az
egyik, melyet �ltal�ban argc-nek neveznek, a param�terek (argumentumok) sz�m�t
adja
meg, a m�sik a param�terekbol �ll� t�mb, ezt rendszerint argv-nek h�vj�k. A
param�terek
karakterl�ncok, ez�rt argv t�pusa char*[argc+1] lesz. A program neve (ahogy az a
parancssorban
elofordul) argc[0]-k�nt ad�dik �t, �gy argc �rt�ke mindig legal�bb 1. A
param�terek
list�j�t a null karakter z�rja le, �gy argv[argc]==0. Vegy�k az al�bbi parancsot:
dc 150/1.1934
Ekkor a param�terek �rt�ke a k�vetkezo:
6. Kifejez�sek �s utas�t�sok 155
argc:
argv:
2
"dc" "150/1.1934"
0
Mivel a main() megh�v�s�ra vonatkoz� szab�lyok a C nyelv k�vetelm�nyeivel
azonosak,
a h�v�skor C t�pus� t�mb�k �s karakterl�ncok haszn�latosak.
A parancssori param�terek beolvas�sa egyszeru, a probl�ma csak az, hogyan
haszn�ljuk
azokat �gy, hogy min�l kevesebbet kelljen programoznunk. Az �tlet a k�vetkezo:
olvassunk
ugyan�gy a parancssori karakterl�ncb�l, mint a bemeneti adatfolyamokb�l. A
karakterl
�ncb�l olvas� adatfolyam neve . micsoda meglepet�s . istringstream. Sajnos nincs
eleg�ns m�dja annak, hogy cin-k�nt az istringstream-re hivatkozhassunk, ez�rt ki
kell tal
�lnunk, hogy a sz�mol�g�p bemeneti f�ggv�nyei hogyan hivatkozzanak vagy az
istringstream-re vagy a cin-re, att�l f�ggoen, milyen parancssori param�tereket
adunk meg.
Egyszeru megold�s, ha bevezet�nk egy input nevu glob�lis mutat�t, amely a
haszn�land�
bemeneti adatfolyamra mutat; minden bemeneti elj�r�sban ezt fogjuk felhaszn�lni:
istream* input; // mutat� bemeneti adatfolyamra
int main(int argc, char* argv[ ])
{
switch (argc) {
case 1: // olvas�s a szabv�nyos bemenetrol
input = &cin;
break;
case 2: // a karakterl�nc param�ter beolvas�sa
input = new istringstream(argv[1]);
break;
default:
error("t�l sok param�ter");
return 1;
}
table["pi"] = 3.1415926535897932385; // elore megadott nevek beilleszt�se
table["e"] = 2.7182818284590452354;
while (*input) {
get_token();
if (curr_tok == END) break;
if (curr_tok == PRINT) continue;
cout << expr(false) << '\n';
}
if (input != &cin) delete input;
return no_of_errors;
}
156 Alapok
Az istringstream olyan istream, amely karakterl�nc param�ter�bol olvas (�21.5.3).
Amikor
el�ri a l�nc v�g�t, pontosan ugyan�gy jelzi azt, mint a t�bbi adatfolyam a bemenet
v�g�t
(�3.6, �21.3.3). Az istringstream haszn�lat�hoz be kell �p�teni az <sstream>
fej�llom�nyt.
K�nnyu lenne �gy m�dos�tani a main()-t, hogy t�bb parancssori param�tert is
elfogadjon,
de erre nincs sz�ks�g, mert egyetlen param�terk�nt t�bb kifejez�st is �tadhatunk:
dc "rate=1.1934;150/rate;19.75/rate;217/rate"
Az�rt haszn�lok id�zojeleket, mert a ; a UNIX rendszerekben parancs-elv�laszt�k�nt
haszn
�latos. M�s rendszerek szab�lyai a program ind�t�sakor param�terek megad�s�ra
vonatkoz
�an elt�roek.
Nem volt eleg�ns dolog �gy m�dos�tani a bemeneti elj�r�sokat, hogy cin helyett
*input-ot
haszn�ljanak, hogy ezzel rugalmasabbak legyenek �s k�l�nb�zo bemeneti forr�sokkal
mu-
k�dhessenek. A v�ltoztat�s elker�lheto lett volna, ha kello elorel�t�ssal m�r a
kezdetektol
bevezet�nk valamilyen, az input-hoz hasonl� dolgot. �ltal�nosabb �s hasznosabb
megold
�st k�sz�thet�nk, ha �szrevessz�k, hogy a bemenet forr�sa val�j�ban a sz�mol�g�p
modul
param�tere kell, hogy legyen. Az alapveto probl�ma, amit ezzel a sz�mol�g�ppel
�rz�keltetni
akartam, az, hogy a .sz�mol�g�p. csak f�ggv�nyek �s adatok gyujtem�nye. Nincs
olyan modul (�2.4) vagy objektum (�2.5.2), amely kifejezett �s egy�rtelmu m�don
�br�zolja
a sz�mol�g�pet. Ha egy sz�mol�g�p modul vagy sz�mol�g�p t�pus tervez�se lett volna

a c�lom, akkor term�szetesen meggondoltam volna, milyen param�terei lehetnek a


modulnak/
t�pusnak (�8.5[3], �10.6[16]).
6.1.8. Megjegyz�s a st�lussal kapcsolatban
A standard k�nyvt�rbeli map szimb�lumt�blak�nt val� haszn�lata majdnem .csal�snak.

tunhet azoknak a programoz�knak a szem�ben, akik nem ismerik az asszociat�v


t�mb�ket.
De nem az. A standard k�nyvt�r �s m�s k�nyvt�rak arra val�k, hogy haszn�lj�k
azokat.
A k�nyvt�rak tervez�skor �s megval�s�t�skor �ltal�ban nagyobb figyelmet kapnak,
mint
amennyit egy programoz� megengedhet mag�nak, amikor saj�t kezuleg olyan k�dot �r,
amit csak egyetlen program haszn�l fel.
Ha megn�zz�k a sz�mol�g�p k�dj�t (k�l�n�sen az elso v�ltozatot), l�thatjuk, hogy
nem
sok hagyom�nyos C st�lus�, alacsonyszintu k�d tal�lhat� benne. Sz�mos hagyom�nyos
tr�kk�t helyettes�tett�nk azzal, hogy olyan standard k�nyvt�rbeli oszt�lyokat
haszn�ltunk,
mint az ostream, string, �s map (�3.4, �3.5, �3.7.4, 17.fejezet).
6. Kifejez�sek �s utas�t�sok 157
Vegy�k �szre, hogy az aritmetika, a ciklusok, sot az �rt�kad�sok is viszonylag
ritk�n fordulnak
elo. �ltal�ban ilyennek kellene lennie egy olyan k�dnak, amely nem kezeli a
hardvert
k�zvetlen�l �s nem �l alacsonyszintu elvont adat�br�zol�sokkal.
6.2. Oper�torok . �ttekint�s
Ez a r�sz �sszefoglalja a kifejez�seket �s bemutat n�h�ny p�ld�t. Minden oper�tort
egy vagy
t�bb n�v k�vet, amely p�ldak�nt szolg�l az �ltal�nosan haszn�lt megnevez�sekre �s
a szok
�sos haszn�latra. A t�bl�zatokban az oszt�lyn�v egy oszt�ly neve, a tag egy tag
neve, az
objektum egy olyan kifejez�s, amelynek az eredm�nye oszt�lyobjektum, a mutat� egy
mutat
� eredm�nyu kifejez�s, a kif egy kifejez�s, �s a bal�rt�k egy olyan kifejez�s,
amely nem
konstans objektumot jel�l.
A t�pus csak akkor lehet egy teljesen �ltal�nos t�pusn�v (*-gal, ()-lel stb.), ha
z�r�jelek k�-
z� van z�rva; m�shol megszor�t�sok vonatkoznak r� (�A.5).
A kifejez�sek form�ja f�ggetlen az operandusok t�pus�t�l. Az itt bemutatott
jelent�sek arra
az esetre vonatkoznak, amikor az operandusok be�p�tett t�pus�ak (�4.1.1). A
felhaszn�l�i
t�pus� operandusokra alkalmazott oper�torok jelent�s�t magunk hat�rozhatjuk meg
(�2.5.2,
11. fejezet).
A t�bl�zat minden cell�j�ban azonos eross�gu (precedenci�j�) oper�torok
tal�lhat�k. A fels
obb cell�kban levo oper�torok az als� cell�kban levokkel szemben elonyt �lveznek.
P�ld
�ul a+b*c jelent�se a+(b*c), nem pedig (a+b)*c, mert a * magasabb precedenci�j�,
mint
a +.
Az egyoperandus� (un�ris) �s az �rt�kad� oper�torok jobbr�l balra, az �sszes t�bbi
balr�l
jobbra �rtelmezendo. P�ld�ul a=b=c jelent�se a=(b=c), a+b+c jelent�se (a+b)+c, *p+
+ jelent
�se pedig *(p++), nem (*p)++.
N�h�ny nyelvtani szab�lyt nem lehet kifejezni a precedenci�val �s az
asszociativit�ssal
(k�t�ssel). P�ld�ul a=b<c?d=e:f=g jelent�se a=((b<c)?(d=e):(f=g)), de ahhoz, hogy
ezt eld
�nthess�k, meg kell n�zn�nk a nyelvtant (�A.5).
158 Alapok
6. Kifejez�sek �s utas�t�sok 159
Oper�tor . �ttekint�s
hat�k�r-felold�s oszt�lyn�v :: tag
hat�k�r-felold�s n�vt�r_n�v :: tag
glob�lis hat�k�r :: n�v
glob�lis hat�k�r :: minos�tett_n�v
tagkiv�laszt�s objektum . tag
tagkiv�laszt�s mutat� -> tag
indexel�s mutat� [kif]
f�ggv�nyh�v�s kif (kif_lista)
�rt�k l�trehoz�sa t�pus (kif_lista)
n�vel�s ut�taggal bal�rt�k ++
cs�kkent�s ut�taggal bal�rt�k --
t�pusazonos�t�s typeid (t�pus)
fut�si ideju t�pusazonos�t�s typeid (kif)
fut�si idoben ellenorz�tt
t�pusk�nyszer�t�s dynamic_cast <t�pus> (kif)
ford�t�si idoben ellenorz�tt
t�pusk�nyszer�t�s static_cast <t�pus> (kif)
nem ellenorz�tt t�pusk�nyszer�t�s reinterpret_cast <t�pus> (kif)
konstans t�pusk�nyszer�t�s const_cast <t�pus> (kif)
objektum m�rete sizeof kif
t�pus m�rete sizeof (t�pus)
n�vel�s elotaggal ++ bal�rt�k
cs�kkent�s elotaggal -- bal�rt�k
komplemensk�pz�s ~ kif
(logikai) nem ! kif
m�nusz elojel - kif
plusz elojel + kif
c�m oper�tor & bal�rt�k
indirekci� * kif
l�trehoz�s (mem�riafoglal�s) new t�pus
l�trehoz�s (mem�riafoglal�s
�s kezdeti �rt�kad�s) new (kif_lista)
l�trehoz�s (elhelyez�s) new (kif_lista) t�pus
l�trehoz�s (elhelyez�s
�s kezdeti �rt�kad�s) new (kif_lista) t�pus (kif_lista)
felsz�mol�s (felszabad�t�s) delete mutat�
t�mb felsz�mol�sa delete [ ] mutat�
t�puskonverzi� (t�pus) kif
160 Alapok
Oper�tor . �ttekint�s (folytat�s)
tagkiv�laszt�s objektum .*tagra_hivatkoz�_mutat�
tagkiv�laszt�s mutat� -> *tagra_hivatkoz�_mutat�
szorz�s kif * kif
oszt�s kif / kif
modul� (marad�kk�pz�s) kif % kif
�sszead�s (plusz) kif + kif
kivon�s (m�nusz) kif - kif
balra l�ptet�s kif << kif
jobbra l�ptet�s kif >> kif
kisebb kif < kif
kisebb vagy egyenlo kif <= kif
nagyobb kif > kif
nagyobb vagy egyenlo kif >= kif
egyenlo kif == kif
nem egyenlo kif != kif
bitenk�nti �S kif & kif
bitenk�nti kiz�r� VAGY kif ^ kif
bitenk�nti megengedo VAGY kif | kif
logikai �S kif && kif
logikai megengedo VAGY kif || kif
felt�teles kifejez�s kif ? kif : kif
6.2.1. Eredm�nyek
Az aritmetikai muveletek eredm�ny�nek t�pus�t az a szab�lyhalmaz d�nti el, amelyet
.�ltal
�nos aritmetikai �talak�t�sok.-nak nevez�nk (�C.6.3). A fo c�l az, hogy a
.legt�gabb.
operandust�pussal megegyezo eredm�ny j�jj�n l�tre. Ha egy bin�ris oper�tor
operandusa
p�ld�ul lebegopontos, a sz�m�t�st lebegopontos aritmetik�val v�gezz�k �s az
eredm�ny egy
lebegopontos �rt�k lesz. Ha long t�pus� operandusa van, a sz�m�t�s hossz� eg�sz
(long) aritmetik
�val t�rt�nik, az eredm�ny pedig long �rt�k lesz. Az int-n�l kisebb operandusok
(mint
a bool �s a char) int-t� alakulnak, mielott az oper�tort alkalmazzuk r�juk.
Az ==, <= stb. rel�ci�s (�sszehasonl�t�) oper�torok logikai �rt�keket adnak
vissza. A felhaszn
�l� �ltal megadott oper�torok jelent�s�t �s eredm�ny�t deklar�ci�juk hat�rozza meg

(�11.2).
Ha egy oper�tornak bal�rt�k operandusa van, akkor . ha ez logikailag lehets�ges .
az oper
�tor eredm�nye egy olyan bal�rt�k lesz, amely a bal�rt�k operandust jel�li:
6. Kifejez�sek �s utas�t�sok 161
Oper�tor . �ttekint�s (folytat�s)
egyszeru �rt�kad�s bal�rt�k = kif
szorz�s �s �rt�kad�s bal�rt�k *= kif
oszt�s �s �rt�kad�s bal�rt�k /= kif
marad�kk�pz�s �s �rt�kad�s bal�rt�k %= kif
�sszead�s �s �rt�kad�s bal�rt�k += kif
kivon�s �s �rt�kad�s bal�rt�k -= kif
balra l�ptet�s �s �rt�kad�s bal�rt�k <<= kif
jobbra l�ptet�s �s �rt�kad�s bal�rt�k >>= kif
�S �s �rt�kad�s bal�rt�k &= kif
megengedo VAGY �s �rt�kad�s bal�rt�k |= kif
kiz�r� VAGY �s �rt�kad�s bal�rt�k ^= kif
kiv�tel kiv�lt�sa throw kif
vesszo (muveletsor) kif , kif
void f(int x, int y)
{
int j = x = y; // x=y �rt�ke az x �rt�kad�s ut�ni �rt�ke
int* p = &++x; // p x-re mutat
int* q = &(x++); // hiba: x++ nem bal�rt�k
int* pp = &(x>y?x:y); // a nagyobb �rt�ku int c�me
}
Ha a ? : m�sodik �s harmadik operandusa is bal�rt�k �s ugyanolyan t�pus�ak, az
eredm�ny
a megfelelo t�pus� bal�rt�k lesz. Az, hogy ilyen m�don megorizz�k a bal�rt�keket,
nagy rugalmass
�got ad az oper�torok haszn�lat�ban. Ez k�l�n�sen akkor fontos, ha olyan k�dot
�runk, amelynek egyform�n �s hat�konyan kell muk�dnie be�p�tett �s felhaszn�l�i
t�pusok
eset�ben is (p�ld�ul ha olyan sablonokat vagy programokat �runk, amelyek C++ k�dot
hoznak
l�tre).
A sizeof eredm�nye a size_t nevu elojel n�lk�li integr�lis t�pus, melynek
meghat�roz�sa
a <cstddef> fej�llom�nyban szerepel, a mutat�-kivon�s� pedig egy elojeles
integr�lis t�pus,
amit ptrdiff_t-nek h�vnak �s szint�n a <cstddef> fej�llom�ny �rja le.
A ford�t�nak nem kell ellenoriznie az aritmetikai t�lcsordul�st �s �ltal�ban nem
is teszi meg.
P�ld�ul:
void f()
{
int i = 1;
while (0 < i) i++;
cout << "Az i negat�v lett!" << i << '\n';
}
A ciklus elobb-ut�bb az i �rt�k�t a legnagyobb eg�sz �rt�ken t�l n�veli. Ami ekkor
t�rt�-
nik, nem meghat�rozott; az �rt�k jellemzoen egy negat�v sz�mig .�r k�rbe. (az �n
g�pemen
ez -2147483648). Hasonl�an, a null�val oszt�s eredm�nye sem meghat�rozott, ez
viszont
rendszerint a program hirtelen befejezod�s�t eredm�nyezi. Az alulcsordul�s, a
t�lcsordul�s
�s a null�val val� oszt�s nem v�lt ki szabv�nyos kiv�teleket (�14.10).
162 Alapok
6.2.2. Ki�rt�kel�si sorrend
A kifejez�seken bel�li r�szkifejez�sek ki�rt�kel�si sorrendje nem meghat�rozott,
�gy nem
t�telezhetj�k fel p�ld�ul azt sem, hogy a kifejez�s ki�rt�kel�se balr�l jobbra
t�rt�nik:
int x = f(2)+g(3); // nem meghat�rozott, hogy f() vagy g() h�v�dik meg elosz�r
Jobb k�dot k�sz�thet�nk, ha a kifejez�sek ki�rt�kel�si sorrendje nem k�t�tt, de a
ki�rt�kel
�si sorrendre vonatkoz� megszor�t�sok hi�nya elore nem meghat�rozott eredm�nyekhez

vezethet:
int i = 1;
v[i] = i++; // nem meghat�rozott eredm�ny
A fenti kifejez�s vagy v[1]=1-k�nt, vagy v[2]=1-k�nt �rt�kelodik ki, esetleg m�g
furcs�bban
viselkedik. A ford�t�programok figyelmeztethetnek az ilyen k�t�rtelmus�gekre,
sajnos,
a legt�bb ezt nem teszi meg.
A , (vesszo), a && (logikai �S), �s a || (logikai VAGY) oper�torok eset�ben
biztos�tott,
hogy a bal oldali operandus a jobb oldali elott �rt�kelodik ki. A b=(a=2,a+1)
p�ld�ul a bnek
3-at ad �rt�k�l. A || �s a && haszn�lat�ra vonatkoz� p�ld�k a �6.2.3-ban
tal�lhat�k.
Be�p�tett t�pusokn�l a && m�sodik operandusa csak akkor �rt�kelodik ki, ha az elso

operandus true, a || m�sodik operandusa pedig csak akkor, ha az elso operandus


�rt�ke
false; ezt n�ha r�vid vagy .r�vidz�ras. ki�rt�kel�snek (short-circuit evaluation)
nevezik. Jegyezz
�k meg, hogy a , (vesszo) muveletsor-jelzo logikailag k�l�nb�zik att�l a
vesszotol,
amit arra haszn�lunk, hogy a f�ggv�nyh�v�sokn�l elv�lasszuk a param�tereket.
N�zz�k az
al�bbi p�ld�t:
f1(v[i],i++); // k�t param�ter
f2( (v[i],i++) ); // egy param�ter
Az f1 megh�v�s�nak k�t param�tere van, v[i] �s i++, a param�ter-kifejez�sek
ki�rt�kel�si
sorrendje pedig nem meghat�rozott. Az olyan megold�s, amely f�gg a param�ter-
kifejez�-
sek sorrendj�tol, nagyon rossz st�lusr�l �rulkodik �s eredm�nye nem meghat�rozott.
Az f2
megh�v�s�hoz egy param�tert adtunk meg; a (v[i], i++) .vesszos. kifejez�s, amely
i++-szal
egyen�rt�ku.
6. Kifejez�sek �s utas�t�sok 163
A csoportos�t�s kik�nyszer�t�s�re z�r�jeleket haszn�lhatunk. P�ld�ul a*b/c
jelent�se (a*b)/c,
ez�rt z�r�jeleket kell haszn�lnunk, ha a*(b/c)-t akarunk kapni. Az a*(b/c)
kifejez�s csak akkor
�rt�kelodhet ki (a*b)/c-k�nt, ha a felhaszn�l� nem tud k�l�nbs�get tenni k�zt�k.
Az
a*(b/c) �s az (a*b)/c sz�mos lebegopontos sz�m�t�sn�l jelentosen k�l�nb�zik, �gy a
ford�t�-
program pontosan �gy fogja az ilyen kifejez�seket ki�rt�kelni, ahogy azokat
le�rtuk.
6.2.3. Az oper�torok sorrendje
A precedencia �s a .k�t�si. (asszociativit�si) szab�lyok a leggyakoribb
haszn�latot t�kr�zik.
P�ld�ul
if (i<=0 || max<i) // ...
azt jelenti, hogy .ha i kisebb vagy egyenlo 0-n�l VAGY max kisebb i-n�l.. Ez
egyen�rt�ku
az al�bbival:
if ( (i<=0) || (max<i) ) // ...
Az al�bbi . �rtelmetlen, de szab�lyos . kifejez�ssel viszont nem:
if (i <= (0||max) < i) // ...
Z�r�jeleket haszn�lni azonban mindig hasznos, ha a programoz�nak k�ts�gei vannak
ezekkel
a szab�lyokkal kapcsolatban. A z�r�jelek haszn�lata m�g gyakoribb, ha a
r�szkifejez�-
sek bonyolultabbak. A bonyolult r�szkifejez�sek mindig hiba forr�sai lehetnek,
ez�rt . ha
�gy �rezz�k, hogy sz�ks�g�nk van z�r�jelekre . fontoljuk meg, hogy nem kellene-e
egy
k�l�n v�ltoz� haszn�lat�val sz�tbontanunk a kifejez�st. Vannak olyan esetek,
amikor az
oper�torok sorrendje nem a .mag�t�l �rtetodo. �rtelmez�st eredm�nyezi:
if (i&mask == 0) // hopp�! == kifejez�s & operandusak�nt
Ekkor nem az t�rt�nik, hogy alkalmazzuk a mask-ot az i-re, majd megn�zz�k, hogy az
eredm
�ny 0-e. Mivel az == elonyt �lvez az & (k�toperandus�) muvelettel szemben, a
kifejez�s
i&(mask==0)-k�nt lesz �rtelmezve. Szerencs�re a ford�t�program k�nnyen
figyelmeztethet
az ilyen hib�kra. Ebben az esetben a z�r�jelek fontosak:
if ((i&mask) == 0) // ...
164 Alapok
�rdemes megjegyezni, hogy a k�vetkezo nem �gy muk�dik, ahogy egy matematikus
elv�rn�:
if (0 <= x <= 99) // ...
Ez megengedett, de �rtelmez�se (0<=x)<=99, ahol az elso �sszehasonl�t�s eredm�nye
vagy
true vagy false. A logikai �rt�ket a ford�t�program azt�n automatikusan 1-re vagy
0-ra alak
�tja, amit azt�n �sszehasonl�tva 99-cel true-t kapunk. A k�vetkezok�ppen
vizsg�lhatjuk
meg, hogy x a 0..99 tartom�nyban van-e:
if (0<=x && x<=99) // ...
Gyakori hiba kezdokn�l, hogy a felt�telekben =-t (�rt�kad�st) haszn�lnak ==
(egyenlo) helyett:
if (a = 7) // hopp�! konstans �rt�kad�s a felt�telben
Ez term�szetes, mert az = jelent�se sok nyelvben .egyenlo.. A ford�t�programok
�ltal�ban
figyelmeztetnek is erre.
6.2.4. Bitenk�nti logikai muveletek
Az &, |, ^, -, >> �s << bitenk�nti logikai oper�torokat integr�lis (eg�sz t�pus�)
objektumokra
�s felsorol�sokra alkalmazzuk . azaz a bool, char, short, int, long t�pusokra,
ezek elojel
n�lk�li (unsigned) megfeleloire �s az enum t�pusokra. Az eredm�ny t�pus�t a
szok�sos aritmetikai
�talak�t�sok (�C.6.3.) d�ntik el.
A bitenk�nti logikai oper�torok jellemzo felhaszn�l�sa a kis halmazok
(bitvektorok) fogalm
�nak megval�s�t�sa. Ebben az esetben egy elojel n�lk�li eg�sz minden bitje a
halmaz egy
elem�t jel�li, �s a bitek sz�ma korl�tozza a halmaz elemeinek sz�m�t. Az & bin�ris
oper�-
tort metszetk�nt, a | oper�tort uni�k�nt, a ^-ot szimmetrikus differenciak�nt, a
~-t pedig
komplemensk�nt �rtelmezz�k. Felsorol� t�pust arra haszn�lhatunk, hogy megnevezz�k
egy ilyen halmaz elemeit. �me egy r�vid p�lda, melyet az ostream megval�s�t�s�b�l
vett�nk
k�lcs�n:
enum ios_base::iostate {
goodbit=0, eofbit=1, failbit=2, badbit=4
};
6. Kifejez�sek �s utas�t�sok 165
Az adatfolyam az �llapotot �gy �ll�thatja be �s ellenorizheti:
state = goodbit;
// ...
if (state&(badbit|failbit)) // nem megfelelo adatfolyam
A k�l�n z�r�jelek az�rt sz�ks�gesek, mert az & elonyt �lvez a | muveleti jellel
szemben.
Egy f�ggv�ny �gy jelezheti, hogy el�rte a bemenet v�g�t:
state |= eofbit;
A |= oper�tort arra haszn�ljuk, hogy az �llapothoz hozz�adjunk valamilyen �j
inform�ci�t.
Az egyszeru state=eofbit �rt�kad�s kit�r�lt volna minden m�s bitet.
Ezek az adatfolyam-�llapotjelzok megfigyelhetok a folyam megval�s�t�s�n k�v�l is.
P�ld�ul
�gy n�zhetj�k meg, hogyan k�l�nb�zik k�t adatfolyam �llapota:
int diff = cin.rdstate()^cout.rdstate(); // rdstate() az �llapotot adja vissza
Az adatfolyam-�llapotok k�l�nbs�geinek kisz�m�t�sa nem t�l gyakori, m�s hasonl�
t�pusokn
�l viszont alapveto muvelet. Vegy�k p�ld�ul azt az esetet, amikor �ssze kell
hasonl�tanunk
azt a bitvektort, amely a kezelt megszak�t�sok halmaz�t jel�li, egy m�sik
bitvektorral,
amely olyan megszak�t�sok halmaz�t �br�zolja, melyek arra v�rnak, hogy kezelj�k
oket.
Jegyezz�k meg, hogy ezt a .zsonglork�d�st. a bitekkel az iostream megval�s�t�s�b�l
vett
�k �s nem a felhaszn�l�i fel�letbol. A k�nyelmes bitkezel�s nagyon fontos lehet,
de a megb
�zhat�s�g, a m�dos�that�s�g, vagy a hordozhat�s�g �rdek�ben a rendszer alacsonyabb

szintjein kell tartanunk. �ltal�nosabb halmazfogalomra n�zz�k meg a standard


k�nyvt�rbeli
set-et (�17.4.3), bitset-et (�17.5.3), �s a vector<bool>-t (�16.3.11).
A mezok (�C.8.1) haszn�lata igaz�n k�nyelmes m�don r�vid�ti le azt a muveletet,
amikor
l�ptet�ssel �s maszkol�ssal vesz�nk ki bitmezoket egy sz�b�l. Ezt term�szetesen
megtehetj
�k a bitenk�nti logikai oper�torokkal is. Egy 32 bites long k�z�pso 16 bitj�t
p�ld�ul �gy vehetj
�k ki:
unsigned short middle(long a) { return (a>>8)&0xffff; }
A bitenk�nti logikai oper�torokat ne keverj�k �ssze az &&, || �s ! logikai
oper�torokkal. Az
ut�bbiak vagy true-t, vagy false-t adnak vissza, �s elsodlegesen akkor hasznosak,
amikor egy
166 Alapok
if, while, vagy for utas�t�sban (�6.3.2, �6.3.3) felt�telt �runk. P�ld�ul az !0
(nem nulla) true
�rt�k, m�g a ~0 (a nulla komplemense) egy csupa egyesbol �ll� bitminta, amely a -1
�rt�k
kettes komplemensbeli �br�zol�sa.
6.2.5. N�vel�s �s cs�kkent�s
A ++ oper�tort arra haszn�ljuk, hogy egy �rt�k n�vel�s�t k�zvetlen�l, �s nem az
�sszead�s
�s �rt�kad�s p�ros�t�s�val fejezz�k ki. Defin�ci� szerint a ++lvalue jelent�se
lvalue+=1, ez
pedig lvalue=lvalue+1-et jelent, felt�ve, hogy a bal�rt�knek nincs .mell�khat�sa".
A n�velend
o objektumot jel�lo kifejez�s (csak) egyszer �rt�kelodik ki. A cs�kkent�st
ugyan�gy
a -- oper�tor fejezi ki. A ++ �s -- oper�torokat haszn�lhatjuk elotagk�nt �s
ut�tagk�nt is.
A ++x �rt�ke az x �j (megn�velt) �rt�ke lesz, p�ld�ul az y=++x egyen�rt�ku az
y=(x+=1)-
gyel. Az x++ �rt�ke azonban az x r�gi �rt�ke: az y=x++ egyen�rt�ku az
y=(t=x,x+=1,t)-vel,
ahol t egy x-szel azonos t�pus� v�ltoz�.
A mutat�k �sszead�s�hoz �s kivon�s�hoz hasonl�an a mutat�kra alkalmazott ++ �s --
mu-
k�d�s�t azok a t�mbelemek hat�rozz�k meg, amelyekre a mutat� hivatkozik; p++ a p-t

a k�vetkezo t�mbelemre �ll�tja (�5.3.1).


A n�velo oper�torok k�l�n�sen a ciklusokban haszn�latosak, v�ltoz�k n�vel�s�re
vagy cs�kkent
�s�re. Egy nulla v�gzod�su karakterl�ncot p�ld�ul a k�vetkezok�ppen m�solhatunk
�t:
void cpy(char* p, const char* q)
{
while (*p++ = *q++) ;
}
A C-hez hasonl�an a C++-t is szeretik �s gyul�lik az�rt, mert megengedi az ilyen
t�m�r, kifejez
�sk�zpont� k�dol�st. Mivel a
while (*p++ = *q++) ;
kifejez�s meglehetosen zavaros a nem C programoz�k sz�m�ra, ez a k�dol�si st�lus
viszont
nem ritka a C-ben �s a C++-ban, meg�ri k�zelebbrol megvizsg�lnunk. Vegy�k elosz�r
a karaktert
�mb�k m�sol�s�nak egy hagyom�nyosabb m�dj�t:
int length = strlen(q);
for (int i = 0; i<=length; i++) p[i] = q[i];
6. Kifejez�sek �s utas�t�sok 167
Ez pazarl�s. A nulla v�gzod�su karakterl�nc hossz�t �gy hat�rozzuk meg, hogy a
nulla v�gz
od�st keresve v�gigolvassuk azt. �gy k�tszer olvassuk v�gig a teljes l�ncot:
egyszer az�rt,
hogy meghat�rozzuk a hossz�t, egyszer pedig az�rt, hogy �tm�soljuk. Ez�rt ink�bb
pr�b�ljuk
ezt:
int i;
for (i = 0; q[i]!=0 ; i++) p[i] = q[i];
p[i] = 0; // lez�r� nulla
Az i v�ltoz�t indexel�sre haszn�ljuk, de ki lehet k�sz�b�lni, mert p �s q mutat�k:

while (*q != 0) {
*p = *q;
p++; // l�ptet�s a k�vetkezo karakterre
q++; // l�ptet�s a k�vetkezo karakterre
}
*p = 0; // lez�r� nulla
Mivel az ut�tagk�nt haszn�lt n�velo oper�tor megengedi, hogy elosz�r felhaszn�ljuk
az �rt
�ket, �s csak azut�n n�velj�k meg, a k�vetkezok�ppen �rhatjuk �jra a ciklust:
while (*q != 0) {
*p++ = *q++;
}
*p = 0; // lez�r� nulla
A *p++ = *q++ �rt�ke *q, ez�rt a p�ld�t �gy m�dos�thatjuk:
while ((*p++ = *q++) != 0) { }
Ebben az esetben addig nem vessz�k �szre, hogy *q nulla, am�g be nem m�soljuk *p-
be �s
meg nem n�velj�k p-t. K�vetkez�sk�ppen elhagyhatjuk az utols� �rt�kad�st, amiben a
nulla
v�gzod�st adjuk �rt�k�l. V�g�l tov�bb r�vid�thetj�k a p�ld�t azzal, hogy
�szrevessz�k,
nincs sz�ks�g�nk az �res blokkra �s hogy felesleges a .!=0. vizsg�lat, mert egy
mutat� vagy
integr�lis felt�tel mindig �sszehasonl�t�dik 0-val. �gy megkapjuk azt a
v�ltozatot, amelyet
c�lul tuzt�nk ki.
while (*p++ = *q++) ;
Ez a v�ltozat vajon kev�sb� olvashat�, mint az elozo? Egy tapasztalt C vagy C++
programoz
� sz�m�ra nem. Hat�konyabb idoben �s t�rter�letben, mint az elozo? Az elso
v�ltozatot ki-
168 Alapok
v�ve, ami megh�vta az strlen()-t, nem igaz�n. Az, hogy melyik v�ltozat a
leghat�konyabb,
a g�p fel�p�t�s�tol �s a ford�t�programt�l f�gg, a nulla v�gzod�su karakterl�ncok
m�sol�-
s�nak leghat�konyabb m�dja viszont �ltal�ban a standard k�nyvt�rbeli m�sol�
f�ggv�ny.
char* strcpy(char*, const char*); // a <string.h> fej�llom�nyb�l
�ltal�nosabb m�sol�sra a szabv�nyos copy algoritmust (�2.7.2, �18.6.1)
haszn�lhatjuk. Ahol
lehets�ges, r�szes�ts�k elonyben a standard k�nyvt�r lehetos�geit a mutat�kkal �s
b�jtokkal
val� �gyesked�ssel szemben. A standard k�nyvt�r f�ggv�nyei lehetnek helyben
kifejtett
f�ggv�nyek (�7.1.1) vagy egyedi g�pi utas�t�sokkal megval�s�tottak. Ez�rt gondosan

fontoljuk meg, mielott elhinn�nk, hogy valamilyen k�zzel �rt k�dr�szlet fel�lm�lja
a k�nyvt
�ri f�ggv�nyek teljes�tm�ny�t.
6.2.6. Szabad t�r
A n�vvel rendelkezo objektumok �lettartam�t (lifetime) hat�k�r�k (�4.9.4) d�nti
el, gyakran
azonban hasznos, ha olyan objektumot hozunk l�tre, amely f�ggetlen�l l�tezik att�l

a hat�k�rtol, ahol l�trehoztuk. Nevezetesen gyakori, hogy olyan objektumokat


hozunk l�tre,
amelyek akkor is felhaszn�lhat�k, miut�n visszat�rt�nk abb�l a f�ggv�nybol, ahol
l�trehoztuk
azokat. Az ilyen objektumokat a new oper�tor hozza l�tre �s a delete oper�tort
haszn
�lhatjuk felsz�mol�sukra. A new �ltal l�trehozott objektumokra azt mondjuk,
hogy .a szabad
t�rban vannak. (free store), vagy azt, hogy .kupac-objektumok. (heap), vagyis .a
dinamikus
mem�ri�ban vannak..
N�zz�k meg, hogyan �rn�nk meg egy ford�t�programot olyan st�lusban, ahogy az
asztali
sz�mol�g�pn�l tett�k (�6.1). A szintaktikai elemzo f�ggv�nyek fel�p�thetnek egy
kifejez�sf
�t a k�dk�sz�to sz�m�ra:
struct Enode {
Token_value oper;
Enode* left;
Enode* right;
// ...
};
Enode* expr(bool get)
{
Enode* left = term(get);
6. Kifejez�sek �s utas�t�sok 169
for (;;)
switch(curr_tok) {
case PLUS:
case MINUS:
{ Enode* n = new Enode; // Enode l�trehoz�sa a szabad t�rban
n->oper = curr_tok;
n->left = left;
n->right = term(true);
left = n;
break;
}
default:
return left; // csom�pont visszaad�sa
}
}
A k�dk�sz�to azt�n felhaszn�ln� az eredm�ny�l kapott csom�pontokat (node) �s
t�r�ln�
azokat:
void generate(Enode* n)
{
switch (n->oper) {
case PLUS:
// ...
delete n; // Enode t�rl�se a szabad t�rb�l
}
}
A new �ltal l�trehozott objektum addig l�tezik, am�g kifejezetten meg nem
semmis�tj�k
a delete-tel. Ezut�n a new �jra felhaszn�lhatja az objektum �ltal lefoglalt
t�rhelyet. A C++-
v�ltozatok nem garant�lj�k, hogy van .szem�tgyujto. (garbage collector), amely
megkeresi
azokat az objektumokat, amelyekre nincs m�r hivatkoz�s �s �jra felhaszn�lhat�v�
teszi
azok hely�t. K�vetkez�sk�ppen felt�telezz�k, hogy a new �ltal l�trehozott
objektumokat
magunknak kell megsemmis�ten�nk, a delete-et haszn�lva. Ha van szem�tgyujto, a
deleteek
a legt�bb esetben elhagyhat�k (�C.9.1).
A delete oper�tort csak a new �ltal visszaadott mutat�ra vagy null�ra lehet
alkalmazni. Ha
a delete-et null�ra alkalmazzuk, nem lesz hat�sa.
A new oper�tornak egyedi v�ltozatait is meghat�rozhatjuk (�15.6).
170 Alapok
6.2.6.1. T�mb�k
A new haszn�lat�val l�trehozhatunk objektumokb�l �ll� t�mb�t is:
char* save_string(const char* p)
{
char* s = new char[strlen(p)+1];
strcpy(s,p); // m�sol�s p-bol s-be
return s;
}
int main(int argc, char* argv[ ])
{
if (argc < 2) exit(1);
char* p = save_string(argv[1]);
// ...
delete[ ] p;
}
A .sima. delete oper�tort arra haszn�lhatjuk, hogy egyes objektumokat
felsz�moljuk,
a delete[ ] t�mb�k felsz�mol�s�ra haszn�latos.
Ha vissza akarjuk nyerni a new �ltal lefoglalt t�rhelyet, a delete-nek vagy a
delete[ ]-nek meg
kell tudni �llap�tani, mekkora a lefoglalt objektum m�rete. Ebbol az k�vetkezik,
hogy
a szabv�nyos new oper�torral l�trehozott objektumok valamivel t�bb helyet
foglalnak, mint
a statikus objektumok. Az objektum m�ret�t �ltal�ban egy g�pi sz� t�rolja.
Jegyezz�k meg, hogy a vector (�3.7.1, �16.3) val�di objektum, ez�rt l�trehoz�s�ra
�s felsz�-
mol�s�ra a sima new-t �s delete-et haszn�lhatjuk:
void f(int n)
{
vector<int>* p = new vector<int>(n); // �n�ll� objektum
int* q = new int[n]; // t�mb
// ...
delete p;
delete[ ] q;
}
A delete[ ] oper�tort csak a new �ltal visszaadott mutat�ra vagy null�ra
alkalmazhatjuk. Ha
a delete[ ]-et null�ra alkalmazzuk, nem lesz hat�sa.
6. Kifejez�sek �s utas�t�sok 171
6.2.6.2. Mem�ria-kimer�l�s
A szabad t�r new, delete, new[ ] �s delete[ ] oper�torai f�ggv�nyekk�nt vannak
megval�s�tva:
void* operator new(size_t); // hely az �n�ll� objektum sz�m�ra
void operator delete(void*);
void* operator new[ ](size_t); // hely a t�mb sz�m�ra
void operator delete[ ](void*);
Ha a new oper�tornak egy objektum sz�m�ra kell helyet foglalnia, az operator
new()-t h�vja
meg, hogy az megfelelo sz�m� b�jtot foglaljon le. Ha t�mb sz�m�ra foglal helyet,
az operator
new[ ]() megh�v�s�ra ker�l sor. Az operator new() �s az operator new [ ]()
szabv�nyos
megval�s�t�sa a visszaadott mem�ri�t nem t�lti fel kezdo�rt�kkel.
Mi t�rt�nik, ha a new nem tal�l lefoglalhat� helyet? Alap�rtelmez�s szerint a
lefoglal�
bad_alloc kiv�telt v�lt ki (a m�sik lehetos�get illetoen l�sd �19.4.5-�t):
void f()
{
try {
for(;;) new char[10000];
}
catch(bad_alloc) {
cerr << "Elfogyott a mem�ria!\n";
}
}
Ak�rmennyi mem�ria �ll a rendelkez�s�nkre, a k�d v�g�l meg fogja h�vni a bad_alloc
esem
�nykezeloj�t.
Magunk is meghat�rozhatjuk, mit csin�ljon a new, amikor kifogy a mem�ria. Ha a new
nem
j�r sikerrel, elosz�r azt a f�ggv�nyt h�vja meg, amelyet a <new> fej�llom�nyban
bevezetett
set_new_handler() f�ggv�nnyel elozoleg be�ll�tottunk (amennyiben ezt megtett�k):
void out_of_store()
{
cerr << "Az operator new nem j�rt sikerrel: nincs t�rhely\n";
throw bad_alloc();
}
172 Alapok
int main()
{
set_new_handler(out_of_store); // out_of_store lesz a new_handler
for (;;) new char[10000];
cout << "k�sz\n";
}
Ez azonban soha nem fog el�rni addig, hogy ki�rja a .k�sz.-t. Ehelyett a
k�vetkezot fogja
ki�rni:
Az operator new nem j�rt sikerrel: nincs t�rhely
L�sd �14.4.5-�t az operator new() egy olyan lehets�ges megval�s�t�s�r�l, amely
megvizsg
�lja, l�tezik-e megh�vhat� kezelof�ggv�ny, �s ha nem tal�l ilyet, bad_alloc-ot
v�lt ki. Egy
new_handler azonban valami okosabbat is tehet, mint hogy egyszeruen befejezi a
programot.
Ha tudjuk, hogyan muk�dik a new �s a delete . p�ld�ul az�rt, mert saj�t operator
new()-t �s operator delete()-et �rtunk .,a kezelof�ggv�ny megpr�b�lhat valamennyi
mem�-
ri�t keresni, hogy a new visszat�rhessen, vagyis a felhaszn�l� gondoskodhat
szem�tgyujto-
rol, �gy elhagyhat�v� teheti a delete-et (b�r ez k�ts�gtelen�l nem kezdoknek val�
feladat).
Majdnem mindenkinek, akinek automatikus szem�tgyujtore van sz�ks�ge, a
leghasznosabb,
ha szerez egy m�r meg�rt �s ellenorz�tt term�ket (�C.9.1).
Azzal, hogy �j new_handler-t �ll�tunk be, felv�llaljuk, hogy nek�nk kell t�rodn�nk
a mem
�ria kimer�l�s�vel kapcsolatos probl�m�kkal a new minden haszn�latakor. A
mem�riafoglal
�snak k�tf�le �tja l�tezik: vagy gondoskodunk nem szabv�nyos lefoglal� �s
felszabad
�t� f�ggv�nyekrol (�15.6) a new szab�lyos haszn�lata sz�m�ra, vagy a felhaszn�l�
�ltal
adott tov�bbi foglal�si adatokra t�maszkodunk (�10.4.11, �19.4.5.).
6.2.7. Meghat�rozott t�puskonverzi�k
N�ha .nyers mem�ri�val. kell dolgoznunk, azaz a t�r olyan objektumot tartalmaz
vagy fog
tartalmazni, melynek t�pusa ismeretlen a ford�t�program sz�m�ra. Ilyen eset,
amikor a mem
�riafoglal� (allok�tor) egy �jonnan lefoglalt mem�riater�letre hivatkoz� void*
t�pus� mutat
�t ad vissza, vagy ha azt akarjuk kifejezni, hogy egy adott eg�sz �rt�ket �gy kell
kezelni,
mint egy I/O eszk�z c�m�t:
void* malloc(size_t);
void f()
{
int* p = static_cast<int*>(malloc(100)); // a new �ltal lefoglalt helyet int-k�nt
haszn�ljuk
IO_device* d1 = reinterpret_cast<IO_device*>(0Xff00); // eszk�z a 0Xff00 c�men
// ...
}
6. Kifejez�sek �s utas�t�sok 173
A ford�t�program nem ismeri a void* �ltal mutatott objektum t�pus�t. Azt sem
tudja, vajon
a 0Xff00 �rv�nyes c�m-e. K�vetkez�sk�ppen az �talak�t�sok helyess�ge teljes
m�rt�kben
a programoz� kez�ben van. Az explicit (pontosan meghat�rozott) t�pusk�nyszer�t�sek

(casting) n�ha sz�ks�gesek, de hagyom�nyosan t�l sokszor haszn�lj�k azokat, �s


jelentos
hibaforr�sok.
A static_cast oper�tor egym�ssal kapcsolatban levo t�pusok k�z�tti konverzi�t
v�gez, p�ld
�ul k�t, ugyanazon oszt�lyhierarchi�ban l�vo mutat�t�pus, integr�lis t�pus �s
felsorol� t�-
pus, vagy lebegopontos t�pus �s integr�lis t�pus k�z�ttit. A reinterpret_class
olyan t�pusok
�talak�t�s�t hajtja v�gre, amelyek nincsenek kapcsolatban, p�ld�ul eg�szrol
mutat�ra vagy
mutat�t�pusr�l egy m�sik, nem rokon mutat�ra konvert�l. Ez a megk�l�nb�ztet�s
lehetov�
teszi, hogy a ford�t�program elv�gezzen bizonyos minim�lis t�pusellenorz�st a
static_cast
eset�ben, �s megk�nny�ti, hogy a programoz� megtal�lja a vesz�lyesebb
�talak�t�sokat,
melyeket a reinterpret_cast jel�l. N�h�ny static_cast .hordozhat�., a
reinterpret_cast-ok
k�z�l viszont csak kev�s. A reinterpret_cast eset�ben nem sok dolog biztos;
�ltal�ban �j t�-
pust hoz l�tre, amelynek ugyanaz a bitmint�ja, mint a param�ter��. Ha a c�l
legal�bb annyi
bites, mint az eredeti �rt�k, az eredm�nyt a reinterpret_cast-tal az eredeti
t�pusra alak�thatjuk
�s haszn�lhatjuk azt. A reinterpret_cast eredm�ny�t csak akkor lehet biztosan
felhaszn
�lni, ha annak t�pusa pontosan az a t�pus, amelyet az �rt�k meghat�roz�s�ra
haszn�ltunk.
Ha k�s�rt�st �rz�nk, hogy pontosan meghat�rozott t�pusk�nyszer�t�st alkalmazzunk,
sz�njunk
idot arra, hogy meggondoljuk, vajon t�nyleg sz�ks�ges-e. A C++-ban az explicit t�-

pusk�nyszer�t�s a legt�bb esetben sz�ks�gtelen olyankor, amikor a C-ben sz�ks�g


lenne r�
(�1.6), �s sok olyan esetben is, ahol a C++ korai v�ltozataiban sz�ks�ges volt
(�1.6.2, �B.2.3).
Sz�mos programban az ilyen t�puskonverzi� teljesen elker�lheto; m�shol n�h�ny
elj�r�sra
korl�tozhatjuk a haszn�lat�t. Ebben a k�nyvben explicit t�pusk�nyszer�t�st
val�s�ghu helyzetekben
csak a �6.2.7, �7.7, �13.5, �15.4, �s �25.4.1 pontokban haszn�lunk.
A fut�si idoben ellenorz�tt konverzi�k egyik form�ja a dynamic_cast (�15.4.1). A
const
minos�tot elt�vol�t� .konstanstalan�t�. const_cast (�15.4.2.1) oper�tort szint�n
haszn�lhatjuk.
A C++ a C-bol �r�k�lte a (T)e jel�l�st, amely b�rmilyen �talak�t�st elv�gez, amit
ki lehet fejezni
a static_cast, reinterpret_cast �s a const_cast kombin�ci�jak�nt. Eredm�ny�l T
t�pus�
�rt�k j�n l�tre (�B.2.3). Ez a C st�lus� konverzi� sokkal vesz�lyesebb, mint a
fent eml�tettek,
mert a jel�l�st nehezebben lehet �szrevenni egy nagy programban �s a programoz�
sz�nd
�ka szerinti �talak�t�s fajt�ja nem nyilv�nval�. Azaz a (T)e lehet, hogy
.hordozhat�. �talak
�t�st v�gez egym�ssal kapcsolatban levo t�pusok k�z�tt, de nem hordozhat�t a nem
rokon
t�pusok k�z�tt, esetleg egy mutat�t�pusr�l elt�vol�tja a const minos�tot. Ha nem
tudjuk T �s
e pontos t�pus�t, ezt nem tudjuk eld�nteni.
174 Alapok
6.2.8. Konstruktorok
Egy T t�pus� �rt�k l�trehoz�sa egy e �rt�kbol a T(e) f�ggv�nyjel�l�ssel fejezheto
ki:
void f(double d)
{
int i = int(d); // d csonkol�sa
complex z = complex(d); // complex l�trehoz�sa d-bol
// ...
}
A T(e) szerkezetet n�ha f�ggv�ny st�lus� konverzi�nak nevezik. Sajnos, be�p�tett T
t�pusokra
T(e) egyen�rt�ku (T)e-vel, ami azt vonja maga ut�n, hogy a T(e) haszn�lata nem
mindig
biztons�gos. Aritmetikai t�pusok eset�ben az �rt�kek csonkulhatnak, �s m�g egy
hosszabb eg�sz t�pusr�l egy r�videbbre (p�ld�ul long-r�l char-ra) val� �talak�t�s
is nem
meghat�rozott viselked�st eredm�nyezhet. A jel�l�st megpr�b�lom kiz�r�lag ott
haszn�lni,
ahol az �rt�k l�trehoz�sa pontosan meghat�rozott, azaz a szuk�to aritmetikai
�talak�t�sokn
�l (�C.6), az eg�szekrol felsorol� t�pusra val� �talak�t�sokn�l (�4.8), �s a
felhaszn�l�i t�pusok
objektumainak l�trehoz�s�n�l (�2.5.2, �10.2.3).
A mutat�-konverzi�kat a T(e) jel�l�st haszn�lva nem fejezhetj�k ki k�zvetlen�l. A
char*(2)
p�ld�ul formai hib�nak sz�m�t. Sajnos az a v�delem, amit a konstruktor jel�l�s
ny�jt az ilyen
vesz�lyes �talak�t�sok ellen, kiker�lheto ha a mutat�t�pusokra typedef neveket
(�4.9.7)
haszn�lunk.
A T alap�rtelmezett �rt�k�nek kifejez�s�re a T() konstruktor jel�l�s haszn�latos:
void f(double d)
{
int j = int(); // alap�rtelmezett int �rt�k
complex z = complex(); // alap�rtelmezett complex �rt�k
// ...
}
A be�p�tett t�pusok konstruktor�nak �rt�ke a 0, amit a ford�t� az adott t�pusra
konvert�l
(�4.9.5). Ez�rt az int() egy m�sfajta m�dja a 0 �r�s�nak. A T felhaszn�l�i t�pusra
T()-t az alap-
�rtelmezett konstruktor (�10.4.2) hat�rozza meg, ha l�tezik ilyen.
A konstruktor jel�l�s haszn�lata be�p�tett t�pusokra sablonok �r�sakor k�l�n�sen
fontos.
Ekkor a programoz� nem tudhatja, hogy a sablon (template) param�tere be�p�tett
vagy felhaszn
�l�i t�pusra vonatkozik-e majd (�16.3.4, �17.4.1.2).
6. Kifejez�sek �s utas�t�sok 175
6.3. Utas�t�sok . �ttekint�s
�me a C++ utas�t�sok �sszefoglal�sa, n�h�ny p�ld�val:
176 Alapok
Az utas�t�sok formai szab�lyai
utas�t�s:
deklar�ci�
{ utas�t�s_listanem k�telezo }
try { utas�t�s_listanem k�telezo } kezelo_lista
kifnem k�telezo ;
if (felt�tel) utas�t�s
if (felt�tel) utas�t�s else utas�t�s
switch (felt�tel) utas�t�s
while (felt�tel) utas�t�s
do utas�t�s while (kif);
for (kezdo�rt�k_meghat�roz� felt�telnem k�telezo ;kifnem k�telezo ) utas�t�s
case konstans_kif : utas�t�s
default : utas�t�s
break ;
continue ;
return kifnem k�telezo ;
goto azonos�t�;
azonos�t� : utas�t�s
utas�t�s_lista:
utas�t�s utas�t�s_listanem k�telezo
felt�tel:
kif
t�pusazonos�t� deklar�tor = kif
kezelo_lista:
catch (kif_deklar�ci�) { utas�t�s_listanem k�telezo }
kezelo_lista kezelo_listanem k�telezo
Jegyezz�k meg, hogy a deklar�ci� egy utas�t�s, �rt�kad� �s elj�r�sh�v� utas�t�sok
pedig
nincsenek: az �rt�kad�sok �s a f�ggv�nyh�v�sok kifejez�sek. A kiv�telek kezel�s�re
vonatkoz
� utas�t�sokat . a try blokkokat . a �8.3.1 pontban t�rgyaljuk.
6.3.1. Deklar�ci�k mint utas�t�sok
A deklar�ci� utas�t�s. Hacsak egy v�ltoz�t static-k�nt nem adunk meg, minden
esetben kezd
o�rt�ket fog kapni, amikor a vez�rl�s �thalad a deklar�ci�j�n (l�sd m�g �10.4.8).
A deklar
�ci�kat az�rt engedj�k meg minden olyan helyen, ahol utas�t�st haszn�lhatunk (�s
m�g p�r
tov�bbi helyen, �6.3.2.1, �6.3.3.1), hogy lehetov� tegy�k a programoz�nak a
kezdo�rt�k
n�lk�li v�ltoz�kb�l sz�rmaz� hib�k cs�kkent�s�t �s a v�ltoz�k hat�k�r�nek leheto
legnagyobb
szuk�t�s�t a k�dban. Ritk�n van ok �j v�ltoz� bevezet�s�re, mielott lenne egy
olyan
�rt�k, amit a v�ltoz�nak tartalmaznia kell:
void f(vector<string>& v, int i, const char* p)
{
if (p==0) return;
if (i<0 || v.size()<=i) error("rossz index");
string s = v[i];
if (s == p) {
// ...
}
// ...
}
A lehetos�g, hogy a deklar�ci�kat v�grehajthat� k�d ut�n is elhelyezhetj�k,
alapveto fontoss
�g� sok konstans eset�ben, illetve az olyan egyszeri �rt�kad�sos programoz�si
st�lusn
�l, ahol egy objektum �rt�ke nem v�ltozik meg annak l�trehoz�sa �s kezdeti
�rt�kad�sa
ut�n. Felhaszn�l�i t�pusokn�l a v�ltoz� meghat�roz�s�nak elhalaszt�sa addig, am�g
egy
megfelelo kezdeti �rt�k rendelkez�sre nem �ll jobb teljes�tm�nyhez is vezethet:
string s; /* ... */ s = "A legjobb a j� ellens�ge.";
A fenti k�nnyen elofordulhat, hogy sokkal lassabb, mint a k�vetkezo:
string s = "Voltaire";
Kezdeti �rt�k n�lk�l �ltal�ban akkor adunk meg egy v�ltoz�t, ha a v�ltoz�nak
utas�t�sra van
sz�ks�ge a kezdeti �rt�kad�shoz. Ilyenek p�ld�ul a bemeneti v�ltoz�k �s a t�mb�k.
6. Kifejez�sek �s utas�t�sok 177
6.3.2. Kiv�laszt� utas�t�sok
Egy �rt�ket az if vagy a switch utas�t�ssal vizsg�lhatunk meg:
if (felt�tel) utas�t�s
if (felt�tel) utas�t�s else utas�t�s
switch (felt�tel) utas�t�s
Az al�bbi �sszehasonl�t� oper�torok a logikai (bool) t�pus� true �rt�ket adj�k
vissza, ha az
�sszehasonl�t�s igaz, �s false-t, ha hamis:
== != < <= > >=
Az if utas�t�sban az elso (�s egyetlen) utas�t�s akkor hajt�dik v�gre, ha a
kifejez�s nem nulla.
Ha nulla, a m�sodik utas�t�sra ugrunk (ha megadtunk ilyet). Ebbol az k�vetkezik,
hogy
b�rmilyen aritmetikai vagy mutat� kifejez�st lehet felt�telk�nt haszn�lni. P�ld�ul
ha x egy
eg�sz, akkor
if (x) // ...
azt jelenti, hogy
if (x != 0) // ...
A p mutat� eset�ben az al�bbi egy k�zvetlen utas�t�s, ami azt a vizsg�latot fejezi
ki, hogy .p
egy �rv�nyes objektumra mutat.:
if (p) // ...
A k�vetkezo k�zvetett m�don ugyanezt a k�rd�st fogalmazza, �gy, hogy
�sszehasonl�tja
egy olyan �rt�kkel, amelyrol tudjuk, hogy nem mutat objektumra:
if (p != 0) // ...
Jegyezz�k meg, hogy a 0 mutat�t nem minden g�p �br�zolja .csupa null�val.
(�5.1.1). Minden
ford�t�program, amivel tal�lkoztam, ugyanazt a k�dot k�sz�tette mindk�t
vizsg�latra.
178 Alapok
A
&& || !
logikai oper�torok leggyakrabban felt�telekben haszn�latosak. Az && �s a ||
muveletek
nem �rt�kelik ki a m�sodik param�tert, csak ha sz�ks�g van r�:
if (p && 1<p->count) // ...
A fenti utas�t�s p�ld�ul elosz�r megvizsg�lja, hogy p nem nulla-e, �s csak akkor
n�zi meg,
hogy l<p->count teljes�l-e, ha p nem nulla.
N�h�ny if utas�t�st k�nyelmesen felt�teles kifejez�sekre cser�lhet�nk. P�ld�ul az
if (a <= b)
max = b;
else
max = a;
jobban kifejezheto �gy:
max = (a<=b) ? b : a;
A felt�tel k�r�l l�vo z�r�jelek nem sz�ks�gesek, �n azonban �gy gondolom, a k�d
k�nnyebben olvashat� lesz tol�k.
A switch utas�t�s if utas�t�sok sorozatak�nt is le�rhat�. P�ld�ul a
switch (val) {
case 1:
f();
break;
case 2:
g();
break;
default:
h();
break;
}
6. Kifejez�sek �s utas�t�sok 179
�gy is kifejezheto:
if (val == 1)
f();
else if (val == 2)
g();
else
h();
A jelent�s ugyanaz, de az elso (switch) v�ltozatot r�szes�tj�k elonyben, mert a
muvelet term
�szete (egy �rt�ket �lland�k halmaz�val hasonl�tunk �ssze) �gy vil�gosabb. A
switch utas
�t�s olvashat�bb olyan p�ld�kn�l, amelyek nem magukt�l �rtetodoek, �s jobb k�dot
is
hozhatunk l�tre vele.
Vigy�zzunk arra, hogy a switch case-�t mindig fejezz�k be valahogy, hacsak nem
akarjuk
a v�grehajt�st a k�vetkezo case-n�l folytatni. Vegy�k a k�vetkezot:
switch (val) { // vigy�zat!
case 1:
cout << "1. eset\n";
case 2:
cout << "2.eset\n";
default:
cout << "Alap�rtelmez�s: nincs ilyen eset\n";
}
Ha val==1-gyel h�vjuk meg, a k�vetkezoket �rja ki:
1. eset
2. eset
Alap�rtelmez�s: nincs ilyen eset
Ez az avatatlanokat nagy meglepet�sk�nt �rheti. J� �tlet, ha megjegyz�sekkel
l�tjuk el azon
(ritka) eseteket, amikor a case-ek k�z�tti tov�bbl�p�s sz�nd�kos, �gy egy nem
magyar�zott
tov�bbl�p�srol felt�telezhetj�k, hogy programhiba. A case befejez�s�nek
leggyakoribb
m�dja a break haszn�lata, de a return is hasznos lehet (�6.1.1).
180 Alapok
6.3.2.1. Deklar�ci�k felt�telekben
A v�letlen hib�s muk�d�s elker�l�s�re �ltal�ban j� �tlet a v�ltoz�kat a legkisebb
lehets�ges
hat�k�rben bevezetni. Nevezetesen, rendszerint legjobb elhalasztani egy ide�lis
v�ltoz� bevezet
�s�t addig, am�g kezdeti �rt�ket nem tudunk adni neki. �gy nem ker�lhet�nk olyan
helyzetbe, hogy a v�ltoz�t m�g azelott haszn�ljuk, mielott kezdeti �rt�k�t
be�ll�tottuk volna.
Az eml�tett k�t elv egyik legeleg�nsabb felhaszn�l�sa, ha a v�ltoz�t egy
felt�telben adjuk
meg. Vegy�k a k�vetkezo p�ld�t:
if (double d = prim(true)) {
left /= d;
break;
}
Itt d deklar�lt �s kezdo�rt�ket is kap, amit a felt�tel �rt�k�vel hasonl�tunk
�ssze. A d hat�-
k�re a deklar�ci� pontj�t�l annak az utas�t�snak a v�g�ig terjed, amit a felt�tel
vez�rel. Ha
volna egy else �g az if utas�t�sban, a d hat�k�re mindk�t �gra kiterjedne.
A m�sik hagyom�nyos �s k�zenfekvo megold�s, ha a d-t a felt�tel elott vezetj�k be.
�gy viszont
nagyobb lesz a d haszn�lat�nak hat�k�re; kiterjedhet a kezdeti �rt�kad�s el� vagy
a d
sz�nd�kolt hasznos �lettartama ut�n is:
double d;
// ...
d2 = d; // hopp�!
// ...
if (d = prim(true)) {
left /= d;
break;
}
// ...
d = 2.0; // d k�t, egym�st�l f�ggetlen haszn�lata
A v�ltoz�k felt�telekben t�rt�no megad�s�nak nemcsak logikai haszna van, t�m�rebb
forr
�sk�dot is eredm�nyez.
A felt�telben l�vo deklar�ci�nak egyetlen v�ltoz�t vagy konstanst kell megadnia �s
felt�ltenie
kezdo�rt�kkel.
6. Kifejez�sek �s utas�t�sok 181
6.3.3. Ciklusutas�t�sok
A ciklusokat for, while vagy do utas�t�ssal fejezhetj�k ki:
while ( felt�tel ) utas�t�s
do utas�t�s while ( kifejez�s ) ;
for ( kezdo�rt�k_meghat�roz� felt�telnem k�telezo ; kifejez�snem k�telezo )
utas�t�s
Ezen utas�t�sok mindegyike ism�telten v�grehajt egy utas�t�st (amit vez�relt
(controlled)
utas�t�snak vagy ciklusmagnak nevez�nk), am�g a felt�tel hamiss� nem v�lik vagy a
programoz
� m�s m�don ki nem l�p a ciklusb�l.
A for utas�t�s szab�lyos ciklusok kifejez�s�re val�. A ciklusv�ltoz�t, a
ciklusfelt�telt, �s
a ciklusv�ltoz�t m�dos�t� kifejez�st egyetlen sorban �rhatjuk le, ami nagyon
megn�velheti
az olvashat�s�got �s ezzel cs�kkentheti a hib�k gyakoris�g�t. Ha nem sz�ks�ges
kezdeti �rt
�kad�s, a kezdo�rt�k_meghat�roz� (inicializ�l�) utas�t�s �res is lehet. Ha a
felt�telt elhagyjuk,
a for utas�t�s �r�kk� a ciklusban marad, hacsak a felhaszn�l� kifejezetten
kil�p�sre
nem k�nyszer�ti egy break, return, goto, vagy throw utas�t�ssal, vagy valami
kev�sb� egyszer
u m�don, p�ld�ul az exit() (�9.4.1.1) megh�v�s�val. Ha a kifejez�st elhagyjuk, a
ciklusmagban
kell m�dos�tanunk egy ciklusv�ltoz�t. Ha a ciklus nem az egyszeru .bevezet�nk
egy ciklusv�ltoz�t, megvizsg�ljuk a felt�telt, m�dos�tjuk a ciklusv�ltoz�t.
fajt�b�l val�, �ltal
�ban jobb, ha while utas�t�ssal fejezz�k ki, de a for is seg�thet olyan ciklusok
�r�s�n�l,
melyeknek nincs meghat�rozott le�ll�si felt�tele:
for(;;) { // "�r�kk�" (v�gtelen ciklus)
// ...
}
A while utas�t�s egyszeruen v�grehajtja a ciklusmagot, am�g felt�tele hamiss� nem
v�lik. Akkor
hajlok arra, hogy a while-t r�szes�tsem elonyben a for-ral szemben, amikor nincs
mag�-
t�l �rtetodo ciklusv�ltoz� vagy amikor a ciklusv�ltoz� m�dos�t�sa term�szetes
m�don
a ciklusmag k�zep�n t�rt�nik. A bemeneti ciklus egy olyan ciklusra p�lda, amelyben
nincs
mag�t�l �rtetodo ciklusv�ltoz�:
while(cin>>ch) // ...
Tapasztalatom szerint a do utas�t�s k�nnyen hib�k �s t�ved�sek forr�sa lehet.
Ennek az az
oka, hogy a ciklusmag mindig v�grehajt�dik egyszer, mielott a felt�tel
ki�rt�kelodik. Ahhoz
azonban, hogy a ciklusmag megfeleloen muk�dj�n, valamilyen felt�telnek m�r az elso
alkalommal
is teljes�lnie kell. A v�rtn�l sokkal gyakrabban vettem �szre azt, hogy egy felt�-

182 Alapok
tel nem �gy teljes�lt, ahogy az elv�rhat� lett volna; vagy amikor a programot
elosz�r meg-
�rt�k �s tesztelt�k, vagy k�sobb, amikor a k�dot m�dos�tott�k. Ezenk�v�l jobban
szeretem
a felt�telt .el�l, ahol j�l l�thatom.. K�vetkez�sk�ppen �n magam pr�b�lom
elker�lni a do
utas�t�sokat.
6.3.3.1. Deklar�ci�k a for utas�t�sban
V�ltoz�kat a for utas�t�s kezdo�rt�k-ad� r�sz�ben adhatunk meg. Ha ez deklar�ci�,
akkor
az �ltala bevezetett v�ltoz� (vagy v�ltoz�k) hat�k�re a for utas�t�s v�g�ig
terjed:
void f(int v[ ], int max)
{
for (int i = 0; i<max; i++) v[i] = i*i;
}
Ha az index v�gso �rt�k�t tudni kell a for ciklusb�l val� kil�p�s ut�n, a
ciklusv�ltoz�t a cikluson
k�v�l kell megadni (pl. �6.3.4.).
6.3.4. Goto
A C++-ban megtal�lhat� a h�rhedt goto :
goto azonos�t� ;
azonos�t� : utas�t�s
A goto az �ltal�nos magasszintu programoz�sban kev�s dologra haszn�lhat�, de
nagyon
hasznos lehet, amikor a C++ k�dot program �s nem k�zvetlen�l egy szem�ly k�sz�ti;
haszn
�lhatjuk p�ld�ul olyan elemzoben, melyet egy k�dk�sz�to program (k�dgener�tor)
hozott
l�tre valamilyen nyelvtan alapj�n. A goto akkor is hasznos lehet, ha a hat�konys�g
alapvet
o k�vetelm�ny, p�ld�ul valamilyen val�s ideju alkalmaz�s belso ciklus�ban.
A goto kev�s �rtelmes haszn�lat�nak egyike a mindennapi k�dban az, hogy kil�p�nk
egy
be�gyazott ciklusb�l vagy switch utas�t�sb�l (a break csak a legbelso ciklusb�l
vagy switch
utas�t�sb�l l�p ki):
void f()
{
int i;
int j;
6. Kifejez�sek �s utas�t�sok 183
for (i = 0; i<n; i++)
for (j = 0; j<m; j++) if (nm[i][j] == a) goto found;
// nem tal�lhat�
// ...
found:
// nm[i][j] == a
}
A ciklus v�g�re ugr� continue utas�t�s muk�d�s�vel a �6.1.5-ben foglalkoztunk.
6.4. Megjegyz�sek �s beh�z�s
A program olvas�s�t �s meg�rt�s�t sokkal kellemesebb� teheti, ha okosan haszn�ljuk

a megjegyz�seket �s a beh�z�st. Sz�mos beh�z�si st�lus haszn�latos �s nem l�tok


alapveto
okot arra, hogy egyiket a m�sikkal szemben elonyben r�szes�ts�k (b�r a legt�bb
programoz
�hoz hasonl�an nekem is van v�lasztott st�lusom . a k�nyv nyilv�n t�kr�zi is azt).
Ugyanez
vonatkozik a megjegyz�sek st�lus�ra is.
A megjegyz�seket sz�mos m�don lehet rosszul haszn�lni, ami �gy nagym�rt�kben
rontja
a program olvashat�s�g�t. A ford�t�program nem �rti a megjegyz�sek tartalm�t,
ez�rt nincs
m�d arra, hogy biztos�tsa azt, hogy egy megjegyz�s
[1] �rtelmes,
[2] a programmal �sszhangban �ll� �s
[3] idoszeru legyen.
Sz�mos program olyan megjegyz�seket tartalmaz, melyek �rthetetlenek,
f�lre�rthetoek,
vagy egyszeruen hib�sak. A rossz megjegyz�sek rosszabbak, mint ha egy�ltal�n nem
haszn
�ln�nk megjegyz�st.
Ha valamit le�rhatunk mag�val a programnyelvvel, akkor tegy�k azt, ne
megjegyz�sben
eml�ts�k meg. Ez az �szrev�tel az ilyenfajta megjegyz�sekre vonatkozik:
// a "v" v�lt�z�nak kezdo�rt�ket kell adni
// a "v" v�ltoz�t csak az "f()" f�ggv�ny haszn�lhatja
// az "init()" f�ggv�nyt minden m�s f�ggv�ny elott meg kell h�vni ebben a f�jlban
184 Alapok
// a "cleanup()" f�ggv�nyt meg kell h�vni a program v�g�n
// a "weird()" f�ggv�nyt ne haszn�ljuk
// az "f()" f�ggv�nynek k�t param�tert kell adni
A C++ megfelelo haszn�lata az ilyen megjegyz�seket �ltal�ban sz�ks�gtelenn� teszi.
A fentieket
p�ld�ul kiv�lthatjuk, ha alkalmazzuk az �sszeszerkeszt�si (�9.2) vagy az
oszt�lyokra
vonatkoz� l�that�s�gi, kezdo�rt�k-ad�si �s felsz�mol�si szab�lyokat (�10.4.1).
Mihelyt valamit vil�gosan le�rtunk a nyelvvel, m�sodszor m�r nem kell
megeml�ten�nk egy
megjegyz�sben:
a = b+c; // a-b�l b+c lesz
count++; // n�velj�k a sz�ml�l�t
Az ilyen megjegyz�sek m�g az egyszeruen feleslegesekn�l is rosszabbak, mert
n�velik az
elolvasand� sz�veg hossz�t, gyakran �sszezavarj�k a program szerkezet�t, �s lehet,
hogy
hib�sak. Meg kell azonban jegyezn�nk, hogy az ilyen megjegyz�sek sz�lesk�ruen
haszn�-
latosak tan�t�si c�lokra az olyan programoz�si nyelvekrol sz�l� k�nyvekben, mint
amilyen
ez is. Ez az egyik, amiben egy k�nyvben l�vo program k�l�nb�zik egy igazi
programt�l.
�n a k�vetkezoket szeretem:
1. Minden forr�sf�jlban van megjegyz�s, amely le�rja, mi a k�z�s a f�jlban levo
deklar�ci�kban, utal a seg�danyagokra, �ltal�nos �tleteket ad a k�d m�dos�t�-
s�val kapcsolatban stb.
2. Minden oszt�lyhoz, sablonhoz �s n�vt�rhez tartozik megjegyz�s.
3. Minden nem mag�t�l �rtetodo f�ggv�nyhez van olyan megjegyz�s, amely le�rja
a f�ggv�ny c�lj�t, a felhaszn�lt algoritmust (ha az nem nyilv�nval�), �s esetleg
azt, hogy mit felt�telez k�rnyezet�rol.
4. Minden glob�lis �s n�vt�r-v�ltoz�hoz, illetve konstanshoz van megjegyz�s.
5. Van n�h�ny megjegyz�s ott, ahol a k�d nem nyilv�nval� �s/vagy m�s rendszerre
nem �t�ltetheto.
6. A fentieken k�v�l kev�s megjegyz�s van.
6. Kifejez�sek �s utas�t�sok 185
P�ld�ul:
// tbl.c: Implementation of the symbol table.
/*
Gaussian elimination with partial pivoting.
See Ralston: "A first course ..." pg 411.
*/
// swap() assumes the stack layout of an SGI R6000.
/*******************************
Copyright (c) 1997 AT&T, Inc.
All rights reserved
*******************************/
A j�l megv�lasztott �s j�l meg�rt megjegyz�sek alapveto r�sz�t k�pezik a j�
programnak. J�
megjegyz�seket �rni legal�bb olyan neh�z, mint meg�rni mag�t a programot. Olyan
muv�-
szet, melyet �rdemes muvelni.
Jegyezz�k meg azt is, hogy ha kiz�r�lag a // megjegyz�seket haszn�ljuk egy
f�ggv�nyben,
akkor ennek a f�ggv�nynek b�rmely r�sz�t megjegyz�sbe tehetj�k a /* */ jel�l�ssel
(ez ford
�tva is igaz).
6.5. Tan�csok
[1] R�szes�ts�k elonyben a standard k�nyvt�rat a t�bbi k�nyvt�rral �s a .k�zzel
�rt
k�ddal. szemben. �6.1.8.
[2] Ker�lj�k a bonyolult kifejez�seket. �6.2.3.
[3] Ha k�ts�geink vannak az oper�torok precedenci�j�val kapcsolatban, z�r�jelezz
�nk. �6.2.3.
[4] Ker�lj�k a t�pusk�nyszer�t�st (cast). �6.2.7.
[5] Ha explicit t�puskonverzi� sz�ks�ges, r�szes�ts�k elonyben a jobban defini�lt
konverzi�s oper�torokat a C st�lus� �talak�t�ssal szemben. �6.2.7.
[6] Kiz�r�lag j�l meghat�rozott szerkezetekn�l haszn�ljuk a T(e) jel�l�st. �6.2.8.

[7] Ker�lj�k az olyan kifejez�seket, melyek ki�rt�kel�si sorrendje nem meghat�ro-


186 Alapok
zott. �6.2.2.
[8] Ker�lj�k a goto-t. �6.3.4.
[9] Ker�lj�k a do utas�t�st. �6.3.3.
[10] Ne adjunk meg v�ltoz�t addig, am�g nincs �rt�k, amivel felt�lthetn�nk.
�6.3.1,
�6.3.2.1, �6.3.3.1.
[11] A megjegyz�seket friss�ts�k rendszeresen. �6.4.
[12] Tartsunk fenn k�vetkezetes st�lust. �6.4.
[13] A glob�lis operator new() helyettes�t�s�re adjunk meg ink�bb egy operator
new() tagot (�15.6). �6.2.6.2.
[14] Bemenet beolvas�sakor mindig vegy�k sz�m�t�sba a rosszul megadott bemenetet
is. �6.1.3.
6.6. Gyakorlatok
1. (*1) �rjuk meg a k�vetkezo for utas�t�ssal egyen�rt�ku while utas�t�st:
for (i=0; i<max_length; i++) if (input_line[i] == '?') quest_count++;
Ezt �rjuk �t �gy, hogy ciklusv�ltoz�k�nt mutat�t haszn�lunk, azaz �gy, hogy
a vizsg�lat *p=='?' alak� legyen.
2. (*1) Z�r�jelezz�k teljesen a k�vetkezo kifejez�seket:
a = b + c * d << 2 & 8
a & 077 != 3
a == b || a == c && c < 5
c = x != 0
0 <= i < 7
f(1,2)+3
a = - 1 + + b -- - 5
a = b == c ++
a = b = c = 0
a[4][2] *= * b ? c : * d * 2
a-b,c=d
3. (*2) Olvassuk be �reshellyel elv�lasztott (n�v- �s �rt�k-) p�rok sorozat�t,
ahol
a n�v egyetlen �reshellyel elv�lasztott sz�, az �rt�k pedig egy eg�sz vagy lebeg
opontos �rt�k. Sz�m�tsuk ki �s �rjuk ki minden n�vre az �rt�kek �sszeg�t �s
sz�mtani k�zep�t, valamint az �sszes n�vre vonatkoz� �sszeget �s sz�mtani
k�zepet. Tipp: �6.1.8.
4. (*1) �rjuk meg a bitenk�nti logikai oper�torok (�6.2.4) �rt�kt�bl�zat�t a 0 �s
1
6. Kifejez�sek �s utas�t�sok 187
operandusok �sszes lehets�ges p�ros�t�s�ra.
5. (*1,5) Tal�ljunk 5 k�l�nb�zo C++ szerkezetet, melynek jelent�se nem meghat�-
rozott (�C.2). (*1,5.) Tal�ljunk 5 k�l�nb�zo C++ szerkezetet, melynek jelent�se
a nyelvi megval�s�t�st�l f�gg (�C.2).
6. (*1) Adjunk 10 k�l�nb�zo p�ld�t nem hordozhat� C++ k�dra.
7. (*2) �rjunk 5 kifejez�st, melyek ki�rt�kel�si sorrendje nem meghat�rozott.
Hajtsuk
oket v�gre �s n�zz�k meg, mit csin�l vel�k egy . de lehetoleg t�bb . C++-
v�ltozat.
8. (*1,5) Mi t�rt�nik a rendszer�nkben, ha null�val osztunk? Mi t�rt�nik
t�lcsordul
�s �s alulcsordul�s eset�n?
9. (*1) Z�r�jelezz�k teljesen a k�vetkezo kifejez�seket:
*p++
*--p
++a--
(int*)p->m
*p.m
*a[i]
10. (*2) �rjuk meg a k�vetkezo f�ggv�nyeket: strlen(), ami egy C st�lus� karakterl
�nc hossz�t adja vissza, strcpy(), ami egy karakterl�ncot m�sol egy m�sikba, �s
strcmp(), ami k�t karakterl�ncot hasonl�t �ssze. Gondoljuk meg, mi legyen a param
�terek �s a visszat�r�si �rt�k t�pusa. Ezut�n hasonl�tsuk �ssze a f�ggv�nyeket
a standard k�nyvt�rban l�vo v�ltozatokkal, ahogy azok a <cstring>-ben
(<string.h>-ban) szerepelnek �s ahogy a �20.4.1 pontban le�rtuk azokat.
11. (*1) N�zz�k meg, hogyan reag�l a ford�t�programunk ezekre a hib�kra:
void f(int a, int b)
{
if (a = 3) // ...
if (a&077 == 0) // ...
a := b+1;
}
.K�sz�ts�nk. t�bb egyszeru hib�t �s n�zz�k meg, hogyan reag�l
a ford�t�program.
12. (*2) M�dos�tsuk �gy a �6.6[3] programot, hogy a k�z�pso �rt�ket (medi�n) is
kisz
�m�tsa.
13. (*2) �rjuk meg a cat() f�ggv�nyt, amelynek k�t C st�lus� karakterl�nc
param�tere
van �s egy olyan karakterl�ncot ad vissza, amely a param�terek �sszefuz�-
s�bol �ll elo. Az eredm�nyeknek foglaljunk helyet a new-val.
14. (*2) �rjuk meg a rev() f�ggv�nyt, amelynek egy karakterl�nc param�tere van �s
188 Alapok
megford�tja a benne l�vo karaktereket. Azaz a rev(p) lefut�sa ut�n p utols�
karaktere
az elso lesz �s �gy tov�bb.
15. (*1,5) Mit csin�l a k�vetkezo p�lda �s mi�rt �rna valaki ilyesmit?
void send(int* to, int* from, int count)
// Duff programja. A megjegyz�seket sz�nd�kosan t�r�ltem.
{
int n = (count+7)/8;
switch (count%8) {
case 0: do { *to++ = *from++;
case 7: *to++ = *from++;
case 6: *to++ = *from++;
case 5: *to++ = *from++;
case 4: *to++ = *from++;
case 3: *to++ = *from++;
case 2: *to++ = *from++;
case 1: *to++ = *from++;
} while (--n>0);
}
}
16. (*2) �rjuk meg az atoi(const char*) f�ggv�nyt, amely egy sz�mokat tartalmaz�
karakterl�ncot kap �s visszaadja a megfelelo eg�szet. P�ld�ul atoi("123") 123
lesz. M�dos�tsuk az atoi()-t �gy, hogy kezelje a C++ okt�lis �s hexadecim�lis jel
�l�s�t is, az egyszeru, t�zes sz�mrendszerbeli sz�mokkal egy�tt. M�dos�tsuk
a f�ggv�nyt �gy is, hogy kezelje a C++ karakterkonstans jel�l�st is.
17. (*2) �rjunk egy olyan itoa(int i, char b[ ]) f�ggv�nyt, amely l�trehozza b-ben
i
karakterl�nc �br�zol�s�t �s visszaadja b-t.
18. (*2) G�pelj�k be teljes eg�sz�ben a sz�mol�g�p p�ld�t �s hozzuk muk�d�sbe.
Ne takar�tsunk meg idot azzal, hogy m�r beg�pelt sz�vegr�szeket haszn�lunk.
A legt�bbet a .kis buta hib�k. kijav�t�s�b�l fogunk tanulni.
19. (*2) M�dos�tsuk a sz�mol�g�pet, hogy ki�rja a hib�k sor�nak sz�m�t is.
20. (*3) Tegy�k lehetov�, hogy a felhaszn�l� f�ggv�nyeket adhasson meg a sz�mol
�g�phez. Tipp: adjunk meg egy f�ggv�nyt muveletek sorozatak�nt, �gy, mintha
a felhaszn�l� g�pelte volna be azokat. Az ilyen sorozatokat karakterl�nck�nt
vagy szimb�lumok (tokenek) list�jak�nt t�rolhatjuk. Ezut�n olvassuk be �s hajtsuk
v�gre ezeket a muveleteket, amikor a f�ggv�ny megh�v�dik. Ha azt akarjuk,
hogy egy felhaszn�l�i f�ggv�nynek param�terei legyenek, akkor arra k�l�n
jel�l�st kell kital�lnunk.
21. (*1,5) Alak�tsuk �t a sz�mol�g�pet, hogy a symbol szerkezetet haszn�lja �s ne
a statikus number_value �s string_value v�ltoz�kat.
22. (*2,5) �rjunk olyan programot, amely kiveszi a megjegyz�seket a C++ progra-
6. Kifejez�sek �s utas�t�sok 189
mokb�l. Azaz, olvassunk a cin-rol, t�vol�tsuk el mind a //, mind a /* */ megjegyz
�seket, majd �rjuk ki az eredm�nyt a cout-ra. Ne t�rodj�nk azzal, hogy a kimenet
sz�p legyen (az egy m�sik, sokkal nehezebb feladat lenne). Ne t�rodj�nk
a hib�s programokkal. �vakodjunk a //, /* �s */ haszn�lat�t�l a megjegyz�sekben,
karakterl�ncokban �s karakterkonstansokban.
23. (*2) N�zz�nk meg n�h�ny programot, hogy elk�pzel�s�nk lehessen a mostans�g
haszn�latos st�lusok (beh�z�sok, elnevez�sek �s megjegyz�sek) v�ltozatoss�g�r�l.
190 Alapok
F�ggv�nyek
.Ism�telni emberi dolog.
Rekurzi�t �rni isteni..
(L. Peter Deutsch)
F�ggv�nydeklar�ci�k �s -defin�ci�k . Param�ter�tad�s . Visszat�r�si �rt�kek .
F�ggv�nyt
�lterhel�s . A t�bb�rtelmus�g felold�sa . Alap�rtelmezett param�terek . stdargs .
F�ggv
�nyekre hivatkoz� mutat�k . Makr�k . Tan�csok . Gyakorlatok
7.1. F�ggv�nydeklar�ci�k
A C++-ban �ltal�ban �gy v�gz�nk el valamit, hogy megh�vunk r� egy f�ggv�nyt, �s a
f�ggv
�ny definici�j�val �rjuk le, hogyan kell azt elv�gezni. A f�ggv�nyt azonban nem
h�vhatjuk
meg �gy, hogy elozetesen nem deklar�ltuk. A f�ggv�ny deklar�ci�ja megadja a
f�ggv�ny
nev�t, visszat�r�si �rt�k�nek t�pus�t (ha van ilyen), �s azon param�terek sz�m�t
�s t�pus�t,
amelyeket �t kell adni a f�ggv�ny megh�v�sakor:
Elem* next_elem();
char* strcpy(char* to, const char* from);
void exit(int);
7
A param�ter�tad�s ugyanazt a szerepet t�lti be, mint a kezdeti �rt�kad�s. A
ford�t�program
ellenorzi a param�terek t�pus�t �s automatikus t�puskonverzi�t v�gez, ha
sz�ks�ges:
double sqrt(double);
double sr2 = sqrt(2); // sqrt() megh�v�sa double(2) param�terrel
double sq3 = sqrt("three"); // hiba: sqrt() double t�pus� param�tert ig�nyel
Az ilyen ellenorz�s �s konverzi� jelentos�g�t nem szabad al�becs�lni.
A f�ggv�nydeklar�ci� param�terneveket is tartalmazhat, melyek seg�tik a program
olvas�-
j�t. A ford�t�program ezeket egyszeruen nem veszi figyelembe. Amint �4.7-ben
eml�tett�k,
a void visszat�r�si t�pus azt jelenti, hogy a f�ggv�ny nem ad vissza �rt�ket.
7.1.1. F�ggv�nydefin�ci�k
Minden f�ggv�nyt, amit megh�vunk a programban, valahol (de csak egyszer) meg kell
hat
�roznunk. A f�ggv�nydefin�ci� (f�ggv�ny-meghat�roz�s) olyan deklar�ci�, amelyben
megadjuk a f�ggv�ny t�rzs�t:
extern void swap(int*, int*); // deklar�ci�
void swap(int* p, int* q) // defin�ci�
{
int t = *p;
*p = *q;
*q = t;
}
A f�ggv�nyek defin�ci�inak �s deklar�ci�inak ugyanazt a t�pust kell
meghat�rozniuk. A param
�terek nevei azonban nem r�szei a t�pusnak, �gy nem kell azonosaknak lenni�k.
Nem ritka az olyan f�ggv�nydefin�ci�, amely nem haszn�lja fel az �sszes
param�tert:
void search(table* t, const char* key, const char*)
{
// a harmadik param�ter nem haszn�latos
}
192 Alapok
Amint l�tjuk, azt a t�nyt, hogy egy param�tert nem haszn�lunk fel, �gy
jel�lhetj�k, hogy
nem nevezz�k meg a param�tert. A n�vtelen param�terek jellemzoen a program
egyszeru-
s�t�se folyt�n vagy annak k�sobbi bov�thetos�g�t biztos�tand� ker�lnek a k�dba.
Mindk�t
esetben azzal, hogy b�r nem haszn�ljuk fel, de a hely�k�n hagyjuk a param�tereket,
biztos
�tjuk, hogy a f�ggv�nyt megh�v�kat nem �rintik a m�dos�t�sok.
A f�ggv�nyeket a ford�t� �ltal a h�v�s sor�ban kifejtendok�nt (inline-k�nt) is
megadhatjuk:
inline int fac(int n)
{
return (n<2) ? 1 : n*fac(n-1);
}
Az inline kulcssz� javaslat a ford�t�program sz�m�ra, hogy a fac() megh�v�s�n�l
pr�b�lja
meg annak k�dj�t a h�v�s sor�ban l�trehozni, ahelyett, hogy elobb l�trehozn� azt,
majd
a szok�sos f�ggv�nyh�v� elj�r�s szerint h�vn� meg. Egy okos ford�t�program a
fac(6)
megh�v�sakor l�tre tudja hozni a720 konstanst. Az egym�st k�lcs�n�sen megh�v�
(k�lcs�-
n�sen rekurz�v) helyben kifejtett f�ggv�nyek, illetve a bemenettol f�ggoen magukat
�jrah�-
v� vagy nem �jrah�v� helyben kifejtett f�ggv�nyek lehetos�ge miatt nem biztos,
hogy egy
inline f�ggv�ny minden h�v�sa a h�v�s sor�ban j�n l�tre. A ford�t�programok
intelligenci�-
j�nak m�rt�ke nem �rhat� elo, �gy elofordulhat, hogy az egyik 720-at, a m�sik
6*fac(5)-�t,
a harmadik pedig a fac(6) nem helyben kifejtett h�v�st hozza l�tre.
Ha nem rendelkez�nk kiv�telesen intelligens ford�t�- �s szerkeszto-programmal, a
h�v�s sor
�ban t�rt�no l�trehoz�st akkor biztos�thatjuk, ha a f�ggv�ny kifejt�se . �s nem
csak deklar
�ci�ja . is a hat�k�rben szerepel (�9.2). Az inline kulcssz� nem befoly�solja a
f�ggv�ny
�rtelmez�s�t. Nevezetesen az ilyen f�ggv�nyeknek . �s static v�ltoz�iknak
(�7.1.2.) is
. ugyan�gy egyedi c�m�k van.
7.1.2. Statikus v�ltoz�k
A lok�lis (helyi) v�ltoz�k akkor kapnak kezdo�rt�ket, amikor a v�grehajt�s el�r a
definici�jukhoz.
Alap�rtelmez�s szerint ez a f�ggv�ny minden megh�v�sakor megt�rt�nik, az egyes
f�ggv
�nyh�v�soknak pedig saj�t m�solatuk van a v�ltoz�r�l. Ha egy lok�lis v�ltoz�t
static-k�nt vezet
�nk be, akkor azt a f�ggv�ny minden megh�v�sakor egyetlen, �lland� c�mu objektum
jel�-
li majd. A v�ltoz� csak egyszer kap �rt�ket, amikor a v�grehajt�s el�ri annak elso
defin�ci�j�t:
7. F�ggv�nyek 193
void f(int a)
{
while (a--) {
static int n = 0; // egyszer kap kezdo�rt�ket
int x = 0; // 'a' alkalommal kap kezdo�rt�ket (az f() minden megh�v�sakor)
cout << "n == " << n++ << ", x == " << x++ << '\n';
}
}
int main()
{
f(3);
}
A fenti a k�vetkezoket �rja ki:
n == 0, x == 0
n == 1, x == 0
n == 2, x == 0
A statikus v�ltoz�k an�lk�l biztos�tanak .eml�kezetet. a f�ggv�nynek, hogy
glob�lis v�ltoz
�t vezetn�nek be, amelyet m�s f�ggv�nyek is el�rhetnek �s m�dos�t�ssal
haszn�lhatatlann
� tehetnek (l�sd m�g �10.2.4).
7.2. Param�ter�tad�s
Amikor egy f�ggv�ny megh�v�dik, a ford�t�program a form�lis param�terek sz�m�ra
t�rter
�letet foglal le, az egyes form�lis param�terek pedig a megfelelo val�di
(aktu�lis) param�-
ter-�rt�kkel t�ltodnek fel. A param�ter�tad�s szerepe azonos a kezdeti
�rt�k�tad�s�val.
A ford�t�program ellenorzi, hogy az aktu�lis param�terek t�pusa megegyezik-e a
form�lis
param�terek t�pus�val, �s v�grehajt minden szabv�nyos �s felhaszn�l�i
t�puskonverzi�t.
A t�mb�k �tad�s�ra egyedi szab�lyok vonatkoznak (�7.2.1), de van lehetos�g nem
ellenorz
�tt (�7.6) �s alap�rtelmezett param�terek (�7.5) �tad�s�ra is. Vegy�k a k�vetkezo
p�ld�t:
void f(int val, int& ref)
{
val++;
ref++;
}
194 Alapok
Amikor f() megh�v�dik, val++ az elso aktu�lis param�ter helyi m�solat�t n�veli,
ref++ pedig
a m�sodik aktu�lis param�tert. Az al�bbi
void g()
{
int i = 1;
int j = 1;
f(i,j);
}
j-t fogja n�velni, de i-t nem. Az elso param�ter (i) �rt�k szerint ad�dik �t, a
m�sodik (j) referencia
szerint. Amint �5.5-ben eml�tett�k, azok a f�ggv�nyek, melyek m�dos�tj�k a
referencia
szerint �tadott param�tereiket, nehezen olvashat�v� teszik a programot �s
�ltal�ban
ker�lendok (ellenben l�sd �21.3.2-et). �szrevehetoen hat�konyabb lehet, ha egy
nagy objektumot
referencia, nem pedig �rt�k szerint adunk �t. Ebben az esetben a param�tert
megadhatjuk const-k�nt, hogy jelezz�k, csak hat�konys�gi okokb�l haszn�lunk
referenci�t
�s nem szeretn�nk lehetov� tenni, hogy a h�vott f�ggv�ny m�dos�thassa az objektum
�rt�-
k�t:
void f(const Large& arg)
{
// "arg" �rt�ke nem m�dos�that�, csak explicit t�puskonverzi�val
}
A referencia-param�ter deklar�ci�j�ban a const elhagy�sa azt fejezi ki, hogy
sz�nd�kunkban
�ll a v�ltoz�t m�dos�tani:
void g(Large& arg); // t�telezz�k fel, hogy g() m�dos�tja arg-ot
Hasonl�an, a const-k�nt megadott mutat� param�ter azt jelzi az olvas�nak, hogy a
param�-
ter �ltal mutatott objektum �rt�k�t a f�ggv�ny nem v�ltoztatja meg:
int strlen(const char*); // karakterek sz�ma egy C st�lus�
// karakterl�ncban
char* strcpy(char* to, const char* from); // C st�lus� karakterl�nc m�sol�sa
int strcmp(const char*, const char*); // C st�lus� karakterl�ncok �sszehasonl�t�sa

A const param�terek haszn�lat�nak fontoss�ga a program m�ret�vel egy�tt no.


Jegyezz�k meg, hogy a param�ter�tad�s szerepe k�l�nb�zik a (nem kezdeti)
�rt�kad�s�t�l.
Ez a const param�terek, a referencia-param�terek, �s n�h�ny felhaszn�l�i t�pus�
param�ter
eset�ben l�nyeges (�10.4.4.1).
7. F�ggv�nyek 195
Liter�lt, �lland�t �s olyan param�tert, amely �talak�t�st ig�nyel, �t lehet adni
const& param
�terk�nt, de nem const&-k�nt nem. Mivel a const T& param�terek konverzi�ja
megengedett,
biztos�tott, hogy egy ilyen param�ternek pontosan ugyanazokat az �rt�keket lehet
adni, mint egy T t�pus� �rt�knek, az�ltal, hogy az �rt�ket ideiglenes v�ltoz�ban
adjuk �t
(amennyiben ez sz�ks�ges):
float fsqrt(const float&); // Fortran st�lus� sqrt referencia-param�terrel
void g(double d)
{
float r = fsqrt(2.0f); // a 2.0f-et tartalmaz� ideiglenes v�ltoz�ra hivatkoz�
// referencia �tad�sa
r = fsqrt(r); // r-re hivatkoz� referencia �tad�sa
r = fsqrt(d); // a float(d)-t tartalmaz� ideiglenes v�ltoz�ra hivatkoz� referencia

// �tad�sa
}
Mivel a nem const referencia t�pus� param�terek konverzi�ja nem megengedett, az
ideiglenes
v�ltoz�k bevezet�s�bol ad�d� buta hib�k elker�lhetok:
void update(float& i);
void g(double d, float r)
{
update(2.0f); // hiba: konstans param�ter
update(r); // r-re hivatkoz� referencia �tad�sa
update(d); // hiba: t�puskonverzi� sz�ks�ges
}
Ha ezek a h�v�sok szab�lyosak lenn�nek, az update() csendben m�dos�totta volna
azokat
az ideiglenes v�ltoz�kat, amelyek azonnal t�rlodtek. Ez rendszerint kellemetlen
meglepet
�sk�nt �rn� a programoz�t.
7.2.1. T�mb param�terek
Ha f�ggv�nyparam�terk�nt t�mb�t haszn�lunk, a t�mb elso elem�re hivatkoz� mutat�
ad�dik �t:
int strlen(const char*);
void f()
{
char v[ ] = "egy t�mb";
int i = strlen(v);
int j = strlen("Nicholas");
}
196 Alapok
Azaz egy T[ ] t�pus� param�ter T* t�pus�v� lesz alak�tva, ha param�terk�nt ad�dik
�t. Ebbol
az k�vetkezik, hogy ha egy param�terk�nt alkalmazott t�mb egy elem�hez �rt�ket
rendel
�nk, a t�mb param�ter is m�dosul, vagyis a t�mb�k abban k�l�nb�znek a t�bbi
t�pust�l,
hogy nem �rt�k szerint ad�dnak �t (ez nem is lehets�ges).
A t�mb m�rete nem hozz�f�rheto a h�vott f�ggv�ny sz�m�ra. Ez bosszant� lehet, de
t�bb
m�d van r�, hogy a probl�m�t megker�lj�k. A C st�lus� karakterl�ncok nulla
v�gzod�suek,
�gy m�ret�k k�nnyen kisz�m�that�. M�s t�mb�kn�l a m�retet egy tov�bbi param�terrel
adhatjuk
meg:
void compute1(int* vec_ptr, int vec_size); // egyik m�dszer
struct Vec {
int* ptr;
int size;
};
void compute2(const Vec& v); // m�sik m�dszer
V�laszthatjuk azt is, hogy t�mb�k helyett olyan t�pusokat haszn�lunk, mint a
vector (�3.7.1,
�16.3). A t�bbdimenzi�s t�mb�k n�mileg bonyolultabbak (l�sd �C.7), de helyett�k
gyakran
haszn�lhatunk mutat�kb�l �ll� t�mb�ket, melyek nem ig�nyelnek k�l�nleges
b�n�sm�dot:
char* day[ ] = {
"h�tfo", "kedd", "szerda", "cs�t�rt�k", "p�ntek", "szombat", "vas�rnap"
};
A vector �s a hozz� hasonl� t�pusok a be�p�tett, alacsonyszintu t�mb�k �s mutat�k
helyett
is haszn�lhat�k.
7.3. Visszat�r�si �rt�k
A main() kiv�tel�vel(�3.2) minden nem void-k�nt megadott f�ggv�nynek �rt�ket kell
visszaadnia. Megford�tva, a void f�ggv�nyek nem adhatnak vissza �rt�ket:
int f1() { } // hiba: nincs visszat�r�si �rt�k
void f2() { } // rendben
7. F�ggv�nyek 197
int f3() { return 1; } // rendben
void f4() { return 1; } // hiba: visszat�r�si �rt�k void f�ggv�nyben
int f5() { return; } // hiba: visszat�r�si �rt�k hi�nyzik
void f6() { return; } // rendben
A visszat�r�si �rt�ket a return utas�t�s hat�rozza meg:
int fac(int n) { return (n>1) ? n*fac(n-1) : 1; }
Az �nmagukat megh�v� f�ggv�nyeket rekurz�v (�jrah�v�) f�ggv�nyeknek nevezz�k.
Egy f�ggv�nyben t�bb return utas�t�s is lehet:
int fac2(int n)
{
if (n > 1) return n*fac2(n-1);
return 1;
}
A param�ter�tad�shoz hasonl�an a f�ggv�ny�rt�k visszaad�s�nak szerepe is azonos a
kezdeti
�rt�kad�s�val. A return utas�t�st �gy tekintj�k, hogy az egy visszat�r�si t�pus�,
n�v n�lk
�li v�ltoz�nak ad kezdo�rt�ket. A ford�t�program �sszehasonl�tja a return
kifejez�s t�pus
�t a visszat�r�si t�pussal �s minden szabv�nyos �s felhaszn�l�i t�pus�talak�t�st
v�grehajt:
double f() { return 1; } // 1 automatikusan double(1)-gy� alakul
Minden egyes alkalommal, amikor egy f�ggv�ny megh�v�dik, param�tereinek �s lok�lis

(automatikus) v�ltoz�inak egy �j m�solata j�n l�tre. A t�r a f�ggv�ny visszat�r�se


ut�n ism
�t felhaszn�l�sra ker�l, ez�rt lok�lis v�ltoz�ra hivatkoz� mutat�t soha nem szabad
visszaadni,
mert a mutatott hely tartalma kisz�m�thatatlan m�don megv�ltozhat:
int* fp() { int local = 1; /* ... */ return &local; } // rossz
Ez a hiba kev�sb� gyakori, mint referenci�t haszn�l� megfeleloje:
int& fr() { int local = 1; /* ... */ return local; } // rossz
Szerencs�re a ford�t�program �ltal�ban figyelmeztet, hogy lok�lis v�ltoz�ra
vonatkoz� hivatkoz
�st adtunk vissza.
198 Alapok
A void f�ggv�nyek nem adhatnak vissza �rt�ket, de megh�v�suk nem is eredm�nyez
ilyet,
k�vetkez�sk�ppen egy void f�ggv�ny return utas�t�s�ban szereplo kifejez�sk�nt
haszn�lhatunk
void f�ggv�nyt:
void g(int* p);
void h(int* p) { /* ... */ return g(p); } // rendben: �res visszat�r�si �rt�k
Ez a fajta visszat�r�s olyan sablon (template) f�ggv�nyek �r�s�n�l fontos, ahol a
visszat�r�-
si t�pus egy sablonparam�ter (l�sd �18.4.4.2).
7.4. T�lterhelt f�ggv�nynevek
A legt�bb esetben j� �tlet k�l�nb�zo f�ggv�nyeknek k�l�nb�zo neveket adni, de
amikor
egyes f�ggv�nyek l�nyeg�ben ugyanazt a muveletet v�gzik k�l�nb�zo t�pus�
objektumokon,
k�nyelmesebb lehet ugyan�gy elnevezni azokat. Azt, hogy k�l�nb�zo t�pusokra
vonatkoz
� muveletekre ugyanazt a nevet haszn�ljuk, t�lterhel�snek (overloading) nevezz�k.
Ez a m�dszer a C++ alapmuveletein�l is haszn�latos. Azaz, csak egyetlen .n�v. van
az
�sszead�sra (+), az m�gis haszn�lhat� eg�sz, lebegopontos, �s mutat� t�pus�
�rt�kek
�sszead�s�ra is. A gondolatot a programoz� �ltal k�sz�tett f�ggv�nyekre is
kiterjeszthetj�k:
void print(int); // eg�sz ki�r�sa
void print(const char*); // C st�lus� karakterl�nc ki�r�sa
Ami a ford�t�programot illeti, az egyetlen, ami k�z�s az azonos nevu
f�ggv�nyekben,
a n�v. A f�ggv�nyek feltehetoen hasonl�ak valamilyen �rtelemben, de a nyelv nem
korl�-
tozza �s nem is seg�ti a programoz�t. Ez�rt a t�lterhelt f�ggv�nynevek
elsodlegesen jel�l�sbeli
k�nyelmet adnak. Ez a k�nyelem az olyan hagyom�nyos nevu f�ggv�nyekn�l igaz�n
l�nyeges, mint az sqrt, print, �s open. Amikor a n�v jelent�se fontos, ez a
k�nyelem alapvet
ov� v�lik. Ez t�rt�nik p�ld�ul a +, * �s << oper�torok, a konstruktorok (�11.7),
valamint az
�ltal�nos�tott (generikus) programoz�s (�2.7.2, 18. fejezet) eset�ben. Amikor egy
f f�ggv�ny
megh�v�dik, a ford�t�programnak ki kell tal�lnia, melyik f nevu f�ggv�nyt h�vja
meg. Ezt
�gy teszi, hogy minden egyes f nevu f�ggv�ny form�lis param�tereinek t�pus�t
�sszehason
�tja az aktu�lis param�terek t�pus�val, majd azt a f�ggv�nyt h�vja meg, amelynek
param�-
terei a legjobban illeszkednek, �s ford�t�si ideju hib�t ad, ha nincs j�l
illeszkedo f�ggv�ny:
7. F�ggv�nyek 199
void print(double);
void print(long);
void f()
{
print(1L); // print(long)
print(1.0); // print(double)
print(1); // hiba, t�bb�rtelmu: print(long(1)) vagy print(double(1))?
}
A ford�t�program a t�lterhelt f�ggv�nyek halmaz�b�l �gy v�lasztja ki a megfelelo
v�ltozatot,
hogy megkeresi azt a f�ggv�nyt, amelyikn�l a h�v�s param�ter-kifejez�s�nek t�pusa
a legjobban illeszkedik a f�ggv�ny form�lis param�tereire. Ahhoz, hogy mindez
elv�r�sainknak
(k�zel�toen) megfelelo m�don t�rt�njen, az al�bbiakat kell megk�s�relni (ebben
a sorrendben):
1. Pontos illeszked�s: nincs sz�ks�g konverzi�ra vagy csak egyszeru konverzi�kat
kell v�gezni (p�ld�ul t�mb nev�t mutat�ra, f�ggv�ny nev�t f�ggv�nyre hivatkoz
� mutat�ra, vagy T-t const T-re).
2. Kiterjeszt�st haszn�l� illeszked�s: csak eg�sz �rt�kre kiterjeszt�s (integral
promotion) sz�ks�ges (bool-r�l int-re, char-r�l int-re, short-r�l int-re, illetve
ezek unsigned megfeleloirol int-re �C.6.1), valamint float-r�l double-ra.
3. Szabv�nyos konverzi�kat haszn�l� illeszked�s: int-rol double-ra, double-r�l
intre,
Derived*-r�l Base*-ra (�12.2), T*-r�l void*-ra (�5.6), vagy int-rol unsigned
int-re (�C.6).
4. Felhaszn�l�i konverzi�kat haszn�l� illeszked�s (�11.4).
5. F�ggv�nydeklar�ci�ban h�rom pontot (.) haszn�l� illeszked�s (�7.6).
Ha azon a szinten, ahol elosz�r tal�lunk megfelelo illeszked�st, k�t illeszked�st
is tal�lunk,
a h�v�st a ford�t� t�bb�rtelmuk�nt elutas�tja. A t�lterhel�st felold� szab�lyok
elsosorban
az�rt ennyire alaposan kidolgozottak, mert figyelembe kellett venni a C �s a C++
be�p�tett
numerikus t�pusokra vonatkoz� bonyolult szab�lyait (�C.6). Vegy�k a k�vetkezo
p�ld�t:
void print(int);
void print(const char*);
void print(double);
void print(long);
void print(char);
void h(char c, int i, short s, float f)
{
print(c); // pontos illeszked�s: print(char) megh�v�sa
print(i); // pontos illeszked�s: print(int) megh�v�sa
200 Alapok
print(s); // kiterjeszt�s eg�ssz�: print(int) megh�v�sa
print(f); // float kiterjeszt�se double-l�: print(double)
print('a'); // pontos illeszked�s: print(char) megh�v�sa
print(49); // pontos illeszked�s: print(int) megh�v�sa
print(0); // pontos illeszked�s: print(int) megh�v�sa
print("a"); // pontos illeszked�s: print(const char*) megh�v�sa
}
A print(0) h�v�s a print(int)-et h�vja meg, mert 0 egy int. A print('a') h�v�s a
print(char)-t,
mivel 'a' egy char (�4.3.1). Az �talak�t�sok (konverzi�k) �s a kiterjeszt�sek
k�z�tt az�rt
tesz�nk k�l�nbs�get, mert elonyben akarjuk r�szes�teni a biztons�gos
kiterjeszt�seket (p�ld
�ul char-r�l int-re) az olyan, nem biztons�gos muveletekkel szemben, mint az int-
rol
char-ra t�rt�no �talak�t�s.
A t�lterhel�s felold�sa f�ggetlen a sz�ba j�heto f�ggv�nyek deklar�ci�s
sorrendj�tol.
A t�lterhel�s viszonylag bonyolult szab�lyrendszeren alapul, �gy a programoz� n�ha
meglep
odhet azon, melyik f�ggv�ny h�v�dik meg. Ez azonban m�g mindig a kisebbik rossz.
Vegy
�k figyelembe a t�lterhel�s alternat�v�j�t: gyakran hasonl� muveleteket kell
v�grehajtanunk
t�bbf�le t�pus� objektumon. T�lterhel�s n�lk�l t�bb f�ggv�nyt kellene megadnunk,
k�l�nb�zo nevekkel:
void print_int(int);
void print_char(char);
void print_string(const char*); // C st�lus� karakterl�nc
void g(int i, char c, const char* p, double d)
{
print_int(i); // rendben
print_char(c); // rendben
print_string(p); // rendben
print_int(c); // rendben? print_int(int(c)) megh�v�sa
print_char(i); // rendben? print_char(char(i)) megh�v�sa
print_string(i); // hiba
print_int(d); // rendben? print_int(int(d)) megh�v�sa
}
A t�lterhelt print()-hez k�pest t�bb n�vre �s arra is eml�kezn�nk kell, hogy a
neveket helyesen
haszn�ljuk. Ez f�raszt� lehet, meghi�s�tja az �ltal�nos�tott programoz�sra
(�2.7.2) ir�-
nyul� erofesz�t�seket, �s �ltal�ban arra �szt�nzi a programoz�t, hogy viszonylag
alacsony
7. F�ggv�nyek 201
szintu t�pusokra ir�ny�tsa figyelm�t. Mivel nincs t�lterhel�s, ezen f�ggv�nyek
param�terein
b�rmilyen szabv�nyos konverzi�t elv�gezhet�nk, ami szint�n hib�khoz vezethet.
Ebbol az
k�vetkezik, hogy a fenti p�ld�ban a n�gy .hib�s. param�terrel val� h�v�s k�z�l
csak egyet
vesz �szre a ford�t�program. A t�lterhel�s n�veli annak az es�ly�t, hogy egy nem
megfelel
o param�tert a ford�t�program elutas�t.
7.4.1. A t�lterhel�s �s a visszat�r�si t�pus
A t�lterhel�s felold�s�n�l a visszat�r�si t�pust nem vessz�k figyelembe. Ez az�rt
sz�ks�ges,
hogy az egyes oper�torokra (�11.2.1, �11.2.4) vagy f�ggv�nyh�v�sra vonatkoz�
felold�s k�rnyezetf
�ggetlen maradjon. Vegy�k a k�vetkezot:
float sqrt(float);
double sqrt(double);
void f(double da, float fla)
{
float fl = sqrt(da); // sqrt(double) megh�v�sa
double d = sqrt(da); // sqrt(double) megh�v�sa
fl = sqrt(fla); // sqrt(float) megh�v�sa
d = sqrt(fla); // sqrt(float) megh�v�sa
}
Ha a visszat�r�si t�pust a ford�t�program figyelembe venn�, t�bb� nem lenne
lehets�ges,
hogy elszigetelten n�zz�k az sqrt() egy h�v�s�t �s eld�nts�k, azzal melyik
f�ggv�nyt h�vt�k
meg.
7.4.2. A t�lterhel�s �s a hat�k�r
A k�l�nb�zo, nem n�vt�r hat�k�rben megadott f�ggv�nyek nem t�lterheltek:
void f(int);
void g()
{
void f(double);
f(1); // f(double) megh�v�sa
}
202 Alapok
Vil�gos, hogy f(int) lett volna a legjobb illeszked�s f(1)-re, de a hat�k�rben
csak f(double)
l�that�. Az ilyen esetekben helyi deklar�ci�kat adhatunk a k�dhoz vagy t�r�lhetj�k
azokat,
hogy megkapjuk a k�v�nt viselked�st. Mint mindig, a sz�nd�kos elfed�s hasznos
m�dszer
lehet, a nem sz�nd�kos azonban meglepet�seket okozhat. Ha oszt�ly-hat�k�r�k
(�15.2.2)
vagy n�vt�r-hat�k�r�k (�8.2.9.2) k�z�tt �tny�l� t�lterhel�st szeretn�nk, using
deklar�ci�-
kat vagy using utas�t�sokat haszn�lhatunk (�8.2.2). L�sd m�g �8.2.6-ot.
7.4.3. A t�bb�rtelmus�g .k�zi. felold�sa
T�bb�rtelmus�ghez vezethet, ha egy f�ggv�nynek t�l sok (vagy t�l kev�s) t�lterhelt
v�ltozat
�t adjuk meg:
void f1(char);
void f1(long);
void f2(char*);
void f2(int*);
void k(int i)
{
f1(i); // t�bb�rtelmu: f1(char) vagy f1(long)
f2(0); // t�bb�rtelmu: f2(char*) vagy f2(int*)
}
Ahol lehets�ges, az ilyen esetekben �gy kell tekints�k egy f�ggv�ny t�lterhelt
v�ltozatainak
halmaz�t, mint eg�szet, �s gondoskodnunk kell r�la, hogy a v�ltozatok azonos
�rtelmuek
legyenek. Ez t�bbnyire �gy oldhat� meg, ha a f�ggv�nynek egy olyan �j v�ltozat�t
adjuk
hozz� az eddigiekhez, amely feloldja a t�bb�rtelmus�get:
inline void f1(int n) { f1(long(n)); }
A fenti f�ggv�nyv�ltozat hozz�ad�sa feloldja az �sszes f1(i)-hez hasonl�
t�bb�rtelmus�get
a sz�lesebb long int t�pus jav�ra.
A h�v�sok felold�s�ra t�pusk�nyszer�t�st is haszn�lhatunk:
f2(static_cast<int*>(0));
Ez azonban �ltal�ban cs�nya �s ideiglenes sz�ks�gmegold�s, hiszen a k�vetkezo .
hamarosan
bek�vetkezo . hasonl� f�ggv�nyh�v�ssal ism�t foglalkoznunk kell majd.
7. F�ggv�nyek 203
N�h�ny kezdo C++ programoz�t bosszantanak a ford�t�program �ltal ki�rt
t�bb�rtelmus�gi
hib�k, a tapasztaltabbak viszont becs�lik ezeket az �zeneteket, mert hasznos
jelzoi a tervez
�si hib�knak.
7.4.4. T�bb param�ter felold�sa
A t�lterhel�st felold� szab�lyok alapj�n biztos�thatjuk, hogy a legegyszerubb
algoritmus
(f�ggv�ny) lesz felhaszn�lva, amikor a sz�m�t�sok hat�konys�ga �s pontoss�ga
jelentosen
k�l�nb�zik a sz�ban forg� t�pusokn�l:
int pow(int, int);
double pow(double, double);
complex pow(double, complex);
complex pow(complex, int);
complex pow(complex, double);
complex pow(complex, complex);
void k(complex z)
{
int i = pow(2,2); // pow(int,int) megh�v�sa
double d = pow(2.0,2.0); // pow(double,double) megh�v�sa
complex z2 = pow(2,z); // pow(double,complex) megh�v�sa
complex z3 = pow(z,2); // pow(complex,int) megh�v�sa
complex z4 = pow(z,z); // pow(complex,complex) megh�v�sa
}
A ketto vagy t�bb param�teru t�lterhelt f�ggv�nyek k�z�tti v�laszt�s folyam�n
minden param
�terre kiv�laszt�dik a legjobban illeszkedo f�ggv�ny, a �7.4 szab�lyai alapj�n. Az

a f�ggv�ny h�v�dik meg, amely az adott param�terre a legjobban, a t�bbire pedig


jobban
vagy ugyan�gy illeszkedik. Ha nem l�tezik ilyen f�ggv�ny, a h�v�st a ford�t�
t�bb�rtelmu-
k�nt elutas�tja:
void g()
{
double d = pow(2.0,2); // hiba: pow(int(2.0),2) vagy pow(2.0,double(2))?
}
A f�ggv�nyh�v�s az�rt t�bb�rtelmu, mert a pow (double,double) elso param�ter�re
2.0,
a pow(int,int) m�sodik param�ter�re pedig 2 a legjobb illeszked�s.
204 Alapok
7.5. Alap�rtelmezett param�terek
Egy �ltal�nos f�ggv�nynek �ltal�ban t�bb param�terre van sz�ks�ge, mint amennyi az
egyszer
u esetek kezel�s�hez kell. Nevezetesen az objektumokat (�10.2.3) l�trehoz� f�ggv�-

nyek gyakran sz�mos lehetos�get ny�jtanak a rugalmass�g �rdek�ben. Vegy�nk egy


f�ggv
�nyt, amely egy eg�szt �r ki. �sszerunek l�tszik megadni a felhaszn�l�nak a
lehetos�get,
hogy meghat�rozza, milyen sz�mrendszerben �rja ki a f�ggv�ny az eg�szt, a legt�bb
program
azonban az eg�szeket t�zes sz�mrendszer szerint �rja ki. P�ld�ul a
void print(int value, int base =10); // az alap�rtelmezett alap 10
void f()
{
print(31);
print(31,10);
print(31,16);
print(31,2);
}
ezt a kimenetet eredm�nyezheti:
31 31 1f 11111
Az alap�rtelmezett (default) param�ter hat�s�t el�rhetj�k t�lterhel�ssel is:
void print(int value, int base);
inline void print(int value) { print(value,10); }
A t�lterhel�s viszont kev�sb� teszi nyilv�nval�v� az olvas� sz�m�ra, hogy az a
sz�nd�kunk,
hogy legyen egy egyszeru print f�ggv�ny�nk �s egy r�vid�t�s�nk.
Az alap�rtelmezett param�ter t�pus�nak ellenorz�se a f�ggv�ny deklar�ci�jakor
t�rt�nik �s
a param�ter a f�ggv�ny h�v�sakor �rt�kelodik ki. Alap�rtelmezett �rt�keket csak a
z�r� param
�tereknek adhatunk:
int f(int, int =0, char* =0); // rendben
int g(int =0, int =0, char*); // hiba
int h(int =0, int, char* =0); // hiba
7. F�ggv�nyek 205
Jegyezz�k meg, hogy a * �s az = k�z�tti sz�k�z l�nyeges (a *= �rt�kad� oper�tor,
�6.2):
int nasty(char*=0); // szintaktikus hiba
Az alap�rtelmezett param�terek ugyanabban a hat�k�rben egy k�sobbi deklar�ci�val
nem
ism�telhetok meg �s nem m�dos�that�k:
void f(int x = 7);
void f(int = 7); // hiba: az alap�rtelmezett param�ter nem adhat� meg k�tszer
void f(int = 8); // hiba: k�l�nb�zo alap�rtelmezett param�terek
void g()
{
void f(int x = 9); // rendben: ez a deklar�ci� elfedi a k�lsot
// ...
}
Hibalehetos�get rejt mag�ban, ha egy nevet �gy adunk meg egy be�gyazott
hat�k�rben,
hogy a n�v elfedi ugyanannak a n�vnek egy k�lso hat�k�rben levo deklar�ci�j�t.
7.6. Nem meghat�rozott sz�m� param�ter
N�h�ny f�ggv�ny eset�ben nem hat�rozhat� meg a h�v�sban elv�rt param�terek sz�ma
�s
t�pusa. Az ilyen f�ggv�nyeket �gy adhatjuk meg, hogy a param�ter-deklar�ci�k
list�j�t a .
jel�l�ssel z�rjuk le, melynek jelent�se .�s tal�n n�h�ny tov�bbi param�ter.:
int printf(const char* ...);
A fenti azt hat�rozza meg, hogy a C standard k�nyvt�r�nak printf() f�ggv�nye
(�21.8)
megh�v�sakor legal�bb egy char* t�pus� param�tert v�r, de lehet, hogy van m�s
param�tere
is:
printf("Hell�, vil�g!\n");
printf("A nevem %s %s\n", vezetek_nev, kereszt_nev);
printf("%d + %d = %d\n",2,3,5);
206 Alapok
Az ilyen f�ggv�nyek olyan adatokra t�maszkodnak, amelyek nem el�rhetok a
ford�t�program
sz�m�ra, amikor az a param�terek list�j�t �rtelmezi. A printf() eset�ben az elso
param
�ter egy form�tum-vez�rlo, amely egyedi karaktersorozatokat tartalmaz, lehetov�
t�ve,
hogy a printf() helyesen kezelje a t�bbi param�tert: a %s p�ld�ul azt jelenti,
hogy .v�rj egy
char* param�tert., a %d pedig azt, hogy .v�rj egy int param�tert.. A
ford�t�program viszont
�ltal�ban nem tudhatja (�s nem is biztos�thatja), hogy a v�rt param�terek t�nyleg
ott vannak
�s megfelelo t�pus�ak-e:
#include <stdio.h>
int main()
{
printf("A nevem %s %s\n",2);
}
A fenti k�dot a ford�t� leford�tja �s (a legjobb esetben) furcs�nak l�tsz�
kimenetet hoz l�tre.
(Pr�b�ljuk ki!)
Term�szetesen ha egy param�ter nem deklar�lt, a ford�t�program nem fog elegendo
inform
�ci�val rendelkezni a szabv�nyos t�pusellenorz�s �s -konverzi� elv�gz�s�hez. Ebben
az
esetben egy short vagy egy char int-k�nt ad�dik �t, egy float pedig double-k�nt, a
programoz
� pedig nem felt�tlen�l ezt v�rja.
Egy j�l megtervezett programban legfeljebb n�h�ny olyan f�ggv�nyre van sz�ks�g,
melynek
param�terei nem teljesen meghat�rozottak. A t�lterhelt vagy alap�rtelmezett
param�tereket
haszn�l� f�ggv�nyek arra haszn�lhat�k, hogy megoldj�k a t�pusellenorz�st a legt�bb

olyan esetben, amikor a param�terek t�pus�t sz�ks�gbol meghat�rozatlanul hagyjuk.


A h�-
rom pont csak akkor sz�ks�ges, ha a param�terek sz�ma �s t�pusa is v�ltozik.
Leggyakrabban
akkor haszn�ljuk, amikor olyan C k�nyvt�ri f�ggv�nyekhez k�sz�t�nk fel�letet,
amelyek m�g nem haszn�lj�k ki a C++ �ltal ny�jtott �jabb lehetos�geket:
int fprintf(FILE*, const char* ...); // a <cstdio> fej�llom�nyb�l
int execl(const char* ...); // UNIX fej�llom�nyb�l
A <cstdarg> fej�llom�nyban szabv�nyos makr�kat tal�lunk, melyekkel hozz�f�rhet�nk
az
ilyen f�ggv�nyek nem meghat�rozott param�tereihez. K�pzelj�k el, hogy egy olyan
hibaf
�ggv�nyt �runk, amelynek van egy eg�sz param�tere, ami a hiba s�lyoss�g�t jelzi,
�s ezt
tetszoleges hossz�s�g� (t�bb karakterl�ncb�l �ll�) sz�veg k�veti. Elk�pzel�s�nk
az, hogy
�gy hozzuk l�tre a hiba�zenetet, hogy minden sz�t k�l�n karakterl�nc param�terk�nt

adunk �t. Ezen param�terek list�j�t egy char-ra hivatkoz� .nullpointer. kell, hogy
lez�rja:
7. F�ggv�nyek 207
extern void error(int ...);
extern char* itoa(int, char[ ]); // l�sd �6.6.[17]
const char* Null_cp = 0;
int main(int argc, char* argv[ ])
{
switch (argc) {
case 1:
error(0,argv[0],Null_cp);
break;
case 2:
error(0,argv[0],argv[1],Null_cp);
break;
default:
char buffer[8];
error(1,argv[0], "with",itoa(argc-1,buffer),"arguments", Null_cp);
}
// ...
}
Az itoa() azt a karakterl�ncot adja vissza, amelyik a f�ggv�ny eg�sz t�pus�
param�ter�nek
felel meg.
Vegy�k �szre, hogy ha a 0 eg�sz �rt�ket haszn�ltuk volna befejez�sk�nt, a k�d nem
lett volna
hordozhat�: n�h�ny nyelvi megval�s�t�s a nulla eg�szt �s a nulla mutat�t
(nullpointer)
nem azonos m�don �br�zolja. Ez a p�lda szeml�lteti a neh�zs�geket �s azt a
t�bbletmunk
�t, amellyel a programoz� szemben�z, amikor a t�pusellenorz�st .elnyomja. a h�rom
pont.
A hibaf�ggv�nyt �gy adhatjuk meg:
void error(int severity ...) // a "severity" (s�lyoss�g) ut�n null�val lez�rt
char*-ok
// k�vetkeznek
{
va_list ap;
va_start(ap,severity); // kezdeti param�terek
for (;;) {
char* p = va_arg(ap,char*);
if (p == 0) break;
cerr << p << ' ';
}
va_end(ap); // param�terek vissza�ll�t�sa
cerr << '\n';
if (severity) exit(severity);
}
208 Alapok
Elosz�r meghat�rozzuk a va_list-et �s a va_start() megh�v�s�val �rt�ket adunk
neki.
A va_start makr� param�terei a va_list neve �s az utols� form�lis param�ter neve.
A va_arg() makr�t arra haszn�ljuk, hogy sorba rendezz�k a nem megnevezett
param�tereket.
A programoz�nak minden egyes h�v�skor meg kell adnia egy t�pust; a va_arg() felt�-

telezi, hogy ilyen t�pus� aktu�lis param�ter ker�lt �tad�sra, de �ltal�ban nincs
m�d arra,
hogy ezt biztos�tani is tudja. Mielott m�g visszat�rn�nk egy olyan f�ggv�nybol,
ahol
a va_start()-ot haszn�ltuk, meg kell h�vnunk a va_end()-et. Ennek az az oka, hogy
a va_start() �gy m�dos�thatja a vermet, hogy a visszat�r�st nem lehet sikeresen
v�ghezvinni.
A va_end() helyre�ll�tja ezeket a m�dos�t�sokat.
7.7. F�ggv�nyre hivatkoz� mutat�k
A f�ggv�nyekkel csak k�t dolgot csin�lhatunk: megh�vhatjuk oket �s
felhaszn�lhatjuk a c�-
m�ket. Amikor a f�ggv�ny c�m�t vessz�k, az �gy kapott mutat�t haszn�lhatjuk arra,
hogy
megh�vjuk a f�ggv�nyt:
void error(string s) { /* ... */ }
void (*efct)(string); // mutat� f�ggv�nyre
void f()
{
efct = &error; // efct az error f�ggv�nyre mutat
efct("error"); // error megh�v�sa efct-n kereszt�l
}
A ford�t�program r� fog j�nni, hogy efct egy mutat� �s megh�vja az �ltala mutatott
f�ggv
�nyt. Azaz, egy f�ggv�nyre hivatkoz� mutat�t nem k�telezo a * oper�torral
feloldanunk.
Ugyan�gy nem k�telezo a & haszn�lata sem a f�ggv�ny c�m�nek lek�rdez�s�re:
void (*f1)(string) = &error; // rendben
void (*f2)(string) = error; // ez is j�; jelent�se ugyanaz, mint az &error-nak
void g()
{
f1("Vasa"); // rendben
(*f1)("Mary Rose"); // ez is j�
}
A f�ggv�nyekre hivatkoz� mutat�k param�tereinek t�pus�t ugyan�gy meg kell adnunk,
mint a f�ggv�nyekn�l. A mutat�kat haszn�l� �rt�kad�sokban �gyelni kell a teljes
f�ggv�ny
t�pus�ra:
7. F�ggv�nyek 209
void (*pf)(string); // mutat� void(string)-re
void f1(string); // void(string)
int f2(string); // int(string)
void f3(int*); // void(int*)
void f()
{
pf = &f1; // rendben
pf = &f2; // hiba: rossz visszat�r�si t�pus
pf = &f3; // hiba: rossz param�tert�pus
pf("H�ra"); // rendben
pf(1); // hiba: rossz param�tert�pus
int i = pf("Zeusz"); // hiba: void �rt�kad�s int-nek
}
A param�ter�tad�s szab�lyai a k�zvetlen f�ggv�nyh�v�sok �s a f�ggv�nyek mutat�n
kereszt
�l t�rt�no megh�v�sa eset�ben ugyanazok. Gyakran k�nyelmes, ha nevet adunk egy
f�ggv
�nyre hivatkoz� mutat� t�pusnak, hogy ne mindig a meglehetosen nehezen �rtheto
deklar
�ci�form�t haszn�ljuk. �me egy p�lda egy UNIX-os rendszer-fej�llom�nyb�l:
typedef void (*SIG_TYP)(int); // a <signal.h> fej�llom�nyb�l
typedef void (*SIG_ARG_TYP)(int);
SIG_TYP signal(int, SIG_ARG_TYP);
A f�ggv�nyekre hivatkoz� mutat�kb�l �ll� t�mb�k gyakran hasznosak. P�ld�ul az
egeret
haszn�l� sz�vegszerkesztom men�rendszere az egyes muveleteket jel�lo f�ggv�nyekre
hivatkoz
� mutat�kb�l �ssze�ll�tott t�mb�kkel van megval�s�tva. Itt nincs lehetos�g�nk,
hogy
a rendszert r�szletesen ismertess�k, de az alapveto �tlet ez:
typedef void (*PF)();
PF edit_ops[ ] = { // szerkesztomuveletek
&cut, &paste, &copy, &search
};
PF file_ops[ ] = { // f�jlkezel�s
&open, &append, &close, &write
};
Az eg�r gombjaival kiv�lasztott men�pontokhoz kapcsol�d� muveleteket vez�rlo
mutat�-
kat �gy hat�rozhatjuk meg �s t�lthetj�k fel �rt�kkel:
PF* button2 = edit_ops;
PF* button3 = file_ops;
210 Alapok
A teljes megval�s�t�shoz t�bb inform�ci�ra van sz�ks�g ahhoz, hogy minden
men�elemet
meghat�rozhassunk. P�ld�ul t�rolnunk kell valahol azt a karakterl�ncot, amelyik
meghat�-
rozza a ki�rand� sz�veget. Ahogy a rendszert haszn�ljuk, az eg�rgombok jelent�se
gyakran
megv�ltozik a k�rnyezettel egy�tt. Az ilyen v�ltoz�sokat (r�szben) �gy hajtjuk
v�gre, hogy
m�dos�tjuk a gombokhoz kapcsolt mutat�k �rt�k�t. Amikor a felhaszn�l� kiv�laszt
egy men
�pontot (p�ld�ul a 3-as elemet a 2-es gomb sz�m�ra), a megfelelo muvelet hajt�dik
v�gre:
button2[2](); // button2 harmadik f�ggv�ny�nek megh�v�sa
Akkor tudn�nk igaz�n nagyra �rt�kelni a f�ggv�nyekre hivatkoz� mutat�k
kifejezoerej�t,
ha n�lk�l�k pr�b�ln�nk ilyen k�dot �rni . �s m�g jobban viselkedo rokonaik, a
virtu�lis
f�ggv�nyek (�12.2.6) n�lk�l. Egy men�t fut�si idoben �gy m�dos�thatunk, hogy �j
f�ggv�-
nyeket tesz�nk a muvelett�bl�ba, de �j men�ket is k�nnyen l�trehozhatunk.
A f�ggv�nyekre hivatkoz� mutat�k arra is haszn�lhat�k, hogy a t�bbalak� (polimorf)
elj�-
r�sok . azaz amelyeket t�bb, k�l�nb�zo t�pus� objektumra lehet alkalmazni .
egyszeru form
�j�t adj�k:
typedef int (*CFT)(const void*, const void*);
void ssort(void* base, size_t n, size_t sz, CFT cmp)
/*
A "base" vektor "n" elem�nek rendez�se n�vekvo sorrendbe
a "cmp" �ltal mutatott �sszehasonl�t� f�ggv�ny seg�ts�g�vel.
Az elemek "sz" m�retuek.
Shell rendez�s (Knuth, 3. k�tet, 84.o.)
*/
{
for (int gap=n/2; 0<gap; gap/=2)
for (int i=gap; i<n; i++)
for (int j=i-gap; 0<=j; j-=gap) {
char* b = static_cast<char*>(base); // sz�ks�ges t�pusk�nyszer�t�s
char* pj = b+j*sz; // &base[j]
char* pjg = b+(j+gap)*sz; // &base[j+gap]
if (cmp(pjg,pj)<0) { // base[j] �s base[j+gap] felcser�l�se
for (int k=0; k<sz; k++) {
char temp = pj[k];
pj[k] = pjg[k];
pjg[k] = temp;
}
}
}
}
7. F�ggv�nyek 211
Az ssort() nem ismeri azoknak az objektumoknak a t�pus�t, amelyeket rendez, csak
az elemek
sz�m�t (a t�mb m�ret�t), az egyes elemek m�ret�t, �s azt a f�ggv�nyt, melyet meg
kell
h�vnia, hogy elv�gezze az �sszehasonl�t�st. Az ssort() t�pus�t �gy v�lasztottuk
meg, hogy
megegyezzen a szabv�nyos C k�nyvt�ri qsort() rendezo elj�r�s t�pus�val. A val�di
programok
a qsort()-ot, a C++ standard k�nyvt�r�nak sort algoritmus�t (�18.7.1), vagy egyedi
rendez
o elj�r�st haszn�lnak. Ez a k�dol�si st�lus gyakori C-ben, de nem a legeleg�nsabb
m�dja,
hogy ezt az algoritmust C++-ban �rjuk le (l�sd �13.3, �13.5.2).
Egy ilyen rendezo f�ggv�nyt a k�vetkezok�ppen lehetne egy t�bl�zat rendez�s�re
haszn�lni:
struct User {
char* name;
char* id;
int dept;
};
User heads[ ] = {
"Ritchie D.M.", "dmr", 11271,
"Sethi R.", "ravi", 11272,
"Szymanski T.G.", "tgs", 11273,
"Schryer N.L.", "nls", 11274,
"Schryer N.L.", "nls", 11275,
"Kernighan B.W.", "bwk", 11276
};
void print_id(User* v, int n)
{
for (int i=0; i<n; i++)
cout << v[i].name << '\t' << v[i].id << '\t' << v[i].dept << '\n';
}
Elosz�r meg kell hat�roznunk a megfelelo �sszehasonl�t� f�ggv�nyeket, hogy
rendezni
tudjunk. Az �sszehasonl�t� f�ggv�nynek negat�v �rt�ket kell visszaadnia, ha az
elso param
�tere kisebb, mint a m�sodik, null�t, ha param�terei egyenloek, egy�b esetben
pedig pozit
�v sz�mot:
int cmp1(const void* p, const void* q) // nevek (name) �sszehasonl�t�sa
{
return strcmp(static_cast<const User*>(p)->name,static_cast<const User*>(q)-
>name);
}
int cmp2(const void* p, const void* q) // oszt�lyok (dept) �sszehasonl�t�sa
{
return static_cast<const User*>(p)->dept - static_cast<const User*>(q)->dept;
}
212 Alapok
Ez a program rendez �s ki�r:
int main()
{
cout << "Fon�k�k �b�c�sorrendben:\n";
ssort(heads,6,sizeof(User),cmp1);
print_id(heads,6);
cout << '\n';
cout << "Fon�k�k oszt�lyok szerint:\n";
ssort(heads,6,sizeof(User),cmp2);
print_id(heads,6);
}
Egy t�lterhelt f�ggv�ny c�m�t �gy haszn�lhatjuk fel, hogy egy f�ggv�nyre hivatkoz�
mutat
�hoz rendelj�k vagy annak kezdo�rt�k�l adjuk. Ebben az esetben a c�l t�pusa
alapj�n v�-
lasztunk a t�lterhelt f�ggv�nyek halmaz�b�l:
void f(int);
int f(char);
void (*pf1)(int) = &f; // void f(int)
int (*pf2)(char) = &f; // int f(char)
void (*pf3)(char) = &f; // hiba: nincs void f(char)
Egy f�ggv�nyt egy f�ggv�nyre hivatkoz� mutat�n kereszt�l pontosan a megfelelo
param�-
ter- �s visszat�r�si t�pusokkal kell megh�vni. Ezen t�pusokra vonatkoz�an nincs
automatikus
konverzi�, ha f�ggv�nyekre hivatkoz� mutat�kat adunk �rt�k�l vagy t�lt�nk fel
kezdo�rt�kkel.
Ez azt jelenti, hogy
int cmp3(const mytype*,const mytype*);
nem megfelelo param�ter az ssort() sz�m�ra. Ha cmp3-at elfogadn�nk az ssort
param�terek
�nt, megszegn�nk azt a v�llal�st, hogy a cmp3-at mytype* t�pus� param�terekkel
fogjuk
megh�vni (l�sd m�g �9.2.5-�t).
7. F�ggv�nyek 213
7.8. Makr�k
A makr�k nagyon fontosak a C-ben, de kevesebb a hasznuk a C++-ban. Az elso
makr�kra
vonatkoz� szab�ly: ne haszn�ljuk oket, ha nem sz�ks�gesek. Majdnem minden makr�
a programoz�si nyelv, a program, vagy a programoz� gyenge pontj�t mutatja. Mivel
�trendezik
a programk�dot, mielott a ford�t�program l�tn� azt, sz�mos programoz�si eszk�z
sz�-
m�ra komoly probl�m�t jelentenek. �gy ha makr�t haszn�lunk, sz�m�thatunk arra,
hogy az
olyan eszk�z�k, mint a hibakeresok, kereszthivatkoz�s-vizsg�l�k �s
hat�konys�gvizsg�l�k
gyeng�bb szolg�ltat�st fognak ny�jtani. Ha makr�t kell haszn�lnunk, olvassuk el
figyelmesen
C++-v�ltozatunk eloford�t�j�nak (preprocessor) hivatkoz�si k�zik�nyv�t �s ne
pr�b�ljunk
t�l okosak lenni. K�vess�k azt a szok�st, hogy a makr�kat �gy nevezz�k el, hogy
sok
nagybetu legyen benn�k. A makr�k formai k�vetelm�nyeit az �A.11 mutatja be.
Egy egyszeru makr�t �gy adhatunk meg:
#define NAME a sor marad�k r�sze
ahol a NAME szimb�lum elofordul, ott kicser�lodik a sor marad�k r�sz�re. P�ld�ul a

named = NAME
kifejez�st a k�vetkezo v�ltja fel:
named = a sor marad�k r�sze
Megadhatunk param�terekkel rendelkezo makr�t is:
#define MAC(x,y) argument1: x argument2: y
Amikor MAC-ot haszn�ljuk, param�terk�nt meg kell adnunk k�t karakterl�ncot. Ezek
x-et
�s y-t fogj�k helyettes�teni, amikor MAC behelyettes�todik. P�ld�ul a
expanded = MAC(foo bar, yuk yuk)
�gy alakul �t:
expanded = argument1: foo bar argument2: yuk yuk
214 Alapok
A makr�neveket nem terhelhetj�k t�l �s a makr�-eloford�t� rekurz�v h�v�sokat sem
tud
kezelni:
#define PRINT(a,b) cout<<(a)<<(b)
#define PRINT(a,b,c) cout<<(a)<<(b)<<(c) /* probl�m�s?: �jb�li defin�ci�, nem
t�lterhel�s */
#define FAC(n) (n>1)?n*FAC(n-1):1 /* probl�m�s: rekurz�v makr� */
A makr�k karakterl�ncokat kezelnek, keveset tudnak a C++ nyelvtan�r�l �s semmit
sem
a C++ t�pusair�l, illetve a hat�k�r�k szab�lyair�l. A ford�t�program csak a makr�
behelyettes
�tett form�j�t l�tja, �gy akkor jelzi a makr�ban l�vo esetleges hib�t, amikor a
makr� behelyettes
�todik, �s nem akkor, amikor a makr�t kifejtj�k, ami nagyon hom�lyos
hiba�zenetekhez
vezet.
�me n�h�ny lehets�ges makr�:
#define CASE break;case
#define FOREVER for(;;)
N�h�ny teljesen f�l�sleges makr�:
#define PI 3.141593
#define BEGIN {
#define END }
�s n�h�ny vesz�lyes makr�:
#define SQUARE(a) a*a
#define INCR_xx (xx)++
Hogy l�ssuk, mi�rt vesz�lyesek, pr�b�ljuk meg behelyettes�teni ezt:
int xx = 0; // glob�lis sz�ml�l�
void f()
{
int xx = 0; // lok�lis v�ltoz�
int y = SQUARE(xx+2); // y=xx+2*xx+2 vagyis y=xx+(2*xx)+2
INCR_xx; // a lok�lis xx n�vel�se
}
7. F�ggv�nyek 215
Ha makr�t kell haszn�lnunk, haszn�ljuk a :: hat�k�r-jelzot, amikor glob�lis
nevekre (�4.9.4)
hivatkozunk, �s a makr� param�terek elofordul�sait tegy�k z�r�jelbe, ahol csak
lehets�ges:
#define MIN(a,b) (((a)<(b))?(a):(b))
Ha bonyolult makr�kat kell �rnunk, amelyek megjegyz�sekre szorulnak, b�lcs
dolog /* */
megjegyz�seket haszn�lnunk, mert a C++ eszk�z�k r�szek�nt n�ha C eloford�t�kat
haszn�lnak,
ezek viszont nem ismerik a // jel�l�st:
#define M2(a) something(a) /* �rtelmes megjegyz�s */
Makr�k haszn�lat�val megtervezhetj�k saj�t, egy�ni nyelv�nket. Ha azonban ezt a
.kibov�-
tett nyelvet. r�szes�tj�k elonyben a sima C++-szal szemben, az a legt�bb C++
programoz�
sz�m�ra �rthetetlen lesz. Tov�bb� a C eloford�t� egy nagyon egyszeru makr�-
feldolgoz�.
Ha valami nem mag�t�l �rtetodot akarunk csin�lni, akkor az vagy lehetetlennek,
vagy sz�ks
�gtelen�l neh�znek bizonyulhat. A const, inline, template, enum �s namespace
megold�sokat arra sz�nt�k, hogy a hagyom�nyos eloford�tott szerkezeteket
kiv�lts�k:
const int answer = 42;
template<class T> inline T min(T a, T b) { return (a<b)?a:b; }
Amikor makr�t �runk, nem ritka, hogy egy �j n�vre van sz�ks�g�nk valami sz�m�ra.
K�t karakterl
�ncot a ## makr�oper�torral �sszefuzve p�ld�ul �j karakterl�ncot hozhatunk l�tre:
#define NAME2(a,b) a##b
int NAME2(hack,cah)();
Ez a k�vetkezot eredm�nyezi a ford�t�program sz�m�ra:
int hackcah();
A
#undef X
utas�t�s biztos�tja, hogy X nevu makr� nem lesz defini�lva . akkor sem, ha az
utas�t�s elott
szerepelt ilyen. Ez bizonyos v�delmet ad a nem k�v�nt makr�k ellen, de nem
tudhatjuk,
hogy egy k�dr�szletben mit felt�telezz�nk X hat�sair�l.
216 Alapok
7.8.1. Felt�teles ford�t�s
A makr�k egy bizonyos haszn�lat�t majdnem lehetetlen elker�lni. Az #ifdef
azonos�t�
direkt�va arra utas�tja a ford�t�programot, hogy felt�telesen minden bemenetet
figyelmen
k�v�l hagyjon, am�g az #endif utas�t�ssal nem tal�lkozik. P�ld�ul az
int f(int a
#ifdef arg_two
,int b
#endif
);
k�dr�szletbol a ford�t�program ennyit l�t (kiv�ve ha az arg_two nevu makr�t a
#define
eloford�t� direkt�v�val kor�bban defini�ltuk):
int f(int a
);
Ez megzavarja azokat az eszk�z�ket, amelyek �sszeru viselked�st t�teleznek fel a
programoz
�r�l.
Az #ifdef legt�bb felhaszn�l�sa kev�sb� bizarr, �s ha m�rs�klettel haszn�lj�k,
kev�s k�rt
okoz. L�sd m�g �9.3.3-at.
Az #ifdef-et vez�rlo makr�k neveit figyelmesen kell megv�lasztani, hogy ne
�tk�zzenek
a szok�sos azonos�t�kkal:
struct Call_info {
Node* arg_one;
Node* arg_two;
// ...
};
Ez az �rtatlannak l�tsz� forr�ssz�veg zavart fog okozni, ha valaki a k�vetkezot
�rja:
#define arg_two x
Sajnos a szokv�nyos �s elker�lhetetlen�l be�p�tendo fej�llom�nyok sok vesz�lyes �s
sz�ks
�gtelen makr�t tartalmaznak.
7. F�ggv�nyek 217
7.9. Tan�csok
[1] Legy�nk gyanakv�ak a nem const referencia param�terekkel kapcsolatban; ha
azt akarjuk, hogy a f�ggv�ny m�dos�tsa param�ter�t, haszn�ljunk ink�bb mutat
�kat �s �rt�k szerinti visszaad�st. �5.5.
[2] Haszn�ljunk const referencia param�tereket, ha a leheto legritk�bbra kell
cs�kkenten
�nk a param�terek m�sol�s�t. �5.5.
[3] Haszn�ljuk a const-ot sz�lesk�ruen, de k�vetkezesen. �7.2.
[4] Ker�lj�k a makr�kat. �7.8.
[5] Ker�lj�k a nem meghat�rozott sz�m� param�terek haszn�lat�t. �7.6.
[6] Ne adjunk vissza lok�lis v�ltoz�kra hivatkoz� mutat�kat vagy ilyen
referenci�kat. �7.3.
[7] Akkor haszn�ljuk a t�lterhel�st, ha a f�ggv�nyek elvben ugyanazt a muveletet
hajtj�k v�gre k�l�nb�zo t�pusokon. �7.4.
[8] Amikor eg�szekre vonatkozik a t�lterhel�s, haszn�ljunk f�ggv�nyeket, hogy
megsz�ntess�k a t�bb�rtelmus�get. �7.4.3.
[9] Ha f�ggv�nyre hivatkoz� mutat� haszn�lat�t fontolgatjuk, vizsg�ljuk meg, hogy
egy virtu�lis f�ggv�ny (�2.5.5) vagy sablon (�2.7.2) haszn�lata nem jobb megold
�s-e. �7.7.
[10] Ha makr�kat kell haszn�lnunk, haszn�ljunk cs�nya neveket, sok nagybetuvel.
�7.8.
7.10. Gyakorlatok
1. (*1) Deklar�ljuk a k�vetkezoket: f�ggv�ny, amelynek egy karakterre hivatkoz�
mutat� �s egy eg�szre mutat� referencia param�tere van �s nem ad vissza �rt�-
ket; ilyen f�ggv�nyre hivatkoz� mutat�; f�ggv�ny, amelynek ilyen mutat� param
�tere van; f�ggv�ny, amely ilyen mutat�t ad vissza. �rjuk meg azt a f�ggv�nyt,
amelynek egy ilyen mutat�j� param�tere van �s visszat�r�si �rt�kk�nt param�-
ter�t adja vissza. Tipp: haszn�ljunk typedef-et.
2. (*1) Mit jelent a k�vetkezo sor? Mire lehet j�?
typedef int (&rifii) (int, int);
218 Alapok
3. (*1,5) �rjunk egy .Hell�, vil�g!.-szeru programot, ami parancssori
param�terk�nt
vesz egy nevet �s ki�rja, hogy .Hell�, n�v!.. M�dos�tsuk ezt a programot �gy,
hogy tetszoleges sz�m� n�v param�tere lehessen �s mondjon hell�t minden
egyes n�vvel.
4. (*1,5) �rjunk olyan programot, amely tetszoleges sz�m� f�jlt olvas be, melyek
nevei parancssori param�terk�nt vannak megadva, �s ki�rja azokat egym�s ut�n
a cout-ra. Mivel ez a program �sszefuzi a param�tereit, hogy megkapja a kimenetet,

elnevezhetj�k cat-nek.
5. (*2) Alak�tsunk egy kis C programot C++ programm�. M�dos�tsuk a fej�llom�-
nyokat �gy, hogy minden megh�vott f�ggv�ny deklar�lva legyen �s hat�rozzuk
meg minden param�ter t�pus�t. Ahol lehets�ges, cser�lj�k ki a #define utas�t�sokat

enum-ra, const-ra vagy inline-ra. T�vol�tsuk el az extern deklar�ci�kat a .c


f�jlokb�l, �s ha sz�ks�ges, alak�tsunk �t minden f�ggv�nyt a C++ f�ggv�nyek
formai k�vetelm�nyeinek megfeleloen. Cser�lj�k ki a malloc() �s free() h�v�sokat
new-ra, illetve delete-re. T�vol�tsuk el a sz�ks�gtelen konverzi�kat.
6. (*2) �rjuk �jra az ssort()-ot (�7.7) egy hat�konyabb rendez�si algoritmus
felhaszn
�l�s�val. Tipp: qsort().
7. (*2,5) Vegy�k a k�vetkezot:
struct Tnode {
string word;
int count;
Tnode* left;
Tnode* right;
};
�rjunk f�ggv�nyt, amellyel �j szavakat tehet�nk egy Tnode-okb�l �ll� f�ba.
�rjunk f�ggv�nyt, amely ki�r egy Tnode-okb�l �ll� f�t. �rjunk olyan f�ggv�nyt,
amely egy Tnode-okb�l �ll� f�t �gy �r ki, hogy a szavak �b�c�sorrendben vannak.
M�dos�tsuk a Tnode-ot, hogy (csak) egy mutat�t t�roljon, ami egy tetszolegesen
hossz� sz�ra mutat, amit a szabad t�r karaktert�mbk�nt t�rol, a new
seg�ts�g�vel. M�dos�tsuk a f�ggv�nyeket, hogy a Tnode �j definici�j�t
haszn�lj�k.
8. (*2,5) �rjunk f�ggv�nyt, amely k�tdimenzi�s t�mb�t invert�l. Tipp: �C.7.
9. (*2) �rjunk titkos�t� programot, ami a cin-rol olvas �s a k�dolt karaktereket
ki�rja
a cout-ra. Haszn�lhatjuk a k�vetkezo, egyszeru titkos�t� s�m�t: c karakter titkos
�tott form�ja legyen c^key[i], ahol key egy karakterl�nc, amely parancssori
param�terk�nt adott. A program ciklikus m�don haszn�lja a key-ben l�vo
karaktereket,
am�g a teljes bemenetet el nem olvasta. Ha nincs megadva key (vagy
a param�ter null-karakterl�nc), a program ne v�gezzen titkos�t�st.
7. F�ggv�nyek 219
10. (*3,5) �rjunk programot, ami seg�t megfejteni a �7.10[9]-ben le�rt m�dszerrel
titkos
�tott �zeneteket, an�lk�l, hogy tudn� a kulcsot. Tipp: l�sd David Kahn: The
Codebreakers, Macmillan, 1967, New York; 207-213. o.
11. (*3) �rjunk egy error nevu f�ggv�nyt, amely %s, %c �s %d kifejez�seket
tartalmaz
�, printf st�lus�, form�zott karakterl�ncokat vesz param�terk�nt �s ezen k�-
v�l tetszoleges sz�m� param�tere lehet. Ne haszn�ljuk a printf()-et. N�zz�k
meg a �21.8-at, ha nem tudjuk, mit jelent a %s, %c �s %d. Haszn�ljuk
a <cstdarg>-ot.
12. (*1) Hogyan v�lasztan�nk meg a typedef haszn�lat�val meghat�rozott f�ggv
�nyekre hivatkoz� mutat�t�pusok neveit?
13. (*2) N�zz�nk meg n�h�ny programot, hogy elk�pzel�s�nk lehessen a mostans
�g haszn�latos nevek st�lus�nak v�ltozatoss�g�r�l. Hogyan haszn�lj�k a nagybet
uket? Hogyan haszn�lj�k az al�h�z�st? Mikor haszn�lnak r�vid neveket, mint
amilyen az i �s x?
14. (*1) Mi a hiba ezekben a makr�kban?
#define PI = 3.141593;
#define MAX(a,b) a>b?a:b
#define fac(a) (a)*fac((a)-1)
15. (*3) �rjunk makr�feldolgoz�t, amely egyszeru makr�kat defini�l �s cser�l ki
(ahogy a C eloford�t� teszi). Olvassunk a cin-rol �s �rjunk a cout-ra. Elosz�r ne
pr�b�ljunk param�terekkel rendelkezo makr�kat kezelni. Tipp: az asztali sz�-
mol�g�p (�6.1) tartalmaz egy szimb�lumt�bl�t �s egy lexikai elemzot, amit m�-
dos�thatunk.
16. (*2) �rjuk meg magunk a print() f�ggv�nyt a �7.5-bol.
17. (*2) Adjunk hozz� a �6.1 pontban l�vo asztali sz�mol�g�phez olyan
f�ggv�nyeket,
mint az sqrt(), log(), �s sin(). Tipp: adjuk meg elore a neveket, a f�ggv�-
nyeket pedig f�ggv�nyre hivatkoz� mutat�kb�l �ll� t�mb�n kereszt�l h�vjuk
meg. Ne felejts�k el ellenorizni a f�ggv�nyh�v�sok param�tereit.
18. (*1) �rjunk olyan faktori�lis f�ggv�nyt, amely nem h�vja meg �nmag�t. L�sd
m�g �11.14[6]-ot.
19. (*2) �rjunk f�ggv�nyeket, amelyek egy napot, egy h�napot, �s egy �vet adnak
hozz� egy Date-hez, ahogy azt a �6.6[13]-ban le�rtuk. �rjunk f�ggv�nyt, ami
megadja, hogy egy adott Date a h�t melyik napj�ra esik. �rjunk olyan f�ggv�nyt,
ami megadja egy adott Date-re k�vetkezo elso h�tfo Date-j�t.
220 Alapok
N�vterek �s kiv�telek
.. Ez a 787-es �v!
. I.sz.?.
(Monty Python)
.Nincs olyan �ltal�nos szab�ly, ami
al�l ne lenne valamilyen kiv�tel..
(Robert Burton)
Modulok, fel�letek �s kiv�telek . N�vterek . using . using namespace .
N�v�tk�z�sek felold
�sa . Nevek keres�se . N�vterek �sszefuz�se . N�vt�r-�lnevek . N�vterek �s C k�d .
Kiv
�telek . throw �s catch . A kiv�telek �s a programok szerkezete . Tan�csok .
Gyakorlatok
8.1. Modulok �s fel�letek
Minden val�s�gos program k�l�n�ll� r�szekbol �ll. M�g az egyszeru .Hell�, vil�g!.
program
is legal�bb k�t r�szre oszthat�: a felhaszn�l�i k�dra, ami a Hell�, vil�g!
ki�r�s�t k�ri, �s
a ki�r�st v�gzo I/O rendszerre.
8
Vegy�k a sz�mol�g�p p�ld�j�t a �6.1-bol. L�thatjuk, hogy 5 r�szbol �ll:
1. A (szintaktikai) elemzobol (parser), ami a szintaktikai elemz�st v�gzi,
2. az adatbeviteli f�ggv�nybol vagy lexikai elemzobol (lexer), ami a karakterekbol

szimb�lumokat hoz l�tre


3. a (karakterl�nc, �rt�k) p�rokat t�rol� szimb�lumt�bl�b�l
4. a main() vez�rlobol
5. �s a hibakezelobol
�br�val:
A fenti �br�ban a ny�l jelent�se: .felhaszn�lja.. Az egyszerus�t�s kedv��rt nem
jel�ltem,
hogy mindegyik r�sz t�maszkodik a hibakezel�sre. Az igazat megvallva a
sz�mol�g�pet h�-
rom r�szbol �ll�ra terveztem, a vez�rlot �s a hibakezelot a teljess�g miatt adtam
hozz�.
Amikor egy modul felhaszn�l egy m�sikat, nem sz�ks�ges, hogy mindent tudjon a
felhaszn
�lt modulr�l. Ide�lis esetben a modulok legnagyobb r�sze nem ismert a felhaszn�l�
elem
sz�m�ra. K�vetkez�sk�ppen k�l�nbs�get tesz�nk a modul �s a modul fel�lete
(interf�sz)
k�z�tt. A szintaktikai elemzo p�ld�ul k�zvetlen�l csak az adatbeviteli f�ggv�ny
fel�let�re,
nem pedig a teljes lexikai elemzore t�maszkodik. Az adatbeviteli f�ggv�ny csak
megval�-
s�tja a fel�let�ben k�zz�tett szolg�ltat�sokat. Ezt �br�val �gy mutathatjuk be:
222 Alapok
vez�rlo
elemzo
adatbeviteli f�ggv�ny
szimb�lumt�bla
hibakezelo
A szaggatott vonalak jelent�se: .megval�s�tja.. Ez tekintheto a program val�di
fel�p�t�s�-
nek. Nek�nk, programoz�knak, az a feladatunk, hogy ezt hu m�don adjuk vissza a
k�dban.
Ha ezt tessz�k, a k�d egyszeru, hat�kony, �rtheto, �s k�nnyen m�dos�that� lesz,
mert
k�zvetlen�l fogja t�kr�zni eredeti elk�pzel�s�nket.
A k�vetkezo r�szben bemutatjuk, hogyan lehet a sz�mol�g�p program logikai
fel�p�t�s�t
vil�gosan kifejezni, a �9.3 pontban pedig azt, hogyan rendezhetj�k el �gy a
program forr�ssz
�veg�t, hogy abb�l elony�nk sz�rmazzon. A sz�mol�g�p kis program; a .val�di
�letben.
nem haszn�ln�m olyan m�rt�kben a n�vtereket �s a k�l�n ford�t�st (�2.4.1, �9.1),
mint itt.
Most csak az�rt haszn�ljuk ezeket, hogy nagyobb programok eset�ben is hasznos
m�dszereket
mutassunk be, an�lk�l, hogy belefulladn�nk a k�dba. A val�di programokban minden
modul, amelyet �n�ll� n�vt�r jel�l, gyakran f�ggv�nyek, oszt�lyok, sablonok stb.
sz�-
zait tartalmazza.
A nyelvi eszk�z�k bo v�laszt�k�nak bemutat�s�hoz t�bb l�p�sben bontom modulokra
a sz�mol�g�pet. Az igazi programokn�l nem val�sz�nu, hogy ezen l�p�sek mindegyik�t

v�grehajtan�nk. A tapasztalt programoz� m�r az elej�n kiv�laszthat egy .k�r�lbel�l


megfelel
o. tervet. Ahogy azonban a program az �vek sor�n fejlodik, nem ritk�k a drasztikus
szerkezeti
v�ltoztat�sok.
A hibakezel�s minden�tt fontos szerepet t�lt be a program szerkezet�ben. Amikor
egy
programot modulokra bontunk vagy egy programot modulokb�l hozunk l�tre, �gyeln�nk
kell arra, hogy a hibakezel�s okozta modulok k�z�tti f�ggos�gekbol min�l kevesebb
legyen.
A C++ kiv�teleket ny�jt arra a c�lra, hogy elk�l�n�ts�k a hib�k �szlel�s�t �s
jelz�s�t
azok kezel�s�tol. Ez�rt miut�n t�rgyaltuk, hogyan �br�zolhatjuk a modulokat
n�vterekk
�nt (�8.2), bemutatjuk, hogyan haszn�lhatjuk a kiv�teleket arra, hogy a
modularit�st tov
�bb jav�tsuk (�8.3).
8. N�vterek �s kiv�telek 223
vez�rlo
hibakezelo
szintaktikai elemzo megval�s�t�sa
lexikai elemzo megval�s�t�sa
szimb�lumt�bla megval�s�t�sa
szintaktikai elemzo fel�lete
lexikai elemzo fel�lete
szimb�lumt�bla fel�lete
A modularit�s fogalma sokkal t�bb m�don �rtelmezheto, mint ahogy ebben �s a
k�vetkez
o fejezetben tessz�k. Programjainkat p�ld�ul r�szekre bonthatjuk p�rhuzamosan
v�grehajtott
�s egym�ssal kapcsolatot tart� folyamatok seg�ts�g�vel is. Ugyan�gy az �n�ll�
c�mterek
(address spaces) �s a c�mterek k�z�tti inform�ci�s kapcsolat is olyan fontos
t�mak�r�k,
amelyeket itt nem t�rgyalunk. �gy gondolom, a modularit�s ezen megk�zel�t�sei
nagyr�szt
egym�st�l f�ggetlenek �s ellent�tesek. �rdekes m�don minden rendszer k�nnyen
modulokra
bonthat�. A neh�zs�get a modulok k�z�tti biztons�gos, k�nyelmes �s hat�kony
kapcsolattart
�s biztos�t�sa jelenti.
8.2. N�vterek
A n�vterek (namespace) mindig valamilyen logikai csoportos�t�st fejeznek ki. Azaz,
ha
egyes deklar�ci�k valamilyen jellemzo alapj�n �sszetartoznak, akkor ezt a t�nyt
kifejezhetj
�k �gy is, hogy k�z�s n�vt�rbe helyezz�k azokat. A sz�mol�g�p elemzoj�nek (�6.1.1)
deklar
�ci�it p�ld�ul a Parser n�vt�rbe tehetj�k:
namespace Parser {
double expr(bool);
double prim(bool get) { /* ... */ }
double term(bool get) { /* ... */ }
double expr(bool get) { /* ... */ }
}
Az expr() f�ggv�nyt elosz�r deklar�ljuk �s csak k�sobb fejtj�k ki, hogy megt�rj�k
a �6.1.1-
ben le�rt f�ggos�gi k�rt.
A sz�mol�g�p bemeneti r�sz�t szint�n �n�ll� n�vt�rbe helyezhetj�k:
namespace Lexer {
enum Token_value {
NAME, NUMBER, END,
PLUS='+', MINUS='-', MUL='*', DIV='/',
PRINT=';', ASSIGN='=', LP='(', RP=')'
};
Token_value curr_tok;
double number_value;
string string_value;
Token_value get_token() { /* ... */ }
}
224 Alapok
A n�vterek ilyen haszn�lata el�g nyilv�nval�v� teszi, mit ny�jt a lexikai �s a
szintaktikai
elemzo a felhaszn�l� programelemnek. Ha azonban a f�ggv�nyek forr�sk�dj�t is a
n�vterekbe
helyeztem volna, a szerkezet zavaross� v�lt volna. Ha egy val�s�gos m�retu n�vt�r
deklar�ci�j�ba beletessz�k a f�ggv�nyt�rzseket is, �ltal�ban t�bb oldalas
(k�pernyos) inform
�ci�n kell �tr�gnunk magunkat, mire megtal�ljuk, milyen szolg�ltat�sok vannak
felk�-
n�lva, azaz, hogy megtal�ljuk a fel�letet.
K�l�n meghat�rozott fel�letek helyett olyan eszk�z�ket is biztos�thatunk, amelyek
kinyerik
a fel�letet egy modulb�l, amely a megval�s�t�st tartalmazza. Ezt nem tekintem j�
megold
�snak. A fel�letek meghat�roz�sa alapveto tervez�si tev�kenys�g (l�sd �23.4.3.4-
et),
hiszen egy modul a k�l�nb�zo programelemek sz�m�ra k�l�nb�zo fel�leteket ny�jthat,
r�-
ad�sul a fel�letet sokszor m�r a megval�s�t�s r�szleteinek kidolgoz�sa elott
megtervezik.
�me a Parser egy olyan v�ltozata, ahol a fel�letet (interf�sz) elk�l�n�tj�k a
megval�s�t�st�l
(implement�ci�):
namespace Parser {
double prim(bool);
double term(bool);
double expr(bool);
}
double Parser::prim(bool get) { /* ... */ }
double Parser::term(bool get) { /* ... */ }
double Parser::expr(bool get) { /* ... */ }
Vegy�k �szre, hogy a fel�let �s a l�nyegi programr�sz sz�tv�laszt�s�nak
eredm�nyek�nt
most minden f�ggv�nynek pontosan egy deklar�ci�ja �s egy defin�ci�ja van. A
felhaszn�l�
programelemek csak a deklar�ci�kat tartalmaz� fel�letet fogj�k l�tni. A program
megval�-
s�t�s�t . ebben az esetben a f�ggv�nyt�rzseket . a felhaszn�l� elem l�t�k�r�n
k�v�l helyezz
�k el.
L�thattuk, hogy egy tagot megadhatunk a n�vt�r meghat�roz�s�n bel�l, �s
kifejthetj�k k�-
sobb, a n�vt�r_neve::tag_neve jel�l�st haszn�lva.
A n�vt�r tagjait a k�vetkezo jel�l�s haszn�lat�val kell bevezetni:
namespace n�vt�r_n�v {
// deklar�ci� �s defin�ci�k
}
8. N�vterek �s kiv�telek 225
A n�vt�rdefin�ci�n k�v�l �j tagot nem adhatunk meg minos�to form�ban:
void Parser::logical(bool); // hiba: nincs logical() a Parser n�vt�rben
A c�l az, hogy k�nnyen meg lehessen tal�lni minden nevet a n�vt�rdeklar�ci�ban, �s
hogy
a g�pel�si, illetve az elt�ro t�pusokb�l ad�d� hib�kat �szrevegy�k:
double Parser::trem(bool); // hiba: nincs trem() a Parser n�vt�rben
double Parser::prim(int); // hiba: Parser::prim() logikai param�teru
A n�vt�r (namespace) egyben hat�k�r (scope), vagyis nagyon alapveto �s viszonylag
egyszer
u fogalom. Min�l nagyobb egy program, ann�l hasznosabbak a n�vterek, hogy kifejezz
�k a program r�szeinek logikai elk�l�n�t�s�t. A k�z�ns�ges lok�lis hat�k�r�k, a
glob�lis
hat�k�r�k �s az oszt�lyok maguk is n�vterek (�C.10.3). Ide�lis esetben egy program
minden
eleme valamilyen felismerheto logikai egys�ghez (modulhoz) tartozik. Ez�rt .
elm�letileg
. egy bonyolultabb program minden deklar�ci�j�t �n�ll� n�vterekbe kellene
helyezni,
melyek neve a programban bet�lt�tt logikai szerepet jelzi. A kiv�tel a main(),
amelynek
glob�lisnak kell lennie, hogy a fut�si ideju k�rnyezet felismerje (�8.3.3).
8.2.1. Minos�tett nevek
A n�vterek k�l�n hat�k�rt alkotnak. Az �ltal�nos hat�k�r-szab�lyok term�szetesen
r�juk is
vonatkoznak, �gy ha egy nevet elozetesen a n�vt�rben vagy egy k�r�lvevo blokkban
adtunk
meg, minden tov�bbi neh�zs�g n�lk�l haszn�lhatjuk. M�sik n�vt�rbol sz�rmaz� nevet
viszont csak akkor haszn�lhatunk, ha minos�tj�k n�vter�nek nev�vel:
double Parser::term(bool get) // figyelj�k meg a Parser:: minos�tot
{
double left = prim(get); // nem kell minos�to
for (;;)
switch (Lexer::curr_tok) { // figyelj�k meg a Lexer:: minos�tot
case Lexer::MUL: // figyelj�k meg a Lexer:: minos�tot
left *= prim(true); // nem kell minos�to
// ...
}
// ...
}
A Parser minos�tore itt az�rt van sz�ks�g, hogy kifejezz�k, hogy ez a term() az,
amelyet
a Parser-ben bevezett�nk, �s nem valamilyen m�s glob�lis f�ggv�ny. Mivel a term()
226 Alapok
a Parser tagja, nem kell minos�tenie a prim()-et. Ha azonban a Lexer minos�tot nem
tessz�k
ki, a ford�t�program a curr_tok v�ltoz�t �gy tekinti, mintha az nem deklar�lt
lenne, mivel
a Lexer n�vt�r tagjai nem tartoznak a Parser n�vt�r hat�k�r�be.
8.2.2. Using deklar�ci�k
Ha egy n�v gyakran haszn�latos saj�t n�vter�n k�v�l, bosszant� lehet �lland�an
minos�teni
n�vter�nek nev�vel. Vegy�k a k�vetkezot:
double Parser::prim(bool get) // elemi szimb�lumok kezel�se
{
if (get) Lexer::get_token();
switch (Lexer::curr_tok) {
case Lexer::NUMBER: // lebegopontos konstans
Lexer::get_token();
return Lexer::number_value;
case Lexer::NAME:
{ double& v = table[Lexer::string_value];
if (Lexer::get_token() == Lexer::ASSIGN) v = expr(true);
return v;
}
case Lexer::MINUS: // m�nusz elojel (egyoperandus� m�nusz)
return -prim(true);
case Lexer::LP:
{ double e = expr(true);
if (Lexer::curr_tok != Lexer::RP) return Error::error(") sz�ks�ges");
Lexer::get_token(); // ')' lenyel�se
return e;
}
case Lexer::END:
return 1;
default:
return Error::error("elemi szimb�lum sz�ks�ges");
}
}
A Lexer minos�t�s ism�telget�se igen f�raszt�, de ki lehet k�sz�b�lni egy using
deklar�ci�-
val, amellyel egy adott helyen kijelentj�k, hogy az ebben a hat�k�rben haszn�lt
get_token
a Lexer get_token-je:
double Parser::prim(bool get) // elemi szimb�lumok kezel�se
{
using Lexer::get_token; // a Lexer get_token-j�nek haszn�lata
using Lexer::curr_tok; // a Lexer curr_tok-j�nak haszn�lata
using Error::error; // az Error error-j�nak haszn�lata
8. N�vterek �s kiv�telek 227
if (get) get_token();
switch (curr_tok) {
case Lexer::NUMBER: // lebegopontos konstans
get_token();
return Lexer::number_value;
case Lexer::NAME:
{ double& v = table[Lexer::string_value];
if (get_token() == Lexer::ASSIGN) v = expr(true);
return v;
}
case Lexer::MINUS: // m�nusz elojel
return -prim(true);
case Lexer::LP:
{ double e = expr(true);
if (curr_tok != Lexer::RP) return error(") sz�ks�ges");
get_token(); // ')' lenyel�se
return e;
}
case Lexer::END:
return 1;
default:
return error("elemi szimb�lum sz�ks�ges");
}
}
A using direkt�va egy lok�lis szinon�m�t vezet be.
A lok�lis szinon�m�kat �ltal�ban c�lszeru a leheto legszukebb hat�k�rrel
haszn�lni, hogy
elker�lj�k a t�ved�seket. A mi eset�nkben azonban az elemzo minden f�ggv�nye
ugyanazokat
a neveket haszn�lja a t�bbi modulb�l, �gy a using deklar�ci�kat elhelyezhetj�k
a Parser n�vt�r meghat�roz�s�ban is:
namespace Parser {
double prim(bool);
double term(bool);
double expr(bool);
using Lexer::get_token; // a Lexer get_token-j�nek haszn�lata
using Lexer::curr_tok; // a Lexer curr_tok-j�nak haszn�lata
using Error::error; // az Error error-j�nak haszn�lata
}
228 Alapok
�gy a Parser f�ggv�nyeit majdnem az eredeti v�ltozatukhoz (�6.1.1) hasonl�ra
egyszerus�thetj
�k:
double Parser::term(bool get) // szorz�s �s oszt�s
{
double left = prim(get);
for (;;)
switch (curr_tok) {
case Lexer::MUL:
left *= prim(true);
break;
case Lexer::DIV:
if (double d = prim(true)) {
left /= d;
break;
}
return error("oszt�s 0-val");
default:
return left;
}
}
Azt is megtehetn�nk, hogy a lexikai szimb�lumok (token, nyelvi egys�g) neveit a
Parser
n�vt�rbe is bevezetj�k. Az�rt hagyjuk oket minos�tett alakban, hogy
eml�keztessenek,
a Parser a Lexer-re t�maszkodik.
8.2.3. Using direkt�v�k
Mit tehet�nk, ha c�lunk az, hogy a Parser f�ggv�nyeit annyira leegyszerus�ts�k,
hogy pontosan
olyanok legyenek, mint eredeti v�ltozataik? Egy nagy program eset�ben �sszerunek
tunik, hogy egy elozo, kev�sb� modul�ris v�ltozat�t n�vtereket haszn�lva alak�tsuk
�t.
A using direkt�va majdnem ugyan�gy teszi el�rhetov� egy n�vt�r neveit, mintha
azokat
a n�vter�k�n k�v�l vezett�k volna be (�8.2.8):
namespace Parser {
double prim(bool);
double term(bool);
double expr(bool);
using namespace Lexer; // a Lexer �sszes nev�t el�rhetov� teszi
using namespace Error; // az Error �sszes nev�t el�rhetov� teszi
}
8. N�vterek �s kiv�telek 229
Ez lehetov� teszi sz�munkra, hogy a Parser f�ggv�nyeit pontosan �gy �rjuk meg,
ahogy azt
eredetileg tett�k (�6.1.1):
double Parser::term(bool get) // szorz�s �s oszt�s
{
double left = prim(get);
for (;;)
switch (curr_tok) { // a Lexer-beli curr_tok
case MUL: // a Lexer-beli MUL
left *= prim(true);
break;
case DIV: // a Lexer-beli DIV
if (double d = prim(true)) {
left /= d;
break;
}
return error("oszt�s 0-val"); // az Error-beli error
default:
return left;
}
}
A using direkt�v�k a n�vterekben m�s n�vterek be�p�t�s�re haszn�lhat�k (�8.2.8),
f�ggv�-
nyekben jel�l�sbeli seg�ts�gk�nt vehetok biztons�gosan ig�nybe (�8.3.3.1). A
glob�lis using
direkt�v�k a nyelv r�gebbi v�ltozatair�l val� �t�ll�sra szolg�lnak (�8.2.9),
egy�bk�nt jobb,
ha ker�lj�k oket.
8.2.4. T�bb fel�let haszn�lata
Vil�gos, hogy a Parser sz�m�ra l�trehozott n�vt�r nem a fel�let, amit a Parser a
felhaszn�-
l� programelem sz�m�ra ny�jt. Ink�bb olyan deklar�ci�halmaznak tekinthetj�k, ami
az
egyes elemzo f�ggv�nyek k�nyelmes meg�r�s�hoz sz�ks�ges. A Parser fel�lete a
felhaszn
�l� elemek sz�m�ra sokkal egyszerubb kellene, hogy legyen:
namespace Parser {
double expr(bool);
}
230 Alapok
Szerencs�re a k�t n�vt�r-meghat�roz�s egy�ttesen l�tezhet, �gy mindketto
felhaszn�lhat�
ott, ahol az a legmegfelelobb. L�thatjuk, hogy a Parser n�vt�r k�t dolgot ny�jt:
[1] K�z�s k�rnyezetet az elemzot megval�s�t� f�ggv�nyek sz�m�ra
[2] K�lso fel�letet, amit az elemzo a felhaszn�l� programelem rendelkez�s�re
bocs�t
Ennek �rtelm�ben a main() vez�rlok�d csak a k�vetkezot kell, hogy l�ssa:
namespace Parser { // felhaszn�l�i fel�let
double expr(bool);
}
B�rmelyik fel�letet is tal�ltuk a legjobbnak az elemzo f�ggv�nyek k�z�s
k�rnyezet�nek �br
�zol�s�ra, a f�ggv�nyeknek l�tniuk kell azt:
namespace Parser { // fel�let a megval�s�t�shoz
double prim(bool);
double term(bool);
double expr(bool);
using Lexer::get_token; // a Lexer get_token-j�nek haszn�lata
using Lexer::curr_tok; // a Lexer curr_tok-j�nak haszn�lata
using Error::error; // az Error error-j�nak haszn�lata
}
�br�val:
A nyilak .a . �ltal ny�jtott fel�leten alapul. viszonyokat fejezik ki.
8. N�vterek �s kiv�telek 231
Parser' Parser
Driver Parser megval�s�t�s
A Parser. (Parser prime) a felhaszn�l� programelemek sz�m�ra ny�jtott szuk
fel�let; nem
C++ azonos�t�. Sz�nd�kosan v�lasztottam, hogy jel�ljem, ennek a fel�letnek nincs
k�l�n
neve a programban. A k�l�n nevek hi�nya nem okozhat zavart, mert a programoz�k az
egyes fel�letek sz�m�ra k�l�nb�zo �s magukt�l �rtetodo neveket tal�lnak ki, �s
mert
a program fizikai elrendez�se (l�sd �9.3-at) term�szetesen k�l�nb�zo (f�jl)neveket
ad.
A programoz�i fel�let nagyobb a felhaszn�l�knak ny�jtottn�l. Ha ez a fel�let egy
val�di
rendszer val�s�gos m�retu modulj�nak fel�lete lenne, sokkal gyakrabban v�ltozna,
mint
a felhaszn�l�k �ltal l�that� fel�let. Fontos, hogy a modulokat haszn�l�
f�ggv�nyeket (ebben
az esetben a Parser-t haszn�l� main()-t) elk�l�n�ts�k az ilyen m�dos�t�sokt�l.
A k�t fel�let �br�zol�s�ra nem kell �n�ll� n�vtereket haszn�lnunk, de ha akarn�nk,
megtehetn
�nk. A fel�letek megtervez�se az egyik legalapvetobb tev�kenys�g, de k�t�lu
fegyver.
K�vetkez�sk�ppen �rdemes v�giggondolni, val�j�ban mit pr�b�lunk megval�s�tani, �s
t�bb megold�st is kipr�b�lni.
Az itt bemutatott megold�s az �ltalunk megtekintettek k�z�l a legegyszerubb �s
gyakran
a legjobb. Legfobb gyeng�je, hogy a k�t fel�let neve nem k�l�nb�zik, valamint hogy
a ford
�t�program sz�m�ra nem �ll rendelkez�sre elegendo inform�ci�, hogy ellenorizze a
n�vt
�r k�t definici�j�nak k�vetkezetess�g�t. A ford�t�program azonban rendszerint
akkor is
megpr�b�lja ellenorizni az �sszef�gg�seket, ha erre nincs mindig lehetos�ge, a
szerkeszto-
program pedig �szreveszi a legt�bb olyan hib�t, amin a ford�t�program �tsiklott.
Az itt bemutatott megold�st haszn�lom a fizikai modularit�s (�9.3) t�rgyal�s�ra
is, �s ezt aj�nlom
arra az esetre is, amikor nincsenek tov�bbi logikai megszor�t�sok (l�sd m�g
�8.2.7-et).
8.2.4.1. Fel�lettervez�si m�dszerek
A fel�letek c�lja az, hogy a lehets�ges m�rt�kig cs�kkents�k a programok k�l�nb�zo
r�szei
k�z�tt fenn�ll� f�ggos�geket. A kisebb fel�let k�nnyebben �rtheto rendszerhez
vezet, melynek
adatrejt�si tulajdons�gai jobbak, k�nnyebben m�dos�that� �s gyorsabban
leford�that�.
Amikor a f�ggos�geket n�zz�k, fontos eml�kezn�nk arra, hogy a ford�t�programok �s
a programoz�k az al�bbi egyszeru hozz��ll�ssal viszonyulnak hozz�juk: .ha egy
defin�ci�
az X pontr�l l�that� (a hat�k�rben van), akkor b�rmi, ami az X pontban van le�rva,
b�rmit
ol f�gghet, ami abban a defin�ci�ban lett meghat�rozva.. Persze a helyzet
�ltal�ban nem
ennyire rossz, mert a legt�bb defin�ci� a legt�bb k�d sz�m�ra nem b�r
jelentos�ggel. Kor
�bbi defin�ci�inkat adottnak v�ve vegy�k a k�vetkezot:
232 Alapok
namespace Parser { // fel�let a megval�s�t�shoz
// ...
double expr(bool);
// ...
}
int main()
{
// ...
Parser::expr(false);
// ...
}
A main() f�ggv�ny csak a Parser::expr() f�ggv�nytol f�gg, de idore, gondolkod�sra,
sz�-
molgat�sra stb. van sz�ks�g ahhoz, hogy erre r�j�jj�nk. K�vetkez�sk�ppen a
val�s�gos m�-
retu programok eset�ben a programoz�k �s a ford�t�si rendszerek t�bbnyire
.biztosra mennek
. �s felt�telezik, hogy ahol elofordulhat f�ggos�g, ott elo is fordul, ami
teljesen �sszeru
megk�zel�t�s. C�lunk ez�rt az, hogy �gy fejezz�k ki programunkat, hogy a
lehets�ges f�gg
os�gek halmaz�t a val�ban �rv�nyben levo f�ggos�gek halmaz�ra szuk�tj�k.
Elosz�r megpr�b�ljuk a mag�t�l �rtetodot: a m�r megl�vo megval�s�t�si fel�let
seg�ts�g�-
vel az elemzo sz�m�ra felhaszn�l�i fel�letet hat�rozunk meg:
namespace Parser { // fel�let a megval�s�t�shoz
// ...
double expr(bool);
// ...
}
namespace Parser_interface { // fel�let a felhaszn�l�knak
using Parser::expr;
}
Nyilv�nval�, hogy a Parser_interface-t haszn�l� programelemek kiz�r�lag . �s
csup�n k�zvetett
m�don . a Parser::expr() f�ggv�nytol f�ggnek. M�gis, ha egy pillant�st vet�nk a
f�gg
os�gek �br�j�ra, a k�vetkezot l�tjuk:
8. N�vterek �s kiv�telek 233
Most a Driver (a vez�rlo) tunik sebezhetonek a Parser fel�let v�ltoz�saival
szemben, pedig
azt hitt�k, j�l elszigetelt�k tole. M�g a f�ggos�g ilyen megjelen�se sem
k�v�natos, �gy megszor
�tjuk a Parser_interface f�ggos�g�t a Parser-tol, �gy, hogy a megval�s�t�si
fel�letnek
csak az elemzo sz�m�ra l�nyeges r�sz�t (ezt kor�bban Parser'-nek nevezt�k) tessz�k
l�that
�v� ott, ahol a Parser_interface-t meghat�rozzuk:
namespace Parser { // fel�let a felhaszn�l�knak
double expr(bool);
}
namespace Parser_interface { // elt�ro nevu fel�let a felhaszn�l�knak
using Parser::expr;
}
�br�val:
234 Alapok
Parser_interface
Parser
Driver Parser megval�s�t�s
Parser_interface
Parser' Parser
Driver Parser megval�s�t�s
A Parser �s a Parser' egys�gess�g�t biztos�tand�, az egyetlen ford�t�si egys�gen
dolgoz�
ford�t�program helyett ism�t a ford�t�si rendszer eg�sz�re t�maszkodunk. Ez a
megold�s
csak abban k�l�nb�zik a �8.2.4-ben szereplotol, hogy kieg�sz�l a Parser_interface
n�vt
�rrel. Ha akarn�nk, a Parser_interface-t egy saj�t expr() f�ggv�nnyel konkr�tan is
�br�zolhatn
�nk:
namespace Parser_interface {
double expr(bool);
}
Most a Parser-nek nem kell a hat�k�rben lennie, hogy meghat�rozhassuk
a Parser_interface-t. Csak ott kell .l�that�nak. lennie, ahol a
Parser_interface::expr() f�ggv
�nyt kifejtj�k:
double Parser_interface::expr(bool get)
{
return Parser::expr(get);
}
Az ut�bbi v�ltozatot �br�val �gy szeml�ltethetj�k:
A f�ggos�geket ezzel a leheto legkevesebbre cs�kkentett�nk. Mindent kifejtett�nk
�s megfelel
oen elnevezt�nk. M�gis, ezt a megold�st a legt�bb esetben t�lz�nak tal�lhatjuk.
8. N�vterek �s kiv�telek 235
Parser_interface
Parser_interface
megval�s�t�s
Parser
Driver Parser megval�s�t�s
8.2.5. A n�v�tk�z�sek elker�l�se
A n�vterek logikai szerkezetek kifejez�s�re val�k. A legegyszerubb eset, amikor
k�t szem
�ly �ltal �rt k�dot kell megk�l�nb�ztetn�nk. Ez gyakran fontos gyakorlati
jelentos�ggel
b�r. Ha csak egyetlen glob�lis hat�k�rt haszn�lunk, igen neh�z lesz a programot
k�l�n�ll�
r�szekbol l�trehozni. Az a probl�ma mer�lhet fel, hogy az �n�ll�nak felt�telezett
r�szek
mindegyike ugyanazokat a neveket haszn�lja, �gy amikor egyetlen programban
egyes�tj�k
azokat, a nevek �tk�zni fognak. Vegy�k a k�vetkezot:
// my.h:
char f(char);
int f(int);
class String { /* ... */ };
// your.h:
char f(char);
double f(double);
class String { /* ... */ };
Ha a fentieket meghat�rozzuk, egy harmadik szem�ly csak nehezen haszn�lhatja
egyszerre
a my.h-t �s a your.h-t is. A k�zenfekvo megold�s, hogy mindk�t deklar�ci�halmazt
saj�t,
k�l�n n�vt�rbe helyezz�k:
namespace My {
char f(char);
int f(int);
class String { /* ... */ };
}
namespace Your {
char f(char);
double f(double);
class String { /* ... */ };
}
Most m�r alkalmazhatjuk a My �s a Your deklar�ci�it, ha minos�toket (�8.2.1),
using deklar
�ci�kat (�8.2.2) vagy using direkt�v�kat (�8.2.3) haszn�lunk.
8.2.5.1. N�vtelen n�vterek
Gyakran hasznos deklar�ci�k halmaz�t n�vt�rbe helyezni, puszt�n az�rt, hogy
v�dekezz
�nk a lehets�ges n�v�tk�z�sekkel szemben. A c�lunk az, hogy a k�d helyileg
maradjon
�rv�nyes, nem pedig az, hogy fel�letet ny�jtsunk a felhaszn�l�knak:
236 Alapok
#include "header.h"
namespace Mine {
int a;
void f() { /* ... */ }
int g() { /* ... */ }
}
Mivel nem akarjuk, hogy a Mine n�v .ismert. legyen az adott k�rnyezeten k�v�l is,
nem �rdemes
olyan felesleges glob�lis nevet kital�lni, amely v�letlen�l �tk�zhet valaki m�s
neveivel.
Ilyen esetben a n�vteret n�vtelen�l hagyhatjuk:
#include "header.h"
namespace {
int a;
void f() { /* ... */ }
int g() { /* ... */ }
}
Vil�gos, hogy kell lennie valamilyen m�dszernek arra is, hogy k�v�lrol f�rhess�nk
hozz�
egy n�vtelen n�vt�r (unnamed namespace) tagjaihoz. A n�vtelen n�vt�rhez tartozik
egy rejtett
using direkt�va is. Az elozo deklar�ci� egyen�rt�ku a k�vetkezovel:
namespace $$$ {
int a;
void f() { /* ... */ }
int g() { /* ... */ }
}
using namespace $$$;
Itt $$$ valamilyen n�v, amely egyedi abban a hat�k�rben, ahol a n�vteret
meghat�roztuk.
A k�l�nb�zo ford�t�si egys�gekben l�vo n�vtelen n�vterek mindig k�l�nb�zoek. Ahogy
azt
szerett�k volna, nincs m�d arra, hogy egy n�vtelen n�vt�r egy tagj�t egy m�sik
ford�t�si
egys�gbol megnevezhess�k.
8.2.6. Nevek keres�se
Egy T t�pus� param�terrel rendelkezo f�ggv�nyt �ltal�ban a T-vel azonos n�vt�rben
szok�s
megadni. K�vetkez�sk�ppen ha egy f�ggv�nyt nem tal�lunk meg haszn�lati k�rnyezet�-

ben, akkor param�tereinek n�vter�ben fogjuk keresni:


namespace Chrono {
class Date { /* ... */ };
8. N�vterek �s kiv�telek 237
bool operator==(const Date&, const std::string&);
std::string format(const Date&); // string �br�zol�s
// ...
}
void f(Chrono::Date d, int i)
{
std::string s = format(d); // Chrono::format()
std::string t = format(i); // hiba: a hat�k�rben nincs format()
}
Ez a keres�si szab�ly . a minos�tok haszn�lat�val ellent�tben . sok g�pel�stol
k�m�li meg
a programoz�t, �s nem is .szennyezi. �gy a n�vteret, mint a using direkt�va
(�8.2.3). Alkalmaz
�sa k�l�n�sen fontos az oper�torok operandusai (�11.2.4) �s a sablonparam�terek
(�C.13.8.4) eset�ben, ahol a minos�tok haszn�lata nagyon f�raszt� lehet.
Vegy�k �szre, hogy maga a n�vt�r a hat�k�rben kell, hogy legyen, a f�ggv�nyt pedig
csak
akkor tal�lhatjuk meg �s haszn�lhatjuk fel, ha elobb bevezett�k.
Term�szetesen egy f�ggv�ny t�bb n�vt�rbol is kaphat param�tereket:
void f(Chrono::Date d, std::string s)
{
if (d == s) {
// ...
}
else if (d == "1914 augusztus 4") {
// ...
}
}
Az ilyen esetekben a f�ggv�nyt a ford�t�program a szok�sos m�don, a h�v�s
hat�k�r�ben,
illetve az egyes param�terek n�vter�ben (bele�rtve a param�terek oszt�ly�t �s
alaposzt�ly�t
is) keresi, �s minden tal�lt f�ggv�nyre elv�gzi a t�lterhel�s felold�s�t (�7.4).
Nevezetesen,
a ford�t� a d==s h�v�sn�l az operator==-t az f()-et k�r�lvevo hat�k�rben, az (==-t
stringekre
meghat�roz�) std n�vt�rben, �s a Chrono n�vt�rben keresi. L�tezik egy
std::operator==(), de ennek nincs Date param�tere, ez�rt a Chrono::operator==()-t
haszn�lja,
amelynek viszont van. L�sd m�g �11.2.4-et.
238 Alapok
Amikor egy oszt�lytag megh�v egy n�vvel rendelkezo f�ggv�nyt, az oszt�ly �s
b�zisoszt�-
ly�nak tagjai elonyben r�szes�lnek azokkal a f�ggv�nyekkel szemben, melyeket a
ford�t�-
program a param�terek t�pusa alapj�n tal�lt. Az oper�torokn�l m�s a helyzet
(�11.2.1,
�11.2.4).
8.2.7. N�vt�r-�lnevek
Ha a felhaszn�l�k n�vtereiknek r�vid neveket adnak, a k�l�nb�zo n�vterek nevei
k�nynyebben
�tk�zhetnek:
namespace A { // r�vid n�v, (elobb-ut�bb) �tk�zni fog
// ...
}
A::String s1 = "Grieg";
A::String s2 = "Nielsen";
Val�di k�dban viszont �ltal�ban nem c�lszeru hossz� n�vt�rneveket haszn�lni:
namespace American_Telephone_and_Telegraph { // t�l hossz�
// ...
}
American_Telephone_and_Telegraph::String s3 = "Grieg";
American_Telephone_and_Telegraph::String s4 = "Nielsen";
A dilemm�t �gy oldhatjuk fel, ha a hosszabb n�vt�rneveknek r�vid �lneveket (alias)
adunk:
// haszn�ljunk n�vt�r-�lneveket a nevek r�vid�t�s�re:
namespace ATT = American_Telephone_and_Telegraph;
ATT::String s3 = "Grieg";
ATT::String s4 = "Nielsen";
A n�vt�r-�lnevek azt is lehetov� teszik a felhaszn�l�nak, hogy .a k�nyvt�rra.
hivatkozzon
�s egyetlen deklar�ci�ban hat�rozza meg, val�j�ban melyik k�nyvt�rra gondol:
namespace Lib = Foundation_library_v2r11;
// ...
Lib::set s;
Lib::String s5 = "Sibelius";
8. N�vterek �s kiv�telek 239
Ez nagym�rt�kben egyszerus�theti a k�nyvt�rak m�sik v�ltozatra t�rt�no cser�j�t.
Az�ltal,
hogy k�zvetlen�l Lib-et haszn�lunk a Foundation_library_v2r11 helyett, a Lib �ln�v
�rt�-
k�nek m�dos�t�s�val �s a program �jraford�t�s�val a .v3r02. v�ltozatra
friss�thetj�k
a k�nyvt�rat. Az �jraford�t�s �szre fogja venni a forr�sszintu
�sszef�rhetetlens�geket. M�sr
�szrol, a (b�rmilyen t�pus�) �lnevek t�lzott haszn�lata zavart is okozhat.
8.2.8. N�vterek �sszefuz�se
Egy fel�letet gyakran m�r l�tezo fel�letekbol akarunk l�trehozni:
namespace His_string {
class String { /* ... */ };
String operator+(const String&, const String&);
String operator+(const String&, const char*);
void fill(char);
// ...
}
namespace Her_vector {
template<class T> class Vector { /* ... */ };
// ...
}
namespace My_lib {
using namespace His_string;
using namespace Her_vector;
void my_fct(String&);
}
Ennek alapj�n . a My_lib n�vteret haszn�lva . m�r meg�rhatjuk a programot:
void f()
{
My_lib::String s = "Byron"; // megtal�lja a My_lib::His_string::String nevet
// ...
}
using namespace My_lib;
void g(Vector<String>& vs)
{
// ...
my_fct(vs[5]);
// ...
}
240 Alapok
Ha az eml�tett n�vt�rben egy explicit m�don minos�tett n�v (mint a My_lib::String)
nem bevezetett,
a ford�t� a nevet a using direkt�v�kban szereplo n�vterekben (p�ld�ul His_string)
fogja keresni.
Egy elem val�di n�vter�t csak akkor kell tudnunk, ha valamit megakarunk hat�rozni:

void My_lib::fill(char c) // hiba: a My_lib-ben nincs megadva fill()


{
// ...
}
void His_string::fill(char c) // rendben: fill() szerepel a His_string-ben
{
// ...
}
void My_lib::my_fct(String& v) // rendben; a String jelent�se My_lib::String, ami
// His_string::String
{
// ...
}
Ide�lis esetben egy n�vt�r
1. logikailag �sszetartoz� szolg�ltat�sok halmaz�t fejezi ki,
2. nem ad hozz�f�r�st a nem kapcsol�d� szolg�ltat�sokhoz,
3. �s nem r� nagy jel�l�sbeli terhet a felhaszn�l�ra.
Az itt �s a k�vetkezo r�szekben bemutatott �sszefuz�si, be�p�t�si m�dszerek .az
#includedal
(�9.2.1) egy�tt . komoly t�mogat�st ny�jtanak ehhez.
8.2.8.1. Kiv�laszt�s
Alkalmank�nt elofordul, hogy egy n�vt�rbol csak n�h�ny n�vhez akarunk hozz�f�rni.
Ezt
meg tudn�nk tenni �gy is, hogy olyan n�vt�r-deklar�ci�t �runk, amely csak azokat a
neveket
tartalmazza, melyeket szeretn�nk. P�ld�ul megadhatn�nk a His_string azon
v�ltozat�t,
amely csak mag�t a String-et �s az �sszefuzo oper�tort ny�jtja:
namespace His_string { // csak egy r�sze a His_string-nek
class String { /* ... */ };
String operator+(const String&, const String&);
String operator+(const String&, const char*);
}
8. N�vterek �s kiv�telek 241
Ez azonban k�nnyen zavaross� v�lhat, hacsak nem mi vagyunk a His_string tervezoi
vagy
.karbantart�i.. A His_string .val�di. meghat�roz�s�nak m�dos�t�sa ebben a
deklar�ci�ban
nem fog t�kr�zodni. Az adott n�vt�rben szereplo szolg�ltat�sok kiv�laszt�s�t
jobban ki lehet
fejezni using deklar�ci�kkal:
namespace My_string {
using His_string::String;
using His_string::operator+; // b�rmelyik His_string-beli + haszn�lhat�
}
A using deklar�ci� az adott n�v minden deklar�ci�j�t a hat�k�rbe helyezi, �gy
p�ld�ul
egyetlen using deklar�ci�val egy t�lterhelt f�ggv�ny �sszes v�ltozat�t
bevezethetj�k.
�gy ha a His_string-et �gy m�dos�tj�k, hogy egy tagf�ggv�nyt vagy az �sszefuzo
muvelet
egy t�lterhelt v�ltozat�t adj�k a String-hez, akkor ez a v�ltoztat�s automatikusan
hozz�f�rhet
o lesz a My_string-et haszn�l� elemek sz�m�ra. Ford�tva is igaz: ha a His_string-
bol elt
�vol�tunk egy szolg�ltat�st vagy megv�ltozatjuk a His_string fel�let�t, a
ford�t�program fel
fogja ismerni a My_string minden olyan haszn�lat�t, amelyre ez hat�ssal van (l�sd
m�g
�15.2.2).
8.2.8.2. �sszefuz�s �s kiv�laszt�s
A (using direkt�v�kkal t�rt�no) �sszefuz�s �s a (using deklar�ci�kkal t�rt�no)
kiv�laszt�s
�sszekapcsol�sa azt a rugalmass�got eredm�nyezi, amelyre a legt�bb val�di
programban
sz�ks�g�nk van. Ezek r�v�n �gy adhatunk hozz�f�r�st k�l�nf�le eszk�z�kh�z, hogy
feloldjuk
az egybe�p�t�s�kbol ad�d� n�v�tk�z�seket �s t�bb�rtelmus�geket:
namespace His_lib {
class String { /* ... */ };
template<class T> class Vector { /* ... */ };
// ...
}
namespace Her_lib {
template<class T> class Vector { /* ... */ };
class String { /* ... */ };
// ...
}
namespace My_lib {
using namespace His_lib; // minden a His_lib-bol
using namespace Her_lib; // minden a Her_lib-bol
242 Alapok
using His_lib::String; // az esetleges �tk�z�sek felold�sa a His_lib jav�ra
using Her_lib::Vector; // az esetleges �tk�z�sek felold�sa a Her_lib jav�ra
template<class T> class List { /* ... */ }; // tov�bbiak
// ...
}
Amikor megvizsg�lunk egy n�vteret, a n�vt�rben l�vo, kifejezetten megadott nevek
(bele-
�rtve a using deklar�ci�kkal megadottakat is) elonyben r�szes�lnek azokkal a
nevekkel
szemben, melyeket m�s hat�k�r�kbol tett�nk hozz�f�rhetov� a using direkt�v�val
(l�sd
m�g �C.10.1-et). K�vetkez�sk�ppen a My_lib.et haszn�l� elemek sz�m�ra a String �s
Vector nevek �tk�z�s�t a ford�t�program a His_lib::String �s Her_lib::Vector
jav�ra fogja feloldani.
Tov�bb� a My_lib::List lesz haszn�latos alap�rtelmez�s szerint, f�ggetlen�l att�l,

hogy szerepel-e List a His_lib vagy Her_lib n�vt�rben.


Rendszerint jobban szeretem v�ltozatlanul hagyni a neveket, amikor �j n�vt�rbe
teszem
azokat. Ily m�don nem kell ugyanannak az elemnek k�t k�l�nb�zo nev�re eml�keznem.
N�ha azonban �j n�vre van sz�ks�g, vagy egyszeruen j�, ha van egy �j nev�nk:
namespace Lib2 {
using namespace His_lib; // minden a His_lib-bol
using namespace Her_lib; // minden a Her_lib-bol
using His_lib::String; // az esetleges �tk�z�sek felold�sa a His_lib jav�ra
using Her_lib::Vector; // az esetleges �tk�z�sek felold�sa a Her_lib jav�ra
typedef Her_lib::String Her_string; // �tnevez�s
template<class T> class His_vec // "�tnevez�s"
: public His_lib::Vector<T> { /* ... */ };
template<class T> class List { /* ... */ }; // tov�bbiak
// ...
}
Az �tnevez�sre nincs k�l�n nyelvi elj�r�s. Ehelyett az �j elemek meghat�roz�s�ra
val� �ltal
�nos m�dszerek haszn�latosak.
8.2.9. N�vterek �s r�gi k�dok
Sok milli� sor C �s C++ k�d t�maszkodik glob�lis nevekre �s l�tezo k�nyvt�rakra.
Hogyan
haszn�lhatjuk a n�vtereket arra, hogy cs�kkents�k az ilyen k�dokban l�vo
probl�m�kat?
A m�r l�tezo k�dok �jra�r�sa nem mindig j�rhat� �t. Szerencs�re a C k�nyvt�rakat
�gy is
8. N�vterek �s kiv�telek 243
haszn�lhatjuk, mintha azokat egy n�vt�rben deklar�lt�k volna. A C++-ban �rt
k�nyvt�rak
eset�ben ez nem �gy van (�9.2.4), m�sr�szrol viszont a n�vtereket �gy tervezt�k,
hogy a lehet
o legcsek�lyebb k�rokoz�ssal be lehessen azokat �p�teni a r�gebbi C++ programokba
is.
8.2.9.1. N�vterek �s a C
Vegy�k a hagyom�nyosan elso C programot:
#include <stdio.h>
int main()
{
printf("Hell�, vil�g!\n");
}
Ezt a programot nem lenne j� �tlet sz�tt�rdelni. Az sem �sszeru, ha a szabv�nyos
k�nyvt�-
rakat egyedi megold�soknak tekintj�k. Emiatt a n�vterekre vonatkoz� nyelvi
szab�lyokat
�gy hat�rozt�k meg, hogy viszonylag k�nnyed�n lehessen egy n�vterek n�lk�l meg�rt
program szerkezet�t n�vterek haszn�lat�val vil�gosabban kifejezni. Tulajdonk�ppen
erre
p�lda a sz�mol�g�p program (�6.1). Ennek megval�s�t�s�hoz a kulcs a using
direkt�va.
A stdio.h C fej�llom�nyban l�vo szabv�nyos bemeneti/kimeneti szolg�ltat�sok
deklar�ci�i
p�ld�ul egy n�vt�rbe ker�ltek, a k�vetkezok�ppen:
// stdio.h:
namespace std {
// ...
int printf(const char* ... );
// ...
}
using namespace std;
Ez megorzi a visszir�ny� kompatibilit�st. Azoknak viszont, akik nem akarj�k, hogy
a nevek
automatikusan hozz�f�rhetok legyenek, k�sz�tett�nk egy �j fej�llom�nyt is, a
cstdio-t:
// cstdio:
namespace std {
// ...
int printf(const char* ... );
// ...
}
244 Alapok
A C++ standard k�nyvt�r�nak azon felhaszn�l�i, akik agg�dnak a deklar�ci�k
m�sol�sa miatt,
a stdio.h-t term�szetesen �gy fogj�k meghat�rozni, hogy beleveszik a cstdio-t:
// stdio.h:
#include<cstdio>
using namespace std;
A using direkt�v�kat elsodlegesen a nyelv r�gebbi v�ltozatair�l val� �t�ll�st
seg�to eszk�z-
�knek tekintem. A legt�bb olyan k�dot, amely m�s n�vt�rben l�vo nevekre
hivatkozik,
sokkal vil�gosabban ki lehet fejezni minos�t�sekkel �s using deklar�ci�kkal.
A n�vterek �s az �sszeszerkeszt�s k�z�tti kapcsolatot a �9.2.4 r�szben t�rgyaljuk.

8.2.9.2. N�vterek �s t�lterhel�s


A t�lterhel�s (�7.4) n�vtereken kereszt�l muk�dik. Ez alapveto ahhoz, hogy a m�r
megl�-
vo k�nyvt�rakat a forr�sk�d leheto legkisebb m�dos�t�s�val fejleszthess�k
n�vtereket haszn
�l�v�. P�ld�ul:
// old A.h:
void f(int);
// ...
// old B.h:
void f(char);
// ...
// old user.c:
#include "A.h"
#include "B.h"
void g()
{
f('a'); // f()-et h�vja B.h-b�l
}
Ezt a programot an�lk�l alak�thatjuk n�vtereket haszn�l� v�ltozatra, hogy a
t�nyleges
programk�dot megv�ltoztatn�nk:
8. N�vterek �s kiv�telek 245
// new A.h:
namespace A {
void f(int);
// ...
}
// new B.h:
namespace B {
void f(char);
// ...
}
// new user.c:
#include "A.h"
#include "B.h"
using namespace A;
using namespace B;
void g()
{
f('a'); // f()-et h�vja B.h-b�l
}
Ha teljesen v�ltozatlanul akartuk volna hagyni a user.c-t, a using direkt�v�kat a
fej�llom�-
nyokba tett�k volna.
8.2.9.3. A n�vterek nyitottak
A n�vterek nyitottak; azaz sz�mos n�vt�r deklar�ci�j�b�l adhatunk hozz�juk
neveket:
namespace A {
int f(); // most f() az A tagja
}
namespace A {
int g(); // most A k�t tagja f() �s g()
}
Ez�ltal �gy hozhatunk l�tre egyetlen n�vt�ren bel�l l�vo nagy programr�szeket,
ahogy egy
r�gebbi k�nyvt�r vagy alkalmaz�s �lt az egyetlen glob�lis n�vt�ren bel�l. Hogy ezt
megtehess
�k, a n�vt�r-meghat�roz�sokat sz�t kell osztanunk sz�mos fej�llom�ny �s forr�sf�jl
k�-
246 Alapok
z�tt. Ahogy azt a sz�mol�g�p p�ld�j�ban (�8.2.4.) mutattuk, a n�vterek nyitotts�ga
leheto-
v� teszi sz�munkra, hogy a k�l�nb�zo programelemeknek k�l�nb�zo fel�leteket
ny�jtsunk
az�ltal, hogy egy adott n�vt�r k�l�nb�zo r�szeit mutatjuk meg nekik. Ez a
nyitotts�g
szint�n a nyelv r�gebbi v�ltozatair�l val� �t�ll�st seg�ti. P�ld�ul a
// saj�t fej�llom�ny:
void f(); // saj�t f�ggv�ny
// ...
#include<stdio.h>
int g(); // saj�t f�ggv�ny
// ...
�jra�rhat� an�lk�l, hogy a deklar�ci�k sorrendj�t megv�ltoztatn�nk:
// saj�t fej�llom�ny:
namespace Mine {
void f(); // saj�t f�ggv�ny
// ...
}
#include<stdio.h>
namespace Mine {
int g(); // saj�t f�ggv�ny
// ...
}
Amikor �j k�dot �rok, jobban szeretek sok kisebb n�vteret haszn�lni (l�sd �8.2.8),
mint igaz
�n nagy programr�szeket egyetlen n�vt�rbe rakni. Ez azonban gyakran
kivitelezhetetlen,
ha nagyobb programr�szeket alak�tunk �t n�vtereket haszn�l� v�ltozatra.
Amikor egy n�vt�r elozetesen bevezetett tagj�t kifejtj�k, biztons�gosabb a Mine::
utas�t�sform
�t haszn�lni ahelyett, hogy �jra megnyitn�nk a Mine-t:
void Mine::ff() // hiba: nincs ff() megadva Mine-ban
{
// ...
}
A ford�t�program ezt a hib�t �szreveszi. Mivel azonban egy n�vt�ren bel�l �j
f�ggv�nyeket
is meghat�rozhatunk, a ford�t�program a fentivel azonos jellegu hib�t az �jra
megnyitott
n�vterekben m�r nem �rz�keli:
8. N�vterek �s kiv�telek 247
namespace Mine { // Mine �jra megnyit�sa f�ggv�nyek meghat�roz�s�hoz
void ff() // hopp�! nincs ff() megadva Mine-ban; ezzel a defin�ci�val adjuk hozz�
{
// ...
}
// ...
}
A ford�t�program nem tudhatja, hogy nem egy �j ff() f�ggv�nyt akartunk
meghat�rozni.
A meghat�roz�sokban szereplo nevek minos�t�s�re haszn�lhatunk n�vt�r-�lneveket
(�8.2.7), de az adott n�vt�r �jb�li megnyit�s�ra nem.
8.3. Kiv�telek
Ha egy program k�l�n�ll� modulokb�l �ll . k�l�n�sen ha ezek k�l�n fejlesztett
k�nyvt�-
rakb�l sz�rmaznak ., a hibakezel�st k�t k�l�n�ll� r�szre kell sz�tv�lasztanunk:
1. az olyan hibaesem�nyek jelz�s�re, melyeket nem lehet helyben megsz�ntetni,
2. illetve a m�shol �szlelt hib�k kezel�s�re.
A k�nyvt�r l�trehoz�ja felismerheti a fut�si ideju hib�kat, de �ltal�ban nem tud
mit kezdeni
vel�k. A k�nyvt�rt felhaszn�l� programelem tudhatn�, hogyan birk�zzon meg a
hib�kkal,
de nem k�pes �szlelni azokat . m�sk�l�nben a felhaszn�l� k�dj�ban szerepeln�nek
a hib�kat kezelo elj�r�sok �s nem a k�nyvt�r tal�ln� meg azokat.
A sz�mol�g�p p�ld�j�ban ezt a probl�m�t azzal ker�lt�k ki, hogy a program eg�sz�t
egyszerre
tervezt�k meg, ez�ltal beilleszthett�k a hibakezel�st a teljes szerkezetbe. Amikor

azonban a sz�mol�g�p logikai r�szeit k�l�nb�zo n�vterekre bontjuk sz�t, l�tjuk,


hogy minden
n�vt�r f�gg az Error n�vt�rtol (�8.2.2), az Error-ban l�vo hibakezelo pedig arra
t�maszkodik,
hogy minden modul megfeleloen viselkedik, miut�n hiba t�rt�nt. Tegy�k fel, hogy
nincs lehetos�g�nk a sz�mol�g�p eg�sz�t megtervezni �s nem akarjuk, hogy az Error
�s
a t�bbi modul k�z�tt szoros legyen a kapcsolat. Ehelyett tegy�k fel, hogy a
elemzot �s
a t�bbi r�szt �gy �rt�k meg, hogy nem tudt�k, hogyan szeretn� a vez�rlo kezelni a
hib�kat.
248 Alapok
B�r az error() nagyon egyszeru volt, mag�ban foglalt egy hibakezel�si m�dszert:
namespace Error {
int no_of_errors;
double error(const char* s)
{
std::cerr << "hiba: " << s << '\n';
no_of_errors++;
return 1;
}
}
Az error() f�ggv�ny egy hiba�zenetet �r ki, olyan alap�rtelmezett �rt�ket ad, mely
lehetov�
teszi a h�v� sz�m�ra, hogy folytassa a sz�mol�st, �s egy egyszeru hiba�llapotot
k�vet nyomon.
Fontos, hogy a program minden r�sze tudjon az error() l�tez�s�rol �s arr�l, hogyan

lehet megh�vni, illetve mit v�rhat tole. Ez t�l sok felt�tel lenne egy olyan
program eset�ben,
amit k�l�n fejlesztett k�nyvt�rakb�l hoztunk l�tre.
A hibajelz�s �s a hibakezel�s sz�tv�laszt�s�ra sz�nt C++ eszk�z a kiv�tel. Ebben a
r�szben
r�viden le�rjuk a kiv�teleket, abban a k�rnyezetben, ahogy a sz�mol�g�p p�ld�j�ban
lenn
�nek haszn�latosak. A 14. fejezet �tfog�bban t�rgyalja a kiv�teleket �s azok
haszn�lat�t.
8.3.1. .Dob�s �s elkap�s.
A kiv�teleket (exception) arra tal�lt�k ki, hogy seg�tsenek megoldani a hib�k
jelz�s�t:
struct Range_error {
int i;
Range_error(int ii) { i = ii; } // konstruktor (�2.5.2, �10.2.3)
};
char to_char(int i)
{
if (i<numeric_limits<char>::min() || numeric_limits<char>::max()<i) // l�sd �22.2
throw Range_error(i);
return i;
}
A to_char() f�ggv�ny vagy az i sz�m�rt�k�t adja vissza karakterk�nt, vagy
Range_error kiv
�telt v�lt ki. Az alapgondolat az, hogy ha egy f�ggv�ny olyan probl�m�t tal�l,
amellyel
nem k�pes megbirk�zni, kiv�telt v�lt ki (.kiv�telt dob., throw), azt rem�lve, hogy
(k�zvetett
vagy k�zvetlen) megh�v�ja k�pes kezelni a probl�m�t. Ha egy f�ggv�ny k�pes erre,
je-
8. N�vterek �s kiv�telek 249
lezheti, hogy el akarja kapni (catch) azokat a kiv�teleket, melyek t�pusa
megegyezik
a probl�ma jelz�s�re haszn�lt t�pussal. Ahhoz p�ld�ul, hogy megh�vjuk a to_char()-
t �s elkapjuk
azt a kiv�telt, amit esetleg kiv�lthat, a k�vetkezot �rhatjuk:
void g(int i)
{
try {
char c = to_char(i);
// ...
}
catch (Range_error) {
cerr << "hopp�\n";
}
}
A
catch ( /* ... */ ) {
// ...
}
szerkezetet kiv�telkezelonek (exception handler) nevezz�k. Csak k�zvetlen�l olyan
blokk
ut�n haszn�lhat�, amit a try kulcssz� eloz meg, vagy k�zvetlen�l egy m�sik
kiv�telkezelo
ut�n. A catch szint�n kulcssz�. A z�r�jelek olyan deklar�ci�t tartalmaznak, amely
a f�ggv
�nyparam�terek deklar�ci�j�hoz hasonl� m�don haszn�latos. A deklar�ci� hat�rozza
meg
azon objektum t�pus�t, melyet a kezelo elkaphat. Nem k�telezo, de megnevezheti az
elkapott
objektumot is. Ha p�ld�ul meg akarjuk tudni a kiv�ltott Range_error �rt�k�t, akkor

pontosan �gy adhatunk nevet a catch param�ter�nek, ahogy a f�ggv�nyparam�tereket


nevezz
�k meg:
void h(int i)
{
try {
char c = to_char(i);
// ...
}
catch (Range_error x) {
cerr << "hopp�: to_char(" << x.i << ")\n";
}
}
Ha b�rmilyen try blokkban szereplo vagy onnan megh�vott k�d kiv�telt v�lt ki, a
try blokk
kezeloit kell megvizsg�lni. Ha a kiv�tel t�pusa megegyezik a kezelonek megadott
t�pussal,
250 Alapok
a kezelo v�grehajtja a megfelelo muveletet. Ha nem, a kiv�telkezeloket figyelmen
k�v�l
hagyjuk �s a try blokk �gy viselkedik, mint egy k�z�ns�ges blokk. Ha a kiv�telt
nem kapja
el egyetlen try blokk sem, a program befejezodik (�14.7).
A C++ kiv�telkezel�se alapvetoen nem m�s, mint a vez�rl�s �tad�sa a h�v� f�ggv�ny
megfelel
o r�sz�nek. Ahol sz�ks�ges, a hib�r�l inform�ci�t adhatunk a h�v�nak. A C
programoz
�k �gy gondolhatnak a kiv�telkezel�sre, mint egy olyan, .j�l viselkedo. elj�r�sra,
amely
a setjmp/longjmp (�16.1.2) haszn�lat�t v�ltja fel. Az oszt�lyok �s a
kiv�telkezel�s k�z�tti k�lcs
�nhat�st a 14. fejezetben t�rgyaljuk.
8.3.2. A kiv�telek megk�l�nb�ztet�se
Egy program fut�sakor �ltal�ban sz�mos hiba l�phet fel, melyeket k�l�nb�zo nevu
kiv�teleknek
feleltethet�nk meg. �n a kiv�telkezel�s c�lj�ra k�l�n t�pusokat szoktam megadni.
Ez
a leheto legkisebbre cs�kkenti a c�ljukkal kapcsolatos zavart. Be�p�tett
t�pusokat, mint amilyen
az int, viszont sohasem haszn�lok kiv�telk�nt. Egy nagy programban nem lenne hat�-

kony m�d arra, hogy megtal�ljam a m�s c�lra haszn�lt int kiv�teleket, ez�rt sosem
lehetn�k
biztos abban, hogy az int egy eff�le elt�ro haszn�lata nem okoz-e zavart az �n
k�domban.
Sz�mol�g�p�nknek (�6.1) k�tfajta fut�si ideju hib�t kell kezelnie: a formai
k�vetelm�nyek
megs�rt�s�t �s a null�val val� oszt�s k�s�rlet�t. A kezelonek nem kell �rt�ket
�tadni abb�l
a k�db�l, amelyik felismerte a null�val val� oszt�s k�s�rlet�t, �gy a null�val
val� oszt�st egy
egyszeru �res t�pussal �br�zolhatjuk:
struct Zero_divide { };
M�sr�szt a kezelo a nyelvi hib�kr�l bizony�ra szeretne jelz�st kapni. Itt egy
karakterl�ncot
adunk �t:
struct Syntax_error {
const char* p;
Syntax_error(const char* q) { p = q; }
};
A k�nyelmesebb jel�l�s v�gett a szerkezethez hozz�adtam egy konstruktort (�2.5.2,
�10.2.3).
Az elemzot haszn�l� programr�szben megk�l�nb�ztethetj�k a k�t kiv�telt, ha
mindketto-
j�k sz�m�ra hozz�adunk egy-egy kezelot a try blokkhoz, �gy sz�ks�g eset�n a
megfelelo
kezelobe l�phet�nk. Ha az egyik kezelo .alj�n kies�nk., a v�grehajt�s a kezelok
list�j�nak
v�g�tol folytat�dik:
8. N�vterek �s kiv�telek 251
try {
// ...
expr(false);
// kiz�r�lag akkor jutunk ide, ha expr() nem okozott kiv�telt
// ...
}
catch (Syntax_error) {
// szintaktikus hiba kezel�se
}
catch (Zero_divide) {
// null�val oszt�s kezel�se
}
// akkor jutunk ide, ha expr() nem okozott kiv�telt vagy ha egy Syntax_error
// vagy Zero_divide kiv�telt elkaptunk (�s kezeloj�k nem t�rt vissza,
// nem v�ltott ki kiv�telt, �s m�s m�don sem v�ltoztatta meg a vez�rl�st).
A kezelok list�ja n�mileg egy switch utas�t�shoz hasonl�t, de itt nincs sz�ks�g
break utas�-
t�sokra. E list�k formai k�vetelm�nyei r�szben ez�rt k�l�nb�znek a case-�tol,
r�szben pedig
az�rt, hogy jel�lj�k, minden kezelo k�l�n hat�k�rt (�4.9.4) alkot.
A f�ggv�nyeknek nem kell az �sszes lehets�ges kiv�telt elkapniuk. Az elozo try
blokk p�ld
�ul nem pr�b�lta elkapni az elemzo bemeneti muveletei �ltal kiv�ltott kiv�teleket,
azok
csup�n .kereszt�lmennek. a f�ggv�nyen, megfelelo kezelovel rendelkezo h�v�t
keresve.
A nyelv szempontj�b�l a kiv�teleket r�gt�n kezeltnek tekintj�k, amint .bel�pnek. a
kezel
oj�kbe, ez�rt a try blokkot megh�v� programr�sznek kell foglalkoznia azokkal a
kiv�telekkel,
melyek a kezelo v�grehajt�sa k�zben l�pnek fel. A k�vetkezo p�ld�ul nem okoz
v�gtelen
ciklust:
class Input_overflow { /* ... */ };
void f()
{
try {
// ...
}
catch (Input_overflow) {
// ...
throw Input_overflow();
}
}
252 Alapok
A kiv�telkezelok egym�sba is �gyazhat�k:
class XXII { /* ... */ };
void f()
{
// ...
try {
// ...
}
catch (XXII) {
try {
// valami bonyolult
}
catch (XXII) {
// a bonyolult kezelo nem j�rt sikerrel
}
}
// ...
}
Ilyen . gyakran rossz st�lusra utal� . egym�sba �gyazott kiv�telkezeloket azonban
ritk�n
�runk.
8.3.3. Kiv�telek a sz�mol�g�pben
Az alapveto kiv�telkezelo elj�r�sokb�l kiindulva �jra�rhatjuk a �6.1 r�szben
szereplo sz�mol
�g�pet, hogy k�l�nv�lasszuk a fut�si idoben tal�lt hib�k kezel�s�t a sz�mol�g�p fo
programr
�sz�tol. Ez a program olyan elrendez�s�t eredm�nyezi, amely jobban hasonl�t a
k�l�n-
�ll�, laz�n kapcsol�d� r�szekbol l�trehozott programok�ra.
Elosz�r kik�sz�b�lhetj�k az error() f�ggv�nyt. Helyette az elemzo f�ggv�nyek csak
a hib
�k jelz�s�re haszn�latos t�pusokr�l fognak tudni:
namespace Error {
struct Zero_divide { };
struct Syntax_error {
const char* p;
Syntax_error(const char* q) { p = q; }
};
}
8. N�vterek �s kiv�telek 253
Az elemzo h�rom szintaktikus hib�t ismer fel:
Lexer::Token_value Lexer::get_token()
{
using namespace std; // az input, isalpha(), stb. haszn�lata miatt (�6.1.7)
// ...
default: // NAME, NAME =, vagy hiba
if (isalpha(ch)) {
input->putback(ch);
*input >> string_value;
return curr_tok=NAME;
string_value = ch;
while (input->get(ch) && isalnum(ch))
string_value.push_back(ch);
input->putback(ch);
return curr_tok=NAME;
}
throw Error::Syntax_error("rossz szimb�lum");
}
}
double Parser::prim(bool get) // elemi szimb�lumok kezel�se
{
// ...
case Lexer::LP:
{ double e = expr(true);
if (curr_tok != Lexer::RP) throw Error::Syntax_error("')' sz�ks�ges");
get_token(); // ')' lenyel�se
return e;
}
case Lexer::END:
return 1;
default:
throw Error::Syntax_error("elemi szimb�lum sz�ks�ges");
}
}
Ha az elemzo ilyen hib�t tal�l, a throw-t haszn�lja arra, hogy �tadja a vez�rl�st
egy kezelo-
nek, amelyet valamilyen (k�zvetett vagy k�zvetlen) h�v� f�ggv�ny hat�roz meg. A
throw
oper�tor egy �rt�ket is �tad a kezelonek. P�ld�ul a
throw Syntax_error("elemi szimb�lum sz�ks�ges");
a kezelonek egy Syntax_error objektumot ad �t, amely a primary expected
karakterl�ncra
hivatkoz� mutat�t tartalmazza.
254 Alapok
A null�val val� oszt�s hib�j�nak jelz�s�hez nem sz�ks�ges semmilyen adatot �tadni:

double Parser::term(bool get) // szorz�s �s oszt�s


{
// ...
case Lexer::DIV:
if (double d = prim(true)) {
left /= d;
break;
}
throw Error::Zero_divide();
// ...
}
Most m�r elk�sz�thetj�k a vez�rlot, hogy az kezelje a Zero_divide �s Syntax_error
kiv�teleket:
int main(int argc, char* argv[ ])
{
// ...
while (*input) {
try {
Lexer::get_token();
if (Lexer::curr_tok == Lexer::END) break;
if (Lexer::curr_tok == Lexer::PRINT) continue;
cout << Parser::expr(false) << '\n';
}
catch(Error::Zero_divide) {
cerr << "null�val oszt�s k�s�rlete\n";
if (Lexer::curr_tok != Lexer::PRINT) skip();
}
catch(Error::Syntax_error e) {
cerr << "formai hiba:" << e.p << "\n";
if (Lexer::curr_tok != Lexer::PRINT) skip();
}
}
if (input != &cin) delete input;
return no_of_errors;
}
Ha nem t�rt�nt hiba a PRINT (azaz sorv�ge vagy pontosvesszo) szimb�lummal lez�rt
kifejez
�s v�g�n, a main() megh�vja a skip() helyre�ll�t� f�ggv�nyt. A skip() az elemzot
egy
meghat�rozott �llapotba pr�b�lja �ll�tani, az�ltal, hogy eldobja a karaktereket
addig, am�g
sorv�g�t vagy pontosvesszot nem tal�l. A skip() f�ggv�ny, a no_of_errors �s az
input k�-
zenfekvo v�laszt�s a Driver n�vt�r sz�m�ra:
8. N�vterek �s kiv�telek 255
namespace Driver {
int no_of_errors;
std::istream* input;
void skip();
}
void Driver::skip()
{
no_of_errors++;
while (*input) { // karakterek elvet�se sort�r�sig vagy pontosvesszoig
char ch;
input->get(ch);
switch (ch) {
case '\n':
case ';':
return;
}
}
}
A skip() k�dj�t sz�nd�kosan �rtuk az elemzo k�dj�n�l alacsonyabb elvonatkoztat�si
szinten.
�gy az elemzoben l�vo kiv�telek nem kapj�k el, mik�zben �ppen az elemzo
kiv�teleinek
kezel�s�t v�gzik. Megtartottam azt az �tletet, hogy megsz�moljuk a hib�kat, �s ez
a sz�m
lesz a program visszat�r�si �rt�ke. Gyakran hasznos tudni a hib�kr�l, m�g akkor
is, ha
a program k�pes volt helyre�llni a hiba ut�n.
A main()-t nem tessz�k a Driver n�vt�rbe. A glob�lis main() a program ind�t�
f�ggv�nye
(�3.2), �gy a main() egy n�vt�ren bel�l �rtelmetlen. Egy val�s�gos m�retu
programban
a main() k�dj�nak legnagyobb r�sz�t a Driver egy k�l�n f�ggv�ny�be tenn�m �t.
8.3.3.1. M�s hibakezelo m�dszerek
Az eredeti hibakezelo k�d r�videbb �s eleg�nsabb volt, mint a kiv�teleket haszn�l�
v�ltozat.
Ezt azonban �gy �rte el, hogy a program r�szeit szorosan �sszekapcsolta. Ez a
megk�-
zel�t�s nem felel meg olyan programok eset�ben, melyeket k�l�n fejlesztett
k�nyvt�rakb�l
hoztak l�tre. Felvetodhet, hogy a k�l�n�ll� skip() hibakezelo f�ggv�nyt a main()-
ben, egy
�llapotv�ltoz� bevezet�s�vel k�sz�b�lj�k ki:
int main(int argc, char* argv[ ]) // rossz st�lus
{
// ...
bool in_error = false;
256 Alapok
while (*Driver::input) {
try {
Lexer::get_token();
if (Lexer::curr_tok == Lexer::END) break;
if (Lexer::curr_tok == Lexer::PRINT) {
in_error = false;
continue;
}
if (in_error == false) cout << Parser::expr(false) << '\n';
}
catch(Error::Zero_divide) {
cerr << "null�val oszt�s k�s�rlete\n";
++ Driver::no_of_errors;
in_error = true;
}
catch(Error::Syntax_error e) {
cerr << "formai hiba:" << e.p << "\n";
++ Driver::no_of_errors;
in_error = true;
}
}
if (Driver::input != &std::cin) delete Driver::input;
return Driver::no_of_errors;
}
Ezt sz�mos okb�l rossz �tletnek tartom:
1. Az �llapotv�ltoz�k gyakran zavart okoznak �s hib�k forr�sai lehetnek, k�l�-
n�sen akkor, ha lehetos�get adunk r�, hogy elszaporodjanak �s hat�suk nagy
programr�szekre terjedjen ki. Nevezetesen az in_error-t haszn�l� main()-t
kev�sb� olvashat�nak tartom, mint a skip() f�ggv�nyt haszn�l� v�ltozatot.
2. �ltal�ban jobb k�l�n tartani a hibakezel�st �s a .k�z�ns�ges. k�dot.
3. Vesz�lyes, ha a hibakezel�s elvonatkoztat�si szintje megegyezik annak a k�dnak
az absztrakci�s szintj�vel, ami a hib�t okozta; a hibakezelo k�d ugyanis
megism�telheti azt a hib�t, amely a hibakezel�st elosz�r kiv�ltotta. (A
gyakorlatok
k�z�tt szerepel, hogy mi t�rt�nik, ha a main() in_error-t haszn�l. �8.5[7]).
4. T�bb munk�val j�r az eg�sz k�dot m�dos�tani a hibakezel�s hozz�ad�s�val,
mint k�l�n hibakezelo f�ggv�nyeket adni a k�dhoz.
A kiv�telkezel�s nem helyi probl�m�k megold�s�ra val�. Ha egy hiba helyben
kezelheto,
akkor majdnem mindig ezt is kell tenn�nk. P�ld�ul nincs ok arra, hogy kiv�telt
haszn�ljunk
a .t�l sok param�ter. hiba fell�p�sekor:
8. N�vterek �s kiv�telek 257
int main(int argc, char* argv[])
{
using namespace std;
using namespace Driver;
switch (argc) {
case 1: // olvas�s szabv�nyos bemenetrol
input = &cin;
break;
case 2: // karakterl�nc param�ter beolvas�sa
input = new istringstream(argv[1]);
break;
default:
cerr << "t�l sok param�ter\n";
return 1;
}
// mint kor�bban
}
A kiv�telek tov�bbi t�rgyal�sa a 14. fejezetben t�rt�nik.
8.4. Tan�csok
[1] Haszn�ljunk n�vtereket a logikai fel�p�t�s kifejez�s�re. �8.2.
[2] A main() kiv�tel�vel minden nem lok�lis nevet helyezz�nk valamilyen n�vt�rbe.
�8.2.
[3] A n�vtereket �gy tervezz�k meg, hogy ut�na k�nyelmesen haszn�lhassuk, an�lk
�l, hogy v�letlen�l hozz�f�rhetn�nk m�s, f�ggetlen n�vterekhez. �8.2.4.
[4] Lehetoleg ne adjunk a n�vtereknek r�vid neveket. �8.2.7.
[5] Ha sz�ks�ges, haszn�ljunk n�vt�r-�lneveket a hossz� n�vt�rnevek r�vid�t�s�re.
�8.2.7.
[6] Lehetoleg ne r�junk neh�z jel�l�sbeli terheket n�vtereink felhaszn�l�ira.
�8.2.2.,
�8.2.3.
[7] Haszn�ljuk a N�vt�r::tag jel�l�st, amikor a n�vt�r tagjait meghat�rozzuk.
�8.2.8.
[8] A using namespace.t csak a C-rol vagy r�gebbi C++-v�ltozatokr�l val�
�t�ll�skor,
illetve helyi hat�k�rben haszn�ljuk. �8.2.9.
[9] Haszn�ljunk kiv�teleket arra, hogy a szok�sos feldolgoz�st v�gzo k�dr�szt
elv�-
lasszuk att�l a r�sztol, amelyben a hib�kkal foglalkozunk. �8.3.2.
258 Alapok
[10] Ink�bb felhaszn�l�i t�pusokat haszn�ljunk kiv�telekk�nt, mint be�p�tett
t�pusokat.
�8.3.2.
[11] Ne haszn�ljunk kiv�teleket, amikor a helyi vez�rl�si szerkezetek is
megfeleloek.
�8.3.3.1.
8.5. Gyakorlatok
1. (*2,5) �rjunk string elemeket tartalmaz� k�tir�ny� l�ncolt lista modult a �2.4-
ben
tal�lhat� Stack modul st�lus�ban. Pr�b�ljuk ki �gy, hogy l�trehozunk egy
programnyelvekb
ol �ll� list�t. Adjunk erre list�ra egy sort() f�ggv�nyt �s egy olyat,
ami megford�tja a list�ban szereplo karakterl�ncok sorrendj�t.
2. (*2) Vegy�nk egy nem t�l nagy programot, amely legal�bb egy olyan k�nyvt
�rat haszn�l, ami nem haszn�l n�vtereket. M�dos�tsuk �gy, hogy a k�nyvt�r
n�vtereket haszn�ljon. Tipp: �8.2.9.
3. (*2) K�sz�ts�nk modult a sz�mol�g�p programb�l n�vterek felhaszn�l�s�val
a �2.4 pont st�lus�ban. Ne haszn�ljunk glob�lis using direkt�v�kat. Jegyezz�k fel,

milyen hib�kat v�tett�nk. Tegy�nk javaslatokat arra, mik�nt ker�lhetn�nk el az


ilyen hib�kat a j�voben.
4. (*1) �rjunk programot, amelyben egy f�ggv�ny kiv�telt .dob., egy m�sik pedig
elkapja.
5. (*2) �rjunk programot, amely olyan egym�st h�v� f�ggv�nyekbol �ll, ahol a h�-
v�s m�lys�ge 10. Minden f�ggv�nynek adjunk egy param�tert, amely eld�nti,
melyik szinten l�pett fel a kiv�tel. A main()-nel kapjuk el a kiv�teleket �s �rjuk

ki, melyiket kaptuk el. Ne felejts�k el azt az esetet, amikor a kiv�telt a kiv�lt�

f�ggv�nyben kapjuk el.


6. (*2) M�dos�tsuk a �8.5[5] programj�t �gy, hogy megm�rj�k, van-e k�l�nbs�g
a kiv�telek elkap�s�nak neh�zs�g�ben att�l f�ggoen, hogy a stack oszt�lyon
bel�l hol j�tt l�tre kiv�tel. Adjunk minden f�ggv�nyhez egy karakterl�nc
objektumot
�s m�rj�k meg �jra a k�l�nbs�get.
7. (*1) Tal�ljuk meg a hib�t a �8.3.3.1-ben szereplo main() elso v�ltozat�ban.
8. (*2) �rjunk f�ggv�nyt, amely vagy visszaad egy �rt�ket, vagy egy param�ter
alapj�n eldobja azt. M�rj�k meg a k�t m�dszer fut�si idej�nek k�l�nbs�g�t.
9. (*2) M�dos�tsuk a �8.5[3]-ban l�vo sz�mol�g�pet kiv�telek haszn�lat�val.
Jegyezz�k fel, milyen hib�kat v�tett�nk. Tegy�nk javaslatokat arra, mik�nt
ker�lhetn�nk el az ilyen hib�kat a j�voben.
10. (*2,5) �rjuk meg a plus(), minus(), multiply() �s divide() f�ggv�nyeket,
amelyek
ellenorzik a t�lcsordul�st �s az alulcsordul�st, �s kiv�teleket v�ltanak ki, ha
ilyen hib�k t�rt�nnek.
11. (*2) M�dos�tsuk a sz�mol�g�pet, hogy a �8.5[10] f�ggv�nyeit haszn�lja.
8. N�vterek �s kiv�telek 259
Forr�sf�jlok �s programok
.A form�nak a rendeltet�shez kell igazodnia..
(Le Corbusier)
K�l�n ford�t�s . �sszeszerkeszt�s . Fej�llom�nyok . A standard k�nyvt�r
fej�llom�nyai .
Az egyszeri defini�l�s szab�lya . �sszeszerkeszt�s nem C++ k�ddal . Az
�sszeszerkeszt�s
�s a f�ggv�nyekre hivatkoz� mutat�k . Fej�llom�nyok haszn�lata a modularit�s
kifejez�s�-
re . Egyetlen fej�llom�nyos elrendez�s . T�bb fej�llom�nyos elrendez�s . �llom�ny-

orszemek . Programok . Tan�csok . Gyakorlatok


9.1. K�l�n ford�t�s
A f�jl (az egyes f�jlrendszerekben) a t�rol�s �s ford�t�s hagyom�nyos egys�ge.
Vannak
olyan rendszerek, amelyek a C++ programokat nem f�jlok halmazak�nt t�rolj�k �s
ford�tj
�k, �s a programok sem f�jlok form�j�ban jelennek meg a programoz� sz�m�ra. Ez a
le�r�s
azonban csak azokra a rendszerekre �sszpontos�t, amelyek a f�jlok hagyom�nyos
haszn�-
lat�ra t�maszkodnak.
9
Egy teljes programot rendszerint lehetetlen egy f�jlban t�rolni, m�r csak az�rt
sem, mert
a szabv�nyos k�nyvt�rak �s az oper�ci�s rendszer forr�sk�dja �ltal�ban nem
szerepel
a program forr�s�ban. A val�s�gos m�retu alkalmaz�sokban az sem k�nyelmes �s
c�lszer
u, ha a felhaszn�l� saj�t k�dj�t egyetlen f�jl t�rolja. A program elrendez�si
m�dja seg�thet
kihangs�lyozni a program logikai fel�p�t�s�t, seg�theti az olvas�t a program
meg�rt�s�ben
�s seg�thet abban is, hogy a ford�t�program kik�nyszer�tse ezt a logikai
szerkezetet. Amikor
a ford�t�si egys�g a f�jl, akkor a teljes f�jlt �jra kell ford�tani, ha (b�rmilyen
kis) v�ltoztat�st
hajtottak v�gre rajta, vagy egy m�sik f�jlon, amelytol az elozo f�gg. Az
�jraford�t�sra haszn
�lt ido m�g egy k�zepes m�retu program eset�ben is jelentosen cs�kkentheto, ha a
programot
megfelelo m�retu f�jlokra bontjuk.
A felhaszn�l� a ford�t�programnak egy forr�sf�jlt (source file) ad �t. Ezut�n a
f�jl eloford�-
t�sa t�rt�nik: azaz v�grehajt�dik a makr�feldolgoz�s (�7.8), az #include
utas�t�sok pedig
be�p�tik a fej�llom�nyokat (�2.4.1, �9.2.1). Az elofeldolgoz�s eredm�ny�t
ford�t�si egys�gnek
(translation unit) h�vj�k. A ford�t�program val�j�ban csak ezekkel dolgozik �s a
C++
szab�lyai is ezek form�j�t �rj�k le. Ebben a k�nyvben csak ott teszek k�l�nbs�get
a forr�sf
�jl �s a ford�t�si egys�g k�z�tt, ahol meg kell k�l�nb�ztetni azt, amit a
programoz� l�t, �s
amit a ford�t�program figyelembe vesz. Ahhoz, hogy a programoz� lehetov� tegye az
elk�-
l�n�tett ford�t�st, olyan deklar�ci�kat kell megadnia, amelyek biztos�tj�k mindazt
az inform
�ci�t, ami ahhoz sz�ks�ges, hogy a ford�t�si egys�get a program t�bbi r�sz�tol
elk�l�n�tve
lehessen elemezni. A t�bb ford�t�si egys�gbol �ll� programok deklar�ci�inak
ugyan�gy
k�vetkezetesnek kell lenni�k, mint az egyetlen forr�sf�jlb�l �ll� programok�nak. A
rendszer
�nkben vannak olyan eszk�z�k, amelyek seg�tenek ezt biztos�tani; nevezetesen a
szerkeszt
oprogram (linker), amely sz�mos k�vetkezetlens�get k�pes �szrevenni. Ez az a
program,
ami �sszekapcsolja a k�l�n ford�tott r�szeket. A szerkesztot n�ha (zavar� m�don)
bet
�ltonek (loader) is szokt�k nevezni. A teljes �sszeszerkeszt�st el lehet v�gezni a
program
fut�sa elott. Emellett lehetos�g van arra is, hogy k�sobb �j k�dot adjunk a
programhoz (.dinamikus
szerkeszt�s.).
A program fizikai szerkezet�n �ltal�ban a forr�sf�jlokba szervezett programot
�rtik. A program
forr�sf�jlokra val� fizikai sz�tv�laszt�s�t a program logikai fel�p�t�se kell,
hogy ir�ny�tsa.
A programok forr�sf�jlokba rendez�s�t is ugyanaz a f�ggos�gi kapcsolat vez�rli,
mint
azok n�vterekbol val� �ssze�ll�t�s�t. A program logikai �s fizikai szerkezet�nek
azonban
nem kell megegyeznie. Hasznos lehet p�ld�ul t�bb forr�sf�jlt haszn�lni egyetlen
n�vt�r
f�ggv�nyeinek t�rol�s�ra, n�vt�r-meghat�roz�sok egy gyujtem�ny�t egyetlen f�jlban
t�rolni,
vagy egy n�vt�r defin�ci�it t�bb f�jl k�z�tt sz�tosztani (�8.2.4).
Elosz�r �ttekint�nk n�h�ny, az �sszeszerkeszt�shez kapcsol�d� r�szletet �s
szakkifejez�st,
majd k�tf�le m�dj�t ismertetj�k annak, hogyan lehet f�jlokra sz�tv�lasztani a
sz�mol�g�pet
(�6.1, �8.2).
262 Alapok
9.2. �sszeszerkeszt�s
A f�ggv�nyek, oszt�lyok, sablonok, v�ltoz�k, n�vterek, felsorol�sok �s felsorol�k
neveit
k�vetkezetesen kell haszn�lni az �sszes ford�t�si egys�gben, kiv�ve, ha
kifejezetten lok�lisk
�nt nem hat�roztuk meg azokat.
A programoz� feladata biztos�tani, hogy minden n�vt�r, oszt�ly, f�ggv�ny stb.
megfeleloen
legyen deklar�lva minden olyan ford�t�si egys�gben, amelyben szerepel, �s hogy
minden
deklar�ci�, amely ugyanarra az egyedre vonatkozik, egys�ges legyen. Vegy�k p�ld�ul
a k�-
vetkezo k�t f�jlt:
// file1.c:
int x = 1;
int f() { /* csin�lunk valamit */ }
// file2.c:
extern int x;
int f();
void g() { x = f(); }
A file2.c-ben l�vo g() �ltal haszn�lt x �s f() meghat�roz�sa a file1.c-ben
szerepel. Az extern
kulcssz� jelzi, hogy a file2.c-ben az x deklar�ci�ja (csak) deklar�ci� �s nem
defin�ci� (�4.9).
Ha x m�r rendelkezne kezdo�rt�kkel, a ford�t�program az extern kulcssz�t
egyszeruen figyelmen
k�v�l hagyn�, mert a kezdo�rt�ket is meghat�roz� deklar�ci�k egyben defin�-
ci�nak is minos�lnek. Egy objektumot a programban csak pontosan egyszer
hat�rozhatunk
meg. Deklar�lni t�bbsz�r is lehet, de a t�pusoknak pontosan meg kell egyezni�k:
// file1.c:
int x = 1;
int b = 1;
extern int c;
// file2.c:
int x; // jelent�se int x = 0;
extern double b;
extern int c;
Itt h�rom hiba van: x-et k�tszer defini�ltuk, b-t k�tszer deklar�ltuk k�l�nb�zo
t�pusokkal,
c-t pedig k�tszer deklar�ltuk, de egyszer sem defini�ltuk. Az effajta hib�kat
(szerkeszt�si hiba,
linkage error) a ford�t�program . ami egyszerre csak egy f�jlt n�z . nem ismeri
fel, a
szerkeszto azonban a legt�bbet igen. Jegyezz�k meg, hogy a glob�lis vagy n�vt�r-
hat�k�r-
9. Forr�sf�jlok �s programok 263
ben kezdo�rt�k n�lk�l megadott v�ltoz�k alap�rtelmez�s szerint kapnak
kezdo�rt�ket. Ez
nem vonatkozik a lok�lis v�ltoz�kra (�4.9.5, �10.4.2) vagy a szabad t�rban
l�trehozott objektumokra
(�6.2.6).
A k�vetkezo programr�szlet k�t hib�t tartalmaz:
// file1.c:
int x;
int f() { return x; }
// file2.c:
int x;
int g() { return f(); }
A file2.c-ben az f() megh�v�sa hiba, mert f()-et a file2.c nem deklar�lja.
Ezenk�v�l a szerkeszt
o nem fogja �sszeszerkeszteni a programot, mert x-et k�tszer defini�ltuk.
Jegyezz�k
meg, hogy az f() megh�v�sa a C nyelvben nem lenne hiba (�B.2.2).
Az olyan neveket, amelyeket a nevet meghat�roz� ford�t�si egys�gtol k�l�nb�zo
ford�t�si
egys�gben is haszn�lhatunk, k�lso szerkeszt�sunek (external linkage) nevezz�k. Az
elozo
p�ld�kban szereplo �sszes n�v k�lso n�v. Az olyan neveket, amelyekre csak abban a
ford
�t�si egys�gben lehet hivatkozni, ahol meghat�roz�suk szerepel, belso szerkeszt�su
n�vnek
nevezz�k.
A helyben kifejtett (inline) f�ggv�nyeket (�7.1.1, �10.2.9) minden olyan ford�t�si
egys�gben
defini�lni kell . azonos m�don (�9.2.3) ., amelyben haszn�latosak. Ez�rt a
k�vetkezo p�lda
nem csak rossz st�lusra vall, hanem szab�lytalan is:
// file1.c:
inline int f(int i) { return i; }
// file2.c:
inline int f(int i) { return i+1; }
Sajnos, ezt a hib�t a C++ egyes v�ltozatai nehezen veszik �szre, ez�rt a helyben
kifejtett k�d
�s a k�lso szerkeszt�s k�vetkezo . k�l�nben teljesen logikus . p�ros�t�sa tiltott,
hogy a ford
�t�program-�r�k �lete k�nnyebb legyen:
// file1.c:
extern inline int g(int i);
int h(int i) { return g(i); } // hiba: g() nincs defini�lva ebben a ford�t�si
egys�gben
// file2.c:
extern inline int g(int i) { return i+1; }
264 Alapok
Alap�rtelmez�s szerint a const-ok (�5.4) �s a typedef-ek (�4.9.7) belso
szerkeszt�suek. K�-
vetkez�sk�ppen ez a p�lda szab�lyos (b�r zavar� lehet):
// file1.c:
typedef int T;
const int x = 7;
// file2.c:
typedef void T;
const int x = 8;
Az olyan glob�lis v�ltoz�k, amelyek egy adott ford�t�si egys�gben lok�lisnak
sz�m�tanak,
gyakran okoznak zavart, ez�rt legjobb elker�lni oket. A glob�lis konstansokat �s a
helyben
kifejtett f�ggv�nyeket rendszerint csak fej�llom�nyokba (�9.2.1) szabadna tenn�nk,
hogy
biztos�tsuk a k�vetkezetess�get. A konstansokat kifejezett utas�t�ssal tehetj�k
k�lso szerkeszt
�suv�:
// file1.c:
extern const int a = 77;
// file2.c:
extern const int a;
void g()
{
cout << a << '\n';
}
Itt g() 77-et fog ki�rni.
A n�vtelen n�vtereket (�8.2.5) arra haszn�lhatjuk, hogy a neveket egy adott
ford�t�si egys�gre
n�zve lok�liss� tegy�k. A n�vtelen n�vterek �s a belso szerkeszt�s hat�sa nagyon
hasonl�:
// file 1.c:
namespace {
class X { /* ... */ };
void f();
int i;
// ...
}
// file2.c:
class X { /* ... */ };
void f();
int i;
// ...
9. Forr�sf�jlok �s programok 265
A file1.c-ben l�vo f() f�ggv�ny nem azonos a file2.c-ben l�vo f() f�ggv�nnyel. Ha
van egy
adott ford�t�si egys�gre n�zve lok�lis nev�nk �s ugyanazt a nevet haszn�ljuk
m�shol egy
k�lso szerkeszt�su egyed sz�m�ra is, akkor magunk keress�k a bajt.
A C nyelvu �s a r�gebbi C++ programokban a static kulcssz�t haszn�lt�k (zavar�an)
annak
a kifejez�s�re, hogy .haszn�lj belso szerkeszt�st. (�B.2.3). A static kulcssz�t
lehetoleg csak
f�ggv�nyeken (�7.2.1) �s oszt�lyokon (�10.2.4) bel�l haszn�ljuk.
9.2.1. Fej�llom�nyok
A t�pusoknak ugyanannak az objektumnak, f�ggv�nynek, oszt�lynak stb. minden
deklar�-
ci�j�ban egys�gesnek kell lenni�k, k�vetkez�sk�ppen a ford�t�nak �tadott �s k�sobb

�sszeszerkesztett forr�sk�dnak is. A k�l�nb�zo ford�t�si egys�gekben l�vo


deklar�ci�k
egys�gess�g�nek el�r�s�re nem t�k�letes, de egyszeru m�dszer, hogy a v�grehajthat�
k�-
dot �s/vagy adatle�r�sokat tartalmaz� forr�sf�jlokba be�p�tj�k (#include) a
fel�letre vonatkoz
� inform�ci�kat tartalmaz� fej�llom�nyokat (header).
Az #include sz�vegkezelo eszk�z, ami arra val�, hogy a forr�sk�d-r�szeket egyetlen
egys
�gbe (f�jlba) gyujts�k �ssze a ford�t�shoz. Az
#include "be�p�tendo"
utas�t�s a be�p�tendo f�jl tartalm�ra cser�li azt a sort, amelyben az #include
elofordul. A f�jl
tartalm�nak C++ forr�ssz�vegnek kell lennie, mert a ford�t�program ennek
olvas�s�val halad
tov�bb.
A standard k�nyvt�rbeli fej�llom�nyok be�p�t�s�hez a f�jl nev�t id�zojelek helyett
a < >
z�r�jelp�rok k�z� kell foglalni:
#include <iostream> // a szabv�nyos include k�nyvt�rb�l
#include "myheader.h" // az aktu�lis k�nyvt�rb�l
Sajnos a be�p�to utas�t�sban a sz�k�z�k mind a < >, mind a " " belsej�ben
fontosak:
#include < iostream > // nem fogja megtal�lni az <iostream>-et
Furcs�nak tunhet, hogy egy f�jlt minden egyes alkalommal �jra kell ford�tani, ha
valahov�
m�shov� be�p�tj�k, de a be�p�tett f�jlok jellemzoen csak deklar�ci�kat
tartalmaznak, �s
nem olyan k�dot, amelyet a ford�t�programnak alaposan elemeznie kellene. Tov�bb� a
leg-
266 Alapok
t�bb modern C++-v�ltozat valamilyen form�ban t�mogatja az eloford�tott
fej�llom�nyokat,
hogy cs�kkentse a munk�t, amit ugyanannak a fej�llom�nynak az ism�telt ford�t�sa
jelent.
Alapszab�lyk�nt fogadjuk el, hogy egy fej�llom�nyban a k�vetkezok szerepelhetnek:
Mindez nem nyelvi k�vetelm�ny, csak �sszeru m�dja az #include haszn�lat�nak a
logikai szerkezet
kifejez�s�re. Ezzel ellent�tben egy fej�llom�ny sohasem tartalmazhatja a
k�vetkezoket:
A fej�llom�nyok hagyom�ny szerint .h kiterjeszt�suek, a f�ggv�ny- �s
adatdefin�ci�kat tartalmaz
� f�jlok kiterjeszt�se pedig .c, ez�rt gyakran h�vj�k ezeket ..h f�jlok.-nak
�s ..c f�jlok
.-nak. M�s szok�sos jel�l�seket is tal�lhatunk, mint a .C, .cxx, .cpp �s .cc.
Ford�t�programunk
dokument�ci�ja ezt j�l meghat�rozza.
9. Forr�sf�jlok �s programok 267
Neves�tett n�vterek namespace N { /* . */ }
T�pusdefin�ci�k struct Point { int x, y; };
Sablondeklar�ci�k template<class T> class Z;
Sablondefin�ci�k template<class T> class V { /* . */ };
F�ggv�nydeklar�ci�k extern int strlen(const char*);
Helyben kifejtett f�ggv�nyek
defin�ci�i inline char get(char* p) { return *p++; }
Adatdeklar�ci�k extern int a;
Konstansdefin�ci�k const float pi = 3.141593;
Felsorol�sok enum Light { red, yellow, green };
N�vdeklar�ci�k class Matrix;
Be�p�to utas�t�sok #include <algorithm>
Makr�defin�ci�k #define VERSION 12
Felt�teles ford�t�si utas�t�sok #ifdef __cplusplus
Megjegyz�sek /* check for end of file */
K�z�ns�ges
f�ggv�nydefin�ci�k char get(char *p) { return *p++; }
Adatdefin�ci�k int a;
Agreg�tum-defin�ci�k short tbl[ ] = { 1, 2, 3 };
N�vtelen n�vterek namespace { /* . */ }
Export�lt
sablondefin�ci�k export template<class T>f(T t) { /* . */ }
Az egyszeru �lland�kat aj�nlatos fej�llom�nyokba tenni. Az agreg�tumokat azonban
nem,
mert az egyes C++-v�ltozatok nehezen tudj�k elker�lni, hogy a t�bb ford�t�si
egys�gben
elofordul� egyedeibol m�sodp�ld�nyt k�sz�tsenek. Ezenk�v�l az egyszeru esetek
sokkal
gyakoribbak, ez�rt j� k�d k�sz�t�s�hez fontosabbak. B�lcs dolog nem t�l okosnak
lenni az
#include haszn�lat�n�l. Azt aj�nlom, csak teljes deklar�ci�kat �s defin�ci�kat
�p�ts�nk be
�s csak glob�lis hat�k�rben, szerkeszt�si blokkokban, vagy olyan
n�vt�rdefin�ci�kn�l, amikor
r�gi k�dot alak�tunk �t (�9.2.2) tegy�k ezt. C�lszeru elker�lni a makr�kkal val�
�gyesked
�st is. Az egyik legkev�sb� kedvelt foglalatoss�gom olyan hib�t nyomon k�vetni,
amit
egy olyan n�v okoz, amelyet egy k�zvetetten be�p�tett, sz�momra teljesen
ismeretlen fej�llom
�nyban szereplo makr� helyettes�t.
9.2.2. A standard k�nyvt�r fej�llom�nyai
A standard k�nyvt�r eszk�zeit szabv�nyos fej�llom�nyok halmaz�n kereszt�l mutatjuk
be
(�16.1.2). A standard k�nyvt�rbeli fej�llom�nyokat nem kell ut�taggal ell�tnunk;
tudjuk r�-
luk, hogy fej�llom�nyok, mert beilleszt�s�kh�z az #include <.> form�t haszn�ljuk
az
#include "." helyett. A .h kiterjeszt�s hi�nya nem utal semmire a fej�llom�ny
t�rol�s�val
kapcsolatban. Egy olyan fej�llom�ny, mint a <map>, val�sz�nuleg a map.h nevu
sz�vegf�jlban
t�rol�dik a szok�sos k�nyvt�rban. M�sfelol a szabv�nyos fej�llom�nyokat nem musz�j

hagyom�nyos m�don t�rolni. Az egyes C++-v�ltozatok sz�m�ra megengedett, hogy


kihaszn
�lj�k a standard k�nyvt�r defin�ci�inak ismeret�t �s ez�ltal optimaliz�lj�k annak
megval�-
s�t�s�t, illetve a szabv�nyos fej�llom�nyok kezel�s�nek m�dj�t. A nyelv adott
megval�s�t�-
sa ismerheti a be�p�tett szabv�nyos matematikai k�nyvt�rat (�22.3) �s �gy
kezelheti az
#include <cmath> utas�t�st, mint egy kapcsol�t, ami an�lk�l teszi el�rhetov� a
szabv�nyos
matematikai f�ggv�nyeket, hogy b�rmilyen f�jlt beolvasn�nk. A C standard
k�nyvt�r�nak
minden <X.h> fej�llom�ny�hoz l�tezik megfelelo szabv�nyos <cX> C++ fej�llom�ny.
Az #include <cstdio> p�ld�ul azt ny�jtja, amit az #include <stdio.h>. A stdio.h
f�jl �ltal�ban
valahogy �gy n�z ki:
#ifdef __cplusplus // csak C++ ford�t�k sz�m�ra (�9.2.4)
namespace std { // a standard k�nyvt�rat az std n�vt�r �rja le (�8.2.9)
extern "C" { // az stdio f�ggv�nyek C szerkeszt�suek (�9.2.4)
#endif
// ...
int printf(const char* ...);
// ...
#ifdef __cplusplus
}
}
using namespace std; // az stdio el�rhetov� t�tele a glob�lis n�vt�rben
#endif
268 Alapok
Azaz a deklar�ci�k (nagy val�sz�nus�ggel) k�z�sek, de az �sszeszerkeszt�ssel �s
n�vterekkel
kapcsolatos dolgokra oda kell figyeln�nk, hogy lehetov� tegy�k, hogy a C �s C++
osztozzanak
a fej�llom�nyon.
9.2.3. Az egyszeri defini�l�s szab�lya
Egy adott oszt�lyt, felsorol�st, sablont stb. mindig csak egyszer defini�lhatunk
egy programban.
Gyakorlati szempontb�l ez azt jelenti, hogy p�ld�ul egy oszt�lynak, amelyet
valahol
egy f�jlban t�rolunk, pontosan egy kifejt�ssel kell rendelkeznie. Sajnos, a nyelvi
szab�ly nem
lehet ennyire egyszeru. Egy oszt�ly defin�ci�j�t p�ld�ul �ssze lehet �ll�tani
makr�k behelyettes
�t�s�vel is, de #include utas�t�sokkal (�9.2.1) sz�veges form�ban k�t
forr�sf�jlban is el
lehet helyezni. M�g enn�l is nagyobb baj, hogy a .f�jl. fogalma nem r�sze a C �s
C++ nyelvnek,
�gy vannak olyan v�ltozatok, amelyek a programokat nem forr�sf�jlokban t�rolj�k.
K�vetkez�sk�ppen a szabv�nyban l�vo szab�lyt . amely azt mondja, hogy egy oszt�ly,
sablon
stb. defin�ci�j�nak egyedinek kell lennie . valamelyest bonyolultabb �s ravaszabb
m�-
don fogalmaztuk meg. Ezt a szab�lyt gyakran az .egyszeri defini�l�s szab�ly�nak.
(ODR,
one-definition rule) nevezik. Azaz egy oszt�ly, sablon, vagy helyben kifejtett
f�ggv�ny k�tf
�le defini�l�sa kiz�r�lag akkor fogadhat� el ugyanazon egyed k�t p�ld�nyak�nt, ha
1. k�l�nb�zo ford�t�si egys�gben szerepelnek �s
2. szimb�lumr�l szimb�lumra megegyeznek �s
3. ezen szimb�lumok jelent�se mindk�t ford�t�si egys�gben ugyanaz.
P�ld�ul:
// file1.c:
struct S { int a; char b; };
void f(S*);
// file2.c:
struct S { int a; char b; };
void f(S* p) { /* ... */ }
Az ODR �rtelm�ben a fenti p�lda helyes �s S ugyanarra az oszt�lyra vonatkozik
mindk�t
forr�sf�jlban. Nem b�lcs dolog azonban egy defin�ci�t ilyen m�don k�tszer le�rni.
Ha valaki
m�dos�tja a file2.c-t, azt felt�telezheti, hogy az ott szereplo S az S egyetlen
defini�l�sa �s
szabadon megv�ltoztathatja azt, ami nehezen felfedezheto hib�t okozhat.
9. Forr�sf�jlok �s programok 269
270 Alapok
Az ODR sz�nd�ka az, hogy megengedje egy oszt�lydefin�ci� beilleszt�s�t k�l�nb�zo
forr
�sf�jlokba egy k�z�s forr�sf�jlb�l:
// file s.h:
struct S { int a; char b; };
void f(S*);
// file1.c:
#include "s.h"
// f() haszn�lata itt
// file2.c:
#include "s.h"
void f(S* p) { /* ... */ }
�br�val:
N�zz�nk p�ld�kat az ODR szab�ly megs�rt�s�nek mindh�rom m�dj�ra:
// file1.c:
struct S1 { int a; char b; };
struct S1 { int a; char b; }; // hiba: k�t defin�ci�
Ez az�rt hiba, mert egy struct-ot egyetlen ford�t�si egys�gben nem lehet k�tszer
defini�lni.
// file1.c:
struct S2 { int a; char b; };
// file2.c:
struct S2 { int a; char bb; };// hiba
s.h:
file1.c: file2.c:
struct S {int a; char b};
void f(S*);
#include "s.h"
// f() haszn�lata itt
#include "s.h"
void f(S*p) {/*...*/}
Ez az�rt hiba, mert S2 olyan oszt�lyokat nevez meg, amelyek egy tag nev�ben
k�l�nb�znek.
// file1.c:
typedef int X;
struct S3 { X a; char b; };
// file2.c:
typedef char X;
struct S3 { X a; char b; }; // hiba
Itt az S3 k�t definici�ja szimb�lumr�l szimb�lumra megegyezik, de a p�lda hib�s,
mert az
X n�v (tr�kk�s m�don) m�st jelent a k�t f�jlban.
A legt�bb C++-v�ltozat nem k�pes a k�l�nb�zo ford�t�si egys�gekben l�vo
oszt�lydefin
�ci�k k�vetkezetess�g�t ellenorizni, ez�rt az ODR-t megs�rto deklar�ci�k nehezen
�szreveheto hib�kat okozhatnak. Sajnos az a m�dszer sem k�pes az ODR utols�k�nt
bemutatott
megszeg�se ellen v�delmet ny�jtani, amikor a k�z�s definici�kat fej�llom�nyokba
tessz�k �s azt�n azokat �p�tj�k be. A helyi typedef-ek �s makr�k ugyanis
m�dos�thatj�k
a be�p�tett deklar�ci�k jelent�s�t:
// file s.h:
struct S { Point a; char b; };
// file1.c:
#define Point int
#include "s.h"
// ...
// file2.c:
class Point { /* ... */ };
#include "s.h"
// ...
Az ilyen k�dm�dosul�s ellen �gy v�dekezhet�nk a legjobban, ha a fej�llom�nyokat
annyira
k�l�n�ll�v� tessz�k, amennyire csak lehets�ges. P�ld�ul ha a Point oszt�lyt az s.h
�llom
�nyban vezett�k volna be, a ford�t�program felismerte volna a hib�t.
A sablondefin�ci�kat t�bb ford�t�si egys�gbe is be�p�thetj�k, am�g ez nem s�rti az
ODR-t,
az export�lt sablonokat pedig �gy is haszn�lhatjuk, hogy csak a deklar�ci�jukat
adjuk meg:
// file1.c:
export template<class T> T twice(T t) { return t+t; }
9. Forr�sf�jlok �s programok 271
// file2.c:
template<class T> T twice(T t); // deklar�ci�
int g(int i) { return twice(i); }
Az export kulcssz� azt jelenti, hogy .m�s ford�t�si egys�gbol el�rheto. (�13.7).
9.2.4. �sszeszerkeszt�s nem C++ k�ddal
A C++ programok �ltal�ban m�s nyelven meg�rt r�szleteket is tartalmaznak.
Hasonl�an gyakori
az is, hogy C++ k�dr�szletet haszn�lnak m�s nyelven meg�rt programok r�szek�nt.
Az egy�ttmuk�d�s a k�l�nb�zo nyelven meg�rt programr�szek k�z�tt nem mindig
k�nnyu . sot m�g az azonos nyelven �rt, de k�l�nb�zo ford�t�programmal leford�tott
k�dr
�szletek k�z�tt sem. A k�l�nb�zo nyelvek �s ugyanazon nyelv k�l�nb�zo
megval�s�t�sai
p�ld�ul k�l�nb�zok�ppen haszn�lhatj�k a g�pi regisztereket a param�terek
t�rol�s�ra,
m�sk�ppen helyezhetik azokat a verembe, k�l�nb�zo lehet a be�p�tett t�pusok,
p�ld�ul
a karakterl�ncok �s eg�szek szerkezete, illetve azon nevek form�ja, melyeket a
ford�t�program
a szerkesztonek �tad, �s a szerkesztotol megk�vetelt t�pusellenorz�sek. Hogy
seg�ts
�nk, �sszeszerkeszt�si szab�lyt hat�rozhatunk meg az extern deklar�ci�kra. A
k�vetkezo
p�lda bevezeti a C �s a C++ standard k�nyvt�raiban levo strcpy() f�ggv�nyt, �s
meghat�-
rozza, hogy a C �sszeszerkeszt�si szab�lyainak megfeleloen kell azt
hozz�szerkeszteni
a k�dhoz:
extern "C" char* strcpy(char*, const char*);
A deklar�ci� hat�sa a .sima. deklar�ci�k�t�l csak az strcpy() h�v�s�ra haszn�lt
�sszeszerkeszt
�si szab�lyban t�r el.
extern char* strcpy(char*, const char*);
Az extern "C" utas�t�s k�l�n�sen fontos a C �s a C++ k�z�tti szoros kapcsolat
miatt. Jegyezz
�k meg, hogy az extern "C"-ben szereplo "C" az �sszeszerkeszt�si szab�lyt, nem
pedig
a programnyelvet jel�li. Az extern "C"-t gyakran haszn�lj�k olyan Fortran vagy
assembler
elj�r�sokkal val� �sszeszerkeszt�shez, melyek v�letlen�l �ppen megfelelnek a C
k�vetelm
�nyeinek.
Az extern "C" utas�t�s (csak) az �sszeszerkeszt�si szab�lyt hat�rozza meg, a
f�ggv�nyh�-
v�sok szerep�t nem befoly�solja. Az extern "C"-k�nt megadott f�ggv�nyekre is a C++
t�-
pusellenorz�si �s param�ter-�talak�t�si szab�lyai vonatkoznak, nem pedig a
gyeng�bb C
szab�lyok.
272 Alapok
P�ld�ul:
extern "C" int f();
int g()
{
return f(1); // hiba: nem v�r param�tert
}
K�nyelmetlen lehet, ha sok deklar�ci�hoz kell hozz�adnunk az extern "C"-t, ez�rt
bevezett
�nk egy elj�r�st, mellyel deklar�ci�k egy csoportj�nak �sszeszerkeszt�s�t
hat�rozhatjuk
meg:
extern "C" {
char* strcpy(char*, const char*);
int strcmp(const char*, const char*);
int strlen(const char*);
// ...
}
Ezt a szerkezetet, melyet gyakran szerkeszt�si blokknak (linkage block) neveznek,
�gy is
haszn�lhatjuk, hogy belefoglalunk egy teljes C fej�llom�nyt �s �gy alkalmass�
tessz�k azt
a C++-ban val� haszn�latra:
extern "C" {
#include <string.h>
}
A fenti m�dszer gyakran haszn�latos arra, hogy C fej�llom�nyokb�l C++
fej�llom�nyokat
hozzanak l�tre. Egy m�sik lehetos�g, ha felt�teles ford�t�st (�7.8.1) haszn�lunk,
hogy k�z�s
C �s C++ fej�llom�nyt k�sz�ts�nk:
#ifdef __cplusplus
extern "C" {
#endif
char* strcpy(char*, const char*);
int strcmp(const char*, const char*);
int strlen(const char*);
// ...
#ifdef __cplusplus
}
#endif
9. Forr�sf�jlok �s programok 273
A .k�szen kapott. __cplusplus makr� haszn�lat�val azt biztos�thatjuk, hogy a C++
szerkezetek
eltunjenek, amikor a f�jlt C fej�llom�nyk�nt haszn�ljuk.
Egy szerkeszt�si blokkon bel�l b�rmilyen deklar�ci� szerepelhet:
extern "C" { // b�rmilyen deklar�ci� j�het ide, pl:
int g1; // defin�ci�
extern int g2; // deklar�ci�, nem defin�ci�
}
Ez a v�ltoz�k hat�k�r�t �s t�rol�si oszt�ly�t nem �rinti, �gy g1 glob�lis v�ltoz�
marad, �s
definici�ja is lesz, nem csak deklar�ci�ja. Ha egy v�ltoz�t csak deklar�lni, nem
pedig
defini�lni akarunk, az extern kulcssz�t k�zvetlen�l a deklar�ci� elott kell
megadnunk:
extern "C" int g3; // deklar�ci�, nem defin�ci�
Ez elso l�t�sra furcs�nak tunik, pedig c�lja csak annyi, hogy a deklar�ci�
jelent�se v�ltozatlan
maradjon, amikor egy extern deklar�ci�hoz "C"-t adunk (�s a f�jl jelent�se is,
amikor
majd a szerkeszt�si blokkba foglaljuk).
Egy C szerkeszt�su nevet n�vt�rben is megadhatunk. A n�vt�r azt befoly�solni
fogja, hogyan
lehet a n�vhez hozz�f�rni C++ programokb�l, de azt nem, hogy a szerkeszto hogyan
fogja l�tni a nevet. Egy jellemzo p�lda erre az std n�vt�r printf() f�ggv�nye:
#include<cstdio>
void f()
{
std::printf("Hell�, "); // rendben
printf("vil�g!\n"); // hiba: nincs glob�lis printf()
}
M�g ha std::printf()-nek nevezz�k is, ez m�g mindig ugyanaz a r�gi C printf()
(�21.8). Ez
lehetov� teszi sz�munkra, hogy C szerkeszt�su k�nyvt�rakat �p�ts�nk be egy
�ltalunk v�-
lasztott n�vt�rbe, ahelyett, hogy a glob�lis n�vteret .szennyezn�nk". Sajnos
ugyanez a rugalmass
�g nem �ll rendelkez�s�nkre az olyan fej�llom�nyok eset�ben, amelyek C++ szerkeszt
�su f�ggv�nyeket hat�roznak meg a glob�lis n�vt�rben. Ennek az az oka, hogy a C++
egyedek �sszeszerkeszt�s�n�l figyelembe kell venni a n�vtereket is, �gy a
l�trehozott t�rgyk
�d (object f�jl) t�kr�zni fogja a n�vterek haszn�lat�t vagy annak hi�ny�t.
274 Alapok
9.2.5. Az �sszeszerkeszt�s �s a f�ggv�nyekre hivatkoz� mutat�k
Ha egy programban a C �s C++ k�dr�szleteket keverj�k, elofordulhat, hogy az egyik
nyelven
meg�rt f�ggv�nyekre hivatkoz� mutat�kat a m�sik nyelven defini�lt f�ggv�nyeknek
szeretn
�nk �tadni. Ha a k�t nyelv adott v�ltozatainak �sszeszerkeszt�si szab�lyai,
illetve a f�ggv
�nyh�v�si elj�r�sok k�z�sek, a f�ggv�nyekre hivatkoz� mutat�k �tad�sa egyszeru.
Ennyi k�-
z�s tulajdons�g azonban �ltal�ban nem t�telezheto fel, �gy figyeln�nk kell arra,
hogy biztos�tsuk
a f�ggv�nyek oly m�don t�rt�no megh�v�s�t, ahogy azt a f�ggv�ny elv�rja. Ha egy
deklar
�ci� sz�m�ra meghat�rozzuk az �sszeszerkeszt�si m�dot, akkor az minden olyan f�ggv
�nyt�pusra, f�ggv�nyn�vre, �s v�ltoz�n�vre vonatkozni fog, amit a deklar�ci�(k)
bevezet(nek). Ez mindenf�le furcsa . de n�ha alapveto . �sszeszerkeszt�si m�dot
leheto-
v� tesz. P�ld�ul:
typedef int (*FT)(const void*, const void*); // FT C++ szerkeszt�su
extern "C" {
typedef int (*CFT)(const void*, const void*); // CFT C szerkeszt�su
void qsort(void* p, size_t n, size_t sz, CFT cmp); // cmp C szerkeszt�su
}
void isort(void* p, size_t n, size_t sz, FT cmp); // cmp C++ szerkeszt�su
void xsort(void* p, size_t n, size_t sz, CFT cmp); // cmp C szerkeszt�su
extern "C" void ysort(void* p, size_t n, size_t sz, FT cmp); // cmp C++
szerkeszt�su
int compare(const void*, const void*); // compare() C++ szerkeszt�su
extern "C" int ccmp(const void*, const void*); // ccmp() C szerkeszt�su
void f(char* v, int sz)
{
qsort(v,sz,1,&compare); // hiba
qsort(v,sz,1,&ccmp); // rendben
isort(v,sz,1,&compare); // rendben
isort(v,sz,1,&ccmp); // hiba
}
Egy olyan nyelvi v�ltozat, amelyben a C �s C++ ugyanazt a f�ggv�nyh�v�si m�dot
haszn�lja,
nyelvi kiterjeszt�sk�nt elfogadhatja a hibak�nt megjel�lt eseteket.
9. Forr�sf�jlok �s programok 275
9.3. Fej�llom�nyok haszn�lata
A fej�llom�nyok haszn�lat�nak illusztr�l�s�ra most bemutatjuk a sz�mol�g�p program

(�6.1, �8.2) n�h�ny lehets�ges fizikai elrendez�s�t.


9.3.1. Egyetlen fej�llom�nyos elrendez�s
Egy programot �gy bonthatunk a legegyszerubben t�bb f�jlra, hogy a defin�ci�kat
megfelel
o sz�m� .c f�jlba, a .c f�jlok k�z�tti kapcsolatot biztos�t� t�pusok deklar�ci�it
pedig
egyetlen .h f�jlba tessz�k, melyet minden .c f�jl be�p�t (#include). A sz�mol�g�p
program
eset�ben �t .c f�jlt . lexer.c, parser.c, table.c, error.c �s main.c .
haszn�lhatn�nk a f�ggv�-
nyek �s adatle�r�sok t�rol�s�ra, �s a dc.h fej�llom�nyban t�rolhatn�nk azoknak a
neveknek
a deklar�ci�it, amelyek egyn�l t�bb f�jlban haszn�latosak.
A dc.h fej�llom�ny �gy n�zne ki:
// dc.h:
namespace Error {
struct Zero_divide { };
struct Syntax_error {
const char* p;
Syntax_error(const char* q) { p = q; }
};
}
#include <string>
namespace Lexer {
enum Token_value {
NAME, NUMBER, END,
PLUS='+', MINUS='-', MUL='*', DIV='/',
PRINT=';', ASSIGN='=', LP='(', RP=')'
};
extern Token_value curr_tok;
extern double number_value;
extern std::string string_value;
Token_value get_token();
}
276 Alapok
namespace Parser {
double prim(bool get); // elemi szimb�lumok kezel�se
double term(bool get); // szorz�s �s oszt�s
double expr(bool get); // �sszead�s �s kivon�s
using Lexer::get_token;
using Lexer::curr_tok;
}
#include <map>
extern std::map<std::string,double> table;
namespace Driver {
extern int no_of_errors;
extern std::istream* input;
void skip();
}
Minden v�ltoz�deklar�ci�ban az extern kulcssz�t haszn�ljuk annak biztos�t�s�ra,
hogy egy
meghat�roz�s ne forduljon elo t�bbsz�r is, amikor a dc.h-t a f�jlokba be�p�tj�k.
Az egyes
defin�ci�k a megfelelo .c f�jlban szerepelnek.
A l�nyegi k�d elhagy�s�val a lexer.c valahogy �gy n�z ki:
// lexer.c:
#include "dc.h"
#include <iostream>
#include <cctype>
Lexer::Token_value Lexer::curr_tok;
double Lexer::number_value;
std::string Lexer::string_value;
Lexer::Token_value Lexer::get_token() { /* ... */ }
A fej�llom�ny ilyen haszn�lata biztos�tja, hogy a benne l�vo minden deklar�ci�
valamilyen
ponton be legyen �p�tve abba a f�jlba, amely a hozz� tartoz� kifejt�st
tartalmazza. A lexer.c
ford�t�sakor p�ld�ul a ford�t�programnak a k�vetkezo k�d ad�dik �t:
namespace Lexer { // a dc.h-b�l
// ...
Token_value get_token();
}
// ...
Lexer::Token_value Lexer::get_token() { /* ... */ }
9. Forr�sf�jlok �s programok 277
�gy a ford�t�program biztosan �szreveszi, ha egy n�vhez megadott t�pusok nem
egys�gesek.
Ha a get_token()-t p�ld�ul Token_value t�pus� visszat�r�si �rt�kkel vezett�k volna
be,
de int visszat�r�si �rt�kkel defini�ltuk volna, a lexer.c ford�t�sa t�pus�tk�z�si
vagy .nem
megfelelo t�pus. (type mismatch) hiba miatt nem siker�lt volna. Ha egy defin�ci�
hi�nyzik,
a szerkeszto fogja �szrevenni a probl�m�t, ha egy deklar�ci�, akkor valamelyik .c
f�jl ford
�t�sa hi�sul meg.
A parser.c f�jl �gy fog kin�zni:
// parser.c:
#include "dc.h"
double Parser::prim(bool get) { /* ... */ }
double Parser::term(bool get) { /* ... */ }
double Parser::expr(bool get) { /* ... */ }
A table.c pedig �gy:
// table.c:
#include "dc.h"
std::map<std::string,double> table;
A szimb�lumt�bla nem m�s, mint egy standard k�nyvt�rbeli map t�pus� v�ltoz�. A
fenti defin
�ci� a table-t glob�lisk�nt hat�rozza meg. Egy val�s�gos m�retu programban a
glob�lis
n�vt�r eff�le kis .szennyezod�sei. felhalmoz�dnak �s v�g�l probl�m�kat okoznak.
Csak
az�rt voltam itt ilyen hanyag, hogy lehetos�gem legyen figyelmeztetni r�.
A main.c f�jl v�g�l �gy fog kin�zni:
// main.c:
#include "dc.h"
#include <sstream>
int Driver::no_of_errors = 0;
std::istream* Driver::input = 0;
void Driver::skip() { /* ... */ }
int main(int argc, char* argv[ ]) { /* ... */ }
278 Alapok
Ahhoz, hogy a program main() f�ggv�ny�nek ismerj�k fel, a main()-nek glob�lis
f�ggv
�nynek kell lennie, ez�rt itt nem haszn�ltunk n�vteret.
A program fizikai elrendez�s�t valahogy �gy lehet bemutatni:
�szrevehetj�k, hogy a fel�l l�vo fej�llom�nyok mind a standard k�nyvt�r f�jljai. A
program
elemz�sekor ezek a k�nyvt�rak sz�mos esetben kihagyhat�k, mert sz�lesk�ruen
ismertek
�s stabilak. A kis programokn�l az elrendez�s egyszerus�theto, ha minden #include
utas�-
t�st k�z�s fej�llom�nyba tesz�nk.
Az egyetlen fej�llom�nyos fizikai r�szekre bont�s akkor a leghasznosabb, ha a
program kicsi
�s r�szeit nem �ll sz�nd�kunkban k�l�n haszn�lni. Jegyezz�k meg, hogy amikor
n�vtereket
haszn�lunk, a dc.h-ban egyben a program logikai fel�p�t�s�t is �br�zoljuk. Ha nem
haszn�lunk n�vtereket, a szerkezet hom�lyos lesz, b�r ezen a megjegyz�sek
seg�thetnek.
A nagyobb programok egyetlen fej�llom�nyos elrendez�se nem muk�dik a hagyom�nyos,
f�jl alap� fejlesztok�rnyezetekben. A k�z�s fej�llom�ny m�dos�t�sa maga ut�n vonja
az eg�sz
program �jraford�t�s�t �s nagy a hibalehetos�g, ha t�bb programoz� is m�dos�tja az
egyetlen
fej�llom�nyt. Hacsak nem fektetnek hangs�lyt a n�vterekkel �s oszt�lyokkal
kapcsolatos
programoz�si st�lusra, a logikai fel�p�t�s a program n�veked�s�vel egy�tt romlani
fog.
9. Forr�sf�jlok �s programok 279
<sstream> <map> <string>
dc.h
<cctype>
main.c parser.c table.c lexer.c
<iostream>
9.3.2. T�bb fej�llom�nyos elrendez�s
Egy m�sik fizikai elrendez�s szerint minden logikai modulnak saj�t fej�llom�nya
lenne,
amely le�rja a modul �ltal ny�jtott szolg�ltat�sokat. Ekkor minden .c f�jlhoz
tartozik egy
megfelelo .h f�jl, ami meghat�rozza a .c szolg�ltat�sait (fel�let�t). Minden .c
f�jl be�p�ti a saj
�t .h f�jlj�t, �s rendszerint tov�bbi olyan .h f�jlokat is, amelyek meghat�rozz�k,
mire van
sz�ks�ge m�s modulokb�l ahhoz, hogy megval�s�tsa a fel�let�ben k�zz�tett
szolg�ltat�sokat.
Ez a fizikai elrendez�s megegyezik a modul logikai fel�p�t�s�vel. A
felhaszn�l�knak
sz�nt fel�letet a .h f�jl tartalmazza, a programoz�i fel�let egy _impl.h v�gzod�su
f�jlban szerepel,
a modul f�ggv�ny- �s v�ltoz�defin�ci�i stb. pedig a .c f�jlokban vannak
elhelyezve.
Ily m�don az elemzot h�rom f�jl k�pviseli, felhaszn�l�i fel�let�t pedig a parser.h
ny�jtja:
// parser.h:
namespace Parser { // fel�let a felhaszn�l�knak
double expr(bool get);
}
Az elemzot megval�s�t� f�ggv�nyek k�z�s k�rnyezet�t a parser_impl.h adja:
// parser_impl.h:
#include "parser.h"
#include "error.h"
#include "lexer.h"
namespace Parser { // fel�let a megval�s�t�shoz
double prim(bool get);
double term(bool get);
double expr(bool get);
using Lexer::get_token;
using Lexer::curr_tok;
}
A parser.h felhaszn�l�i fej�llom�nyt az�rt �p�tj�k be, hogy a ford�t�program
ellenorizhesse
a k�vetkezetess�get (�9.3.1). Az elemzo f�ggv�nyeket a parser.c f�jlban egy�tt
t�roljuk
azokra a fej�llom�nyokra vonatkoz� #include utas�t�sokkal, melyekre a Parser
f�ggv�nyeinek
sz�ks�ge van:
// parser.c:
#include "parser_impl.h"
#include "table.h"
double Parser::prim(bool get) { /* ... */ }
double Parser::term(bool get) { /* ... */ }
double Parser::expr(bool get) { /* ... */ }
280 Alapok
Az elemzo �s annak a vez�rlo �ltali haszn�lata �br�val �gy mutathat� be:
Ahogy v�rtuk, ez el�g j�l egyezik a �8.3.3-ban le�rt logikai szerkezettel. Ha a
table.h-t
a parser_impl.h-ba �p�tett�k volna be a parser.c helyett, a szerkezetet m�g tov�bb
egyszer
us�thett�k volna. A table.h azonban valami olyasmire p�lda, ami nem sz�ks�ges az
elemz
o f�ggv�nyek k�z�s k�rnyezet�nek kifejez�s�hez, csak a f�ggv�nyek
megval�s�t�sainak
van sz�ks�ge r�. Tulajdonk�ppen egyetlen f�ggv�ny, a prim() haszn�lja, �gy ha a
f�ggos�-
geket val�ban a leheto legkevesebbre szeretn�nk cs�kkenteni, a prim()-et tegy�k
k�l�n .c
f�jlba �s csak oda �p�ts�k be a table.h-t:
9. Forr�sf�jlok �s programok 281
parser.h lexer.h
parser_impl.h
main.c parser.c
error.h table.h
parser.h lexer.h
parser_impl.h
parser.c prim.c
error.h table.h
Ilyen alaposs�gra a nagyobb modulokat kiv�ve nincs sz�ks�g. A val�s�gos m�retu
modulok
eset�ben gyakori, hogy tov�bbi f�jlokat �p�tenek be ott, ahol egyes f�ggv�nyek
sz�m�-
ra azok sz�ks�gesek. Tov�bb� nem ritka, hogy egyn�l t�bb _impl.h f�jl van, mivel a
modul
f�ggv�nyeinek r�szhalmazai k�l�nb�zo k�z�s k�rnyezetet ig�nyelnek.
Meg kell jegyezn�nk, hogy az _impl.h haszn�lata nem szabv�nyos �s m�g csak nem is
gyakori
megold�s . �n egyszeruen �gy szeretek elnevezni dolgokat.
Mi�rt t�rod�nk ezzel a bonyolultabb t�bb fej�llom�nyos elrendez�ssel? Nyilv�n
sokkal kevesebb
gondolkod�st ig�nyel, ha egyszeruen minden deklar�ci�t bedobunk egy fej�llom
�nyba, mint ahogy azt a dc.h-n�l tett�k.
A t�bb fej�llom�nyos elrendez�s olyan modulok �s programok eset�ben hat�sos,
amelyek
nagys�grendekkel nagyobbak, mint a mi apr� elemzonk �s sz�mol�g�p�nk. Alapvetoen
az�rt haszn�ltuk ezt az elrendez�st�pust, mert jobban azonos�tja a kapcsolatokat.
Egy nagy
program elemz�sekor vagy m�dos�t�sakor alapveto, hogy a programoz� viszonylag kis
k�dr�szletre �sszpontos�thasson. A t�bb fej�llom�nyos elrendez�s seg�t, hogy
pontosan eld
�nthess�k, mitol f�gg az elemzo k�d, �s hogy figyelmen k�v�l hagyhassuk a program
t�bbi
r�sz�t. Az egyetlen fej�llom�nyos elrendez�s r�k�nyszer�t minket, hogy minden
olyan
deklar�ci�t megn�zz�nk, amelyet valamelyik modul haszn�l, �s eld�nts�k, hogy
odaillo-e.
A l�nyeg, hogy a k�d m�dos�t�sa mindig hi�nyos inform�ci�k �s helyi n�zopont
alapj�n
t�rt�nik. A t�bb fej�llom�nyos elrendez�s megengedi, hogy sikeresen dolgozzunk
.bel�lr
ol kifel�., csak helyi szemsz�gbol. Az egyetlen fej�llom�nyos elrendez�s . mint
minden
m�s elrendez�s, ahol egy glob�lis inform�ci�t�r van a k�z�ppontban . fel�lrol
lefel� halad
� megk�zel�t�st ig�nyel, �gy �r�kk� gondolkodnunk kell azon, hogy pontosan mi f�gg

egy m�sik dologt�l.


A jobb �sszpontos�t�s azt eredm�nyezi, hogy kevesebb inform�ci� kell a modul
leford�t�-
s�hoz, �gy az gyorsabban t�rt�nik. A hat�s dr�mai lehet. Elofordul, hogy a
ford�t�si ido tizedr
�sz�re cs�kken, puszt�n az�rt, mert egy egyszeru f�ggos�gelemz�s a fej�llom�nyok
jobb haszn�lat�hoz vezet.
9.3.2.1. A sz�mol�g�p egy�b moduljai
A sz�mol�g�p t�bbi modulj�t az elemzoh�z hasonl�an rendezhetj�k el. Ezek a modulok

azonban olyan kicsik, hogy nem ig�nyelnek saj�t _impl.h f�jlokat. Az ilyen f�jlok
csak ott
kellenek, ahol egy logikai modul sok f�ggv�nybol �ll, amelyeknek k�z�s k�rnyezetre
van
sz�ks�g�k.
282 Alapok
A hibakezelot a kiv�telt�pusok halmaz�ra egyszerus�tett�k, �gy nincs sz�ks�g�nk az
error.c-re:
// error.h:
namespace Error {
struct Zero_divide { };
struct Syntax_error {
const char* p;
Syntax_error(const char* q) { p = q; }
};
}
Az adatbeviteli k�d (lexikai elemzo, lexer) meglehetosen nagy �s rendezetlen
fel�letet
ny�jt:
// lexer.h:
#include <string>
namespace Lexer {
enum Token_value {
NAME, NUMBER, END,
PLUS='+', MINUS='-', MUL='*', DIV='/',
PRINT=';', ASSIGN='=', LP='(', RP=')'
};
extern Token_value curr_tok;
extern double number_value;
extern std::string string_value;
Token_value get_token();
}
A lexer.h-n k�v�l a lexikai elemzo az error.h-ra, az <iostream>-re �s a <ctype>-
ban megadott,
a karakterek fajt�it eld�nto f�ggv�nyekre t�maszkodik:
// lexer.c:
#include "lexer.h"
#include "error.h"
#include <iostream>
#include <cctype>
9. Forr�sf�jlok �s programok 283
Lexer::Token_value Lexer::curr_tok;
double Lexer::number_value;
std::string Lexer::string_value;
Lexer::Token_value Lexer::get_token() { /* ... */ }
Az error.h #include utas�t�sait k�l�n tehett�k volna, a Lexer-hez tartoz� _impl.h
f�jlba, ez
azonban t�lz�s egy ilyen kis program eset�ben.
A modul megval�s�t�s�ban szok�sos m�don �p�tj�k be (#include) a modul �ltal
ny�jtott fel
�letet . ebben az esetben a lexer.h-t ., hogy a ford�t�program ellenorizhesse a
k�vetkezetess
�get.
A szimb�lumt�bla alapvetoen �n�ll�, b�r a standard k�nyvt�rbeli <map> fej�llom�ny
haszn
�lat�val sz�mos �rdekes dolog ker�lhet bele, hogy hat�konyan val�s�thassa meg a
map
sablonoszt�lyt:
// table.h:
#include <map>
#include <string>
extern std::map<std::string,double> table;
Mivel feltessz�k, hogy az egyes fej�llom�nyok t�bb .c f�jlba is bele lehetnek
�p�tve, a table
deklar�ci�j�t k�l�n kell v�lasztanunk annak kifejt�s�tol, m�g akkor is, ha a
table.c �s
a table.h k�z�tti k�l�nbs�g csak az extern kulcssz�:
// table.c:
#include "table.h"
std::map<std::string,double> table;
A vez�rlo tulajdonk�ppen mindenre t�maszkodik:
// main.c:
#include "parser.h"
#include "lexer.h"
#include "error.h"
#include "table.h"
284 Alapok
namespace Driver {
int no_of_errors;
std::istream* input;
void skip();
}
#include <sstream>
int main(int argc, char* argv[ ]) { /* ... */ }
Mivel a Driver n�vteret kiz�r�lag a main() haszn�lja, a main.c-be tessz�k azt.
K�l�n is szerepelhetne
driver.h f�jlk�nt, amit az #include utas�t�ssal be�p�t�nk.
A nagyobb programokat rendszerint meg�ri �gy elrendezni, hogy a vez�rlonek
kevesebb
k�zvetlen f�ggos�ge legyen. Gyakran �sszeru az olyan muveletekbol is min�l
kevesebbet
alkalmazni, amit a main() tesz, nevezetesen hogy megh�v egy k�l�n forr�sf�jlban
l�vo vez
�rlo f�ggv�nyt. Ez k�l�n�sen fontos olyan k�dok eset�ben, amelyeket k�nyvt�rk�nt
akarunk
haszn�lni. Ekkor ugyanis nem t�maszkodhatunk a main()-ben meg�rt k�dra �s fel kell

k�sz�ln�nk arra is, hogy k�l�nb�zo f�ggv�nyekbol h�vj�k meg k�dunkat (�9.6[8]).
9.3.2.2. A fej�llom�nyok haszn�lata
A programban haszn�lt fej�llom�nyok (header file) sz�ma t�bb t�nyezotol f�gg. Ezen
t�-
nyezok k�z�l sok ink�bb a rendszer f�jlkezel�s�bol ad�dik �s nem a C++-b�l.
P�ld�ul, ha
sz�vegszerkeszto programunk nem k�pes arra, hogy t�bb f�jlt n�zz�nk vele
egyszerre, akkor
nem elony�s sok fej�llom�nyt haszn�lnunk. Hasonl�an, ha 20 darab 50 soros f�jl
olvas
�sa �szrevehetoen t�bb idot ig�nyel, mint egyetlen 1000 soros f�jl�, akkor k�tszer
is gondoljuk
meg, mielott egy kis projektben a t�bb fej�llom�nyos st�lust haszn�ljuk.
N�h�ny figyelmeztet�s: egy tucatnyi fej�llom�ny (term�szetesen a szok�sos
fej�llom�-
nyokkal egy�tt, melyeket gyakran sz�zas nagys�grendben sz�molhatunk) a program
v�grehajt
�si k�rnyezete sz�m�ra rendszerint m�g kezelheto. Ha azonban egy nagy program
deklar�ci�it logikailag a leheto legkisebb fej�llom�nyokra bontjuk (p�ld�ul �gy,
hogy minden
szerkezet deklar�ci�j�t k�l�n f�jlba tessz�k), k�nnyen egy t�bb sz�z f�jlb�l �ll�,
kezelhetetlen
zurzavar lehet az eredm�ny.
Nagy projektekn�l persze elker�lhetetlen a sok fej�llom�ny. Az ilyenekn�l t�bb
sz�z f�jl
(nem sz�molva a szok�sos fej�llom�nyokat) az �ltal�nos. Az igazi bonyodalom ott
kezdo-
dik, amikor el�rik az ezres nagys�grendet. A fent t�rgyalt alapveto m�dszerek
ekkor is alkalmazhat
�k, de az �llom�nyok kezel�se sziszifuszi feladatt� v�lik. Eml�kezz�nk, hogy
9. Forr�sf�jlok �s programok 285
a val�di m�retu programokn�l az egyetlen fej�llom�nyos elrendez�st �ltal�ban nem
v�laszthatjuk,
mert az ilyen programok rendszerint eleve t�bb fej�llom�nyt tartalmaznak. A
k�tfajta
elrendez�si m�dszer k�z�tt a program alkot�r�szeinek l�trehoz�sakor kell (n�ha
t�bbsz
�r is) v�lasztanunk.
Igaz�n nem is a mi �zl�s�nkre van b�zva, hogy az egyetlen �s a t�bb fej�llom�nyos
elrendez
�s k�z�l v�lasszunk. Ezek olyan egym�st kieg�sz�to m�dszerek, melyeket mindig
figyelembe
kell venn�nk a l�nyegi modulok tervez�sekor, �s �jra kell gondolnunk azokat,
ahogy a rendszer fejlodik. Rendk�v�l fontos eml�kezn�nk arra, hogy egy fel�let nem
szolg
�lhat minden c�lra ugyanolyan j�l. Rendszerint meg�ri k�l�nbs�get tenni a
fejlesztoi �s
a felhaszn�l�i fel�let k�z�tt. Ezenk�v�l sok nagyobb program szerkezete olyan,
hogy c�lszer
u a felhaszn�l�k t�bbs�g�nek egyszeru, a tapasztaltabb felhaszn�l�knak pedig
terjedelmesebb
fel�letet ny�jtani. A tapasztalt felhaszn�l�k fel�letei (a .teljes fel�letek.)
sokkal
t�bb szolg�ltat�st �p�tenek be, mint amennyirol egy �tlagos felhaszn�l�nak tudnia
kell. Val
�j�ban az �tlagos felhaszn�l� fel�let�t �gy hat�rozhatjuk meg, hogy nem �p�tj�k be
azokat
a fej�llom�nyokat, amelyek olyan szolg�ltat�sokat �rnak le, amelyek ismeretlenek
lenn�nek
az �tlagos felhaszn�l� sz�m�ra. Az .�tlagos felhaszn�l�. kifejez�s nem
lekicsinylo. Ahol
nem musz�j szak�rtonek lennem, jobban szeretek �tlagos felhaszn�l� lenni. �gy
ugyanis
kevesebb a veszeked�s.
9.3.3. .�llom�ny-orszemek.
A t�bb fej�llom�nyos megk�zel�t�s gondolata az, hogy minden logikai modult
k�vetkezetes,
�n�ll� egys�gk�nt �br�zoljunk. A program eg�sz�nek szempontj�b�l n�zve viszont
azon deklar�ci�k t�bbs�ge, melyek ahhoz kellenek, hogy minden logikai egys�g
teljes legyen,
felesleges. Nagyobb programokn�l az ilyen f�l�sleg (redundancia) hib�khoz
vezethet,
amint egy oszt�lyle�r�st vagy helyben kifejtett f�ggv�nyeket tartalmaz�
fej�llom�nyt
ugyanabban a ford�t�si egys�gben (�9.2.3) k�tszer �p�t�nk be az #include-dal.
K�t v�laszt�sunk lehet.
1. �tszervezhetj�k a programunkat, hogy elt�vol�tsuk a f�l�sleget, vagy
2. tal�lunk valamilyen m�dot arra, hogy a fej�llom�nyok t�bbsz�ri be�p�t�se
megengedett legyen.
Az elso megk�zel�t�s . ami a sz�mol�g�p v�gso v�ltozat�hoz vezetett . f�raszt� �s
val�s�-
gos m�retu programokn�l gyakorlatilag kivitelezhetetlen. A f�l�slegre az�rt is
sz�ks�g�nk
van, hogy a program egyes egys�gei elk�l�n�lten is �rthetoek legyenek. A f�l�s
#includeok
kiszur�se �s az ennek eredm�nyek�ppen l�trej�tt egyszerus�tett program nagyon elo-

ny�s lehet mind logikai szempontb�l, mind az�ltal, hogy cs�kken a ford�t�si ido.
Az �sszes
286 Alapok
elofordul�s megtal�l�sa azonban ritk�n siker�l, �gy alkalmaznunk kell valamilyen
eszk�zt,
ami megengedi a f�l�s #include-ok jelenl�t�t. Lehetoleg szisztematikusan kell
haszn�lnunk,
mert nem tudhatjuk, hogy a felhaszn�l� mennyire alapos elemz�st tart �rdemesnek.
A hagyom�nyos megold�s az, hogy a fej�llom�nyokba .�llom�ny-orszemeket.
(be�p�t�sfigyel
oket, include-guards) illeszt�nk:
// error.h:
#ifndef CALC_ERROR_H
#define CALC_ERROR_H
namespace Error {
// ...
}
#endif // CALC_ERROR_H
A f�jlnak az #ifndef �s az #endif k�z�tti tartalm�t a ford�t�program nem veszi
figyelembe,
ha a CALC_ERROR_H m�r defini�lt. Ez�rt amikor a ford�t�program az error.h-val
elosz�r tal
�lkozik, beolvassa annak tartalm�t, a CALC_ERROR_H pedig �rt�ket kap. Ha ism�t
tal�lkozna
vele a ford�t�s sor�n, m�sodszor m�r nem fogja figyelembe venni. Ez makr�kkal val
� �gyesked�s, de muk�dik �s minden�tt jelen van a C �s C++ vil�g�ban. A standard
k�nyvt
�r fej�llom�nyainak mindegyike tartalmaz �llom�ny-orszemeket.
A fej�llom�nyokat mindenf�le k�rnyezetben haszn�lj�k, a makr�nevek �tk�z�se ellen
pedig
nincs n�vt�r v�delem. Az �llom�ny-orszemeknek ez�rt hossz� �s cs�nya neveket
szoktam
v�lasztani.
Amint a programoz� hozz�szokik a fej�llom�nyokhoz �s az �llom�ny-orszemekhez,
hajlamos
k�zvetlen�l vagy k�zvetve sok fej�llom�nyt be�p�teni. Ez nem k�v�natos, m�g
azokn�l
a C++-v�ltozatokn�l sem, melyek optimaliz�lj�k a fej�llom�nyok feldolgoz�s�t.
Sz�ks�gtelen
�l hossz� ford�t�si idot okozhatnak �s sz�mos deklar�ci�t �s makr�t el�rhetov�
tehetnek,
ami kisz�m�thatatlanul �s kedvezotlen�l befoly�solhatja a program jelent�s�t. Csak

akkor �p�ts�nk be fej�llom�nyokat, amikor t�nyleg sz�ks�g van r�.


9. Forr�sf�jlok �s programok 287
9.4. Programok
A program k�l�n ford�tott egys�gek gyujtem�nye, melyet a szerkesztoprogram
egyes�t.
Minden, ebben a gyujtem�nyben haszn�lt f�ggv�nynek, objektumnak, t�pusnak stb.
egyedi
meghat�roz�ssal (defin�ci�val) kell rendelkeznie (�4.9, �9.2.3) �s pontosan egy
main()
nevu f�ggv�nyt kell tartalmaznia (�3.2). A program �ltal v�gzett fo tev�kenys�g a
main()
megh�v�s�val kezdodik �s az abb�l val� visszat�r�ssel �r v�get. A main() �ltal
visszaadott
int �rt�k lesz a program visszat�r�si �rt�ke, amit a main()-t megh�v� rendszer
megkap.
Ezen az egyszeru meghat�roz�son a glob�lis v�ltoz�kat tartalmaz� (�10.4.9) vagy el
nem
kapott kiv�telt (�14.7) kiv�lt� programok eset�ben finom�tanunk kell.
9.4.1. Kezdeti �rt�kad�s nem lok�lis v�ltoz�knak
Elvileg a f�ggv�nyeken k�v�l megadott, nem lok�lisnak sz�m�t� v�ltoz�k (azaz a
glob�lis,
n�vt�r-, vagy static oszt�lyv�ltoz�k) a main() megh�v�sa elott, a ford�t�si
egys�gben
definici�juk sorrendj�ben kapnak kezdo�rt�ket (�10.4.9). Ha egy ilyen v�ltoz�nak
nincs
pontosan meghat�rozott (explicit) kezdo�rt�ke, akkor a t�pus�nak megfelelo
alap�rtelmezett
�rt�kkel t�ltodik fel (�10.4.2). A be�p�tett t�pusok �s felsorol�sok eset�ben az
alap�rtelmezett
kezdo�rt�k a 0:
double x = 2; // nem lok�lis v�ltoz�k
double y;
double sqx = sqrt(x+y);
Itt az x �s az y az sqx elott kap kezdo�rt�ket, �gy az sqrt(2) h�v�dik meg.
A k�l�nb�zo ford�t�si egys�gekben l�vo glob�lis v�ltoz�k kezdo�rt�kkel val�
ell�t�s�nak
sorrendje nem k�t�tt, k�vetkez�sk�ppen nem b�lcs dolog ezekn�l a kezdo�rt�kek
k�z�tt
sorrendi f�ggos�geket l�trehozni. Tov�bb� nem lehets�ges olyan kiv�telt sem
elkapni, amit
egy glob�lis v�ltoz� kezdeti �rt�kad�sa v�ltott ki (�14.7). �ltal�ban az a
legjobb, ha min�l
kevesebb glob�lis v�ltoz�t haszn�lunk; foleg a bonyolult kezdeti �rt�kad�st
ig�nylo glob�-
lis v�ltoz�k haszn�lat�t kell korl�toznunk.
A k�l�nb�zo ford�t�si egys�gekben l�vo glob�lis v�ltoz�k kezdeti �rt�kkel val�
felt�lt�s�nek
sorrendj�t sz�mos m�don k�nyszer�thetj�k ki, de nincs k�zt�k olyan, amely
egyszerre .hordozhat
�. �s hat�kony is lenne. Foleg a dinamikus csatol�s� k�nyvt�rak (DLL) nem k�pesek
288 Alapok
a bonyolult f�ggos�gekkel rendelkezo glob�lis v�ltoz�kkal boldogan egy�tt �lni.
Glob�lis
v�ltoz�k helyett gyakran haszn�lhatunk referenci�t visszaad� f�ggv�nyeket:
int& use_count()
{
static int uc = 0;
return uc;
}
A use_count() h�v�s most glob�lis v�ltoz�k�nt muk�dik, kiv�ve, hogy elso
haszn�latakor
kap kezdo�rt�ket (�5.5):
void f()
{
cout << ++use_count(); // n�vel�s �s ki�r�s
// ...
}
A nem lok�lis statikus v�ltoz�k kezdeti �rt�kad�s�t b�rmilyen elj�r�s vez�relheti,
amit az
adott nyelvi v�ltozat arra haszn�l, hogy elind�tsa a C++ programot. Csak akkor
garant�lt,
hogy a m�dszer megfeleloen muk�dik, ha a main() v�grehajt�s�ra sor ker�l, ez�rt el
kell
ker�ln�nk azon nem lok�lis v�ltoz�k haszn�lat�t, melyek fut�si ideju kezdeti
�rt�kad�st
ig�nyelnek olyan C++ k�dban, amit nem C++ program haszn�l.
Jegyezz�k meg, hogy a kezdo�rt�ket konstans kifejez�sektol kap� v�ltoz�k (�C.5)
nem
f�gghetnek m�s ford�t�si egys�gben levo objektumok �rt�k�tol �s nem ig�nyelnek
fut�si
ideju kezdeti �rt�kad�st, �gy minden esetben biztons�gosan haszn�lhat�k.
9.4.1.1. A program befejez�se
A programok fut�sa sz�mos m�don �rhet v�get:
� A main()-bol val� visszat�r�ssel
� Az exit() megh�v�s�val
� Az abort() megh�v�s�val
� El nem kapott kiv�tel kiv�lt�s�val
Tov�bb� t�bbf�le hib�s fel�p�t�s �s nyelvi v�ltozatt�l f�ggo m�dszer l�tezik arra,
hogy egy
program �sszeomoljon. Ha a program befejez�s�re a standard k�nyvt�rbeli exit()
f�ggv�nyt
haszn�ljuk, akkor megh�v�dnak a l�trehozott statikus objektumok destruktorai
(�10.4.9,
�10.2.4). Ha azonban a program a standard k�nyvt�r abort() f�ggv�ny�t haszn�lja,
9. Forr�sf�jlok �s programok 289
a destruktorok megh�v�s�ra nem ker�l sor. Jegyezz�k meg: ez azt is jelenti, hogy
az exit()
nem fejezi be r�gt�n a programot; destruktorban val� megh�v�sa v�gtelen ciklust
eredm�-
nyezhet. Az exit() f�ggv�ny t�pusa
void exit(int);
A main() visszat�r�si �rt�k�hez (�3.2) hasonl�an az exit() param�tere is
visszaad�dik
.a rendszernek. a program visszat�r�si �rt�kek�nt. A nulla sikeres befejez�st
jelent.
Az exit() megh�v�sa azt jelenti, hogy a h�v� f�ggv�ny lok�lis v�ltoz�inak �s az
azt h�v� f�ggv
�nyek hasonl� v�ltoz�inak destruktorai nem h�v�dnak meg. A lok�lis objektumok
megfelel
o megsemmis�t�s�t (�14.4.7) egy kiv�tel .dob�sa. �s elkap�sa biztos�tja. Emellett
az exit()
megh�v�sa �gy fejezi be a programot, hogy az exit() h�v�j�nak nem ad lehetos�get
arra,
hogy megoldja a probl�m�t. Ez�rt gyakran az a legjobb, ha a k�rnyezetet egy
kiv�tel kiv�lt
�s�val elhagyjuk, �s megengedj�k egy kiv�telkezelonek, hogy eld�ntse, mi legyen a
tov�bbiakban.
A C (�s C++) standard k�nyvt�r�nak atexit() f�ggv�nye lehetos�get ad arra, hogy
k�dot hajthassunk v�gre a program befejezod�sekor:
void my_cleanup();
void somewhere()
{
if (atexit(&my_cleanup)==0) {
// norm�l programbefejez�skor a my_cleanup h�v�dik meg
}
else {
// hopp�: t�l sok atexit f�ggv�ny
}
}
Ez nagyban hasonl�t a glob�lis v�ltoz�k destruktorainak a program befejezod�sekor
t�rt�-
no automatikus megh�v�s�hoz (�10.4.9, �10.2.4). Jegyezz�k meg, hogy az atexit()
param�-
ter�nek nem lehet param�tere �s nem adhat vissza �rt�ket. Az atexit f�ggv�nyek
sz�m�t az
adott nyelvi v�ltozat korl�tozza; a f�ggv�ny nem nulla �rt�k visszaad�s�val jelzi,
ha ezt
a korl�tot el�rt�k. Ezek a korl�toz�sok az atexit()-et kev�sb� haszn�lhat�v�
teszik, mint
amilyennek elso pillant�sra l�tszik.
Az atexit(f) megh�v�sa elott l�trehozott objektum destruktora az f megh�v�sa ut�n
fog megh
�v�dni, az atexit(f) megh�v�sa ut�n l�trehozott objektum destruktora pedig az f
megh�v�-
sa elott.
Az exit(), abort(), �s atexit() f�ggv�nyek deklar�ci�j�t a <cstdlib> fej�llom�ny
tartalmazza.
290 Alapok
9.5. Tan�csok
[1] Haszn�ljuk fej�llom�nyokat a fel�letek �br�zol�s�ra �s a logikai szerkezet
kihangs�lyoz�s�ra. �9.1, �9.3.2.
[2] Abban a forr�sf�jlban �p�ts�k be oket (#include), amelyben f�ggv�nyeiket
kifejtj�k. �9.3.1.
[3] Ne adjunk meg glob�lis egyedeket ugyanazzal a n�vvel �s hasonl�, de k�l�nb�-
zo jelent�ssel k�l�nb�zo ford�t�si egys�gekben. �9.2.
[4] Ker�lj�k a fej�llom�nyokban a nem helyben kifejtendo f�ggv�nyeket. �9.2.1.
[5] Csak glob�lis hat�k�rben �s n�vterekben haszn�ljuk az #include-ot. �9.2.1.
[6] Csak teljes deklar�ci�kat �p�ts�nk be. �9.2.1
[7] Haszn�ljunk .�llom�ny-orszemeket.. �9.3.3.
[8] A C fej�llom�nyokat n�vterekben �p�ts�k be, hogy elker�lj�k a glob�lis
neveket.
�9.3.2.
[9] Tegy�k a fej�llom�nyokat k�l�n�ll�v�. �9.2.3.
[10] K�l�nb�ztess�k meg a fejlesztoi �s a felhaszn�l�i fel�letet. �9.3.2.
[11] K�l�nb�ztess�k meg az �tlagos �s a tapasztalt felhaszn�l�k fel�let�t. �9.3.2.

[12] Ker�lj�k az olyan nem lok�lis objektumok haszn�lat�t, amelyek fut�si ideju
kezdeti
�rt�kad�st ig�nyelnek olyan k�dban, amit nem C++ program r�szek�nt
sz�nd�kozunk felhaszn�lni. �9.4.1.
9.6. Gyakorlatok
1. (*2) Tal�ljuk meg, hol t�rolja rendszer�nk a szabv�nyos fej�llom�nyokat.
�rassuk
ki neveiket. Van-e olyan nem szabv�nyos fej�llom�ny, amely ezekkel egy�tt
t�rol�dik? Be lehet-e �p�teni nem szabv�nyos fej�llom�nyokat a <> jel�l�st
haszn�lva?
2. (*2) Hol t�rol�dnak a nem szabv�nyos .foundation. k�nyvt�rak fej�llom�nyai?
3. (*2,5) �rjunk programot, amely beolvas egy forr�sf�jlt �s ki�rja a be�p�tett
f�jlok
neveit. Haszn�ljunk beh�z�st a be�p�tett f�jlok �ltal be�p�tett f�jlok ki�r�sakor,

a befoglal�s m�lys�g�nek jel�l�s�re. Pr�b�ljuk ki a programot n�h�ny val�di


forr�sf�jlon (hogy elk�pzel�s�nk legyen a be�p�tett inform�ci� nagys�g�r�l).
4. (*3) M�dos�tsuk az elobbi programot, hogy minden be�p�tett f�jlra ki�rja a
megjegyz
�sek �s a nem megjegyz�sek sorainak sz�m�t, illetve a nem megjegyz
�sk�nt szereplo, �reshelyekkel elv�lasztott szavak sz�m�t.
9. Forr�sf�jlok �s programok 291
5. (*2,5) A k�lso be�p�t�sfigyelo olyan programelem, amely a megfigyelt f�jlon k�-

v�l v�gzi az ellenorz�st, �s ford�t�sonk�nt csak egyszer v�gez be�p�t�st. K�sz�ts


�nk egy ilyen szerkezeti elemet, tervezz�nk m�dszert a tesztel�s�re, �s fejts�k
ki elonyeit �s h�tr�nyait a �9.3.3-ban le�rt .�llom�ny-orszemekkel. szemben.
Van-e a k�lso be�p�t�sfigyeloknek b�rmilyen jelentos fut�si idobeli elonye
a rendszer�nkben?
6. (*3) Hogyan val�sul meg a dinamikus csatol�s (szerkeszt�s) a rendszer�nkben?
Milyen megszor�t�sok vonatkoznak a dinamikusan szerkesztett k�dra? Milyen
k�vetelm�nyeknek kell, hogy megfeleljen a k�d, hogy dinamikusan csatolhat�
legyen?
7. (*3) Nyissunk meg �s olvassunk be 100 f�jlt, melyek mindegyike 1500 karaktert
tartalmaz. Nyissunk meg �s olvassunk be egy 150 000 karakterbol �ll� f�jlt.
Tipp: n�zz�k meg a p�ld�t a �21.5.1 pontban. Van-e elt�r�s a teljes�tm�nyben?
H�ny f�jl lehet egyszerre megnyitva rendszer�nkben? V�laszoljuk meg ezeket
a k�rd�seket a be�p�tett f�jlok haszn�lat�val kapcsolatban is.
8. (*2) M�dos�tsuk a sz�mol�g�pet, hogy meg lehessen h�vni a main()-bol vagy
m�s f�ggv�nybol is, egy egyszeru f�ggv�nyh�v�ssal.
9. (*2) Rajzoljuk meg a .modulf�ggos�gi diagramokat. (�9.3.2) a sz�mol�g�p azon
v�ltozataira, melyek az error()-t haszn�lt�k kiv�telek helyett. (�8.2.2).
292 Alapok
M�sodik r�sz
Absztrakci�s m�dszerek
Ebben a r�szben azzal foglalkozunk, milyen lehetos�geket ny�jt a C++ nyelv �j
t�pusok
meghat�roz�s�ra �s haszn�lat�ra, illetve bemutatjuk az �sszefoglal� n�ven
objektumorient
�lt programoz�snak �s �ltal�nos�tott (generikus) programoz�snak nevezett
elj�r�sokat.
Fejezetek
10. Oszt�lyok
11. Oper�torok t�lterhel�se
12. Sz�rmaztatott oszt�lyok
13. Sablonok
14. Kiv�telkezel�s
15. Oszt�lyhierarchi�k
.... nincs nehezebb, k�tesebb kimenetelu, vesz�lyesebb dolog, mint �j t�rv�nyek
bevezet�-
s��rt s�krasz�llni. Mert ellens�gei azok, akiknek a r�gi t�rv�nyek haszn�ra
vannak, azok pedig,
akiknek az �j rendelkez�sek szolg�lnak hasznukra, puszt�n lagymatag v�delmezoi....

Niccolo Machiavelli
(A fejedelem (�vi), Lutter �va ford�t�sa)
Oszt�lyok
.Ezek a t�pusok nem .elvontak.;
ugyanannyira val�s�gosak,
mint az int �s a float..
(Doug McIlroy)
Fogalmak �s oszt�lyok . Oszt�lytagok . Az el�rhetos�g szab�lyoz�sa . Konstruktorok
. Statikus
tagok . Alap�rtelmezett m�sol�s . const tagf�ggv�nyek . this . struct-ok .
Oszt�lyon
bel�li f�ggv�nydefin�ci�k . Konkr�t oszt�lyok . Tagf�ggv�nyek �s seg�df�ggv�nyek .
Oper
�torok t�lterhel�se . A konkr�t oszt�lyok haszn�lata . Destruktorok .
Alap�rtelmezett
konstruktorok . Lok�lis v�ltoz�k . Felhaszn�l�i m�sol�s . new �s delete .
Tagobjektumok
. T�mb�k . Statikus t�rol�s . Ideiglenes v�ltoz�k . Uni�k . Tan�csok . Gyakorlatok

10.1. Bevezet�s
A C++ nyelv oszt�lyai azt a c�lt szolg�lj�k, hogy a programoz� a be�p�tett
adatt�pusokkal
azonos k�nyelmi szinten haszn�lhat� �j adatt�pusokat hozhasson l�tre. Ezenk�v�l az
�r�kl
od�s (12. fejezet) �s a sablonok (13. fejezet) seg�ts�g�vel �gy szervezhetj�k az
egym�ssal
kapcsolatban �ll� oszt�lyokat, hogy kapcsolataikat hat�konyan haszn�lhassuk ki.
10
A t�pus egy fogalom konkr�t �br�zol�sa. A C++ be�p�tett float t�pusa p�ld�ul a +,
-, * stb.
muveleteivel egy�tt a val�s sz�m matematikai fogalm�nak egy megk�zel�t�se. Az
oszt�ly
egy felhaszn�l�i t�pus. Az�rt tervez�nk �j t�pust, hogy meghat�rozzunk egy
fogalmat,
amelynek nincs k�zvetlen megfeleloje a nyelv be�p�tett t�pusai k�z�tt. Lehet
p�ld�ul
Trunk_line t�pusunk egy telefonos kapcsolatokat kezelo programban, Explosion
t�pusunk
egy vide�j�t�k sz�m�ra, vagy list<Paragraph> t�pusunk egy sz�vegszerkeszto
programban.
Egy programot k�nnyebb meg�rteni �s m�dos�tani, ha abban az �ltala kezelt
fogalmaknak
megfelelo t�pusok szerepelnek. Ha a programoz� alkalmas oszt�lyokat haszn�l, a
program
t�m�rebb lesz, r�ad�sul sokf�le k�delemzo elj�r�s haszn�lata v�lik lehetov�. A
ford�t�program
p�ld�ul felder�theti az objektumok nem szab�lyos haszn�lat�t, amit m�sk�nt csak
egy
alapos ellenorz�s sor�n fedezhetn�nk fel.
�j t�pus defini�l�sakor az alapveto szempont a megval�s�t�s v�letlenszeru,
esetleges r�szleteinek
(p�ld�ul a t�roland� adatok elrendez�s�nek) elv�laszt�sa a t�pus helyes haszn�lat
�hoz alapvetoen sz�ks�ges tulajdons�gokt�l, p�ld�ul az adatokat el�ro f�ggv�nyek
teljes
list�j�t�l. Ez az elv�laszt�s legjobban �gy fejezheto ki, ha az adott t�pus
adatszerkezet�t �rint
o �sszes k�lso haszn�latot �s belso rendrak� f�ggv�nyt csak az adott t�pusra
vonatkoz�
programoz�si fel�leten kereszt�l tessz�k el�rhetov�. Ez a fejezet a viszonylag
egyszeru,
.konkr�t. felhaszn�l�i t�pusokkal foglalkozik. Ide�lis esetben ezek csak
l�trehoz�suk m�djukban
k�l�nb�znek a be�p�tett t�pusokt�l, a haszn�lat m�dj�ban nem.
10.2. Oszt�lyok
Az oszt�ly (class) a programoz� �ltal meghat�rozott, m�s n�ven felhaszn�l�i t�pus.
Az al�bbiakban
az oszt�lyok meghat�roz�s�nak, illetve az oszt�lyba tartoz� objektumok l�trehoz�-
s�nak �s haszn�lat�nak fobb eszk�zeit mutatjuk be.
10.2.1. Tagf�ggv�nyek
Vizsg�ljuk meg, hogyan �br�zoln�nk a .d�tum. fogalm�t egy Date adatszerkezettel
(strukt
�r�val, struct) �s egy sor, ilyen v�ltoz�kat kezelo f�ggv�nnyel:
struct Date { // �br�zol�s
int d, m, y;
};
296 Absztrakci�s m�dszerek
void init_date(Date& d, int, int, int); // kezdeti �rt�kad�s d-nek
void add_year(Date& d, int n); // n �vet ad d-hez
void add_month(Date& d, int n); // n h�napot ad d-hez
void add_day(Date& d, int n); // n napot ad d-hez
Az adatt�pus �s ezen f�ggv�nyek k�z�tt nincs kifejezett kapcsolat. Ilyen
kapcsolatot az�ltal
hozhatunk l�tre, hogy a f�ggv�nyeket tagf�ggv�nyekk�nt adjuk meg:
struct Date {
int d, m, y;
void init(int dd, int mm, int yy); // kezdeti �rt�kad�s
void add_year(int n); // n �v hozz�ad�sa
void add_month(int n); // n h�nap hozz�ad�sa
void add_day(int n); // n nap hozz�ad�sa
};
Az oszt�lydefin�ci�n bel�l bevezetett f�ggv�nyeket (a struct is oszt�ly, �10.2.8)
tagf�ggv�-
nyeknek h�vjuk. A tagf�ggv�nyeket az adatszerkezetek tagjainak el�r�s�re vonatkoz�
szok
�sos form�ban alkalmazhatjuk �s csak megfelelo t�pus� objektumra:
Date my_birthday;
void f()
{
Date today;
today.init(16,10,1996);
my_birthday.init(30,12,1950);
Date tomorrow = today;
tomorrow.add_day(1);
// ...
}
Minthogy a k�l�nb�zo adatszerkezeteknek azonos nevu f�ggv�nyeik is lehetnek, a
tagf
�ggv�nyek meghat�roz�sakor meg kell adnunk az adatszerkezet nev�t is:
void Date::init(int dd, int mm, int yy)
{
d = dd;
m = mm;
y = yy;
}
10. Oszt�lyok 297
A tagf�ggv�nyekben a tagokat az objektum kifejezett megad�sa n�lk�l is
haszn�lhatjuk. Ekkor
a n�v azon objektum megfelelo tagj�ra vonatkozik, amelyre a tagf�ggv�nyt
megh�vtuk.
Amikor p�ld�ul a Date::init() tagf�ggv�nyt alkalmazzuk a today v�ltoz�ra, az m=mm
�rt�kad
�s a today.m v�ltoz�ra vonatkozik. Ha ugyanezt a tagf�ggv�nyt a my_birthday
v�ltoz�-
ra alkalmazn�nk, az m=mm �rt�kad�s a my_birthday.m v�ltoz�ra vonatkozna. A
tagf�ggv
�ny mindig .tudja., hogy milyen objektumra h�vt�k meg.
A
class X { ... };
kifejez�st oszt�lydefin�ci�nak h�vjuk, mert egy �j t�pust hat�roz meg. T�rt�neti
okokb�l az
oszt�lydefin�ci�t n�ha oszt�lydeklar�ci�k�nt eml�tik. Azon deklar�ci�khoz
hasonlatosan,
amelyek nem defin�ci�k, az oszt�lydefin�ci�k az #include utas�t�s felhaszn�l�s�val
t�bb forr
�s�llom�nyban is szerepeltethetok, felt�ve, hogy nem s�rtj�k meg az egyszeri
defini�l�s
szab�ly�t (�9.2.3).
10.2.2. Az el�rhetos�g szab�lyoz�sa
A Date elozo pontbeli deklar�ci�ja azon f�ggv�nyek halmaz�t adja meg, melyekkel a
Date
t�pus� objektumot kezelhetj�k. Ebbol azonban nem der�l ki, hogy kiz�r�lag ezek
lehetnek
mindazok a f�ggv�nyek, amelyek k�zvetlen�l f�ggnek a Date t�pus �br�zol�s�t�l �s
k�zvetlen
�l el�rhetik az ilyen t�pus� objektumokat. A megszor�t�st �gy fejezhetj�k ki, ha
struct
helyett class-t haszn�lunk:
class Date {
int d, m, y;
public:
void init(int dd, int mm, int yy); // kezdeti �rt�kad�s
void add_year(int n); // n �v hozz�ad�sa
void add_month(int n); // n h�nap hozz�ad�sa
void add_day(int n); // n nap hozz�ad�sa
};
A public c�mke k�t r�szre osztja az oszt�ly t�rzs�t. Az elso, priv�t (private)
r�szbeli neveket
csak a tagf�ggv�nyek haszn�lhatj�k. A m�sodik, nyilv�nos (public) r�sz az oszt�ly
nyilv�-
nos fel�lete. A struct szerkezetek egyszeruen olyan oszt�lyok, melyekben a tagok
alap�rtelmezett
el�rhetos�ge nyilv�nos (�10.2.8). A tagf�ggv�nyeket a megszokott m�don
defini�lhatjuk �s haszn�lhatjuk:
298 Absztrakci�s m�dszerek
inline void Date::add_year(int n)
{
y += n;
}
Mindazon�ltal a nem tag f�ggv�nyek a priv�t tagokat nem haszn�lhatj�k:
void timewarp(Date& d)
{
d.y -= 200; // hiba: Date::y priv�t
}
Sz�mos elonnyel j�r, ha a tagok el�rhetos�g�t egy pontosan megadott lista
f�ggv�nyeire
korl�tozzuk. P�ld�ul, ha egy hiba miatt a Date �rv�nytelen �rt�ket kap (mondjuk
1985. december
36.-�t), akkor biztosak lehet�nk abban, hogy ez a hiba csak valamelyik tagf�ggv
�nyben lehet. Ebbol k�vetkezik, hogy a hibakeres�s elso szakasza, a hiba hely�nek
behat
�rol�sa m�r azelott megt�rt�nik, hogy a program egy�ltal�n lefutna. Ez egyik esete
annak
az �ltal�nos megfigyel�snek, hogy az oszt�ly viselked�s�nek b�rmilyen m�dos�t�sa
csakis
a tagf�ggv�nyek megv�ltoztat�s�val �rheto el. P�ld�ul ha megv�ltoztatjuk egy
oszt�ly adat-
�br�zol�s�t, akkor el�g a tagf�ggv�nyeket ennek megfeleloen m�dos�tanunk. Az
oszt�lyt
haszn�l� k�d k�zvetlen�l csak az oszt�ly nyilv�nos fel�let�tol f�gg, ez�rt nem
kell �jra�rni
(b�r lehet, hogy �jra kell ford�tani). A m�sik elony, hogy a leendo felhaszn�l�nak
el�g a tagf
�ggv�nyek meghat�roz�s�t tanulm�nyoznia ahhoz, hogy megtudja, hogyan lehet
haszn�lni
az oszt�lyt.
A priv�t tagok v�delme az oszt�lytagok n�v szerinti el�rhetos�g�nek korl�toz�s�n
m�lik,
ez�rt a c�mek megfelelo kezel�s�vel vagy pontosan meghat�rozott t�puskonverzi�val
megker�lheto. Ez persze csal�s. A C++ a v�letlen hib�k ellen v�d, nem a v�delmi
rendszer
tudatos megker�l�se, a csal�s ellen. Egy �ltal�nos c�l� nyelvben csak
hardverszinten lehetne
a rosszindulat� haszn�lat ellen v�dekezni, �s igazi rendszerekben m�g ez is
nehezen kivitelezhet
o.
Az init() f�ggv�nyt r�szben az�rt vett�k fel, mert �ltal�ban c�lszeru, ha van egy,
az objektumnak
�rt�ket ad� f�ggv�ny�nk, r�szben pedig az�rt, mert az adattagok priv�tt� t�tele
miatt
erre k�nyszer�lt�nk.
10.2.3. Konstruktorok
Az init()-hez hasonl� f�ggv�nyek haszn�lata az objektumok kezdeti �rt�kad�s�ra nem
eleg
�ns �s hib�k forr�sa lehet. Minthogy sehol sincs lefektetve, hogy egy objektumnak
kezdo-
�rt�ket kell adni, a programoz� elfelejtheti azt . vagy �ppen t�bbsz�r is
megteheti (mind-
10. Oszt�lyok 299
k�t esetben egyform�n v�gzetes k�vetkezm�nyekkel). Jobb megold�s, ha lehetov�
tessz�k
a programoz�nak, hogy megadjon egy olyan f�ggv�nyt, melynek c�lja kifejezetten az
objektumok
elok�sz�t�se. Mivel az ilyen f�ggv�ny l�trehozza az adott t�pus� �rt�keket,
konstruktornak (vagyis l�trehoz�nak, constructor) h�vjuk. A konstruktort arr�l
ismerj�k
meg, hogy ugyanaz a neve, mint mag�nak az oszt�lynak:
class Date {
// ...
Date(int, int, int); // konstruktor
};
Ha egy oszt�ly rendelkezik konstruktorral, akkor minden, ebbe az oszt�lyba tartoz�
objektum
kap kezdo�rt�ket. Ha a konstruktornak param�terekre van sz�ks�ge, azokat meg kell
adni:
Date today = Date(23,6,1983);
Date xmas(25,12,1990); // r�vid�tett forma
Date my_birthday; // hiba: nincs kezdo�rt�k
Date release1_0(10,12); // hiba: a harmadik param�ter hi�nyzik
Gyakran c�lszeru, ha a kezdeti �rt�kad�s t�bbf�lek�ppen is lehets�ges. Ezt �gy
�rhetj�k el,
ha t�bbf�le konstruktor �ll rendelkez�sre:
class Date {
int d, m, y;
public:
// ...
Date(int, int, int); // nap, h�nap, nap
Date(int, int); // nap, h�nap, aktu�lis �v
Date(int); // nap, aktu�lis h�nap �s �v
Date(); // alap�rtelmezett Date: mai d�tum
Date(const char*); // a d�tum karakterl�nccal �br�zolva
};
A konstruktorokra ugyanazok a t�lterhel�si szab�lyok vonatkoznak, mint m�s
f�ggv�nyekre
(�7.4). Am�g a konstruktorok kelloen k�l�nb�znek a param�terek t�pusaiban, a
ford�t�-
program ki fogja tudni v�lasztani, melyiket kell az egyes megh�v�sokkor
alkalmazni:
Date today(4);
Date july4("July 4, 1983");
Date guy("5 Nov");
Date now; // alap�rtelmezett kezdeti �rt�kad�s az aktu�lis d�tummal
A Date p�lda eset�ben megfigyelhetj�k a konstuktorok .elburj�nz�s�t., ami
�ltal�nos jelens
�g. A programoz� egy oszt�ly tervez�sekor mindig k�s�rt�st �rez �j �s �j
f�ggv�nyekkel
bov�teni azt, mondv�n, valakinek �gyis sz�ks�ge lesz r�juk. T�bb gondot ig�nyel
ugyanis
300 Absztrakci�s m�dszerek
m�rlegelni, mire van igaz�n sz�ks�g �s arra szor�tkozni. Ez az odafigyel�s
ugyanakkor �ltal
�ban kisebb �s �rthetobb programokhoz vezet. Az egym�ssal rokon f�ggv�nyek
sz�m�nak
cs�kkent�s�re az egyik m�d az alap�rtelmezett param�ter-�rt�kek haszn�lata (�7.5).
A Date
oszt�ly param�tereinek p�ld�ul egy olyan alap�rtelmezett �rt�ket adhatunk, melynek
jelent
�se: .vegy�k az alap�rtelmezett today-t..
class Date {
int d, m, y;
public:
Date(int dd =0, int mm =0, int yy =0);
// ...
};
Date::Date(int dd, int mm, int yy)
{
d = dd ? dd : today.d;
m = mm ? mm : today.m;
y = yy ? yy : today.y;
// ellenorizz�k, hogy Date �rv�nyes d�tum-e
}
Ha egy param�ter-�rt�ket az alap�rtelmezett �rt�k jelz�s�re haszn�lunk, annak
k�v�l kell esnie
a lehets�ges �rt�kek halmaz�n. A day (nap) �s month (h�nap) param�terek eset�ben
ez
a halmaz vil�gosan meghat�rozhat�, a year (�v) mezon�l azonban a z�r� �rt�k nem
esik
nyilv�nval�an a halmazon k�v�lre. Szerencs�re az eur�pai napt�rban nincs 0-dik �v;
az ido-
sz�m�t�sunk ut�ni elso �v (year==1) k�zvetlen�l az idosz�m�t�sunk elotti elso �v
(year==-1)
ut�n k�vetkezik.
10.2.4. Statikus tagok
A Date t�pushoz tartoz� k�nyelmes alap�rtelmezett �rt�ket egy jelentos rejtett
probl�ma
�r�n hoztuk l�tre: Date oszt�lyunk a today nevu glob�lis v�ltoz�t�l f�gg. �gy az
oszt�ly csak
akkor haszn�lhat�, ha a today v�ltoz�t defini�ltuk �s minden k�dr�szletben
megfeleloen
haszn�ljuk. Ez a fajta megszor�t�s az oszt�lyt az eredeti k�rnyezeten k�v�l
haszn�lhatatlann
� teszi. A felhaszn�l�knak t�l sok kellemetlen meglepet�sben lesz r�sz�k, amikor
ilyen
k�rnyezetf�ggo oszt�lyokat pr�b�lnak haszn�lni �s a k�d m�dos�t�sa is
problematikus lesz.
Ezzel az egy .kis glob�lis v�ltoz�val. m�g tal�n megbirk�zunk, de ez a st�lus
vezet az eredeti
programoz�n k�v�l m�s sz�m�ra haszn�lhatatlan k�dhoz. Ker�lj�k el!
Szerencs�re a k�v�nt c�lt el�rhetj�k a nyilv�nosan el�rheto glob�lis v�ltoz�
jelentette tehert
�tel n�lk�l is. Az olyan v�ltoz�kat, melyek egy oszt�lyhoz tartoznak, de annak
objektumaihoz
nem, statikus tagnak nevezz�k. A statikus tagokb�l mindig pontosan egy p�ld�ny
10. Oszt�lyok 301
l�tezik, nem pedig objektumonk�nt egy, mint a k�z�ns�ges, nem statikus
adattagokb�l. Ehhez
hasonl�an az olyan f�ggv�nyeket, melyek egy adott oszt�lytaghoz hozz�f�rnek, de
nem sz�ks�ges objektumra megh�vni azokat, statikus tagf�ggv�nynek h�vjuk.
Tervezz�k �t
az oszt�lyt �gy, hogy megorizz�k az alap�rtelmezett konstruktor-�rt�kek szerep�t,
de k�zben
elker�lj�k a glob�lis v�ltoz� haszn�lat�nak h�tr�ny�t:
class Date {
int d, m, y;
static Date default_date;
public:
Date(int dd =0, int mm =0, int yy =0);
// ...
static void set_default(int, int, int);
};
A Date konstruktort imm�r �gy hat�rozhatjuk meg:
Date::Date(int dd, int mm, int yy)
{
d = dd ? dd : default_date.d;
m = mm ? mm : default_date.m;
y = yy ? yy : default_date.y;
// ellenorizz�k, hogy Date �rv�nyes d�tum-e
}
Amikor sz�ks�ges, m�dos�thatjuk az alap�rtelmezett �rt�ket. Egy statikus tagra
ugyan�gy
hivatkozhatunk, mint b�rmilyen m�s tagra, sot, ak�r egy objektum megnevez�se
n�lk�l is;
ekkor az oszt�ly nev�vel minos�thetj�k:
void f()
{
Date::set_default(4,5,1945);
}
A statikus tagokat . mind az adattagokat, mind a f�ggv�nyeket . defini�lni kell
valahol:
Date Date::default_date(16,12,1770);
void Date::set_default(int d, int m, int y)
{
Date::default_date = Date(d,m,y);
}
302 Absztrakci�s m�dszerek
Az alap�rtelmezett �rt�k itt Beethoven sz�let�si d�tuma, am�g valaki �t nem
�ll�tja valami
m�sra. Vegy�k �szre, hogy a Date() jel�l�s a Date::default_date �rt�ket
szolg�ltatja:
Date copy_of_default_date = Date();
K�vetkez�sk�ppen nincs sz�ks�g k�l�n f�ggv�nyre az alap�rtelmezett d�tum
lek�rdez�s�hez.
10.2.5. Oszt�ly t�pus� objektumok m�sol�sa
Alap�rtelmez�s szerint az oszt�ly t�pus� objektumok m�solhat�k �s kezdo�rt�kk�nt
egy
azonos t�pus� oszt�ly egy objektum�nak m�solat�t is kaphatj�k, m�g akkor is, ha
konstruktorokat
is megadtunk:
Date d = today; // kezdeti �rt�kad�s m�sol�ssal
Alap�rtelmez�s szerint az oszt�ly objektum m�solata minden tag m�solat�b�l �ll. Ha
nem
ez a megfelelo viselked�s egy X oszt�ly sz�m�ra, az X::X(const X&) m�sol�
konstruktorral
megv�ltoztathatjuk azt. (Erre a �10.4.4.1 pontban r�szletesebben is visszat�r�nk.)
Ennek
megfeleloen az oszt�ly objektumokat alap�rtelmez�s szerint �rt�kad�ssal is
m�solhatjuk:
void f(Date& d)
{
d = today;
}
Az alap�rtelmezett viselked�s itt is a tagonk�nti m�sol�s. Ha ez nem megfelelo egy
oszt�ly
sz�m�ra, a programoz� megadhatja a megfelelo �rt�kad� oper�tort (�10.4.4.1).
10.2.6. Konstans tagf�ggv�nyek
A Date oszt�lyhoz eddig olyan tagf�ggv�nyeket adtunk, melyek �rt�ket adnak egy
Date
objektumnak vagy megv�ltoztatj�k azt, de az �rt�k lek�rdez�s�re sajnos nem adtunk
lehet
os�get. Ezen k�nnyen seg�thet�nk, ha k�sz�t�nk n�h�ny f�ggv�nyt, amelyekkel
kiolvashatjuk
az �vet, a h�napot �s a napot:
class Date {
int d, m, y;
public:
int day() const { return d; }
int month() const { return m; }
int year() const;
// ...
};
10. Oszt�lyok 303
Vegy�k �szre a const minos�tot a f�ggv�nydeklar�ci�kban az (�res) param�terlista
ut�n. Ez
azt jelenti, hogy ezek a f�ggv�nyek nem v�ltoztatj�k meg az objektum �llapot�t.
Term�-
szetesen a ford�t�program megakad�lyozza, hogy v�letlen�l megszegj�k ezt az
�g�retet:
inline int Date::year() const
{
return y++; // hiba: k�s�rlet tag �rt�k�nek m�dos�t�s�ra konstans f�ggv�nyben
}
Ha egy konstans tagf�ggv�nyt oszt�ly�n k�v�l hat�rozzuk meg, a const ut�tagot ki
kell
�rnunk:
inline int Date::year() const // helyes
{
return y;
}
inline int Date::year() // hiba: a const minos�to hi�nyzik a tagf�ggv�ny t�pus�b�l

{
return y;
}
Vagyis a const minos�t�s r�sze a Date::day() �s Date::year() f�ggv�nyek t�pus�nak.

Egy konstans tagf�ggv�nyt alkalmazhatunk �lland� (konstans) �s v�ltoz� (nem


konstans) objektumokra
is, a nem konstans tagf�ggv�nyeket viszont csak nem konstans objektumokra:
void f(Date& d, const Date& cd)
{
int i = d.year(); // rendben
d.add_year(1); // rendben
int j = cd.year(); // rendben
cd.add_year(1); // hiba: cd konstans, �rt�ke nem m�dos�that�
}
10.2.7. �nhivatkoz�s
Az add_year(), add_month(), �s add_year() �llapotfriss�to f�ggv�nyeket �gy
hat�roztuk
meg, hogy azok nem adnak vissza �rt�ket. Az ilyen, egym�ssal kapcsolatban levo
friss�to
f�ggv�nyek eset�ben sokszor hasznos, ha visszaadunk egy, a friss�tett objektumra
mutat�
referenci�t, mert a muveleteket ekkor l�ncba kapcsolhatjuk (.l�ncolhatjuk.).
304 Absztrakci�s m�dszerek
Tegy�k fel, hogy a k�vetkezot szeretn�nk �rni:
void f(Date& d)
{
// ...
d.add_day(1).add_month(1).add_year(1);
// ...
}
Ezzel egy napot, egy h�napot �s egy �vet adunk d-hez. Ehhez viszont minden
f�ggv�nyt
�gy kell megadnunk, hogy azok egy Date t�pus� referenci�t adjanak vissza:
class Date {
// ...
Date& add_year(int n); // n �v hozz�ad�sa
Date& add_month(int n); // n h�nap hozz�ad�sa
Date& add_day(int n); // n nap hozz�ad�sa
};
Minden (nem statikus) tagf�ggv�ny tudja, melyik objektumra h�vt�k meg, �gy
pontosan hivatkozhat
r�:
Date& Date::add_year(int n)
{
if (d==29 && m==2 && !leapyear(y+n)) { // figyelj�nk febru�r 29-re!
d = 1;
m = 3;
}
y += n;
return *this;
}
A *this kifejez�s azt az objektumot jelenti, amelyre a tagf�ggv�nyt megh�vt�k.
(Egyen�rt�-
ku a Simula nyelv THIS �s a Smalltalk self kifejez�s�vel.)
Egy nem statikus tagf�ggv�nyben a this kulcssz� egy mutat�t jelent arra az
objektumra,
amelyre a f�ggv�nyt megh�vt�k. Az X oszt�ly egy nem const tagf�ggv�ny�ben a this
t�pusa
X*. Mindazon�ltal a this nem k�z�ns�ges v�ltoz�, �gy nem lehet a c�m�t
felhaszn�lni vagy
�rt�ket adni neki. Az X oszt�ly egy konstans tagf�ggv�nyben a this t�pusa const X*
lesz,
hogy ne lehessen megv�ltoztatni mag�t az objektumot (l�sd m�g �5.4.1).
10. Oszt�lyok 305
A this haszn�lata legt�bbsz�r automatikus. P�ld�ul minden nem statikus tagra val�
hivatkoz
�s tulajdonk�ppen a this-t haszn�lja, hogy a megfelelo objektum tagj�t �rje el. Az
add_year
f�ggv�nyt p�ld�ul egyen�rt�ku, �m f�rads�gos m�don �gy is megadhattuk volna:
Date& Date::add_year(int n)
{
if (this->d==29 && this->m==2 && !leapyear(this->y+n)) {
this->d = 1;
this->m = 3;
}
this->y += n;
return *this;
}
A this-t meghat�rozott (explicit) m�don gyakran l�ncolt list�k kezel�s�re
haszn�ljuk (p�ld
�ul �24.3.7.4).
10.2.7.1. Fizikai �s logikai konstansok
Esetenk�nt elofordulhat, hogy egy tagf�ggv�ny logikailag �lland�, m�gis meg kell
v�ltoztatnia
egy tag �rt�k�t. A felhaszn�l� sz�m�ra a f�ggv�ny nem m�dos�tja az objektum
�llapot
�t, de valamilyen, a felhaszn�l� �ltal k�zvetlen�l nem l�that� r�szlet
megv�ltozik.
Az ilyen helyzetet gyakran h�vj�k logikai konstans mivoltnak. A Date oszt�lyt
p�ld�ul egy
f�ggv�ny visszat�r�si �rt�ke egy karakterl�nccal �br�zolhatja, melyet a
felhaszn�l� a kimenetben
felhaszn�lhat. Egy ilyen �br�zol�s fel�p�t�se idoig�nyes feladat, ez�rt �rdemes
egy
p�ld�nyt t�rolni belole, amit az egym�st k�veto lek�rdez�sek mind
felhaszn�lhatnak, am�g
a Date �rt�ke meg nem v�ltozik. Ilyen belso gyors�t�t�r (gyorst�r, cache) ink�bb
bonyolultabb
adatszerkezetekn�l haszn�latos, de n�zz�k meg, hogyan muk�dhetne ez a Date oszt
�ly eset�ben:
class Date {
bool cache_valid;
string cache;
void compute_cache_value(); // gyorst�r felt�lt�se
// ...
public:
// ...
string string_rep() const; // �br�zol�s karakterl�nccal
};
306 Absztrakci�s m�dszerek
A felhaszn�l� szemsz�g�bol a string_rep f�ggv�ny nem v�ltoztatja meg az objektum
�llapot
�t, ez�rt vil�gos, hogy konstans tagf�ggv�nynek kell lennie. M�sr�szt a
gyors�t�t�rat fel
kell t�lteni a haszn�lat elott. Ezt el�rhetj�k t�pusk�nyszer�t�s alkalmaz�s�val
is:
string Date::string_rep() const
{
if (cache_valid == false) {
Date* th = const_cast<Date*>(this); // konstans elvet�se
th->compute_cache_value();
th->cache_valid = true;
}
return cache;
}
Vagyis a const_cast oper�tort (�15.4.2.1) haszn�ltuk, hogy egy Date* t�pus�
mutat�t kapjunk
a this-re. Ez aligha eleg�ns megold�s, �s nem biztos, hogy egy eredetileg is
�lland�-
k�nt megadott objektum eset�ben is muk�dik:
Date d1;
const Date d2;
string s1 = d1.string_rep();
string s2 = d2.string_rep(); // nem meghat�rozott viselked�s
A d1 v�ltoz� eset�ben a string_rep() egyszeruen az eredeti t�pusra alak�t vissza,
�gy a dolog
muk�dik. �m d2-t konstansk�nt adtuk meg �s az adott nyelvi v�ltozat esetleg
valamilyen
mem�ria-v�delmet alkalmaz az �lland� �rt�kek megorz�s�re. Ez�rt a d2.string_rep()
h�v�s
nem biztos, hogy pontosan meghat�rozhat�, az adott nyelvi v�ltozatt�l f�ggetlen
eredm
�nnyel fog j�rni.
10.2.7.2. A mutable minos�to
Az elobb le�rt t�pusk�nyszer�t�s (a const minos�to �talak�t�sa) �s a vele j�r�,
megval�s�t�st�l
f�ggo viselked�s elker�lheto, ha a gyors�t�t�rba ker�lo adatokat .v�ltoz�kony.-
k�nt
(mutable) adjuk meg:
class Date {
mutable bool cache_valid;
mutable string cache;
void compute_cache_value() const; // (v�ltoz�kony) gyorst�r felt�lt�se
// ...
public:
// ...
string string_rep() const; // �br�zol�s karakterl�nccal
};
10. Oszt�lyok 307
A mutable t�rol�si minos�t�s azt jelenti, hogy a tagot �gy kell t�rolni, hogy
akkor is m�dos
�that� legyen, ha konstans objektum. Vagyis a mutable azt jelenti, hogy .soha nem
�lland
�.. Ezt felhaszn�lva egyszerus�thet�nk a string_rep() meghat�roz�s�n:
string Date::string_rep() const
{
if (!cache_valid) {
compute_cache_value();
cache_valid = true;
}
return cache;
}
Ez�ltal a string_rep()-et megfeleloen haszn�latba vehetj�k:
Date d3;
const Date d4;
string s3 = d3.string_rep();
string s4 = d4.string_rep(); // rendben!
A tagok v�ltoz�konyk�nt val� megad�sa akkor alkalmas legink�bb, ha az �br�zol�snak
csak
egy r�sze v�ltozhat. Ha az objektum logikailag v�ltozatlan marad, de a tagok
t�bbs�ge m�-
dosulhat, jobb a v�ltoz� adatr�szt k�l�n objektumba tenni �s k�zvetett �ton
el�rni. Ezzel
a m�dszerrel a gyors�t�t�rba helyezett karakterl�ncot tartalmaz� program �gy
�rhat� meg:
struct cache {
bool valid;
string rep;
};
class Date {
cache* c; // kezdeti �rt�kad�s a konstruktorban (�10.4.6)
void compute_cache_value() const; // a gyorst�r �ltal mutatott elem felt�lt�se
// ...
public:
// ...
string string_rep() const; // �br�zol�s karakterl�nccal
};
string Date::string_rep() const
{
if (!c->valid) {
compute_cache_value();
c->valid = true;
}
return c->rep;
}
308 Absztrakci�s m�dszerek
A gyors�t�t�rat t�mogat� elj�r�sok az �n. .lusta. vagy takaros ki�rt�kel�s (lazy
evaluation)
k�l�nf�le form�ira is �tvihetok.
10.2.8. Strukt�r�k �s oszt�lyok
Defin�ci� szerint a strukt�ra (struct), olyan oszt�ly, melynek tagjai
alap�rtelmez�s szerint
nyilv�nosak. Vagyis a
struct s { ...
egyszeruen r�vid�t�se az al�bbinak:
class s { public: ...
A private: el�rhetos�gi minos�t�s annak jelz�s�re haszn�lhat�, hogy a k�vetkezo
tagok priv
�t el�r�suek, a public: pedig azt mondja, hogy a k�vetkezo tagok nyilv�nosak.
Att�l eltekintve,
hogy a nevek k�l�nb�znek, az al�bbi deklar�ci�k egyen�rt�kuek:
class Date1 {
int d, m, y;
public:
Date1(int dd, int mm, int yy);
void add_year(int n); // n �v hozz�ad�sa
};
struct Date2 {
private:
int d, m, y;
public:
Date2(int dd, int mm, int yy);
void add_year(int n); // n �v hozz�ad�sa
};
A v�lasztott st�lust csak a k�r�lm�nyek �s az egy�ni �zl�s hat�rozza meg. �n
�ltal�ban
azokat az oszt�lyokat adom meg struct-k�nt, amelyekben minden tag nyilv�nos.
Ezekre az
oszt�lyokra �gy gondolok, mint amik nem igazi t�pusok, csak adatszerkezetek. A
konstruktorok
�s lek�rdezo f�ggv�nyek nagyon hasznosak lehetnek a strukt�r�k sz�m�ra is, de
ink�bb csak jel�l�sbeli k�nnyebbs�get jelentenek, mintsem a t�pus tulajdons�gait
garant�lj
�k (mint az invari�nsok, l�sd �24.3.7.1).
10. Oszt�lyok 309
Az oszt�lyokban nem sz�ks�ges elosz�r az adattagokat megadni, sot, sokszor jobb
azokat
a deklar�ci� v�g�re tenni, hogy kihangs�lyozzuk a nyilv�nos felhaszn�l�i fel�letet
alkot�
f�ggv�nyeket:
class Date3 {
public:
Date3(int dd, int mm, int yy);
void add_year(int n); // n �v hozz�ad�sa
private:
int d, m, y;
};
Val�di k�dban, ahol �ltal�ban mind a nyilv�nos fel�let, mind a t�nyleges
megval�s�t�s terjedelmesebb,
mint a tank�nyvi p�ld�kban, rendszerint a Date3 st�lus�t r�szes�tem elonyben.
Az el�rhetos�gi minos�t�seket az oszt�lydeklar�ci�kon bel�l t�bbsz�r is
haszn�lhatjuk:
class Date4 {
public:
Date4(int dd, int mm, int yy);
private:
int d, m, y;
public:
void add_year(int n); // n �v hozz�ad�sa
};
Ha azonban a deklar�ci� t�bb nyilv�nos r�szt is tartalmaz (mint a Date4
oszt�lyn�l), akkor
a k�d zavaross� v�lhat. T�bb priv�t r�sz haszn�lata szint�n ezt eredm�nyezi.
Mindazon�ltal
a sz�m�t�g�p �ltal elk�sz�tett k�dok sz�m�ra kedvezo, hogy az el�rhetos�gi
minos�t�sek
ism�tlodhetnek.
10.2.9. Oszt�lyon bel�li f�ggv�nydefin�ci�k
Az oszt�lyon bel�l defini�lt (nem csak deklar�lt) f�ggv�nyek helyben kifejtett
(inline) tagf
�ggv�nynek sz�m�tanak, azaz a ford�t�program a f�ggv�ny megh�v�sa helyett
k�zvetlen�l
beilleszti a k�dot. Vagyis az oszt�ly meghat�roz�s�n bel�li kifejt�s kicsi, de
gyakran haszn
�lt f�ggv�nyek sz�m�ra hasznos. Ahhoz az oszt�ly-definici�hoz hasonl�an, amelyben
szerepel,
az oszt�lyon bel�l kifejtett f�ggv�ny is szerepelhet t�bb ford�t�si egys�gben (az
#include utas�t�ssal be�p�tve). Persze az oszt�lyhoz hasonl�an jelent�s�nek minden
felhaszn
�l�sakor azonosnak kell lennie (�9.2.3).
310 Absztrakci�s m�dszerek
Az a st�lus, mely szerint az adattagokat az oszt�ly definici�j�nak v�g�re
helyezz�k, kisebb
gondhoz vezet az adat�br�zol�st felhaszn�l� nyilv�nos .inline. f�ggv�nyek
tekintet�ben.
Vegy�k ezt a p�ld�t:
class Date { // zavar� lehet
public:
int day() const { return d; } // return Date::d
// ...
private:
int d, m, y;
};
Ez szab�lyos C++-k�d, mivel egy oszt�ly egy tagf�ggv�nye az oszt�ly minden tagj�ra
hivatkozhat,
mintha az oszt�ly definici�ja m�r a tagf�ggv�ny-t�rzsek beolvas�sa elott teljes
lett
volna. A k�dot olvas� programoz�t azonban ez megzavarhatja, ez�rt �n vagy
eloreveszem
az adatokat, vagy az .inline. tagf�ggv�nyeket az oszt�ly ut�n fejtem ki:
class Date {
public:
int day() const;
// ...
private:
int d, m, y;
};
inline int Date::day() const { return d; }
10.3. Hat�kony felhaszn�l�i t�pusok
Az elozo Date oszt�ly p�ld�j�n bemutattuk az oszt�lyok meghat�roz�s�hoz sz�ks�ges
alapvet
o nyelvi elemeket. Most az egyszeru �s hat�kony tervez�sre helyezz�k a hangs�lyt
�s azt
mutatjuk be, hogy az egyes nyelvi elemek hogyan t�mogatj�k ezt.
Sz�mos program haszn�l egyszeru, de surun elofordul� elvont fogalmakat, konkr�t
t�pusokkal
�br�zolva: latin vagy k�nai karaktereket, lebegopontos sz�mokat, komplex sz�-
mokat, pontokat, mutat�kat, koordin�t�kat, (mutat�.eltol�s (offset)) p�rokat,
d�tumokat,
idopontokat, �rt�kk�szleteket, kapcsolatokat, csom�pontokat, (�rt�k.egys�g)
p�rokat, lemezc
�meket, forr�sk�d-helyeket, BCD karaktereket, p�nznemeket, vonalakat,
t�glalapokat,
r�gz�tett pontos sz�mokat, t�rtr�sszel b�r� sz�mokat, karakterl�ncokat, vektorokat
�s t�mb
�ket. Gyakran elofordul, hogy egy program k�zvetetten t�maszkodik ezen t�pusok n�-

melyik�re �s m�g t�bbre k�zvetlen�l, k�nyvt�rak k�zvet�t�s�vel.


10. Oszt�lyok 311
A C++ m�s programoz�si nyelvekkel egyetemben k�zvetlen�l t�mogat n�h�nyat a fenti
t�-
pusok k�z�l, �m sz�muk miatt nem lehets�ges az �sszeset k�zvetlen�l t�mogatni. Egy
�ltal
�nos c�l� programoz�si nyelv tervezoje nem is l�thatja elore az egyes alkalmaz�sok
ig�-
nyeit. Teh�t sz�ks�g van olyan elj�r�sokra, melyekkel a felhaszn�l� adott c�l�
t�pusokat
adhat meg. Az ilyen t�pusokat konkr�t t�pusoknak vagy konkr�t oszt�lyoknak h�vjuk,
hogy
megk�l�nb�ztess�k oket az absztrakt (elvont) oszt�lyokt�l (�12.3), illetve az
oszt�lyhierarchi
�k oszt�lyait�l (�12.2.4 �s �12.4).
A C++ nyelv egyik kifejezett c�lja volt, hogy az ilyen felhaszn�l�i t�pusok
megad�s�t �s hat
�kony haszn�lat�t is t�mogassa, mert ezek az .eleg�ns. programoz�s alapk�vei. Mint
�ltal
�ban, itt is �rv�nyes, hogy az egyszeru �s f�ldh�zragadt sokkal jelentosebb, mint
a bonyolult
�s k�rm�nfont.
Ennek f�ny�ben k�sz�ts�nk egy jobb d�tumoszt�lyt:
class Date {
public: // nyilv�nos fel�let
enum Month { jan=1, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec };
class Bad_date { }; // kiv�teloszt�ly
Date(int dd =0, Month mm =Month(0), int yy =0); // 0 jelent�se "vedd az
// alap�rtelmezettet"
// f�ggv�nyek a Date vizsg�lat�hoz
int day() const;
Month month() const;
int year() const;
string string_rep() const; // �br�zol�s karakterl�nccal
void char_rep(char s[ ]) const; // �br�zol�s C st�lus� karakterl�nccal
static void set_default(int, Month, int);
// f�ggv�nyek a Date m�dos�t�s�hoz
Date& add_year(int n); // n �v hozz�ad�sa
Date& add_month(int n); // n h�nap hozz�ad�sa
Date& add_day(int n); // n nap hozz�ad�sa
private:
int d, m, y; // �br�zol�s
static Date default_date;
};
312 Absztrakci�s m�dszerek
A v�gezheto muveletek ilyen halmaza meglehetosen jellemzo a felhaszn�l�i
adatt�pusokra.
A k�vetkezok szerepelnek benne:
1. Egy konstruktor, amely kezdo�rt�ket ad az objektumoknak �s v�ltoz�knak
2. Lek�rdezo f�ggv�nyek, melyekkel egy Date-et megvizsg�lhatunk. Ezek const
minos�t�se jelzi, hogy nem m�dos�tj�k annak az objektumnak vagy v�ltoz�nak
az �llapot�t, amelyre megh�vt�k oket.
3. A Date objektumokat �s v�ltoz�kat kezelo f�ggv�nyek, melyek az �br�zol�s
vagy a konkr�t megval�s�t�s ismerete, illetve az egyes elemek szerep�vel val�
bajl�d�s n�lk�l is megh�vhat�k.
4. Automatikusan defini�lt muveletek, melyek seg�ts�g�vel a Date-ek szabadon
m�solhat�k.
5. A Bad_date oszt�ly, mellyel a hib�k mint kiv�telek jelezhetok.
A Month (h�nap) t�pust az�rt vezettem be, hogy kezeljem azt a probl�m�t, amit az
okoz,
hogy eml�kezn�nk kell r�: vajon j�nius 7-�t amerikai st�lusban Date(6,7)-nek vagy
eur�pai
st�lusban Date(7,6)-nak kell-e �rnunk. Az alap�rtelmezett param�ter-�rt�kek
kezel�s�re is
gondoltam, ezzel k�l�n elj�r�s foglalkozik.
Gondolkodtam azon, hogy a napok �s �vek �br�zol�s�ra a Day-t �s a Year-t, mint
�n�ll� t�-
pusokat bevezessem, hogy a Date(1995,jul,27) �s a Date(27,jul,1995)
�sszekevered�s�-
nek vesz�ly�t elker�ljem. Ezek a t�pusok azonban nem lenn�nek annyira hasznosak,
mint
a Month. Majdnem minden ilyen hiba am�gy is kider�l fut�si idoben . nemigen
dolgozom
olyan d�tumokkal, mint a 27-ik �v j�lius 26-ika. Az 1800 elotti t�rt�nelmi d�tumok
kezel�-
se annyira bonyolult, hogy jobb t�rt�n�sz szak�rtokre b�zni. Ezenk�v�l pedig egy
.valahanyadik�t. nem lehet rendesen ellenorizni a h�nap �s az �v ismerete n�lk�l.
(Egy alkalmas
Year t�pus meghat�roz�s�ra n�zve l�sd: �11.7.1.)
Az alap�rtelmezett d�tumot mint �rv�nyes Date objektumot defini�lni kell valahol:
Date Date::default_date(22,jan,1901);
A �10.2.7.1-ben eml�tett gyors�t�t�ras (cache) m�dszer egy ilyen egyszeru t�pusn�l
felesleges,
�gy kihagytam. Ha m�gis sz�ks�ges, kieg�sz�thetj�k vele az oszt�lyt, mint a
felhaszn�-
l�i fel�letet nem �rinto megval�s�t�si r�szlettel.
10. Oszt�lyok 313
�me egy kicsi elm�leti p�lda arra, hogy lehet Date-eket haszn�lni:
void f(Date& d)
{
Date lvb_day = Date(16,Date::dec,d.year());
if (d.day()==29 && d.month()==Date::feb) {
// ...
}
if (midnight()) d.add_day(1);
cout << "A k�vetkezo nap:" << d+1 << '\n';
}
Felt�telezz�k, hogy a << kimeneti �s a + �sszead� muvelet a Date-ekre defini�lt;
(ezt
a �10.3.3-ban val�ban meg is tessz�k).
Figyelj�k meg a Date::feb jel�l�st. Az f() nem tagf�ggv�nye Date-nek, �gy meg kell
adni,
hogy a Date-nek �s nem valami m�snak a feb-j�rol van sz�.
Mi�rt �ri meg egy k�l�n t�pust megadni egy olyan egyszeru dolog sz�m�ra, mint egy
d�tum?
V�g�l is be�rhetn�nk egy egyszeru adatszerkezettel...
struct Date {
int day, month, year;
};
...�s hagyn�nk, hogy a programoz�k d�nts�k el, mit csin�lnak vele. De ha ezt
tenn�nk, akkor
minden felhaszn�l�nak mag�nak kellene a Date-ek �sszetevoit kezelnie: vagy
k�zvetlen
�l, vagy k�l�n f�ggv�nyekben. Ez pedig azzal j�rna, hogy a d�tum fogalma .sz�tsz�-

r�dna., �gy azt nehezebb lenne meg�rteni, dokument�lni �s m�dos�tani. Ha egy


fogalmat
egyszeru adatszerkezetk�nt bocs�tunk a felhaszn�l�k rendelkez�s�re, az
sz�ks�gszeruen
k�l�n munk�t ig�nyel tol�k.
Ezenk�v�l b�r a Date t�pus l�tsz�lag egyszeru, m�gis gondot ig�nyel �gy meg�rni,
hogy helyesen
muk�dj�k. P�ld�ul egy Date objektum n�vel�s�hez sz�ko�vekkel kell t�rodni, azzal
a t�nnyel, hogy a h�napok k�l�nb�zo hossz�s�g�ak �s �gy tov�bb (l�sd a �10.6[1]-es
feladatot).
Az �v-h�nap-nap adat�br�zol�s r�ad�sul sok program sz�m�ra szeg�nyes. Ha viszont
�gy d�nt�nk, hogy megv�ltoztatjuk, csak a kijel�lt f�ggv�nyeket kell m�dos�tanunk.

Ha a Date-et p�ld�ul az 1970. janu�r elseje ut�ni vagy elotti napok sz�m�val
akarn�nk �br
�zolni, csak a Date tagf�ggv�nyeit kellene megv�ltoztatnunk (�10.6.[2]).
314 Absztrakci�s m�dszerek
10.3.1. Tagf�ggv�nyek
Term�szetesen minden tagf�ggv�nyt ki kell fejteni valahol. �me a Date
konstruktor�nak
defin�ci�ja:
Date::Date(int dd, Month mm, int yy)
{
if (yy == 0) yy = default_date.year();
if (mm == 0) mm = default_date.month();
if (dd == 0) dd = default_date.day();
int max;
switch (mm) {
case feb:
max = 28+leapyear(yy);
break;
case apr: case jun: case sep: case nov:
max = 30;
break;
case jan: case mar: case may: case jul: case aug: case oct: case dec:
max = 31;
break;
default:
throw Bad_date(); // valaki csalt
}
if (dd<1 || max<dd) throw Bad_date();
y = yy;
m = mm;
d = dd;
}
A konstruktor ellenorzi, hogy a kapott adatok �rv�nyes d�tumot adnak-e. Ha nem,
mint
p�ld�ul a Date(30,Date::Feb,1994) eset�ben, kiv�telt v�lt ki (�8.3, 14. fejezet),
amely jelzi,
hogy olyan jellegu hiba t�rt�nt, amit nem lehet figyelmen k�v�l hagyni. Ha a
kapott adatok
elfogadhat�ak, a kezdeti �rt�kad�s megt�rt�nik. Ez meglehetosen jellemzo
elj�r�sm�d.
M�sfelol ha a Date objektum m�r l�trej�tt, akkor az tov�bbi ellenorz�s n�lk�l
felhaszn�lhat
� �s m�solhat�. M�s sz�val a konstruktor fel�ll�tja az oszt�lyra jellemzo
invari�nst (ebben
az esetben azt, hogy egy �rv�nyes d�tumr�l van sz�). A t�bbi tagf�ggv�ny sz�m�that
erre
az �llapotra �s k�teless�ge fenntartani azt. Ez a tervez�si m�dszer �ri�si
m�rt�kben leegyszer
us�theti a k�dot (l�sd a 24.3.7.1-es pontot).
10. Oszt�lyok 315
A Month(0) �rt�ket (amely nem jelent igazi h�napot) a .vegy�k az alap�rtelmezett
h�napot
. jelz�s�re haszn�ljuk. A Month felsorol�sban megadhatn�nk egy �rt�ket
kifejezetten ennek
jelz�s�re, de jobb egy nyilv�nval�an �rv�nytelen �rt�ket haszn�lni erre a c�lra,
mint
hogy olyan l�tszatot kelts�nk, hogy 13 h�nap van egy �vben. Vegy�k �szre, hogy a 0
�rt�-
ket az�rt haszn�lhatjuk, mert az a Month felsorol�s biztos�tott garant�lt
�rt�ktartom�nyba
esik (�4.8).
Gondolkodtam azon, hogy az adatellenorz�st k�l�n, egy is_date() f�ggv�nybe teszem,
de
ez olyan k�dhoz vezetne, amely bonyolultabb �s kev�sb� hat�kony, mint a kiv�telek
elkap
�s�n alapul�. Tegy�k fel p�ld�ul, hogy a >> muvelet �rtelmezett a Date oszt�lyra:
void fill(vector<Date>& aa)
{
while (cin) {
Date d;
try {
cin >> d;
}
catch (Date::Bad_date) {
// saj�t hibakezelo
continue;
}
aa.push_back(d); // l�sd �3.7.3
}
}
Mint az ilyen egyszeru konkr�t oszt�lyok eset�ben szok�sos, a tagf�ggv�nyek
meghat�roz
�sa a trivi�lis �s a nem t�l bonyolult k�z�tt mozog. P�ld�ul:
inline int Date::day() const
{
return d;
}
Date& Date::add_month(int n)
{
if (n==0) return *this;
if (n>0) {
int delta_y = n/12;
int mm = m+n%12;
if (12 < mm) { // megjegyz�s: int(dec)==12
delta_y++;
mm -= 12;
}
316 Absztrakci�s m�dszerek
// most azok az esetek j�nnek, amikor Month(mm)-nek nincs d napja
y += delta_y;
m = Month(mm);
return *this;
}
// negat�v n kezel�se
return *this;
}
10.3.2. Seg�df�ggv�nyek
Egy oszt�lyhoz �ltal�ban sz�mos olyan f�ggv�ny tartozhat, melyeket nem sz�ks�ges
mag�-
ban az oszt�lyban tagk�nt megadni, mert nincs sz�ks�g�k a belso adat�br�zol�s
k�zvetlen
el�r�s�re:
int diff(Date a, Date b); // napok sz�ma az [a,b] vagy [b,a] tartom�nyban
bool leapyear(int y);
Date next_weekday(Date d);
Date next_saturday(Date d);
Ha ezeket a f�ggv�nyeket mag�ban az oszt�lyban fejten�nk ki, az bonyolultabb�
tenn� az
oszt�ly fel�let�t �s a belso adat�br�zol�s esetleges m�dos�t�sakor t�bb f�ggv�nyt
kellene
ellenorizni.
Hogyan kapcsol�dnak az ilyen seg�df�ggv�nyek a Date oszt�lyhoz? Hagyom�nyosan
a deklar�ci�jukat az oszt�ly deklar�ci�j�val azonos f�jlba tenn�nk, �gy azon
felhaszn�l�k
sz�m�ra, akiknek sz�ks�g�k van a Date oszt�lyra, r�gt�n ezek is rendelkez�sre
�lln�nak
a fel�letet le�r� fej�llom�ny be�p�t�se ut�n (�9.2.1):
#include "Date.h"
A Date.h fej�llom�ny haszn�lata mellett vagy helyett a seg�df�ggv�nyek �s az
oszt�ly kapcsolat
�t �gy tehetj�k nyilv�nval�v�, hogy az oszt�lyt �s seg�df�ggv�nyeit egy n�vt�rbe
foglaljuk
(�8.2):
namespace Chrono { // d�tumkezelo szolg�ltat�sok
class Date { /* ... */};
int diff(Date a, Date b);
bool leapyear(int y);
10. Oszt�lyok 317
Date next_weekday(Date d);
Date next_saturday(Date d);
// ...
}
A Chrono n�vt�r term�szetesen a t�bbi kapcsol�d� oszt�lyt is tartalmazn�, p�ld�ul
a Time
(Ido) �s Stopwatch (Stopper) oszt�lyokat �s azok seg�df�ggv�nyeit is. Egy egyetlen
oszt�lyt
tartalmaz� n�vt�r haszn�lata �ltal�ban csak t�lbonyol�tott, k�nyelmetlen k�dhoz
vezet.
10.3.3. Oper�torok t�lterhel�se
Gyakran hasznos lehet olyan f�ggv�nyeket felvenni, amelyek a hagyom�nyos
jel�l�sm�d
haszn�lat�t biztos�tj�k. Az operator== f�ggv�ny p�ld�ul lehetov� teszi az ==
egyenlos�gi
oper�tor haszn�lat�t a Date objektumokra:
inline bool operator==(Date a, Date b) // egyenlos�g
{
return a.day()==b.day() && a.month()==b.month() && a.year()==b.year();
}
Egy�b k�zenfekvo jel�ltek:
bool operator!=(Date, Date); // egyenlotlens�g
bool operator<(Date, Date); // kisebb
bool operator>(Date, Date); // nagyobb
// ...
Date& operator++(Date& d); // Date n�vel�se egy nappal
Date& operator--(Date& d); // Date cs�kkent�se egy nappal
Date& operator+=(Date& d, int n); // n nap hozz�ad�sa
Date& operator-=(Date& d, int n); // n nap kivon�sa
Date operator+(Date d, int n); // n nap hozz�ad�sa
Date operator-(Date d, int n); // n nap kivon�sa
ostream& operator<<(ostream&, Date d); // d ki�r�sa
istream& operator>>(istream&, Date& d); // beolvas�s d-be
A Date oszt�ly sz�m�ra ezen oper�torok haszn�lhat�s�ga puszt�n k�nyelmi
szempontnak
tunik. �m sok t�pus . p�ld�ul a komplex sz�mok (�11.3), a vektorok (�3.7.1) �s a
f�ggv
�nyszeru objektumok (�18.4) . eset�ben ezek haszn�lata annyira beidegzod�tt a
felhaszn
�l�kn�l, hogy szinte k�telezo megadni oket. Az oper�torok t�lterhel�s�vel a 11.
fejezet
foglalkozik.
318 Absztrakci�s m�dszerek
10.3.4. A konkr�t oszt�lyok jelentos�ge
Az�rt h�vjuk a Date �s m�s egyszeru felhaszn�l�i t�pusokat konkr�t t�pusoknak,
hogy megk
�l�nb�ztessem azokat az absztrakt oszt�lyokt�l (�2.5.4) �s az
oszt�lyhierarchi�kt�l (12.3),
illetve hogy hangs�lyozzam az olyan be�p�tett t�pusokkal val� hasonl�s�gukat, mint
az int
vagy a float. Ezeket �rt�kt�pusoknak (value types) is nevezik, haszn�latukat pedig
�rt
�kk�zpont� programoz�snak (value-oriented programming). Haszn�lati modellj�k �s
m�-
g�tte levo .filoz�fia. nagyon k�l�nb�zik att�l, amit gyakran objektum-orient�lt
programoz
�snak h�vnak (�2.6.2).
A konkr�t oszt�lyok dolga az, hogy egyetlen, viszonylag egyszeru dolgot j�l �s
hat�konyan
csin�ljanak. �ltal�ban nem c�l, hogy a felhaszn�l�nak eszk�zt adjunk a kez�be egy
konkr
�t oszt�ly viselked�s�nek megv�ltoztat�s�ra. �gy a konkr�t oszt�lyokat nem sz�njuk
arra
sem, hogy t�bbalak� (polimorf) viselked�st tan�s�tsanak (�2.5.5, �12.2.6).
Ha nem tetszik egy konkr�t t�pus viselked�se, akkor �rhatunk egy m�sikat, ami a
k�v�nalmaknak
megfeleloen muk�dik. Ez az adott t�pus .�jrahasznos�t�s�val. is el�rhetj�k; a
t�pust
pontosan �gy haszn�lhatjuk fel az �j t�pus megval�s�t�s�hoz, mint egy int-et:
class Date_and_time {
private:
Date d;
Time t;
public:
Date_and_time(Date d, Time t);
Date_and_time(int d, Date::Month m, int y, Time t);
// ...
};
A 12. fejezetben t�rgyalt �r�klod�si elj�r�st �gy haszn�lhatjuk fel egy �j t�pus
meghat�roz�-
s�ra, hogy csak az elt�r�seket kell le�rnunk. A Vec oszt�lyt p�ld�ul a vector
alapj�n k�sz�thetj
�k el (�3.7.2).
Egy valamireval� ford�t�programmal egy, a Date-hez hasonl� konkr�t oszt�ly
haszn�lata
nem j�r a sz�ks�ges t�rol�hely vagy a fut�si ido rejtett n�veked�s�vel. A konkr�t
oszt�lyok
m�rete ford�t�si idoben ismert, ez�rt az objektumok sz�m�ra helyet foglalhatunk a
fut�si
veremben is, azaz a szabad t�rat �rinto muveletek n�lk�l. A mem�riakioszt�s is
ismert, �gy
a helyben ford�t�s egyszeru feladat. A mem�riakioszt�snak m�s nyelvekkel, p�ld�ul
a C-vel
vagy a Fortrannal val� �sszeegyeztet�se is hasonl�an k�nnyen, k�l�n erofesz�t�s
n�lk�l
megoldhat�.
10. Oszt�lyok 319
Az ilyen egyszeru t�pusok megfelelo halmaza teljes programok alapj�ul szolg�lhat.
Ha egy
alkalmaz�sban nincsenek meg a megfelelo kicsi, de hat�kony t�pusok, akkor a t�l
�ltal�nos
�s .k�lts�ges. oszt�lyok haszn�lata komoly fut�si idobeli �s t�rfelhaszn�l�s-beli
pazarl�shoz
vezethet. A konkr�t t�pusok hi�nya m�sfelol zavaros programokat eredm�nyez,
illetve
azt, hogy minden programoz� meg�rja az .egyszeru �s surun haszn�lt.
adatszerkezeteket
k�zvetlen�l kezelo k�dot.
10.4. Objektumok
Objektumok t�bbf�lek�ppen j�hetnek l�tre: lehetnek automatikus vagy glob�lis
v�ltoz�k,
oszt�lyok tagjai stb. Az al�bbiakban ezeket a lehetos�geket, a r�juk vonatkoz�
szab�lyokat,
az objektumok kezdo�llapot�t be�ll�t� konstruktorokat �s a haszn�latb�l kiker�lo
objektumok
.eltakar�t�s�ra. szolg�l� destruktorokat t�rgyaljuk.
10.4.1. Destruktorok
Az objektumok kezdo�llapot�t a konstruktorok �ll�tj�k be, vagyis a konstruktorok
hozz�k
l�tre azt a k�rnyezetet, amelyben a tagf�ggv�nyek muk�dnek. Esetenk�nt az ilyen
k�rnyezet
l�trehoz�sa valamilyen eroforr�s . f�jl, z�r, mem�riater�let . lefoglal�s�val j�r,
amit
a haszn�lat ut�n fel kell szabad�tani (�14.4.7). K�vetkez�sk�ppen n�melyik
oszt�lynak
sz�ks�ge van egy olyan f�ggv�nyre, amely biztosan megh�v�dik, amikor egy objektum
megsemmis�l, hasonl�an ahhoz, ahogy a konstruktor megh�v�s�ra is biztosan sor
ker�l,
amikor egy objektum l�trej�n: ezek a destruktor (megsemmis�to, destructor)
f�ggv�nyek.
Feladatuk �ltal�ban a rendbet�tel �s az eroforr�sok felszabad�t�sa. A destruktorok
automatikusan
megh�v�dnak, amikor egy automatikus v�ltoz�t tartalmaz� blokk lefut, egy
dinamikusan
l�trehozott objektumot t�r�lnek �s �gy tov�bb. Nagyon k�l�nleges esetben van csak
sz�ks�g arra, hogy a programoz� kifejezetten megh�vja a destruktort (�10.4.11).
A destruktor legjellemzobb feladata, hogy felszabad�tsa a konstruktorban lefoglalt
mem�-
riater�letet. Vegy�nk p�ld�ul egy valamilyen Name t�pus� elemek t�bl�zat�t
tartalmaz�
Table oszt�lyt. A konstruktornak le kell foglalnia az elemek t�rol�s�hoz sz�ks�ges
mem�-
ri�t. Ha a Table objektum b�rmilyen m�don t�rlodik, a mem�ri�t fel kell
szabad�tani, hogy
m�shol fel lehessen majd haszn�lni. Ezt �gy �rhetj�k el, hogy meg�rjuk a
konstruktort kieg
�sz�to f�ggv�nyt:
class Name {
const char* s;
// ...
};
320 Absztrakci�s m�dszerek
class Table {
Name* p;
size_t sz;
public:
Table(size_t s = 15) { p = new Name[sz = s]; } // konstruktor
~Table() { delete[ ] p; } // destruktor
Name* lookup(const char *);
bool insert(Name*);
};
A destruktort jelento ~Table() jel�l�s a komplemensk�pz�st jel�lo ~ szimb�lumot
haszn�lva
utal a destruktornak a Table() konstruktorhoz val� viszony�ra. Az �sszetartoz�
konstruktor
.destruktor p�r meghat�roz�sa a C++-ban szok�sos elj�r�s v�ltoz� m�retu objektumok

megval�s�t�s�ra. A standard k�nyvt�r t�rol�i, p�ld�ul a map, ennek a m�dszernek


valamelyik v�ltozat�t haszn�lj�k, hogy az elemeik sz�m�ra t�rol�helyet
biztos�tsanak, ez�rt
a programoz� a k�vetkezokben le�rtakra t�maszkodik, amikor valamelyik standard
k�nyvt
�rbeli t�rol�t haszn�lja.(�gy viselkedik p�ld�ul a szabv�nyos string oszt�ly is.)
A le�rtak alkalmazhat
�ak a destruktor n�lk�li oszt�lyokra is. Ezekre �gy tekinthet�nk, mint amelyekn
�l egy olyan destruktorunk van, amely nem csin�l semmit.
10.4.2. Alap�rtelmezett konstruktorok
Hasonl�k�ppen a legt�bb t�pust �gy tekinthetj�k, mint amelynek van alap�rtelmezett

konstruktora. Az alap�rtelmezett konstruktor az, amelyiket param�ter n�lk�l


h�vhatjuk
meg. Minthogy a fenti p�ld�ban a 15 mint alap�rtelmezett �rt�k adott, a
Table::Table(size_t)
f�ggv�ny alap�rtelmezett konstruktor. Ha a programoz� megadott alap�rtelmezett
konstruktort, akkor a ford�t�program azt fogja haszn�lni, m�sk�l�nben sz�ks�g
eset�n
megpr�b�l l�trehozni egyet. A ford�t�program �ltal l�trehozott alap�rtelmezett
konstruktor
automatikusan megh�vja az oszt�ly t�pus� tagok �s a b�zisoszt�lyok (�12.2.2)
alap�rtelmezett
konstruktor�t:
struct Tables {
int i;
int vi[10];
Table t1;
Table vt[10];
};
Tables tt;
10. Oszt�lyok 321
Itt tt kezdo�rt�kkel val� felt�lt�se ford�t�s k�zben l�trehozott alap�rtelmezett
konstruktor
seg�ts�g�vel t�rt�nik, amely a Table(15)-�t h�vja meg tt.t1-re �s tt.vt minden
egyes elem�-
re. M�sr�szt tt.i �s tt.vi elemei nem kapnak kezdo�rt�ket, mert ezek az objektumok
nem
oszt�ly t�pus�ak. Az oszt�lyok �s a be�p�tett t�pusok egym�st�l elt�ro
kezel�sm�dj�nak a Cvel
val� egyeztet�s �s a fut�si ido n�vel�s�tol val� tart�zkod�s az oka.
Mivel a const-ok �s a referenci�k k�telezoen kezdo�rt�ket kell, hogy kapjanak
(�5.5, �5.4),
az ilyeneket tartalmaz� tagoknak nem lehet alap�rtelmezett konstruktora, hacsak a
programoz
� kifejezetten nem gondoskodik konstruktorr�l (�10.4.6.1):
struct X {
const int a;
const int& r;
};
X x; // hiba: nincs alap�rtelmezett konstruktor X sz�m�ra
Az alap�rtelmezett konstruktorok k�zvetlen m�don is h�vhat�k (�10.4.10). A
be�p�tett t�pusoknak
szint�n van alap�rtelmezett konstruktoruk (�6.2.8).
10.4.3. L�trehoz�s �s megsemmis�t�s
Tekints�k �t a k�l�nb�zo m�dokat: hogyan hozhatunk l�tre objektumot �s k�sobb az
hogyan
semmis�l meg. Objektum a k�vetkezo m�dokon hozhat� l�tre:
�10.4.4 N�vvel ell�tott automatikus objektumk�nt, amely akkor keletkezik, amikor
a program v�grehajt�sa sor�n deklar�ci�ja ki�rt�kelodik, �s akkor
semmis�l meg, amikor a program kil�p abb�l a blokkb�l, amelyen bel�l
a deklar�ci� szerepelt.
�10.4.5 Szabad t�rbeli objektumk�nt, amely a new oper�tor haszn�lat�val j�n l�tre
�s a delete oper�tor haszn�lat�val semmis�l meg.
�10.4.6 Nem statikus tagobjektumk�nt, amely egy m�sik oszt�ly objektum tagjak
�nt j�n l�tre �s azzal egy�tt keletkezik, illetve semmis�l meg.
�10.4.7 T�mbelemk�nt, amely akkor keletkezik �s semmis�l meg, amikor
a t�mb, melynek eleme.
�10.4.8 Lok�lis statikus objektumk�nt, amely akkor j�n l�tre, amikor a program
v�grehajt�sa sor�n elosz�r tal�lkozik a deklar�ci�j�val �s egyszer semmis
�l meg: a program befejez�sekor.
�10.4.9 Glob�lis, n�vt�rbeli vagy statikus oszt�ly-objektumk�nt, amely egyszer,
a program indul�sakor j�n l�tre �s a program befejez�sekor semmis�l meg.
322 Absztrakci�s m�dszerek
�10.4.10 Ideiglenes objektumk�nt, amely egy kifejez�s ki�rt�kel�sekor j�n l�tre �s

a teljes kifejez�s v�g�n, melyben elofordult, semmis�l meg.


�10.4.11 Felhaszn�l� �ltal �rt f�ggv�nnyel v�gzett, param�terekkel vez�relt
lefoglal
�si muvelet seg�ts�g�vel nyert, a mem�ri�ba helyezett objektumk�nt.
�10.4.12 Uni� tagjak�nt, amelynek nem lehet sem konstruktora, sem destruktora.
Ez a felsorol�s nagyj�b�l a fontoss�g sorrendj�ben k�sz�lt. A k�vetkezo
alpontokban r�szletesen
elmagyar�zzuk az objektumok l�trehoz�s�nak ezen v�ltozatait �s haszn�latukat.
10.4.4. Lok�lis v�ltoz�k
A lok�lis v�ltoz�k konstruktora minden alkalommal v�grehajt�dik, valah�nyszor a
vez�rl�s
fonala .kereszt�lhalad. a v�ltoz� deklar�ci�j�n, a destruktor v�grehajt�s�ra pedig
akkor ker
�l sor, amikor kil�p�nk a v�ltoz� blokkj�b�l. A lok�lis v�ltoz�k destruktorai
konstruktoraik
sorrendj�hez viszony�tva ford�tott sorrendben hajt�dnak v�gre:
void f(int i)
{
Table aa;
Table bb;
if (i>0) {
Table cc;
// ...
}
Table dd;
// ...
}
Itt aa, bb �s dd ebben a sorrendben keletkeznek az f() megh�v�sakor �s a dd, bb,
aa sorrendben
semmis�lnek meg, amikor a vez�rl�s kil�p az f()-bol. Ha egy h�v�sn�l i>0, a cc
a bb ut�n j�n l�tre, �s dd l�trej�tte elott semmis�l meg.
10.4.4.1. Objektumok m�sol�sa
Ha t1 �s t2 a Table oszt�lyba tartoz� objektumok, t2=t1 alap�rtelmez�s szerint t1-
nek tagonk
�nti �tm�sol�s�t jelenti t2-be (�10.2.5). Ha nem b�r�ljuk fel�l ezt az
alap�rtelmezett viselked
�st, meglepo (�s rendszerint nemk�v�natos) hat�s l�phet fel, ha olyan oszt�ly
objektumaira
alkalmazzuk, melynek mutat� tagjai vannak. A tagonk�nti m�sol�s rendszerint nem
megfelelo olyan objektumok sz�m�ra, amelyek egy konstruktor.destruktor p�r �ltal
kezelt
eroforr�sokat tartalmaznak:
10. Oszt�lyok 323
void h()
{
Table t1;
Table t2 = t1; // kezdeti �rt�kad�s m�sol�ssal: probl�m�s
Table t3;
t3 = t2; // �rt�kad�s m�sol�ssal: probl�m�s
}
Itt a Table alap�rtelmezett konstruktora k�tszer h�v�dik meg: egyszer t1-re �s
egyszer t3-ra.
A t2-re nem h�v�dik meg, mert ez a v�ltoz� a t1-bol val� m�sol�ssal kapott
kezdo�rt�ket.
A Table destruktor viszont h�romszor h�v�dik meg: t1-re, t2-re �s t3-ra is.
Alap�rtelmez�s szerint
az �rt�kad�s tagonk�nti m�sol�st jelent, �gy a h() f�ggv�ny v�g�n t1, t2 �s t3
mindegyike
arra a n�vt�mbre hivatkoz� mutat�t fogja tartalmazni, amely t1 l�trej�ttekor
kapott helyet
a szabad t�rban. A mutat�, mely a t3 l�trej�ttekor kijel�lt n�vt�mbre mutat, nem
marad meg,
mert a t3=t2 �rt�kad�s k�vetkezt�ben fel�l�r�dik, �gy az �ltala elfoglalt
t�rter�let a program
sz�m�ra �r�kre elv�sz, hacsak nincs automatikus szem�tgyujt�s (�10.4.5). M�sr�szt
a t1 r�sz�-
re l�trehozott t�mb t1-ben, t2-ben �s t3-ban egyar�nt megjelenik, teh�t h�romszor
is t�rlodik.
Ez nem meghat�rozott �s val�sz�nuleg katasztrof�lis eredm�nyhez vezet.
Az ilyen anom�li�k elker�lhetok, ha megadjuk, mit jelent egy Table objektum
m�sol�sa:
class Table {
// ...
Table(const Table&); // m�sol� konstruktor
Table& operator=(const Table&); // m�sol� �rt�kad�s
};
A programoz� b�rmilyen alkalmas jelent�st meghat�rozhat ezen m�sol� muveletek
sz�m�-
ra, de az ilyen t�pus� t�rol�k eset�ben a m�sol� muvelet hagyom�nyos feladata az,
hogy lem
�solja a tartalmazott elemeket (vagy legal�bbis a felhaszn�l� sz�m�ra �gy tesz,
mintha ez
a m�sol�s megt�rt�nt volna, l�sd �11.12):
Table::Table(const Table& t) // m�sol� konstruktor
{
p = new Name[sz=t.sz];
for (int i = 0; i<sz; i++) p[i] = t.p[i];
}
Table& Table::operator=(const Table& t) // �rt�kad�s
{
if (this != &t) { // �vakodjunk az �n-�rt�kad�st�l: t = t
delete[ ] p;
324 Absztrakci�s m�dszerek
p = new Name[sz=t.sz];
for (int i = 0; i<sz; i++) p[i] = t.p[i];
}
return *this;
}
Mint majdnem mindig, a m�sol� konstruktor �s az �rt�kad� muvelet itt is jelentosen
elt�r.
Ennek alapveto oka az, hogy a m�sol� konstruktor le nem foglalt mem�ri�t k�sz�t
fel a felhaszn
�l�sra, m�g az �rt�kad� muveletnek egy m�r l�trehozott objektumot kell helyesen
kezelnie.
Az �rt�kad�st bizonyos esetekben optimaliz�lni lehet, de az �rt�kad� oper�tor
�ltal�nos
c�lja egyszeru: v�dekezni kell a saj�t mag�val val� �rt�kad�s ellen, t�r�lni kell
a r�gi elemeket,
elok�sz�teni �s bem�solni az �j elemeket. �ltal�ban minden nem statikus tagot m�-
solni kell (�10.4.6.3.)
10.4.5. A szabad t�r
A dinamikusan kezelt mem�riater�leten, a szabad t�rban l�trehozott objektumok
konstruktor
�t a new oper�tor h�vja meg, �s ezek az objektumok addig l�teznek, am�g a r�juk
hivatkoz� mutat�ra nem alkalmazzuk a delete oper�tort:
int main()
{
Table* p = new Table;
Table* q = new Table;
delete p;
delete p; // val�sz�nuleg fut�si ideju hib�t okoz
}
A Table::Table() konstruktort k�tszer h�vjuk meg, csak�gy, mint a Table::~Table()
destruktort. Sajnos azonban ebben a p�ld�ban a new-k �s delete-ek nem felelnek meg
egym
�snak: a p �ltal hivatkozott objektumot k�tszer t�r�lt�k, m�g a q �ltal mutatottat
egyszer
sem. Nyelvi szempontb�l egy objektum nem t�rl�se nem hiba, mind�ssze a mem�ria
pazarl
�sa, mindazon�ltal egy hosszan fut� programn�l az ilyen .mem�riasziv�rg�s. vagy
.mem
�rialyuk. (memory leak) s�lyos �s nehezen felder�theto hiba. Szerencs�re l�teznek
az
ilyesfajta mem�riasziv�rg�st kereso eszk�z�k is. A p �ltal mutatott objektum
k�tszeri t�rl�-
se s�lyos hiba; a program viselked�se nem meghat�rozott �s nagy val�sz�nus�ggel
katasztrof
�lis lesz.
10. Oszt�lyok 325
Bizonyos C++-v�ltozatok automatikusan �jrahasznos�tj�k az el�rhetetlen objektumok
�ltal
elfoglalt mem�ri�t (ezek a szem�tgyujt�st alkalmaz� megval�s�t�sok), de
viselked�s�k nem
szabv�nyos�tott. Ha van is szem�tgyujt�s, a delete oper�tor k�tszeri megh�v�sa
egyben
a destruktor (ha van ilyen) k�tszeri megh�v�s�t fogja eredm�nyezi, �gy az objektum
k�tszer
t�rlodik, ami ilyenkor is s�lyos hiba. A legt�bb esetben az objektumok ezen
viselked�se
csak apr�bb k�nyelmetlens�get jelent. Jeles�l, ahol van szem�tgyujt�s, ott is a
csak mem�-
ria-felszabad�t�st v�gzo destruktorokat lehet megtakar�tani. Ennek az
egyszerus�t�snek
a hordozhat�s�g elveszt�se az �ra, sot bizonyos programokn�l a fut�si ido
n�veked�se �s
a viselked�s megj�solhatatlans�ga is (�C.9.1).
Miut�n egy objektumot a delete muvelettel t�r�lt�nk, b�rmilyen hozz�f�r�si
k�s�rlet az objektumhoz
hib�nak sz�m�t. Sajnos az egyes nyelvi v�ltozatok nem k�pesek megb�zhat� m�-
don jelezni az ilyen hib�kat.
A programoz� megszabhatja, hogyan t�rt�nj�k a new haszn�lata eset�n a mem�ria
lefoglal
�sa, illetve annak a delete-tel val� felszabad�t�sa (�6.2.6.2 �s �15.6).
Lehets�ges a lefoglal�s,
a konstruktorok �s a kiv�telek egy�ttmuk�d�s�nek a megad�sa is (�14.4.5 �s
19.4.5). A szabad
t�rban levo t�mb�ket a �10.4.7. t�rgyalja.
10.4.6. Oszt�ly t�pus� tagok
N�zz�nk egy oszt�lyt, amely egy kisebb c�grol t�rolhat adatokat:
class Club {
string name;
Table members;
Table officers;
Date founded;
// ...
Club(const string& n, Date fd);
};
A Club oszt�ly konstruktor�n�l param�terk�nt meg kell adni a nevet �s az alap�t�s
d�tum�t.
Az oszt�lytagok konstruktorainak param�tereit a tartalmaz� oszt�ly
konstruktordefinici
�j�nak tag-kezdo�rt�k list�j�ban (member initializer) adjuk meg:
Club::Club(const string& n, Date fd)
: name(n), members(), officers(), founded(fd)
{
// ...
}
326 Absztrakci�s m�dszerek
A tagok kezdo�rt�k-list�j�t kettospont elozi meg �s az egyes tagoknak kezdo�rt�ket
ad� kifejez
�seket vesszok v�lasztj�k el.
A tagok konstruktorainak v�grehajt�sa megelozi a tartalmaz� oszt�ly saj�t
konstruktora
t�rzs�nek v�grehajt�s�t. A konstruktorok a tagoknak az oszt�ly deklar�ci�j�ban
elfoglalt
sorrendj�ben �s nem a kezdo�rt�ket ad� kifejez�seknek a list�ban val� felsorol�si
sorrendj
�ben hajt�dnak v�gre. Az esetleges zavarok elker�l�se �rdek�ben nyilv�n c�lszeru a
tagokat
a deklar�ci�ban elfoglalt sorrendj�kben felvenni a kezdo�rt�k-ad� kifejez�sek
list�j�ra.
A tagok destruktorai a konstruktorok sorrendj�vel ellenkezo sorrendben h�v�dnak
meg.
Ha egy tag konstruktor�nak nincs sz�ks�ge param�terre, nem sz�ks�ges felvenni a
list�ra,
�gy a k�vetkezo k�dr�szlet egyen�rt�ku az elozo p�ldabelivel:
Club::Club(const string& n, Date fd)
: name(n), founded(fd)
{
// ...
}
A Table::Table konstruktor a Club::officers tagot mindk�t esetben a 15-tel, mint
alap�rtelmezett
param�terrel hozza l�tre.
Ha egy oszt�lynak oszt�ly t�pus� tagjai vannak, az oszt�ly megsemmis�t�sekor
elosz�r saj�t
destruktor f�ggv�ny�nek (ha van ilyen) t�rzse h�v�dik meg, majd a tagok
destruktorai
a deklar�ci�val ellent�tes sorrendben. A konstruktor alulr�l felfel� haladva (a
tagokat elo-
sz�r) �p�ti fel a tagf�ggv�nyek v�grehajt�si k�rnyezet�t, a destruktor pedig
fel�lrol lefel�
(a tagokat utolj�ra) bontja le azt.
10.4.6.1. A tagok sz�ks�gszeru kezdeti �rt�kad�sa
Azon tagok felt�lt�se kezdo�rt�kkel sz�ks�gszeru, amelyekn�l a kezdeti �rt�kad�s
k�l�nb
�zik az egyszeru �rt�kad�st�l . azaz az alap�rtelmezett konstruktor n�lk�li
oszt�lyba tartoz
�, a const �s a referencia t�pus� tagok�:
class X {
const int i;
Club c;
Club& pc;
// ...
X(int ii, const string& n, Date d, Club& c) : i(ii), c(n,d), pc(c) { }
};
10. Oszt�lyok 327
Ezen tagok kezdeti �rt�kad�s�ra nincs egy�b lehetos�g, �s hiba azt nem megtenni
is. A legt
�bb t�pus eset�ben azonban a programoz� v�laszthat a kezdeti �s a .sima. �rt�kad�s
k�-
z�l. Ilyenkor �n �ltal�ban a tag-kezdo�rt�k list�s megold�st v�lasztom, hogy
egy�rtelmu legyen
a kezdeti �rt�kad�s t�nye. Ez a m�dszer r�ad�sul hat�konyabb is:
class Person {
string name;
string address;
// ...
Person(const Person&);
Person(const string& n, const string& a);
};
Person::Person(const string& n, const string& a)
: name(n)
{
address = a;
}
Itt a name az n egy m�solat�val kap kezdo�rt�ket. M�sfelol az address elosz�r egy
�res karakterl
�nccal t�ltodik fel, majd �rt�k�l az a egy m�solat�t kapja.
10.4.6.2. Konstans tagok
Egy statikus, eg�sz t�pus� konstans tagot lehets�ges a deklar�ci�ban egy
kezdo�rt�k-ad�
konstans kifejez�ssel is felt�lteni:
class Curious {
public:
static const int c1 = 7; // rendben, de ne felejts�k el a meghat�roz�st
static int c2 = 11; // hiba: nem �lland�
const int c3 = 13; // hiba: nem statikus
static const int c4 = f(17); // hiba: a kezdo�rt�k-ad� nem �lland�
static const float c5 = 7.0; // hiba: a kezdo�rt�k-ad� nem eg�sz �rt�ku
// ...
};
Akkor �s csak akkor, ha a kezdo�rt�ket kapott tagot mem�ri�ban t�rolt objektumk�nt
haszn
�ljuk, sz�ks�ges, hogy az ilyen tag (de csak egy helyen) defini�lt legyen, de ott
nem szabad
megism�telni a kezdo�rt�k-ad� kifejez�st:
const int Curious::c1; // sz�ks�ges, de a kezdo�rt�k-ad� nem szerepelhet itt m�g
egyszer
const int* p = &Curious::c1; // rendben: Curious::c1 meghat�rozott
328 Absztrakci�s m�dszerek
M�sik megold�sk�nt, jelk�pes �lland�k�nt haszn�lhatunk felsorol� konstanst (�4.8,
�14.4.6,
�15.3) is az oszt�ly deklar�ci�j�n bel�l, ha sz�ks�ges:
class X {
enum { c1 = 7, c2 = 11, c3 = 13, c4 = 17 };
// ...
};
�gy a programoz� nem fog k�s�rt�sbe esni, hogy az oszt�lyban v�ltoz�knak,
lebegopontos
sz�moknak stb. adjon kezdo�rt�ket.
10.4.6.3. Tagok m�sol�sa
Az alap�rtelmezett m�sol� konstruktor �s az alap�rtelmezett m�sol� �rt�kad�s
(�10.4.4.1)
az oszt�ly �sszes tagj�t m�solja. Ha ez nem lehets�ges, az ilyen oszt�ly� objektum
m�sol�-
si k�s�rlete hiba:
class Unique_handle {
private: // a m�sol� muveleteket priv�tt� tessz�k, megelozendo az
// alap�rtelmezett m�sol�st (�11.2.2)
Unique_handle(const Unique_handle&);
Unique_handle& operator=(const Unique_handle&);
public:
// ...
};
struct Y {
// ...
Unique_handle a; // explicit kezdo�rt�ket ig�nyel
};
Y y1;
Y y2 = y1; // hiba: Y::a nem m�solhat�
Ezenk�v�l az alap�rtelmezett �rt�kad�s nem j�het l�tre a ford�t�skor, ha az
oszt�ly egy nem
statikus tagja: referencia, konstans, vagy olyan felhaszn�l�i t�pus melynek
nincsen m�sol�
�rt�kad�sa.
10. Oszt�lyok 329
Jegyezz�k meg, hogy a referencia t�pus� tagok ugyanarra az objektumra hivatkoznak
az eredeti
objektumban �s a m�solatban is. Ez gond lehet, ha a hivatkozott objektumot t�r�lni
kell.
Ha m�sol� konstruktort �runk, �gyelj�nk arra, hogy minden tagot m�soljunk, amelyet
sz�ks
�ges. Alap�rtelmez�s szerint az elemek alap�rtelmezett m�don kapnak kezdo�rt�ket,
de
sokszor nem erre van sz�ks�g egy m�sol� konstruktorban:
Person::Person(const Person& a) : name(a.name) { } // vigy�zat!
Itt elfelejtettem az address tagot m�solni, �gy az alap�rtelmez�s szerinti �res
karakterl�ncot
kapja kezdo�rt�kk�nt. Ha �j taggal bov�t�nk egy oszt�lyt, ne felejts�k el
ellenorizni, hogy
vannak-e olyan felhaszn�l� �ltal megadott konstruktorok, amelyeket az �j tagok
kezdeti �rt
�kad�s�ra �s m�sol�s�ra val� tekintettel meg kell v�ltoztatni.
10.4.7. T�mb�k
Ha egy oszt�ly egy tagj�nak van alap�rtelmezett, azaz param�ter n�lk�l h�vhat�
konstruktora,
akkor ilyen oszt�ly� objektumok t�mbj�t is meghat�rozhatjuk:
Table tbl[10];
A fenti egy 10 Table elembol �ll� t�mb�t hoz l�tre �s minden elemet a
Table::Table()
konstruktorral, a 15 �rt�ku alap�rtelmezett param�terrel t�lt fel.
A kezdo�rt�k-lista (�5.2.1, �18.6.7) alkalmaz�s�n k�v�l nincs m�s m�d egy t�mb
elemeinek
konstruktorai sz�m�ra (nem alap�rtelmezett) param�tereket megadni. Ha felt�tlen�l
sz�ks
�ges, hogy egy t�mb tagjai k�l�nb�zo kezdo�rt�ket kapjanak, �rjunk olyan
alap�rtelmezett
konstruktort, amely elo�ll�tja a k�v�nt �rt�keket:
class Ibuffer {
string buf;
public:
Ibuffer() { cin>>buf; }
// ...
};
void f()
{
Ibuffer words[100]; // minden elem a cin-rol kap kezdo�rt�ket
// ...
}
Az ilyen tr�kk�ket azonban �ltal�ban jobb elker�lni.
330 Absztrakci�s m�dszerek
Amikor egy t�mb megsemmis�l, az �sszes elem�re megh�v�dik a destruktor. Ha nem new

muvelettel l�trehozott t�mbrol van sz�, akkor ez automatikusan t�rt�nik. A C


nyelvhez hasonl
�an a C++ sem k�l�nb�zteti meg az egyedi elemre �s a t�mb kezdoelem�re hivatkoz�
mutat�t (�5.3), ez�rt a programoz�nak meg kell adnia, hogy egyedi elemet vagy
t�mb�t
kell-e t�r�lni:
void f(int sz)
{
Table* t1 = new Table;
Table* t2 = new Table[sz];
Table* t3 = new Table;
Table* t4 = new Table[sz];
delete t1; // helyes
delete[ ] t2; // helyes
delete[ ] t3; // helytelen; probl�ma
delete t4; // helytelen; probl�ma
}
A t�mb�k �s egyedi elemek dinamikus t�rter�leten val� elhelyez�se az adott nyelvi
v�ltozatt
�l f�gg. Ez�rt a k�l�nb�zo v�ltozatok k�l�nb�zok�ppen fognak viselkedni, ha
hib�san
haszn�ljuk a delete �s delete[ ] oper�torokat. Egyszeru �s �rdektelen esetekben,
mint az elo-
zo p�lda, a ford�t� �szreveheti a hib�t, de �ltal�ban futtat�skor fog valami
cs�nya dolog
t�rt�nni.
A kifejezetten t�mb�k t�rl�s�re szolg�l� delete[ ] logikailag nem sz�ks�ges.
Elk�pzelheto
lenne, hogy a szabad t�rt�l megk�vetelj�k, hogy minden objektumr�l tartsa nyilv�n,
hogy
egyedi objektum avagy t�mb. Ekkor a nyilv�ntart�s terh�t levenn�nk a programoz�
v�ll�-
r�l, de ez a k�telezetts�g egyes C++-v�ltozatokban jelentos mem�ria- �s fut�si
ido-t�bbletet
jelentene. Ha az olvas� t�l neh�zkesnek tal�lja a C st�lus� t�mb�k haszn�lat�t,
itt is haszn
�lhat helyett�k olyan oszt�lyokat, mint a vector (�3.7.1, �16.3):
void g()
{
vector<Table>* p1 = new vector<Table>(10);
Table* p2 = new Table;
delete p1;
delete p2;
}
10. Oszt�lyok 331
10.4.8. Lok�lis statikus adatok
A lok�lis statikus objektumok (�7.1.2) konstruktora akkor hajt�dik v�gre, amikor a
v�grehajt
�si sz�l elosz�r halad kereszt�l az objektum meghat�roz�s�n:
void f(int i)
{
static Table tbl;
// ...
if (i) {
static Table tbl2;
// ...
}
}
int main()
{
f(0);
f(1);
f(2);
// ...
}
Itt tbl konstruktora f() elso megh�v�sakor h�v�dik meg. Mivel tbl-t statikusk�nt
adtuk meg,
�gy nem semmis�l meg, amikor f()-bol visszat�r a vez�rl�s �s nem j�n �jra l�tre
f() m�sodik
megh�v�sakor. Mivel a tbl2 v�ltoz� deklar�ci�j�t tartalmaz� blokk nem hajt�dik
v�gre
az f(0) megh�v�skor, tbl2 is csak f(1) v�grehajt�sakor j�n l�tre, a blokk �jb�li
v�grehajt�sakor
nem.
A lok�lis statikus objektumok destruktorai akkor h�v�dnak meg, amikor a program
le�ll
(�9.4.1.1). Hogy pontosan mikor, az nincs meghat�rozva.
10.4.9. Nem lok�lis adatok
A f�ggv�nyeken k�v�l meghat�rozott (azaz glob�lis, n�vt�rbeli �s oszt�lyhoz
tartoz� statikus)
v�ltoz�k a main() f�ggv�ny megh�v�sa elott j�nnek l�tre (�s kapnak kezdo�rt�ket),
�s
minden l�trehozott objektum destruktora a main() f�ggv�nybol val� kil�p�s ut�n
v�gre fog
hajt�dni. A dinamikus k�nyvt�rak haszn�lata (dinamikus csatol�s) kiss�
bonyolultabb� teszi
ezt, hiszen ilyenkor a kezdeti �rt�kad�sra akkor ker�l sor, amikor a dinamikus k�d
a fut
� programhoz kapcsol�dik.
332 Absztrakci�s m�dszerek
A ford�t�si egys�geken bel�l a nem lok�lis objektumok konstruktorainak
v�grehajt�sa
a definici�juk sorrendj�ben t�rt�nik:
class X {
// ...
static Table memtbl;
};
Table tbl;
Table X::memtbl;
namespace Z {
Table tbl2;
}
A konstruktorok v�grehajt�si sorrendje a k�vetkezo: tbl, X::memtbl, Z::tbl2.
Vegy�k �szre,
hogy a defin�ci� �s nem a deklar�ci� sorrendje sz�m�t. A destruktorok a
konstruktorokkal
ellent�tes sorrendben hajt�dnak v�gre: Z::tbl2, X::memtbl, tbl.
Nincs nyelvi v�ltozatt�l f�ggetlen meghat�roz�sa annak, hogy az egyes ford�t�si
egys�gek
nem lok�lis objektumai milyen sorrendben j�nnek l�tre:
// file1.c:
Table tbl1;
// file2.c:
Table tbl2;
Az, hogy tbl1 vagy tbl2 fog elobb l�trej�nni, a C++ adott v�ltozat�t�l f�gg, de a
sorrend
azon bel�l is v�ltozhat. Dinamikus csatol�s haszn�lata vagy ak�r a ford�t�si
folyamat kis
m�dos�t�sa is megv�ltoztathatja a sorrendet. A destruktorok v�grehajt�si sorrendje
is hasonl
�an v�ltozatf�ggo.
K�nyvt�rak tervez�sekor sz�ks�ges vagy egyszeruen k�nyelmes lehet egy olyan,
konstruktorral �s destruktorral b�r� t�pus elk�sz�t�se, amely kiz�r�lag a kezdeti
�rt�kad�s �s
rendrak�s c�lj�t szolg�lja. Ilyen t�pus� adatot csak arra c�lra fogunk haszn�lni,
hogy egy statikus
objektum sz�m�ra mem�riater�letet foglaljunk le az�rt, hogy lefusson a
konstruktora
�s a destruktora:
class Zlib_init {
Zlib_init(); // Zlib elok�sz�t�se haszn�latra
~Zlib_init(); // Zlib ut�ni takar�t�s
};
10. Oszt�lyok 333
class Zlib {
static Zlib_init x;
// ...
};
Sajnos egy t�bb ford�t�si egys�gbol �ll� program eset�ben nincs garancia arra,
hogy egy
ilyen objektum kezdeti �rt�kad�sa az elso haszn�lat elott megt�rt�nik �s a
destruktor az
utols� haszn�lat ut�n fut le. Egyes C++-v�ltozatok biztos�thatj�k ezt, de a
legt�bb nem.
Programoz�i szinten azonban lehets�ges azt a megold�st alkalmazni, amit a nyelvi
v�ltozatok
�ltal�ban a lok�lis statikus objektumokra alkalmaznak: egy-egy, az elso
haszn�latot figyel
o kapcsol�t:
class Zlib {
static bool initialized;
static void initialize() { /* kezdeti �rt�kad�s */ initialized = true; }
public:
// nincs konstruktor
void f()
{
if (initialized == false) initialize();
// ...
}
// ...
};
Ha sok f�ggv�nyben kell lek�rdezni az elso haszn�latot figyelo kapcsol�t, az
f�raszt� feladat
lehet, de megoldhat�. Ez a m�dszer azon alapul, hogy a konstruktor n�lk�li
statikus
objektumok 0 kezdo�rt�ket kapnak. A dolog akkor v�lik igaz�n problematikuss�, ha
az objektum
elso haszn�lata egy v�grehajt�si idore �rz�keny f�ggv�nyben t�rt�nik, ahol az
ellen-
orz�s �s sz�ks�g eset�n a kezdeti �rt�kad�s t�l sok idot vehet ig�nybe. Ilyenkor
tov�bbi
tr�kk�kre van sz�ks�g (�21.5.2).
Egy lehets�ges m�sik megk�zel�t�s, hogy az egyes objektumokat f�ggv�nyekkel
helyettes
�tj�k (�9.4.1):
int& obj() { static int x = 0; return x; } // kezdeti �rt�kad�s elso haszn�latkor
Az elso haszn�latot figyelo kapcsol�k nem kezelnek minden elk�pzelheto helyzetet.
Lehets
�ges p�ld�ul olyan objektumokat megadni, amelyek a kezdeti �rt�kad�s alatt
egym�sra hivatkoznak
. az ilyesmit jobb elker�lni. Ha m�gis ilyen objektumokra van sz�ks�g, akkor
�vatosan, fokozatosan kell l�trehozni azokat. Egy m�sik probl�ma, hogy az utols�
haszn�-
latot nem tudjuk egy jelzovel jelezni. Ehelyett l�sd �9.4.1.1 �s �21.5.2.
334 Absztrakci�s m�dszerek
10.4.10. Ideiglenes objektumok
Ideiglenes objektumok legt�bbsz�r aritmetikai kifejez�sekbol j�nnek l�tre. P�ld�ul
az
x*y+z kifejez�s ki�rt�kel�se sor�n egy ponton az x*y r�szeredm�nyt valahol t�rolni
kell.
Hacsak nem a program gyors�t�s�n dolgozik (�11.6), a programoz� ritk�n kell, hogy
az ideiglenes
objektumokkal t�rodj�k, hab�r ez is elofordul (�11.6, �22.4.7).
Egy ideiglenes objektum, hacsak nincs referenci�hoz k�tve vagy nem egy neves�tett
objektumnak
ad kezdo�rt�ket, t�rlodik a tartalmaz� teljes kifejez�s ki�rt�kel�se v�g�n. A
teljes
kifejez�s olyan kifejez�s, amely nem r�szkifejez�se m�s kifejez�snek.
A szabv�nyos string oszt�ly c_str() nevu tagf�ggv�nye egy C st�lus�,
nullkarakterrel lez�rt
karaktert�mb�t ad vissza (�3.5.1, �20.4.1). A + oper�tor karakterl�ncok eset�ben
�sszefuz�st
jel�l. Ezek nagyon hasznos dolgok a karakterl�ncok kezel�sekor, de egy�ttes
haszn�latuk
furcsa probl�m�khoz vezethet:
void f(string& s1, string& s2, string& s3)
{
const char* cs = (s1+s2).c_str();
cout << cs;
if (strlen(cs=(s2+s3).c_str())<8 && cs[0]=='a') {
// cs haszn�lata
}
}
Az olvas� val�sz�nuleg azt mondja erre, hogy .nem kell ilyet csin�lni., �s
egyet�rtek vele,
de ilyen k�dot szoktak �rni, �gy �rdemes tudni, hogyan kell azt �rtelmezni.
Elosz�r egy ideiglenes, string oszt�ly� objektum j�n l�tre, amely az s1+s2 muvelet
eredm�-
ny�t t�rolja. Ettol az objektumt�l azt�n elk�rj�k a C st�lus� karaktert�mb�t, majd
a kifejez�s
v�g�n az ideiglenes objektum t�rlodik. Vajon hol foglalt helyet a ford�t� a C
st�lus� karaktert
�mb sz�m�ra? Val�sz�nuleg az s1+s2-t tartalmaz� ideiglenes objektumban, �s annak
megsemmis�l�se ut�n nem biztos, hogy nem semmis�l meg az a ter�let is,
k�vetkez�sk�ppen
cs felszabad�tott mem�riater�letre mutat. A cout << cs kimeneti muvelet muk�dhet
a v�rt m�don, de ez puszta szerencse k�rd�se. A ford�t�program esetleg
felder�theti az ilyen
probl�m�t �s figyelmeztethet r�.
Az if utas�t�sos p�lda egy kicsit ravaszabb. Maga a felt�tel a v�rakoz�snak
megfeleloen fog
muk�dni, mert a teljes kifejez�s, amelyben az s2+s3-at tartalmaz� ideiglenes
objektum l�trej
�n, maga az if felt�tele. Mindazon�ltal az ideiglenes objektum a felt�telesen
v�grehajtand
� utas�t�s v�grehajt�s�nak megkezd�se elott megsemmis�l, �gy a cs v�ltoz�
b�rmif�le ottani
haszn�lata nem biztos, hogy muk�dik.
10. Oszt�lyok 335
Vegy�k �szre, hogy ebben az esetben, mint sok m�s esetben is, az ideiglenes
objektumokkal
kapcsolatos probl�ma abb�l ad�dik, hogy egy magasabb szintu adatot alacsony
szinten
haszn�ltunk. Egy tiszt�bb programoz�si st�lus nem csak jobban olvashat�
programr�szletet
eredm�nyezett volna, de az ideiglenes objektumokkal kapcsolatos probl�m�kat is
teljesen
elker�lte volna:
void f(string& s1, string& s2, string& s3)
{
cout << s1+s2;
string s = s2+s3;
if (s.length()<8 && s[0]=='a') {
// s haszn�lata
}
}
Ideiglenes v�ltoz�t haszn�lhatunk konstans referencia vagy neves�tett objektum
kezdo�rt�-
kek�nt is:
void g(const string&, const string&);
void h(string& s1, string& s2)
{
const string& s = s1+s2;
string ss = s1+s2;
g(s,ss); // s �s ss itt haszn�lhat�
}
Ez a k�dr�szlet j�l muk�dik. Az ideiglenes v�ltoz� megsemmis�l, amikor az .o.
hivatkoz�-
s�t vagy neves�tett objektum�t tartalmaz� k�dblokk lefut. Eml�kezz�nk arra, hogy
hiba egy
lok�lis v�ltoz�ra mutat� referenci�t visszaadni egy f�ggv�nybol (�7.3) �s hogy
ideiglenes
objektumot nem adhatunk egy nem konstans referencia kezdo�rt�k��l (�5.5).
Ideiglenes
v�ltoz�t l�trehozhatunk kifejezett konstruktorh�v�ssal is:
void f(Shape& s, int x, int y)
{
s.move(Point(x,y)); // Point l�trehoz�sa a Shape::move() sz�m�ra
// ...
}
Az ilyen m�don l�trehozott ideiglenes v�ltoz�k is ugyanolyan szab�lyok szerint
semmis�lnek
meg, mint az automatikusan l�trehozottak.
336 Absztrakci�s m�dszerek
10.4.11. Az objektumok elhelyez�se
A new oper�tor alap�rtelmez�s szerint a szabad t�rban hozza l�tre az objektumokat.
Mit tegy
�nk, ha m�shol szeretn�nk, hogy egy objektum l�trej�jj�n? Vegy�nk p�ldak�nt egy
egyszer
u oszt�lyt:
class X {
public:
X(int);
// ...
};
Az objektumokat tetsz�s szerinti helyre tehetj�k, ha megadunk egy mem�ria-
lefoglal� f�ggv
�nyt, amelynek tov�bbi param�terei vannak, �s a new oper�tor haszn�latakor
megadjuk
ezeket a param�tereket:
void* operator new(size_t, void* p) { return p; } // explicit elhelyezo oper�tor
void* buf = reinterpret_cast<void*>(0xF00F); // fontos c�m
X* p2 = new(buf)X; // X l�trehoz�sa a 'buf-ban', az operator
// new(sizeof(X),buf) megh�v�s�val
Ezen haszn�lat miatt a new (buf) X utas�t�sforma, amely az operator new-nak
tov�bbi param
�tereket ad, elhelyezo utas�t�sk�nt (placement syntax) ismert. Jegyezz�k meg, hogy

minden new oper�tor a m�retet v�rja elso param�terk�nt, �s ezt, mint a


l�trehozand� objektum
m�ret�t, automatikusan megkapja (�15.6). Hogy melyik oper�tort fogja egy adott h�-

v�s el�rni, azt a szok�sos param�ter-egyeztet�si szab�lyok fogj�k eld�nteni


(�7.4); minden
new() oper�tornak egy size_t t�pus� elso param�tere van.
Az .elhelyezo. operator new() a legegyszerubb ilyen lefoglal� f�ggv�ny, �s
definici�ja
a <new> szabv�nyos fej�llom�nyban szerepel.
A reinterpret_cast a .legdurv�bb. �s a legnagyobb k�rokoz�sra k�pes a
t�puskonverzi�s
oper�torok k�z�l (�6.2.7). Legt�bbsz�r egyszeruen a param�ter�nek megfelelo
bitsorozat�
�rt�ket, mint a k�v�nt t�pust adja vissza, �gy azt�n a l�nyeg�bol fakad�an nyelvi
v�ltozatt�l
f�ggo, vesz�lyes �s esetenk�nt felt�tlen�l sz�ks�ges eg�szek �s mutat�k k�z�tti
�talak�t�sra
haszn�lhat�.
Az elhelyezo new oper�tor felhaszn�lhat� arra is, hogy egy bizonyos helyrol (Arena
objektumt
�l) foglaljunk mem�ri�t:
10. Oszt�lyok 337
class Arena {
public:
virtual void* alloc(size_t) =0;
virtual void free(void*) =0;
// ...
};
void* operator new(size_t sz, Arena* a)
{
return a->alloc(sz);
}
A k�l�nb�zo Arena objektumokban sz�ks�g szerint tetszoleges t�pus� objektumokat
hozhatunk
l�tre:
extern Arena* Persistent;
extern Arena* Shared;
void g(int i)
{
X* p = new(Persistent) X(i); // X �lland� t�rter�leten
X* q = new(Shared) X(i); // X megosztott mem�ri�ban
// ...
}
Ha egy objektumot olyan helyre helyez�nk, amelyet nem (k�zvetlen�l) a szabv�nyos
szabadt
�r-kezelo kezel, n�mi �vatoss�gra van sz�ks�g annak megsemmis�t�sekor. Ennek
alapvet
o m�dja az, hogy k�zvetlen�l megh�vjuk a destruktort:
void destroy(X* p, Arena* a)
{
p->~X(); // destruktor megh�v�sa
a->free(p); // mem�ria felszabad�t�sa
}
Jegyezz�k meg, hogy a destruktorok k�zvetlen megh�v�s�t . csak�gy, mint az egyedi
ig�-
nyeket kiel�g�to glob�lis mem�ria-lefoglal�k . haszn�lat�t ink�bb ker�lj�k el, ha
lehet. Esetenk
�nt m�gis alapveto sz�ks�g�nk van r�juk: p�ld�ul neh�z lenne egy hat�konyan muk�-
do �ltal�nos t�rol�oszt�lyt k�sz�teni a standard k�nyvt�r vector (�3.7.1, �16.3.8)
t�pusa nyom
�n, k�zvetlen destruktorh�v�s n�lk�l. Mindazon�ltal egy kezdo C++-programoz�
ink�bb
h�romszor gondolja meg, mielott k�zvetlen�l
338 Absztrakci�s m�dszerek
megh�vna egy destruktort �s akkor is ink�bb k�rje elotte tapasztalt koll�g�j�nak
tan�cs�t.
Az elhelyezo oper�tor �s a kiv�telkezel�s kapcsolat�r�l l�sd a �14.4.4-es pontot.
A t�mb�kn�l nincs megfeleloje az elhelyezo oper�tornak, de nincs is sz�ks�g r�,
mert az
elhelyezo oper�tort tetszoleges t�pusokra alkalmazhatjuk. T�mb�kre vonatkoz�an
azonban
megadhatunk p�ld�ul egyedi operator delete()-et (�19.4.5).
10.4.12. Uni�k
Egy neves�tett uni� (union) olyan adatszerkezet (struct), amelyben minden tag c�me
azonos
(l�sd �C.8.2). Egy uni�nak lehetnek tagf�ggv�nyei, de nem lehetnek statikus
tagjai.
A ford�t�program �ltal�ban nem tudhatja, hogy az uni� melyik tagja van
haszn�latban, vagyis
nem ismert, hogy milyen t�pus� objektum van az uni�ban. Ez�rt egy uni�nak nem
lehet
olyan tagja, amelynek konstruktorral vagy destruktorral rendelkezik, mert akkor
nem
lehetne a helyes mem�riakezel�st biztos�tani, illetve azt, hogy az uni�
megsemmis�l�s�vel
a megfelelo destruktor h�v�dik meg.
Az uni�k felhaszn�l�sa legink�bb alacsony szinten vagy olyan oszt�lyok belsej�ben
t�rt�-
nik, amelyek nyilv�ntartj�k, hogy mi van az uni�ban (�10.6[20]).
10.5. Tan�csok
[1] A fogalmakat oszt�lyokra k�pezz�k le. �10.1.
[2] Csak akkor haszn�ljunk nyilv�nos adatokat (struct-okat), amikor t�nyleg csak
adatok vannak �s nincs r�juk n�zve invari�nst ig�nylo felt�tel. �10.2.8.
[3] A konkr�t t�pusok a legegyszerubb oszt�lyok. Hacsak lehet, haszn�ljunk ink�bb
konkr�t t�pust, mint bonyolultabb oszt�lyokat vagy egyszeru adatszerkezeteket.
�10.3.
[4] Egy f�ggv�ny csak akkor legyen tagf�ggv�ny, ha k�zvetlen�l kell hozz�f�rnie
az oszt�ly �br�zol�s�hoz. �10.3.2.
[5] Haszn�ljunk n�vteret arra, hogy nyilv�nval�v� tegy�k egy oszt�lynak �s seg�df
�ggv�nyeinek �sszetartoz�s�t. �10.3.2.
[6] Egy tagf�ggv�ny, ha nem v�ltozatja meg az objektum�nak az �rt�k�t, legyen
const tagf�ggv�ny. �10.2.6.
[7] Egy f�ggv�ny, amelynek hozz� kell f�rnie az oszt�ly �br�zol�s�hoz, de nem
10. Oszt�lyok 339
sz�ks�ges, hogy egy objektumon kereszt�l h�vjuk meg, legyen statikus tagf�ggv
�ny. �10.2.4.
[8] Az oszt�lyra �llapotbiztos�t�it (invari�ns) a konstruktorban �ll�tsunk be.
�10.3.1.
[9] Ha egy konstruktor lefoglal valamilyen eroforr�st, akkor legyen destruktora az

oszt�lynak, amelyik felszabad�tja azt. �10.4.1.


[10] Ha egy oszt�lynak van mutat� tagja, akkor legyenek m�sol� muveletei (m�sol�
konstruktora �s m�sol� �rt�kad�sa). �10.4.4.1.
[11] Ha egy oszt�lynak van referencia tagja, val�sz�nuleg sz�ks�ge lesz m�sol� mu-

veletekre (m�sol� konstruktorra �s m�sol� �rt�kad�sra) is. �10.4.6.3.


[12] Ha egy oszt�lynak sz�ks�ge van m�sol� muveletre vagy destruktorra, val�sz�-
nuleg sz�ks�ge lesz konstruktorra, destruktorra, m�sol� konstruktorra �s m�sol
� �rt�kad�sra is. �10.4.4.1.
[13] A m�sol� �rt�kad�sn�l �gyelj�nk az �nmag�val val� �rt�kad�sra. �10.4.4.1.
[14] M�sol� konstruktor �r�sakor �gyelj�nk arra, hogy minden sz�ks�ges elemet
m�soljunk (�gyelj�nk az alap�rtelmezett kezdeti �rt�kad�sra). �10.4.4.1.
[15] Ha �j taggal bov�t�nk egy oszt�lyt, ellenorizz�k, nincsenek-e felhaszn�l�i
konstruktorok, amelyekben kezdo�rt�ket kell adni az �j tagnak. 10.4.6.3.
[16] Haszn�ljunk felsorol� konstansokat, ha eg�sz konstansokra van sz�ks�g egy
oszt�ly deklar�ci�j�ban. �10.4.6.2.
[17] Glob�lis vagy n�vt�rhez tartoz� objektumok haszn�latakor ker�lj�k a v�grehajt
�si sorrendtol val� f�gg�st. �10.4.9.
[18] Haszn�ljunk elso haszn�latot jelzo kapcsol�kat, hogy a v�grehajt�si
sorrendtol
val� f�gg�st a leheto legkisebbre cs�kkents�k. �10.4.9.
[19] Gondoljunk arra, hogy az ideiglenes objektumok annak a teljes kifejez�snek
a v�g�n megsemmis�lnek, amelyben l�trej�ttek. �10.4.10.
10.6. Gyakorlatok
1. (*1) Tal�ljuk meg a hib�t a �10.2.2-beli Date::add_year() f�ggv�nyben. Azt�n
tal�ljunk m�g k�t tov�bbi hib�t a �10.2.7-beli v�ltozatban.
2. (*2.5) Fejezz�k be �s pr�b�ljuk ki a Date oszt�lyt. �rjuk �jra �gy, hogy az
adat-
�br�zol�sra az 1970.01.01. �ta eltelt napokat haszn�ljuk.
3. (*2) Keress�nk egy kereskedelmi haszn�latban levo Date oszt�lyt. Elemezz�k
az �ltala ny�jtott szolg�ltat�sokat. Ha lehets�ges, vitassuk meg az oszt�lyt egy
t�nyleges felhaszn�l�val.
4. (*1) Hogyan �rj�k el a Chrono n�vt�r Date oszt�ly�nak set_default f�ggv�ny�t
(�10.3.2)? Adjunk meg legal�bb h�rom v�ltozatot.
5. (*2) Hat�rozzuk meg a Histogram oszt�lyt, amely a konstruktor�ban param�ter-
340 Absztrakci�s m�dszerek
k�nt megadott idotartom�nyokra vonatkoz� gyakoris�gokat tartja nyilv�n. Biztos
�tsunk muveletet a grafikon ki�rat�s�ra �s kezelj�k az �rtelmez�si tartom�-
nyon k�v�l eso �rt�keket is.
6. (*2) Hat�rozzunk meg oszt�lyokat, amelyek bizonyos (p�ld�ul egyenletes vagy
exponenci�lis) eloszl�sok szerinti v�letlen sz�mokat adnak. Mindegyik oszt�lynak
legyen egy konstruktora, amely az eloszl�st megadja, �s egy draw f�ggv�-
nye, amely a k�vetkezo �rt�ket adja vissza.
7. (*2.5) K�sz�ts�k el a Table oszt�lyt, amely (n�v.�rt�k) p�rokat t�rol. Ezut�n
m�-
dos�tsuk a sz�mol�g�p programot (�6.1), hogy az a map helyett a Table oszt�lyt
haszn�lja. Hasonl�tsuk �ssze a k�t v�ltozatot.
8. (*2) �rjuk �jra a �7.10[7]-beli Tnode-ot, mint olyan oszt�lyt, amelynek
konstruktorai,
destruktorai stb. vannak. Adjuk meg a Tnode-ok egy f�j�t, mint oszt�lyt
(konstruktorokkal �s destruktorokkal).
9. (*3) Hat�rozzuk meg, k�sz�ts�k el �s ellenorizz�k az Intset oszt�lyt, amely
eg�-
szek halmaz�t �br�zolja. Legyen meg az uni�, a metszet, �s a szimmetrikus
differencia
muvelet is.
10. (*1.5) M�dos�tsuk az Intset oszt�lyt, hogy csom�pontok (Node objektumok)
halmaz
�t jelentse, ahol a Node egy meghat�rozott adatszerkezet.
11. (*3) Hozzunk l�tre egy olyan oszt�lyt, amely eg�sz konstansokb�l �s a +, -, *
�s
/ muveletekbol �ll� egyszeru aritmetikai kifejez�seket k�pes elemezni, ki�rt�-
kelni, t�rolni �s ki�rni. A nyilv�nos fel�let ilyesmi legyen:
class Expr {
// ...
public:
Expr(const char*);
int eval();
void print();
};
Az Expr::Expr() konstruktor karakterl�nc param�tere a kifejez�s. Az Expr::eval()
f�ggv�ny visszaadja a kifejez�s �rt�k�t, az Expr::print() pedig �br�zolja azt
a cout-on. A program �gy n�zhet ki:
Expr x("123/4+123*4-3");
cout << "x = " << x.eval() << "\n";
x.print();
Hat�rozzuk meg az Expr oszt�lyt k�tf�lek�ppen: egyszer mint csom�pontok
l�ncolt list�j�t, m�sszor egy karakterl�nccal �br�zolva. K�s�rletezz�nk a
kifejez�s
k�l�nb�zo ki�rat�saival: teljesen z�r�jelezve, a muveleti jelet ut�tagk�nt haszn
�lva, assembly k�ddal stb.
10. Oszt�lyok 341
12. (*2) Hat�rozzuk meg a Char_queue oszt�lyt, hogy a nyilv�nos fel�let ne f�ggj
�n az �br�zol�st�l. K�sz�ts�k el a Char_queue-t mint (a) l�ncolt list�t, illetve
(b)
vektort.
13. (*3) Tervezz�nk egy szimb�lumt�bla �s egy szimb�lumt�bla-elem oszt�lyt
valamely
nyelv sz�m�ra. N�zz�k meg az adott nyelv egy ford�t�programj�ban, hogyan
n�znek ki ott az igazi szimb�lumt�bl�k.
14. (*2) M�dos�tsuk a 10.6[11]-beli kifejez�soszt�lyt, hogy v�ltoz�kat is kezelni
tudjon,
valamint a = �rt�kad� muveletet is. Haszn�ljuk a 10.6[131]-beli szimb�lumt
�bla oszt�lyt.
15. (*1) Adott a k�vetkezo program:
#include <iostream>
int main()
{
std::cout << "Hell�, vil�g!\n";
}
M�dos�tsuk �gy, hogy a k�vetkezo kimenetet adja:
Kezdeti �rt�kad�s
Hell�, vil�g!
Takar�t�s
A main() f�ggv�nyt semmilyen m�don nem v�ltoztathatjuk meg.
16. (*2) Hat�rozzunk meg egy olyan Calculator oszt�lyt, amilyet a �6.1-beli
f�ggv�-
nyek nagyr�szt megval�s�tanak. Hozzunk l�tre Calculator objektumokat �s
alkalmazzuk
azokat a cin-bol sz�rmaz� bemenetre, a parancssori param�terekre
�s a programban t�rolt karakterl�ncokra. Tegy�k lehetov� a kimenetnek a bemenethez

hasonl� m�don t�bbf�le helyre val� ir�ny�t�s�t.


17. (*2) Hat�rozzunk meg k�t oszt�lyt, mindegyikben egy-egy statikus taggal, �gy,
hogy mindegyik l�trehoz�s�hoz a m�sikra hivatkozunk. Hol fordulhat elo ilyesmi
igazi k�dban? Hogyan lehet m�dos�tani az oszt�lyokat, hogy kik�sz�b�lj�k
a v�grehajt�si sorrendtol val� f�gg�st?
18. (*2.5) Hasonl�tsuk �ssze a Date oszt�lyt (�10.3) az �5.9[13] �s a �7.10[19]
feladatra
adott megold�ssal. �rt�kelj�k a megtal�lt hib�kat �s gondoljuk meg, milyen
k�l�nbs�gekkel kell sz�molni a k�t oszt�ly m�dos�t�sakor.
19. (*3) �rjunk olyan f�ggv�nyt, amely egy istream-bol �s egy vector<string>-bol
kiindulva
elk�sz�t egy map<string,vector<int> > objektumot, amely minden karakterl
�ncot �s azok elofordul�s�nak sorsz�m�t tartalmazza. Futtassuk a programot
egy olyan sz�vegf�jllal, amely legal�bb 1000 sort tartalmaz, �s legal�bb 10
342 Absztrakci�s m�dszerek
Oper�torok t�lterhel�se
.Amikor �n haszn�lok egy
sz�t, azt �rtem alatta,
amit �n akarok . se t�bbet,
se kevesebbet..
(Humpty Dumpty)
Jel�l�s . Oper�tor f�ggv�nyek . Egy- �s k�toperandus� muveleti jelek . Az
oper�torok
elore meghat�rozott jelent�se . Az oper�torok felhaszn�l�i jelent�se . Oper�torok
�s n�vterek
. Komplex sz�m t�pusok . Tag �s nem tag oper�torok . Vegyes m�d� aritmetika .
Kezdeti �rt�kad�s . M�sol�s . Konverzi�k . Liter�lok . Seg�df�ggv�nyek .
Konverzi�s
oper�torok . A t�bb�rtelmus�g felold�sa . Bar�t f�ggv�nyek �s oszt�lyok . Tagok �s
bar
�t f�ggv�nyek . Nagy objektumok . �rt�kad�s �s kezdeti �rt�kad�s . Indexel�s .
F�ggv
�nyh�v�s . Indirekci� . N�vel�s �s cs�kkent�s . Egy karakterl�nc oszt�ly .
Tan�csok .
Gyakorlatok
11
11.1. Bevezet�s
Minden muszaki szakter�letnek . �s a legt�bb nem muszakinak is . kialakultak a
maga
megszokott r�vid�t�sei, amelyek k�nyelmess� teszik a gyakran haszn�lt fogalmak
kifejez�-
s�t, t�rgyal�s�t. Az al�bbi p�ld�ul
x+y*z
vil�gosabb sz�munkra, mint a
vegy�k y-t z-szer �s az eredm�nyt adjuk x-hez
Nem lehet el�gg� megbecs�lni a szok�sos muveletek t�m�r jel�l�s�nek fontoss�g�t.
A legt�bb nyelvvel egy�tt a C++ is t�mogat egy sor, a be�p�tett t�pusokra
vonatkoz� muveletet.
A legt�bb fogalomnak, amelyre muveleteket szoktak alkalmazni, azonban nincs
megfelel
oje a be�p�tett t�pusok k�z�tt, �gy felhaszn�l�i t�pussal kell azokat �br�zolni.
P�ld�ul ha
komplex sz�mokkal akarunk sz�molni, ha m�trix-muveletekre, logikai jel�l�sekre
vagy karakterl
�ncokra van sz�ks�g�nk a C++-ban, oszt�lyokat haszn�lunk, hogy ezeket a fogalmakat

�br�zoljuk. Ha ezekre az oszt�lyokra vonatkoz� muveleteket defini�lunk,


megszokottabb
�s k�nyelmesebb jel�l�s felhaszn�l�s�val kezelhetj�k az objektumokat, mintha csak
az
alapveto f�ggv�ny-jel�l�st haszn�ln�nk.
class complex { // nagyon leegyszerus�tett complex t�pus
double re, im;
public:
complex(double r, double i) : re(r), im(i) { }
complex operator+(complex);
complex operator*(complex);
};
Itt p�ld�ul a komplex sz�m fogalm�nak egy egyszeru megval�s�t�s�t l�thatjuk. Egy
complex
�rt�ket egy k�tszeres pontoss�g� lebegopontos sz�mp�r �br�zol, melyet a + �s a *
muveletek
kezelnek. A felhaszn�l� adja meg a complex::operator+() �s complex::operator*()
oper�torokat, hogy �rtelmezze a + �s * muveleteket. Ha p�ld�ul b �s c complex
t�pus�ak,
akkor a b+c a b.operator(c)-t jelenti. Ezek ut�n k�zel�toleg meghat�rozhatjuk a
complex sz�-
mokat tartalmaz� kifejez�sek megszokott jelent�s�t:
344 Absztrakci�s m�dszerek
void f()
{
complex a = complex(1, 3.1);
complex b = complex(1.2, 2);
complex c = b;
a = b+c;
b = b+c*a;
c = a*b+complex(1,2);
}
A szok�sos ki�rt�kel�si szab�lyok �rv�nyesek, �gy a m�sodik kifejez�s azt jelenti,
hogy
b=b+(c*a), �s nem azt, hogy b=(b+c)*a.
Az oper�torok t�lterhel�s�nek legnyilv�nval�bb alkalmaz�sai k�z�l sok konkr�t
t�pusokra
vonatkozik (�10.3). Az oper�torok t�lterhel�se azonban nemcsak konkr�t t�pusokn�l
hasznos.
�ltal�nos �s absztrakt fel�letek fel�p�t�s�n�l p�ld�ul gyakran haszn�lunk olyan
oper�-
torokat, mint a ->, a [ ] �s a ().
11.2. Oper�tor f�ggv�nyek
A k�vetkezo oper�torok (�6.2) jelent�s�t meghat�roz� f�ggv�nyeket megadhatjuk:
+ - * / % ^ &
| ~ ! = < > +=
-= *= /= %= ^= &= |=
<< >> >>= <<= == != <=
>= && || ++ -- ->* ,
-> [ ] () new new[ ] delete delete[ ]
A k�vetkezoknek viszont nem lehet felhaszn�l�i jelent�st tulajdon�tani:
:: (hat�k�r-felold�s, �4.9.4, �10.2.4)
. (tagkiv�laszt�s, �5.7)
.* (tagkiv�laszt�s a tagra hivatkoz� mutat�n kereszt�l, �15.5)
Ezek olyan oper�torok (muveleti jelek), amelyek m�sodik operandusk�nt nem �rt�ket,
hanem
nevet v�rnak �s a tagokra val� hivatkoz�s alapveto m�djai. Ha t�l lehetne terhelni
ezeket
. azaz ha a felhaszn�l� hat�rozhatn� meg jelent�s�ket . akkor ez �rdekes
mell�khat�-
sokkal j�rhatna [Stroustrup, 1994]. A h�romparam�teru felt�teles-kifez�s oper�tor,
a ?:
(�6.3.2) sem terhelheto t�l, mint ahogy a sizeof (�4.6) �s a typeid (�15.4.4) sem.

11. Oper�torok t�lterhel�se 345


�j muveleti jeleket sem adhatunk meg; ehelyett a f�ggv�nyh�v�si jel�l�s
haszn�lhat�, ha
a rendelkez�sre �ll�kon k�v�l tov�bbi oper�torokra is sz�ks�g van. �gy p�ld�ul ne
**-ot
haszn�ljunk, hanem azt, hogy pow(). Ezek a megszor�t�sok t�l szigor�nak tunhetnek,
de rugalmasabb
szab�lyok k�nnyen az egy�rtelmus�g elveszt�s�hez vezetn�nek. Elso pillant�sra
nyilv�nval�nak �s egyszerunek tunhet a ** oper�tort haszn�lni a hatv�nyoz�sra, de
gondoljunk
csak meg: a ** muveleti jel balr�l k�ss�n, mint a Fortranban, vagy jobbr�l, mint
az
Algolban? Az a**p kifejez�st hogyan �rtelmezz�k: mint a*(*p)-t vagy mint (a)**(p)-
t?
Az oper�tor f�ggv�nyek neve az operator kulcssz�b�l �s azt k�vetoen mag�b�l az
oper�-
torb�l �ll; p�ld�ul operator <<. Az oper�tor f�ggv�nyeket ugyan�gy deklar�lhatjuk
�s h�vhatjuk
meg, mint a t�bbi f�ggv�nyt. Az oper�torral val� jel�l�s csak az oper�tor f�ggv�ny

k�zvetlen megh�v�s�nak r�vid�t�se:


void f(complex a, complex b)
{
complex c = a + b; // r�vid forma
complex d = a.operator+(b); // explicit h�v�s
}
A complex elozo definici�j�t adottnak v�ve a fenti k�t kezdeti �rt�kad�s jelent�se
azonos.
11.2.1. Egy- �s k�toperandus� muveletek
K�toperandus� muveleti jelet egyparam�teru nem statikus tagf�ggv�nyk�nt vagy
k�tparam
�teru nem tag f�ggv�nyk�nt defini�lhatunk. Ha @ k�toperandus� muveletet jel�l,
akkor
aa@bb vagy aa.operator@(bb)-t, vagy operator@(aa,bb)-t jel�li. Ha mindketto
�rtelmezett,
a t�lterhel�s-felold�si szab�lyok (�7.4) d�ntik el, melyik alkalmazhat�, illetve
hogy egy�ltal
�n b�rmelyik alkalmazhat�-e:
class X {
public:
void operator+(int);
X(int);
};
void operator+(X,X);
void operator+(X,double);
void f(X a)
{
a+1; // a.operator+(1)
1+a; // ::operator+(X(1),a)
a+1.0; // ::operator+(a,1.0)
}
346 Absztrakci�s m�dszerek
Az egyoperandus� (ak�r elo-, ak�r ut�tagk�nt haszn�lt) muveleti jelek param�ter
n�lk�li
nem statikus tagf�ggv�nyk�nt vagy egyparam�teru nem tag f�ggv�nyk�nt
defini�lhat�k.
Ha @ elotag �s egyoperandus� muveletet jel�l, akkor @aa vagy aa.operator@()-t,
vagy
operator@(aa)-t jel�li. Ha mindketto �rtelmezett, a t�lterhel�s-felold�si
szab�lyok (�7.4)
d�ntik el, melyik alkalmazhat�, illetve hogy egy�ltal�n b�rmelyik alkalmazhat�-e.
Ha @
ut�tag �s egyoperandus� muveletet ad meg, akkor aa@ vagy aa.operator@(int)-et,
vagy
operator@(aa,int)-et jel�li. (Ezt r�szletesebben a �11.11 pont �rja le.) Ha
mindketto �rtelmezett,
ism�t csak a t�lterhel�s-felold�si szab�lyok (�7.4) d�ntik el, melyik
alkalmazhat�, illetve
hogy egy�ltal�n b�rmelyik alkalmazhat�-e. Oper�tort csak a nyelvi szab�lyoknak
megfeleloen defini�lhatunk (�A.5), �gy nem lehet p�ld�ul egyoperandus� % vagy
h�romoperandus� + muvelet�nk:
class X {
// tagok (a 'this' mutat� automatikus):
X* operator&(); // elotagk�nt haszn�lt egyoperandus� & (c�m)
X operator&(X); // k�toperandus� & (�s)
X operator++(int); // ut�tagk�nt haszn�lt n�velo oper�tor (l�sd �11.1)
X operator&(X,X); // hiba: h�romoperandus�
X operator/(); // hiba: egyoperandus� /
};
// nem tag f�ggv�nyek :
X operator-(X); // elotagk�nt haszn�lt egyoperandus� m�nusz (m�nusz elojel)
X operator-(X,X); // k�toperandus� m�nusz (kivon�s)
X operator--(X&,int); // ut�tagk�nt haszn�lt cs�kkento oper�tor
X operator-(); // hiba: nincs operandus
X operator-(X,X,X); // hiba: h�romoperandus�
X operator%(X); // hiba: egyoperandus� %
A [ ] oper�tort a �11.8, a () oper�tort a �11.9, a -> oper�tort a �11.10, a ++ �s
-- oper�torokat
a 11.11, a mem�riafoglal� �s felszabad�t� oper�torokat a �6.2.6.2, a �10.4.11 �s a
�15.6 pontokban
�rjuk le.
11.2.2. Az oper�torok elore meghat�rozott jelent�se
A felhaszn�l�i oper�torok jelent�s�nek csak n�h�ny elo�r�snak kell megfelelni�k.
Az operator=, operator[ ], operator() �s az operator-> nem statikus tagf�ggv�ny
kell, hogy
legyen; ez biztos�tja, hogy elso operandusuk bal�rt�k (lvalue) lesz (�4.9.6).
11. Oper�torok t�lterhel�se 347
Bizonyos be�p�tett oper�torok jelent�se megegyezik m�s oper�toroknak ugyanazon
param
�terre �sszetetten gyakorolt hat�s�val. P�ld�ul ha a egy int, akkor ++a jelent�se
megegyezik
a+=1-gyel, ami pedig azt jelenti, hogy a=a+1. Hacsak a felhaszn�l� nem gondoskodik

r�la, ilyen �sszef�gg�sek nem �llnak fenn a felhaszn�l�i oper�torokra, �gy a


ford�t�-
program p�ld�ul nem fogja kital�lni a Z::operator+=() muvelet jelent�s�t puszt�n
abb�l,
hogy megadtuk a Z::operator+() �s Z::operator=() muveleteket.
Hagyom�nyosan az = (�rt�kad�), a & (c�mk�pzo) �s a , (vesszo; �6.2.2) oper�torok
elore
defini�ltak, ha oszt�lyba tartoz� objektumra alkalmazzuk azokat. Ezeket az elore
meghat�-
rozott jelent�seket az �ltal�nos felhaszn�l� elol elrejthetj�k, ha priv�tk�nt
adjuk meg azokat:
class X {
private:
void operator=(const X&);
void operator&();
void operator,(const X&);
// ...
};
void f(X a, X b)
{
a = b; // hiba: az �rt�kad� oper�tor priv�t
&a; // hiba: a c�m oper�tor (&) priv�t
a,b; // hiba: a vesszo oper�tor (,) priv�t
}
Alkalmas m�don defini�lva azonban �j jelent�s is tulajdon�that� nekik.
11.2.3. Oper�torok �s felhaszn�l�i t�pusok
Az oper�toroknak tagf�ggv�nynek kell lenni�k vagy param�tereik k�z�tt legal�bb egy
felhaszn
�l�i t�pusnak kell szerepelnie (kiv�telek ez al�l a new �s delete oper�torok
jelent�s�t
fel�lb�r�l� f�ggv�nyek.) Ez a szab�ly biztos�tja, hogy a programoz� egy kifejez�s
�rtelm�t
csak akkor m�dos�thassa, ha legal�bb egy felhaszn�l�i t�pus elofordul benne. Ebbol
ad�-
d�an nem defini�lhat� olyan oper�tor, amely kiz�r�lag mutat�kkal muk�dik. A C++
teh�t
bov�theto, de nem v�ltoztathat� meg, (az oszt�lyba tartoz� objektumokra vonatkoz�
=, &
�s , oper�torokat kiv�ve).
Az olyan oper�torok, melyeket arra sz�nunk, hogy elso param�terk�nt valamilyen
alapt�-
pust fogadjanak el, nem lehetnek tagf�ggv�nyek. Vegy�k p�ld�ul azt az esetet,
amikor egy
complex v�ltoz�t akarunk a 2 eg�szhez hozz�adni: az aa+2 kifejez�st alkalmas
tagf�ggv�ny
348 Absztrakci�s m�dszerek
megl�te eset�n �rtelmezhetj�k aa.operator+(2)-k�nt, de a 2+aa kifejez�st nem, mert
nincs
int oszt�ly, amelynek + olyan tagf�ggv�nye lehetne, hogy a 2.operator(aa)
eredm�nyre jussunk.
De ha lenne is, akkor is k�t tagf�ggv�ny kellene ahhoz, hogy 2+aa-val �s aa+2-vel
is megbirk�zzunk. Minthogy a ford�t�program nem ismeri a felhaszn�l�i + muvelet
jelent�-
s�t, nem t�telezheti fel r�la a felcser�lhetos�get (kommutativit�st), hogy annak
alapj�n
2+aa-t mint aa+2-t kezelje. Az ilyesmit rendszerint nem tag f�ggv�nyekkel
kezelhetj�k
(�11.3.2, �11.5).
A felsorol�sok felhaszn�l�i t�pusok, �gy r�juk is �rtelmezhet�nk oper�torokat:
enum Day { sun, mon, tue, wed, thu, fri, sat };
Day& operator++(Day& d)
{
return d = (sat==d) ? sun : Day(d+1);
}
A ford�t�program minden kifejez�st ellenoriz, hogy nem l�p-e fel t�bb�rtelmus�g.
Ha egy
felhaszn�l�i oper�tor is biztos�t lehets�ges �rtelmez�st, a kifejez�s ellenorz�se
a �7.4 pontban
le�rtak szerint t�rt�nik.
11.2.4. N�vterek oper�torai
Az oper�tor mindig valamilyen oszt�ly tagja vagy valamilyen n�vt�rben (esetleg a
glob�lisban)
defini�lt. Vegy�k p�ld�ul a standard k�nyvt�r karakterl�nc-ki�r�si muvelet�nek
egyszer
us�tett v�ltozat�t:
namespace std { // egyszerus�tett std
class ostream {
// ...
ostream& operator<<(const char*);
};
extern ostream cout;
class string {
// ...
};
ostream& operator<<(ostream&, const string&);
}
11. Oper�torok t�lterhel�se 349
int main()
{
char* p = "Hell�";
std::string s = "vil�g";
std::cout << p << ", " << s << "!\n";
}
Ez term�szetesen azt �rja ki, hogy .Hell�, vil�g!.. De mi�rt? Vegy�k �szre, hogy
nem tettem
mindent el�rhetov� az std n�vt�rbol az�ltal, hogy azt �rtam volna:
using namespace std;
Ehelyett az std:: elotagot alkalmaztam a string �s a cout elott. Vagyis a
legrendesebben viselkedve
nem .szennyeztem be. a glob�lis n�vteret �s egy�b m�don sem vezettem be sz�ks
�gtelen f�gg�seket.
A C st�lus� karakterl�ncok (char*) kimeneti muvelete az std::ostream egy tagja,
�gy
std::cout << p
jelent�se defin�ci� szerint:
std::cout.operator<<(p)
Mivel azonban az std::ostream-nek nincs olyan tagja, amelyet az std::string-re
alkalmazhatn
�nk, �gy
std::cout << s
jelent�se:
operator<<(std::cout,s)
A n�vt�rben defini�lt oper�torokat ugyan�gy operandusuk t�pusa szerint tal�lhatjuk
meg,
mint ahogy a f�ggv�nyeket param�tereik t�pusa szerint (�8.2.6). Minthogy a cout az
std n�vt
�rben van, �gy az std is sz�ba ker�l, amikor a << sz�m�ra alkalmas defin�ci�t
keres�nk. �gy
azt�n a ford�t�program megtal�lja �s felhaszn�lja a k�vetkezo f�ggv�nyt:
std::operator<<(std::ostream&, const std::string&)
350 Absztrakci�s m�dszerek
Jel�lj�n @ egy k�toperandus� muveletet. Ha x az X t�pusba, az y pedig az Y t�pusba
tartozik,
akkor x@y felold�sa, azaz a param�terek t�pus�nak megfelelo f�ggv�ny megkeres�se
a k�vetkezok�ppen t�rt�nik:
� Ha X egy oszt�ly, keres�nk egy operator@-t, amely az X oszt�lynak vagy
valamelyik
b�zisoszt�ly�nak tagf�ggv�nye.
� Keres�nk egy operator@ deklar�ci�t az x@y kifejez�st k�r�lvevo k�rnyezetben.
� Ha X az N n�vt�r tagja, az operator@-t az N n�vt�rben keress�k.
� Ha Y az M n�vt�r tagja, az operator@-t az M n�vt�rben keress�k.
Ha az operator@ t�bbf�le deklar�ci�j�t is megtal�ltuk, a felold�si szab�lyokat
kell alkalmazni
(�7.4), hogy a legjobb egyez�st megtal�ljuk, ha egy�ltal�n van ilyen. Ez a
keres�si elj�r�s
csak akkor alkalmazand�, ha legal�bb egy felhaszn�l�i t�pus szerepel az
operandusok k�-
z�tt, ami azt is jelenti, hogy a felhaszn�l�i konverzi�kat (�11.3.2, �11.4) is
figyelembe
vessz�k. (A typedef-fel megadott nevek csak szinonim�k, nem felhaszn�l�i t�pusok
(�4.9.7).) Az egyoperandus� muveletek felold�sa hasonl�an t�rt�nik.
Jegyezz�k meg, hogy az oper�torok felold�s�ban a tagf�ggv�nyek nem �lveznek elonyt

a nem tag f�ggv�nyekkel szemben. Ez elt�r a n�vvel megadott f�ggv�nyek keres�s�tol

(�8.2.6). Az oper�torok el nem rejt�se biztos�tja, hogy a be�p�tett oper�torok nem


v�lnak el-
�rhetetlenn�, �s hogy a felhaszn�l� a meglevo oszt�lydeklar�ci�k m�dos�t�sa n�lk�l
adhat
meg �j jelent�seket. A szabv�nyos iostream k�nyvt�r p�ld�ul defini�lja a <<
tagf�ggv�nyeket
a be�p�tett t�pusokra, a felhaszn�l� viszont a felhaszn�l�i t�pusoknak a <<
muvelettel val
� kimenetre k�ld�s�t az ostream oszt�ly (�21.2.1) m�dos�t�sa n�lk�l defini�lhatja.

11.3. Komplex sz�m t�pusok


A komplex sz�moknak a bevezetoben eml�tett megval�s�t�sa t�l keveset ny�jt ahhoz,
hogy
b�rkinek is tess�k. Egy matematika tank�nyvet olvasva azt v�rn�nk, hogy a
k�vetkezo
f�ggv�ny muk�dik:
void f()
{
complex a = complex(1,2);
complex b = 3;
complex c = a+2.3;
complex d = 2+b;
complex e = -b-c;
b = c*2*c;
}
11. Oper�torok t�lterhel�se 351
R�ad�sul elv�rn�nk, hogy l�tezz�k n�h�ny tov�bbi muvelet is, p�ld�ul a == az
�sszehasonl
�t�sra �s a << a kimenetre, �s m�g a matematikai f�ggv�nyek (mint a sin() �s a
sqrt()) megfelel
o k�szlet�t is ig�nyeln�nk.
A complex oszt�ly egy konkr�t t�pus, �gy fel�p�t�se megfelel a �10.3-beli
elveknek. R�ad�-
sul a komplex aritmetika felhaszn�l�i olyan nagy m�rt�kben �p�tenek az
oper�torokra,
hogy a complex oszt�ly defini�l�sa az oper�tor-t�lterhel�sre vonatkoz� szinte
valamennyi
szab�ly alkalmaz�s�t ig�nyli.
11.3.1. Tag �s nem tag oper�torok
Elony�s lenne, ha min�l kevesebb f�ggv�ny f�rne hozz� k�zvetlen�l egy adott
objektum
belso adat�br�zol�s�hoz. Ezt �gy �rhetj�k el, ha csak azokat az oper�torokat adjuk
meg
mag�ban az oszt�lyban, amelyek �rtelm�kn�l fogva m�dos�tj�k elso param�ter�ket,
mint
p�ld�ul a +=. Azokat az oper�torokat, amelyek csak egy �j �rt�ket �ll�tanak elo
param�tereik
alapj�n, mint p�ld�ul a +, az oszt�lyon k�v�l defini�lom �s az alapveto oper�torok
seg
�ts�g�vel val�s�tom meg:
class complex {
double re, im;
public:
complex& operator+=(complex a); // hozz� kell f�rni az �br�zol�shoz
// ...
};
complex operator+(complex a, complex b)
{
complex r = a;
return r += b; // az �br�zol�s el�r�se a += oper�toron kereszt�l
}
Ezen deklar�ci�k alapj�n m�r le�rhatjuk a k�vetkezot:
void f(complex x, complex y, complex z)
{
complex r1 = x+y+z; // r1 = operator+(operator+(x,y),z)
complex r2 = x; // r2 = x
r2 += y; // r2.operator+=(y)
r2 += z; // r2.operator+=(z)
}
Esetleges hat�konys�gi k�l�nbs�gektol eltekintve r1 �s r2 kisz�m�t�sa egyen�rt�ku.

352 Absztrakci�s m�dszerek


Az �sszetett �rt�kad� oper�torokat, p�ld�ul a += -t �s a *= -t �ltal�ban k�nnyebb
defini�lni,
mint egyszeru megfeleloiket, a + �s * oper�torokat. Ez t�bbnyire meglep�st kelt,
pedig
puszt�n abb�l k�vetkezik, hogy az �sszead�sn�l 3 objektum j�tszik szerepet (a k�t
�sszeadand
� �s az eredm�ny), m�g a += oper�torn�l csak ketto. Az ut�bbi eset�ben hat�konyabb

a megval�s�t�s, ha nem haszn�lunk ideiglenes v�ltoz�kat:


inline complex& complex::operator+=(complex a)
{
re += a.re;
im += a.im;
return *this;
}
A fenti megold�sn�l nincs sz�ks�g ideiglenes v�ltoz�ra az eredm�ny t�rol�s�ra �s a
ford�-
t�program sz�m�ra is k�nnyebb feladat a teljes helyben kifejt�s.
Egy j� ford�t�program az optim�lishoz k�zeli k�dot k�sz�t a sima + oper�tor
haszn�lata eset
�n is. De nincs mindig j� optimaliz�l�nk �s nem minden t�pus olyan .egyszeru.,
mint
a complex, ez�rt a �11.5 pont t�rgyalja, hogyan adhatunk meg olyan oper�torokat,
amelyek
hozz�f�rhetnek az oszt�ly �br�zol�s�hoz.
11.3.2. Vegyes m�d� aritmetika
Ahhoz, hogy a
complex d = 2+b;
k�dot kezelni tudjuk, olyan + oper�torra van sz�ks�g�nk, amely k�l�nb�zo t�pus�
param�-
tereket is elfogad. A Fortran kifejez�s�vel �lve teh�t .vegyes m�d� aritmetik�ra.
(mixedmode
arithmetic) van sz�ks�g. Ezt k�nnyen megval�s�thatjuk, ha megadjuk az oper�tor
megfelelo v�ltozatait:
class complex {
double re, im;
public:
complex& operator+=(complex a) {
re += a.re;
im += a.im;
return *this;
}
11. Oper�torok t�lterhel�se 353
complex& operator+=(double a) {
re += a;
return *this;
}
// ...
};
complex operator+(complex a, complex b)
{
complex r = a;
return r += b; // complex::operator+=(complex)-et h�vja meg
}
complex operator+(complex a, double b)
{
complex r = a;
return r += b; // complex::operator+=(double)-t h�vja meg
}
complex operator+(double a, complex b)
{
complex r = b;
return r += a; // complex::operator+=(double)-t h�vja meg
}
Egy double hozz�ad�sa egy komplex sz�mhoz egyszerubb muvelet, mint egy komplex
sz�m hozz�ad�sa; ezt t�kr�zik a fenti defin�ci�k is. A double operandust kezelo
muveletek
nem �rintik a komplex sz�m k�pzetes r�sz�t, �gy hat�konyabbak lesznek.
A fenti deklar�ci�k mellett most m�r le�rhatjuk a k�vetkezot:
void f(complex x, complex y)
{
complex r1 = x+y; // operator+(complex,complex)-et h�vja meg
complex r2 = x+2; // operator+(complex,double)-t h�vja meg
complex r3 = 2+x; // operator+(double,complex)-et h�vja meg
}
11.3.3. Kezdeti �rt�kad�s
A complex v�ltoz�knak skal�rokkal val� kezdeti �s egyszeru �rt�kad�s kezel�s�hez
sz�ks�-
g�nk van a skal�rok (eg�sz vagy lebegopontos (val�s) �rt�kek) complex-sz�
�talak�t�s�ra:
complex b = 3; // b.re=3, b.im=0-t kell jelentenie
354 Absztrakci�s m�dszerek
Az olyan konstruktor, amely egyetlen param�tert v�r, konverzi�t jelent a param�ter
t�pus�-
r�l a konstruktor t�pus�ra:
class complex {
double re, im;
public:
complex(double r) : re(r), im(0) { }
// ...
};
Ez a konstruktor a val�s sz�megyenesnek a komplex s�kba val� szok�sos be�gyaz�s�t
jelenti.
Egy konstruktor mindig azt �rja elo, hogyan hozhatunk l�tre egy adott t�pus�
�rt�ket. Ha egy
adott t�pus� �rt�ket kell l�trehozni egy (kezdeti vagy egyszeru) �rt�kad�
kifejez�s �rt�k�-
bol �s ebbol egy konstruktor l�tre tudja hozni a k�v�nt t�pus� �rt�ket, akkor
konstruktort alkalmazunk.
Ez�rt az egyparam�teru konstruktorokat nem kell explicit megh�vnunk:
complex b = 3;
A fenti egyen�rt�ku a k�vetkezovel:
complex b = complex(3);
Felhaszn�l�i konverzi�ra csak akkor ker�l sor automatikusan, ha az egy�rtelmu
(�7.4). Arra
n�zve, hogyan adhatunk meg csak explicite megh�vhat� konstruktorokat, l�sd a
�11.7.1
pontot.
Term�szetesen sz�ks�g�nk lesz egy olyan konstruktorra is, amelynek k�t double
t�pus� param
�tere van, �s a (0,0) kezdo�rt�ket ad� alap�rtelmezett konstruktor is hasznos:
class complex {
double re, im;
public:
complex() : re(0), im(0) { }
complex(double r) : re(r), im(0) { }
complex(double r, double i) : re(r), im(i) { }
// ...
};
11. Oper�torok t�lterhel�se 355
Alap�rtelmezett param�ter-�rt�keket haszn�lva �gy r�vid�thet�nk:
class complex {
double re, im;
public:
complex(double r =0, double i =0) : re(r), im(i) { }
// ...
};
Ha egy t�pusnak van konstruktora, a kezdeti �rt�kad�sra nem haszn�lhatunk
kezdo�rt�klist
�t (�5.7, �4.9.5):
complex z1 = { 3 }; // hiba: complex rendelkezik konstruktorral
complex z2 = { 3, 4 }; // hiba: complex rendelkezik konstruktorral
11.3.4. M�sol�s
A megadott konstruktorokon k�v�l a complex oszt�lynak lesz egy alap�rtelmezett
m�sol�
konstruktora (�10.2.5) is. Az alap�rtelmezett m�sol� konstruktor egyszeruen
lem�solja a tagokat.
A muk�d�st pontosan �gy hat�rozhatn�nk meg:
class complex {
double re, im;
public:
complex(const complex& c) : re(c.re), im(c.im) { }
// ...
};
�n elonyben r�szes�tem az alap�rtelmezett m�sol� konstruktort azon oszt�lyok
eset�ben,
amelyekn�l ez megfelelo. R�videbb lesz a k�d, mintha b�rmi m�st �rn�k, �s a k�d
olvas�-
j�r�l felt�telezem, hogy ismeri az alap�rtelmezett muk�d�st. A ford�t�program is
ismeri �s
azt is, hogyan lehet azt optimaliz�lni. Ezenk�v�l pedig sok tag eset�n f�raszt�
dolog k�zzel
ki�rni a tagonk�nti m�sol�st �s k�nnyu k�zben hib�zni (�10.4.6.3).
A m�sol� konstruktor param�terek�nt referenci�t kell haszn�lnom. A m�sol�
konstruktor hat
�rozza meg a m�sol�s jelent�s�t . bele�rtve a param�ter m�sol�s��t is . �gy a
complex::complex(complex c) : re(c.re), im(c.im) { } // hiba
hib�s, mert a f�ggv�ny megh�v�sa v�gtelen rekurzi�hoz vezet.
356 Absztrakci�s m�dszerek
M�s, complex param�teru f�ggv�nyek eset�ben �n �rt�k �s nem referencia szerinti
param
�ter-�tad�st haszn�lok. Mindig az oszt�ly k�sz�toje d�nt. A felhaszn�l�
szemsz�g�bol n�zve
nincs sok k�l�nbs�g egy complex �s egy const complex& param�tert kap� f�ggv�ny
k�z�tt. Errol bovebben �r a �11.6 pont.
Elvileg a m�sol� konstruktort az ilyen egyszeru kezdeti �rt�kad�sokn�l haszn�ljuk:

complex x = 2; // complex(2) l�trehoz�sa; ezzel adunk kezdo�rt�ket x-nek


complex y = complex(2,0); // complex(2,0) l�trehoz�sa; ezzel adunk kezdo�rt�ket y-
nak
A ford�t�program azonban optimaliz�l �s elhagyja a m�sol� konstruktor megh�v�s�t.
�rhattuk
volna �gy is:
complex x(2); // x kezdo�rt�ke 2
complex y(2,0); // y kezdo�rt�ke (2,0)
A complex-hez hasonl� aritmetikai t�pusok eset�ben jobban kedvelem az = jel
haszn�lat�t.
Ha a m�sol� konstruktort priv�tt� tessz�k (�11.2.2) vagy ha egy konstruktort
explicit-k�nt
adunk meg (�11.7.1), az = st�lus� �rt�kad�s �ltal elfogadhat� �rt�kek k�r�t a ()
st�lus� �rt
�kad�s �ltal elfogadotthoz k�pest korl�tozhatjuk.
A kezdeti �rt�kad�shoz hasonl�an a k�t azonos oszt�lyba tartoz� objektum k�z�tti
�rt�kad
�s alap�rtelmez�s szerint tagonk�nti �rt�kad�st jelent (�10.2.5). A complex
oszt�lyn�l erre
a c�lra megadhatn�nk kifejezetten a complex::operator= muveletet, de ilyen
egyszeru
oszt�ly eset�ben erre nincs ok, mert az alap�rtelmezett muk�d�s pont megfelelo.
A m�sol� konstruktor . ak�r a ford�t�program hozta l�tre, ak�r a programoz� �rta .
nemcsak
a v�ltoz�k kezdo�rt�k�nek be�ll�t�s�ra haszn�latos, hanem param�ter-�tad�skor,
�rt�k
visszaad�sakor �s a kiv�telkezel�skor is (l�sd �11.7). Ezek szerep�t a nyelv a
kezdeti �rt�kad
�s�val azonosk�nt hat�rozza meg (�7.1, �7.3, �14.2.1).
11.3.5. Konstruktorok �s konverzi�k
A n�gy alapveto aritmetikai muveletnek eddig h�rom-h�rom v�ltozat�t hat�roztuk
meg:
complex operator+(complex,complex);
complex operator+(complex,double);
complex operator+(double,complex);
// ...
11. Oper�torok t�lterhel�se 357
Ez f�raszt�v� v�lhat, �s ami f�raszt�, ott k�nnyen elofordulhatnak hib�k. Mi
lenne, ha minden
param�ter h�romf�le t�pus� lehetne? Minden egyparam�teru muveletbol h�rom v�ltozat

kellene, a k�tparam�teruekbol kilenc, a h�romparam�teruekbol huszonh�t �s �gy tov


�bb. Ezek a v�ltozatok gyakran nagyon hasonl�ak. Val�j�ban majdnem mindegyik �gy
muk�dik, hogy a param�tereket egy k�z�s t�pusra alak�tja, majd egy szabv�nyos
algoritmust
hajt v�gre.
Ahelyett, hogy a param�terek minden lehets�ges p�ros�t�s�ra megadn�nk egy
f�ggv�nyt,
t�puskonverzi�kra hagyatkozhatunk. Tegy�k fel, hogy complex oszt�lyunknak van egy
olyan konstruktora, amely egy double �rt�ket alak�t complex-sz�, �gy a complex
oszt�ly sz�-
m�ra el�g egyetlen egyenlos�g-vizsg�l� muveletet megadnunk:
bool operator==(complex,complex);
void f(complex x, complex y)
{
x==y; // jelent�se operator==(x,y)
x==3; // jelent�se operator==(x,complex(3))
3==y; // jelent�se operator==(complex(3),y)
}
Lehetnek azonban okok, melyek miatt jobb k�l�n f�ggv�nyeket megadni. Egyes
esetekben
p�ld�ul a konverzi� t�l bonyolult muvelet lehet, m�skor bizonyos
param�tert�pusokra egyszer
ubb algoritmusok alkalmazhat�k. Ahol ilyen okok nem l�pnek fel jelentos m�rt�kben,

ott a f�ggv�ny leg�ltal�nosabb form�j�t megadva (esetleg n�h�ny kritikus


v�ltozattal kieg�-
sz�tve) �s a konverzi�kra hagyatkozva elker�lhetj�k, hogy a vegyes m�d�
aritmetik�b�l
ad�d�an nagyon sokf�le f�ggv�nyt kelljen meg�rnunk.
Ha egy f�ggv�ny vagy oper�tor t�bb v�ltozattal rendelkezik, a ford�t�program
feladata
a legalkalmasabb v�ltozat kiv�laszt�sa, a param�tert�pusok �s a lehets�ges
(szabv�nyos
vagy felhaszn�l�i) konverzi�k alapj�n. Ha nincs legjobb v�ltozat, a kifejez�s
t�bb�rtelmu �s
hib�s (l�sd �7.4).
Az olyan objektumok, melyeket a konstruktor k�zvetlen megh�v�sa vagy automatikus
haszn
�lata hozott l�tre, ideiglenes v�ltoz�nak sz�m�tanak �s amint lehets�ges,
megsemmis�lnek
(l�sd �10.4.10). A . �s -> oper�torok bal oldal�n nem t�rt�nik automatikus
felhaszn�l�i
konverzi�. Ez akkor is �gy van, ha maga a . implicit (a kifejez�sbe bele�rtett):
void g(complex z)
{
3+z; // rendben: complex(3)+z
3.operator+=(z); // hiba: 3 nem egy oszt�ly objektuma
3+=z; // hiba: 3 nem egy oszt�ly objektuma
}
358 Absztrakci�s m�dszerek
Ezt kihaszn�lva egy muveletet tagf�ggv�nny� t�ve kifejezhetj�k, hogy a muvelet bal
oldali
operandusk�nt bal�rt�ket v�r.
11.3.6. Liter�lok
Oszt�ly t�pus� liter�lokat nem defini�lhatunk abban az �rtelemben, ahogyan 1.2 �s
1.2e3
double t�pus� liter�lok. Az alapveto t�pusokba tartoz� liter�lokat viszont gyakran
haszn�lhatjuk,
ha a tagf�ggv�nyek fel vannak k�sz�tve a kezel�s�kre. Az egyparam�teru
konstruktorok �ltal�nos elj�r�st biztos�tanak erre a c�lra. Egyszeru �s helyben
kifejtett
(inline) konstruktorok eset�ben �sszeru a liter�l param�teru konstruktorh�v�sokra
mint liter
�lokra gondolni. A complex(3) kifejez�st p�ld�ul �n �gy tekintem, mint egy complex
�rt
�ku liter�lt, noha a sz� .technikai. �rtelm�ben v�ve nem az.
11.3.7. Kieg�sz�to tagf�ggv�nyek
Eddig csak konstruktorokat �s aritmetikai muveleteket adtunk a complex oszt�lyhoz.

A t�nyleges haszn�lathoz ez kev�s. A val�s �s a k�pzetes r�sz lek�rdez�se p�ld�ul


surun
haszn�latos:
class complex {
double re, im;
public:
double real() const { return re; }
double imag() const { return im; }
// ...
};
A complex oszt�ly t�bbi tagf�ggv�ny�vel ellent�tben a real() �s az imag() nem
v�ltoztatja
meg egy complex objektum �rt�k�t, �gy const-k�nt adhat� meg.
A real() �s imag() f�ggv�nyek alapj�n egy sor hasznos f�ggv�nyt defini�lhatunk
an�lk�l,
hogy azoknak hozz�f�r�st kellene adnunk a complex oszt�ly adat�br�zol�s�hoz:
inline bool operator==(complex a, complex b)
{
return a.real()==b.real() && a.imag()==b.imag();
}
Vegy�k �szre, hogy a val�s �s a k�pzetes r�szt el�g olvasnunk, �rnunk sokkal
ritk�bban kell.
11. Oper�torok t�lterhel�se 359
Ha .r�szleges friss�t�sre. van sz�ks�g�nk, a k�vetkezot �rhatjuk:
void f(complex& z, double d)
{
// ...
z = complex(z.real(),d); // d hozz�rendel�se z.im-hez
}
Egy j�l optimaliz�l� ford�t� ebbol egyetlen �rt�kad�st k�sz�t.
11.3.8. Seg�df�ggv�nyek
Ha mindent �sszerakunk, complex oszt�lyunk �gy alakul:
class complex {
double re, im;
public:
complex(double r =0, double i =0) : re(r), im(i) { }
double real() const { return re; }
double imag() const { return im; }
complex& operator+=(complex);
complex& operator+=(double);
// -=, *=, �s /=
};
Kieg�sz�t�sk�nt egy sor seg�df�ggv�nyt kell biztos�tanunk:
complex operator+(complex,complex);
complex operator+(complex,double);
complex operator+(double,complex);
// -, *, �s /
complex operator-(complex); // egyoperandus� m�nusz
complex operator+(complex); // egyoperandus� plusz
bool operator==(complex,complex);
bool operator!=(complex,complex);
istream& operator>>(istream&,complex&); // bemenet
ostream& operator<<(ostream&,complex); // kimenet
360 Absztrakci�s m�dszerek
Vegy�k �szre, hogy a real() �s imag() f�ggv�nyek szerepe alapveto az
�sszehasonl�t� f�ggv
�nyek defini�l�s�ban. A k�vetkezo seg�df�ggv�nyek is nagyr�szt ezekre �p�tenek.
Megadhatn�nk olyan f�ggv�nyeket is, amelyek a pol�r-koordin�t�s jel�l�st
t�mogatj�k:
complex polar(double rho, double theta);
complex conj(complex);
double abs(complex);
double arg(complex);
double norm(complex);
double real(complex); // a k�nyelmesebb jel�l�s�rt
double imag(complex); // a k�nyelmesebb jel�l�s�rt
V�g�l sz�ks�g�nk lesz a tov�bbi alapveto matematikai f�ggv�nyekre:
complex acos(complex);
complex asin(complex);
complex atan(complex);
// ...
Felhaszn�l�i szemsz�gbol n�zve az itt bemutatott complex oszt�ly szinte azonos
a complex<double>-lal (l�sd a standard k�nyvt�rbeli <complex>-et, �22.5).
11.4. Konverzi�s oper�torok
Konstruktorok haszn�lata t�puskonverzi� c�lj�ra k�nyelmes lehet, de nemk�v�natos
k�vetkezm
�nyei vannak. Egy konstruktor nem tud
1. automatikus �talak�t�st megadni felhaszn�l�i adatt�pusr�l be�p�tett adatt�pusra

(mert a be�p�tett adatt�pusok nem oszt�lyok)


2. �talak�t�st megadni egy �jabban megadott oszt�lyr�l egy r�gebbire, a r�gebbi
oszt�ly deklar�ci�j�nak megv�ltoztat�sa n�lk�l.
Ezeket a feladatokat az �talak�tand� oszt�ly konverzi�s (�talak�t�) oper�tor�nak
defini�l�s�val oldhatjuk meg. Ha T egy t�pus neve, akkor az X::operator T()
f�ggv�ny hat�-
11. Oper�torok t�lterhel�se 361
rozza meg az X t�pus T-re val� konverzi�j�t. Defini�lhatunk p�ld�ul a 6 bites, nem
negat�v
eg�szeket �br�zol� Tiny oszt�lyt, melynek objektumait aritmetikai kifejez�sekben
szabadon
keverhetj�k eg�szekkel:
class Tiny {
char v;
void assign(int i) { if (i&~077) throw Bad_range(); v=i; }
public:
class Bad_range { };
Tiny(int i) { assign(i); }
Tiny& operator=(int i) { assign(i); return *this; }
operator int() const { return v; } // konverzi� int t�pusra
};
Amikor egy Tiny egy eg�sztol kap �rt�ket vagy kezdo�rt�ket, ellenorizz�k, hogy az
�rt�k
a megengedett tartom�nyba esik-e. Minthogy egy Tiny m�sol�sakor nincs sz�ks�g az
�rt�kellen
orz�sre, az alap�rtelmezett m�sol� konstruktor �s �rt�kad�s �ppen megfelelo.
Ahhoz, hogy a Tiny v�ltoz�kra is lehetov� tegy�k az eg�szekn�l szok�sos
muveleteket, hat
�rozzuk meg a Tiny-rol int-re val� automatikus konverzi�t, a Tiny::operator int()-
et. Jegyezz
�k meg, hogy a konverzi� c�lt�pusa az oper�tor nev�nek r�sze �s nem szabad ki�rni,

mint a konverzi�s f�ggv�ny visszat�r�si �rt�k�t:


Tiny::operator int() const { return v; } // helyes
int Tiny::operator int() const { return v; } // hiba
Ilyen tekintetben a konverzi�s oper�tor a konstruktorra hasonl�t.
Ha egy int hely�n egy Tiny szerepel, akkor arra a helyre a megfelelo int �rt�k fog
ker�lni:
int main()
{
Tiny c1 = 2;
Tiny c2 = 62;
Tiny c3 = c2-c1; // c3 = 60
Tiny c4 = c3; // nincs tartom�nyellenorz�s (nem sz�ks�ges)
int i = c1+c2; // i = 64
c1 = c1+c2; // tartom�nyhiba: c1 nem lehet 64
i = c3-64; // i = -4
c2 = c3-64; // tartom�nyhiba: c2 nem lehet -4
c3 = c4; // nincs tartom�nyellenorz�s (nem sz�ks�ges)
}
362 Absztrakci�s m�dszerek
A konverzi�s f�ggv�nyek k�l�n�sen hasznosak olyan adatszerkezetek kezel�sekor,
amelyekn
�l az adatoknak (a konverzi�s oper�tor �ltal defini�lt) kiolvas�sa egyszeru
feladat, ellent
�tben az �rt�kad�ssal �s a kezdo�rt�k-ad�ssal.
Az istream �s ostream t�pusok egy konverzi� seg�ts�g�vel t�mogatj�k az al�bbihoz
hasonl
� vez�rl�si szerkezeteket:
while (cin>>x) cout<<x;
A cin>>x bemeneti muvelet egy istream& referenci�t ad vissza, amely automatikusan
a cin
objektum �llapot�t t�kr�zo �rt�kre alak�t�dik. Ezt azut�n a while utas�t�s
ellenorzi
(�21.3.3.). �ltal�ban azonban nem j� �tlet adatveszt�ssel j�r� automatikus
konverzi�t meghat
�rozni k�t t�pus k�z�tt.
C�lszeru takar�koskodni a konverzi�s oper�torok bevezet�s�vel. Ha t�l sok van
belol�k,
az a kifejez�sek t�bb�rtelmus�g�hez vezethet. A t�bb�rtelmus�get mint hib�t jelzi
ugyan
a ford�t�program, de kik�sz�b�lni f�rads�gos lehet. Tal�n a legjobb elj�r�s az, ha
kezdetben
neves�tett f�ggv�nyekkel v�geztetj�k az �talak�t�st (p�ld�ul X::make_int()). Ha
k�sobb
valamelyik ilyen f�ggv�ny annyira n�pszeru lesz, hogy alkalmaz�sa nem .eleg�ns.
t�bb�,
akkor kicser�lhetj�k az X::operator int() konverzi�s oper�torra.
Ha vannak felhaszn�l�i konverzi�k �s felhaszn�l�i oper�torok is, lehets�ges, hogy
t�bb�rtelm
us�g l�p fel a felhaszn�l�i �s a be�p�tett oper�torok k�z�tt:
int operator+(Tiny,Tiny);
void f(Tiny t, int i)
{
t+i; // hiba, t�bb�rtelmu: operator+(t,Tiny(i)) vagy int(t)+i ?
}
Ez�rt vagy felhaszn�l�i konverzi�kra �p�ts�nk, vagy felhaszn�l�i oper�torokra, de
ne mindkett
ore.
11.4.1. T�bb�rtelmus�g
Egy X oszt�ly� objektum �rt�kad�sa egy V t�pus� �rt�kkel akkor megengedett, ha van
olyan
X::operator=(Z) �rt�kad� oper�tor, amely szerint V t�pus egyben Z is, vagy ha van
egy egyedi
konverzi� V-rol Z-re. A kezdeti �rt�kad�sn�l hasonl� a helyzet.
11. Oper�torok t�lterhel�se 363
Bizonyos esetekben a k�v�nt t�pus� �rt�ket konstruktorok �s konverzi�s oper�torok
ism�-
telt alkalmaz�s�val �ll�thatjuk elo. Ezt a helyzetet k�zvetlen konverzi�val kell
megoldani; az
automatikus felhaszn�l�i konverzi�knak csak egy szintje megengedett. N�ha a k�v�nt
t�pus
� �rt�k t�bbf�lek�ppen is l�trehozhat�, ez pedig hiba:
class X { /* ... */ X(int); X(char*); };
class Y { /* ... */ Y(int); };
class Z { /* ... */ Z(X); };
X f(X);
Y f(Y);
Z g(Z);
void k1()
{
f(1); // hiba: t�bb�rtelmu f(X(1)) vagy f(Y(1))?
f(X(1)); // rendben
f(Y(1)); // rendben
g("Mack"); // hiba: k�t felhaszn�l�i konverzi� sz�ks�ges; g(Z(X("Mack")))-et
// nem pr�b�ltuk
g(X("Doc")); // rendben: g(Z(X("Doc")))
g(Z("Suzy")); // rendben: g(Z(X("Suzy")))
}
A felhaszn�l�i konverzi�kat a ford�t�program csak akkor veszi figyelembe, ha
sz�ks�gesek
egy h�v�s felold�s�hoz:
class XX { /* ... */ XX(int); };
void h(double);
void h(XX);
void k2()
{
h(1); // h(double(1)) vagy h(XX(1))? h(double(1))!
}
A h(1) h�v�s a h(double(1)) h�v�st jelenti, mert ehhez csak egy szabv�nyos (�s nem
felhaszn
�l�i) konverzi�ra van sz�ks�g (�7.4). A konverzi�s szab�lyok se nem a
legegyszerubben
megval�s�that�, se nem a legegyszerubben le�rhat�, de nem is az elk�pzelheto
leg�ltal�nosabb
szab�lyok. Viszont viszonylag biztons�gosak �s alkalmaz�sukkal kev�sb� fordulnak
elo meglepo eredm�nyek. A programoz�nak sokkal k�nnyebb egy t�bb�rtelmus�get
feloldani,
mint megtal�lni egy hib�t, amit egy nem sejtett konverzi� alkalmaz�sa okoz.
364 Absztrakci�s m�dszerek
Az elemz�s sor�n alkalmazott szigor�an .alulr�l felfel�. val� halad�s elv�bol az
is k�vetkezik,
hogy a visszat�r�si �rt�ket nem vessz�k figyelembe a t�lterhel�sek felold�sakor:
class Quad {
public:
Quad(double);
// ...
};
Quad operator+(Quad,Quad);
void f(double a1, double a2)
{
Quad r1 = a1+a2; // k�tszeres pontoss�g� �sszead�s
Quad r2 = Quad(a1)+a2; // Quad aritmetika kik�nyszer�t�se
}
Ezen tervez�si m�d v�laszt�s�nak egyik oka, hogy a szigor� .alulr�l felfel�. val�
halad�s elve
�rthetobb, a m�sik pedig az, hogy nem a ford�t�program dolga eld�nteni, milyen
fok�
pontoss�got akar a programoz� egy �sszead�sn�l.
Ha egy kezdeti vagy egyszeru �rt�kad�s mindk�t oldal�nak eldolt a t�pusa, akkor az
�rt�kad
�s felold�sa ezen t�pusok figyelembe v�tel�vel t�rt�nik:
class Real {
public:
operator double();
operator int();
// ...
};
void g(Real a)
{
double d = a; // d = a.double();
int i = a; // i = a.int();
d = a; // d = a.double();
i = a; // i = a.int();
}
Az elemz�s itt is alulr�l felfel� t�rt�nik, egyszerre csak egy oper�tornak �s
param�tereinek
figyelembe v�tel�vel.
11. Oper�torok t�lterhel�se 365
11.5. Bar�t f�ggv�nyek
Amikor egy f�ggv�nyt egy oszt�ly tagjak�nt adunk meg, h�rom, logikailag k�l�nb�zo
dolgot
jelz�nk:
1. A f�ggv�ny hozz�f�rhet az oszt�ly deklar�ci�j�nak priv�t r�szeihez.
2. A f�ggv�ny az oszt�ly hat�k�r�be tartozik.
3. A f�ggv�nyt az oszt�ly egy objektum�ra kell megh�vni (egy this mutat� �ll
a rendelkez�s�re).
Ha egy tagf�ggv�nyt static-k�nt hat�rozunk meg (�10.2.4), akkor ez csak az elso
k�t tulajdons
�got jelenti; ha friend-k�nt (.bar�tk�nt.), csak az elsot.
Defini�ljunk p�ld�ul egy Matrix-ot egy Vector-ral szorz� oper�tort. Term�szetesen
mind
a Matrix, mind a Vector oszt�ly alkalmazza az adatrejt�s elv�t, �s csak
tagf�ggv�nyeiken kereszt
�l kezelhetj�k oket. A szorz�st megval�s�t� f�ggv�ny azonban nem lehet mindk�t
oszt
�ly tagja. Nem is akarunk �ltal�nos, alacsonyszintu hozz�f�r�st megengedni, hogy
minden
felhaszn�l� �rhassa �s olvashassa a Matrix �s Vector oszt�lyok teljes
adat�br�zol�s�t. Ahhoz,
hogy ezt elker�lj�k, a * oper�tort mindk�t oszt�lyban friend (.bar�t.)
f�ggv�nyk�nt hat�-
rozzuk meg:
class Matrix;
class Vector {
float v[4];
// ...
friend Vector operator*(const Matrix&, const Vector&);
};
class Matrix {
Vector v[4];
// ...
friend Vector operator*(const Matrix&, const Vector&);
};
Vector operator*(const Matrix& m, const Vector& v)
{
Vector r;
for (int i = 0; i<4; i++) { // r[i] = m[i] * v;
r.v[i] = 0;
for (int j = 0; j<4; j++) r.v[i] += m.v[i].v[j] * v.v[j];
}
return r;
}
366 Absztrakci�s m�dszerek
A friend deklar�ci�t az oszt�ly priv�t �s nyilv�nos r�sz�be is tehetj�k. A
tagf�ggv�nyekhez
hasonl�an a bar�t f�ggv�nyeket is az oszt�ly deklar�ci�j�ban adjuk meg, �gy
ugyanolyan
m�rt�kben hozz�tartoznak az oszt�ly fel�let�hez, mint a tagf�ggv�nyek.
Egy oszt�ly tagf�ggv�nye lehet egy m�sik oszt�ly bar�t f�ggv�nye:
class List_iterator {
// ...
int* next();
};
class List {
friend int* List_iterator::next();
// ...
};
Nem szokatlan helyzet, hogy egy oszt�ly �sszes tagf�ggv�nye egy m�sik oszt�ly
.bar�tja..
Ennek jelz�s�re egy r�vid�t�s szolg�l:
class List {
friend class List_iterator;
// ...
};
E deklar�ci� hat�s�ra a List_iterator oszt�ly �sszes tagf�ggv�nye a List oszt�ly
bar�t f�ggv�-
nye lesz.
Vil�gos, hogy friend oszt�lyokat csak szorosan �sszetartoz� fogalmak kifejez�s�re
szabad
haszn�lnunk. Sz�mos esetben viszont v�laszthatunk, hogy egy oszt�lyt tag
(be�gyazott oszt
�ly) vagy nem tag bar�tk�nt adunk meg (�24.4).
11.5.1. A bar�t f�ggv�nyek el�r�se
A tagf�ggv�nyek deklar�ci�j�hoz hasonl�an a friend deklar�ci�k sem vezetnek be �j
nevet
a tartalmaz� hat�k�rbe:
class Matrix {
friend class Xform;
friend Matrix invert(const Matrix&);
// ...
};
Xform x; // hiba: a hat�k�rben nincs Xform
Matrix (*p)(const Matrix&) = &invert; // hiba: a hat�k�rben nincs invert()
11. Oper�torok t�lterhel�se 367
Nagy programok �s oszt�lyok eset�ben elony�s, ha egy oszt�ly nem ad hozz� titokban
�j
neveket a tartalmaz� hat�k�rh�z, azokn�l a sablon oszt�lyokn�l pedig, amelyek t�bb
k�-
l�nb�zo k�rnyezetben p�ld�nyos�that�k (13. fejezet), ez kifejezetten fontos.
A bar�t (friend) oszt�lyt elozoleg meg kell adnunk a tartalmaz� hat�k�rben vagy ki
kell fejten
�nk az oszt�lyt k�zvetlen�l tartalmaz� nem oszt�ly t�pus� hat�k�rben. A
k�zvetlen�l
tartalmaz� n�vt�r hat�k�r�n k�v�li neveket nem vesz�nk figyelembe:
class AE { /* ... */ }; // nem "bar�tja" Y-nak
namespace N {
class X { /* ... */ }; // Y "bar�tja"
class Y {
friend class X;
friend class Z;
friend class AE;
};
class Z { /* ... */ }; // Y "bar�tja"
}
A bar�t f�ggv�nyeket ugyan�gy megadhatjuk pontosan, mint a bar�t oszt�lyokat, de
el�rhetj
�k param�tereik alapj�n is (�8.2.6), m�g akkor is, ha nem a k�zvetlen�l tartalmaz�

hat�k�rben adtuk meg:


void f(Matrix& m)
{
invert(m); // a Matrix "bar�t" invert()-je
}
Ebbol k�vetkezik, hogy egy bar�t f�ggv�nyt vagy egy tartalmaz� hat�k�rben kell
k�zvetlen
�l megadnunk, vagy az oszt�ly�nak megfelelo param�terrel kell rendelkeznie, m�sk�-

l�nben nem h�vhatjuk meg:


// a hat�k�rben nincs f()
class X {
friend void f(); // �rtelmetlen
friend void h(const X&); // param�tere alapj�n megtal�lhat�
};
void g(const X& x)
{
f(); // a hat�k�rben nincs f()
h(x); // X h() "bar�tja"
}
368 Absztrakci�s m�dszerek
11.5.2. Bar�tok �s tagf�ggv�nyek
Mikor haszn�ljunk bar�t f�ggv�nyt �s mikor jobb v�laszt�s egy tagf�ggv�ny egy
muvelet sz�-
m�ra? Az elso szempont egy oszt�lyn�l az, hogy min�l kevesebb f�ggv�ny �rje el
k�zvetlen
�l az adat�br�zol�st �s hogy az adatlek�rdez�st a seg�df�ggv�nyek megfelelo
k�r�vel t�-
mogassuk. Ez�rt az elsodleges k�rd�s nem az, hogy .ez a f�ggv�ny tag legyen,
statikus tag
vagy bar�t?., hanem az, hogy .t�nyleg sz�ks�ge van-e az �br�zol�s el�r�s�re?.
�ltal�ban kevesebb
f�ggv�nynek van erre t�nylegesen sz�ks�ge, mint elso r�n�z�sre gondoln�nk.
Bizonyos muveleteknek tagoknak kell lenni�k: p�ld�ul a konstruktoroknak,
destruktoroknak
�s a virtu�lis f�ggv�nyeknek (�12.2.6). Sokszor azonban van m�rlegel�si leheto-
s�g. Mivel egy tagf�ggv�ny neve az oszt�lyra n�zve lok�lisnak sz�m�t, a f�ggv�nyt
ink�bb
tagf�ggv�nyk�nt adjuk meg, hacsak nem sz�l valamilyen �rv amellett, hogy nem tag
f�ggv
�ny legyen.
Vegy�nk egy X oszt�lyt, amely egy muvelet k�l�nf�le m�dozatait jelen�ti meg:
class X {
// ...
X(int);
int m1();
int m2() const;
friend int f1(X&);
friend int f2(const X&);
friend int f3(X);
};
A tagf�ggv�nyeket csak az adott oszt�ly objektumaira alkalmazhatjuk; felhaszn�l�i
�talak�-
t�st a ford�t� nem v�gez:
void g()
{
99.m1(); // hiba: nem pr�b�ltuk X(99).m1()-et
99.m2(); // hiba: nem pr�b�ltuk X(99).m2()-ot
}
Az X(int) �talak�t�st a ford�t� nem alkalmazza, hogy a 99-bol X t�pus� objektumot
csin�ljon.
Az f1() glob�lis f�ggv�ny hasonl� tulajdons�ggal rendelkezik, mert nem const
referencia
param�terekre a ford�t� nem alkalmaz felhaszn�l�i �talak�t�st (�5.5, �11.3.5). Az
f2() �s f3()
param�tereire azonban alkalmazhat� ilyen:
11. Oper�torok t�lterhel�se 369
void h()
{
f1(99); // hiba: nem pr�b�ltuk f1(X(99))-et
f2(99); // rendben: f2(X(99));
f3(99); // rendben: f3(X(99));
}
Ez�rt egy, az objektum �llapot�t megv�ltoztat� muvelet vagy tag legyen, vagy pedig
nem
const referencia (vagy nem const mutat�) param�teru glob�lis f�ggv�ny. Olyan
muveletet,
amelynek bal�rt�kre van sz�ks�ge, ha alapveto adatt�pusra alkalmazzuk (=, *=, ++
stb.),
a legterm�szetesebb m�don felhaszn�l�i t�pus tagf�ggv�nyek�nt defini�lhatunk.
Megford�tva: ha egy muvelet �sszes operandusa automatikusan konvert�lhat�, akkor
a megval�s�t� f�ggv�ny csak olyan nem tag f�ggv�ny lehet, amely param�terk�nt
const
referencia vagy nem referencia t�pust v�r. Ez gyakori eset olyan muveleteket
megval�s�t�
f�ggv�nyekn�l, melyeknek nincs sz�ks�g�k bal�rt�kre, ha alapveto adatt�pusra
alkalmazzuk
azokat (+, -, || stb.). Az ilyen muveleteknek gyakran az operandus-oszt�ly
�br�zol�s�-
nak el�r�s�re van sz�ks�g�k, ez�rt azt�n a k�toperandus� oper�torok a friend
f�ggv�nyek
leggyakoribb forr�sai.
Ha nincs t�puskonverzi�, akkor nincs k�nyszer�to ok arra sem, hogy v�lasszunk a
tagf�ggv
�ny �s a referencia param�tert v�r� bar�t f�ggv�ny k�z�l. Ilyenkor a programoz�
aszerint
d�nthet, hogy melyik form�t r�szes�ti elonyben. A legt�bb embernek p�ld�ul jobban
tetszik
az inv(m) jel�l�s, ha egy m Matrix inverz�rol van sz�, mint a m�sik lehets�ges
m.inv() jel
�l�s. Ha azonban az inv() azt a Matrix-ot invert�lja, amelyikre alkalmaztuk �s nem
egy �j
Matrix-k�nt adja vissza az inverzt, akkor persze csak tagf�ggv�ny lehet.
Ha m�s szempontok nem j�tszanak k�zre, v�lasszunk tagf�ggv�nyt. Nem tudhatjuk,
hogy
valaki nem ad-e majd meg valamikor egy konverzi�s oper�tort, �s azt sem l�thatjuk
elore,
hogy egy j�vobeli m�dos�t�s nem v�ltoztatja-e meg az objektum �llapot�t. A
tagf�ggv�nyh
�v�si forma vil�goss� teszi a felhaszn�l� sz�m�ra, hogy az objektum �llapota
megv�ltozhat;
referencia param�ter haszn�lata eset�n ez sokkal kev�sb� nyilv�nval�. Tov�bb�
sokkal
r�videbbek a kifejez�sek egy tagf�ggv�ny t�rzs�ben, mint a k�lso f�ggv�nybeli
megfelelo-
ik; egy nem tag f�ggv�nynek meghat�rozott param�terre van sz�ks�ge, m�g a
tagf�ggv�ny
automatikusan haszn�lhatja a this mutat�t. Ezenk�v�l, mivel a tagf�ggv�nyek neve
az oszt
�lyra n�zve lok�lisnak sz�m�t, a k�lso f�ggv�nyek neve hosszabb szokott lenni.
370 Absztrakci�s m�dszerek
11.6. Nagy objektumok
A complex oszt�ly muveleteinek param�tereit complex t�pus�k�nt hat�roztuk meg. Ez
azt
jelenti, hogy a param�terek minden muveletn�l lem�sol�dnak. K�t double m�sol�sa
.k�lts
�ges. muvelet lehet ugyan, de val�sz�nuleg .olcs�bb., mint egy p�r mutat��. Nem
minden
oszt�lynak van azonban k�nyelmesen kicsi �br�zol�sa. A nagym�rvu m�sol�sokat elker
�lendo, megadhatunk referencia t�pus� param�tereket kezelo f�ggv�nyeket:
class Matrix {
double m[4][4];
public:
Matrix();
friend Matrix operator+(const Matrix&, const Matrix&);
friend Matrix operator*(const Matrix&, const Matrix&);
};
A referenci�k alkalmaz�sa nagy objektumokra is lehetov� teszi a szok�sos
aritmetikai mu-
veletek haszn�lat�t, nagym�rvu m�sol�sok n�lk�l is. Mutat�kat nem haszn�lhatunk,
mert
a mutat�ra alkalmazott oper�torok jelent�s�t nem v�ltoztathatjuk meg. Az
�sszead�st �gy
defini�lhatn�nk:
Matrix operator+(const Matrix& arg1, const Matrix& arg2)
{
Matrix sum;
for (int i=0; i<4; i++)
for (int j=0; j<4; j++)
sum.m[i][j] = arg1.m[i][j] + arg2.m[i][j];
return sum;
}
Ez az operator+() az operandusokat referenci�kon kereszt�l �ri el, de objektum-
�rt�ket ad
vissza. Referenci�t visszaadni hat�konyabbnak tunhet:
class Matrix {
// ...
friend Matrix& operator+(const Matrix&, const Matrix&);
friend Matrix& operator*(const Matrix&, const Matrix&);
};
Ez szab�lyos k�d, de egy mem�ria-lefoglal�si probl�m�t okoz. Minthogy a
f�ggv�nybol az
eredm�nyre vonatkoz� referenci�t adjuk vissza, az eredm�ny maga nem lehet
automatikus
v�ltoz� (�7.3). Mivel egy muveletet t�bbsz�r is alkalmazhatunk egy kifejez�sen
bel�l, az
11. Oper�torok t�lterhel�se 371
eredm�ny nem lehet lok�lis statikus v�ltoz� sem. Ez�rt azt�n az eredm�nynek
jellemzoen
a szabad t�rban foglaln�nk helyet. A visszat�r�si �rt�k m�sol�sa (v�grehajt�si
idoben, k�d-
�s adatm�retben m�rve) gyakran olcs�bb, mint az objektum szabad t�rba helyez�se �s
onnan
elt�vol�t�sa, �s programozni is sokkal egyszerubb.
Az eredm�ny m�sol�s�nak elker�l�s�re vannak m�dszerek. A legegyszerubb ezek k�z�l
egy statikus objektumokb�l �ll� �tmeneti t�r haszn�lata:
const max_matrix_temp = 7;
Matrix& get_matrix_temp()
{
static int nbuf = 0;
static Matrix buf[max_matrix_temp];
if (nbuf == max_matrix_temp) nbuf = 0;
return buf[nbuf++];
}
Matrix& operator+(const Matrix& arg1, const Matrix& arg2)
{
Matrix& res = get_matrix_temp();
// ...
return res;
}
�gy egy Matrix m�sol�sa csak egy kifejez�s �rt�k�n alapul� �rt�kad�skor t�rt�nik
meg. De
az �g legyen irgalmas, ha olyan kifejez�st tal�ln�nk �rni, amelyhez
max_matrix_temp-n�l
t�bb ideiglenes �rt�k kell!
Hib�kra kevesebb lehetos�get ad� m�dszer, ha a m�trix t�pust csak a t�nyleges
adatot t�rol
� t�pus le�r�jak�nt (handle, �25.7) hat�rozzuk meg. �gy azt�n a m�trixle�r�k �gy
k�pviselhetik
az objektumokat, hogy k�zben a leheto legkevesebb helyfoglal�s �s m�sol�s t�rt�-
nik (�11.12 �s �11.14[18]). Ez az elj�r�s azonban a visszat�r�si �rt�kk�nt
objektumot �s nem
referenci�t vagy mutat�t haszn�l� oper�torokon alapul. Egy m�sik m�dszer
h�romv�ltoz�s
muveletek meghat�roz�s�ra �s azok olyankor automatikusan t�rt�no megh�v�s�ra
t�maszkodik,
amikor olyan kifejez�sek ki�rt�kel�se t�rt�nik, mint a=b+c vagy a+b*i (�21.4.6.3
�s
�22.4.7).
372 Absztrakci�s m�dszerek
11.7. Alapveto oper�torok
�ltal�noss�gban, ha X egy t�pus, akkor az X(const X&) m�sol� konstruktor kezeli
azt az
esetet, amikor egy X t�pus� objektumnak egy ugyanilyen objektumot adunk
kezdo�rt�k�l.
Nem lehet el�gg� hangs�lyozni, hogy a kezdeti �s az egyszeru �rt�kad�s k�l�nb�zo
muveletek
(�10.4.4.1). Ez k�l�n�sen fontos akkor, amikor a destruktorral is sz�molnunk kell.
Ha
az X oszt�lynak van valamilyen nem mag�t�l �rtetodo feladatot . p�ld�ul a szabad
t�rban
lefoglalt mem�ria felszabad�t�s�t . v�gzo destruktora, akkor az oszt�lynak
val�sz�nuleg
sz�ks�ge lesz az objektum l�trehoz�s�t, megsemmis�t�s�t �s m�sol�s�t v�gzo �sszes
f�ggv
�nyre:
class X {
// ...
X(Sometype); // konstruktor: objektumok l�trehoz�sa
X(const X&); // m�sol� konstruktor
X& operator=(const X&); // m�sol� �rt�kad�s: takar�t�s �s m�sol�s
~X(); // destruktor: takar�t�s
};
Ezenk�v�l m�g h�romf�le helyzetben m�sol�dik egy objektum: �tadott f�ggv�nyparam
�terk�nt, f�ggv�ny visszat�r�si �rt�kek�nt, illetve kiv�telk�nt. Ha param�terk�nt
ker
�l �tad�sra, egy addig kezdo�rt�k n�lk�li v�ltoz�, a form�lis param�ter kap
kezdo�rt�ket.
Ennek szerepe azonos az egy�b kezdeti �rt�kad�sok�val. Ugyanez igaz a visszat�r�si
�rt�kre
�s a kiv�telre is, m�g ha kev�sb� nyilv�nval� is. Ilyen esetben a m�sol�
konstruktor v�gzi
a munk�t:
string g(string arg) // string �rt�k szerint �tadva (m�sol� konstruktor
haszn�lat�val)
{
return arg; // string visszaad�sa (m�sol� konstruktor haszn�lat�val)
}
int main ()
{
string s = "Newton"; // string kezdo�rt�ket kap (m�sol� konstruktor haszn�lat�val)

s = g(s);
}
Vil�gos, hogy az s v�ltoz� �rt�k�nek "Newton"-nak kell lennie a g() megh�v�sa
ut�n. Nem
neh�z feladat az s �rt�k�nek egy m�solat�t az arg form�lis param�terbe m�solni; a
string
oszt�ly m�sol� konstruktor�nak h�v�sa ezt megteszi. Amikor g() visszaadja a
visszat�r�si �rt
�ket, a string(const string&) �jabb h�v�sa k�vetkezik, amikor egy olyan ideiglenes

11. Oper�torok t�lterhel�se 373


v�ltoz� kap �rt�ket, amely azt�n az s-nek ad �rt�ket. Hat�konys�gi okokb�l az
egyik (de
csak az egyik) m�sol�st gyakran elhagyhatjuk. Az ideiglenes v�ltoz�k azt�n persze
a string::~string() destruktor seg�ts�g�vel megsemmis�lnek (�10.4.10).
Ha a programoz� nem ad meg m�sol� konstruktort vagy m�sol� �rt�kad�st egy oszt�ly
sz�-
m�ra, a ford�t�program hozza l�tre a hi�nyz� f�ggv�nyt vagy f�ggv�nyeket
(�10.2.5).
Ez egyben azt is jelenti, hogy a m�sol� muveletek nem �r�klodnek (�12.2.3).
11.7.1. Explicit konstruktorok
Alap�rtelmez�s szerint az egyparam�teru konstruktor egyben automatikus konverzi�t
is jelent.
Bizonyos t�pusok sz�m�ra ez ide�lis:
complex z = 2; // z kezdeti �rt�kad�sa complex(2)-vel
M�skor viszont nem k�v�natos �s hib�k forr�sa lehet:
string s = 'a'; // s karakterl�nc, int('a') sz�m� elemmel
Nagyon val�sz�nutlen, hogy az s-et megad� programoz� ezt akarta volna.
Az automatikus konverzi�kat az explicit kulcssz� alkalmaz�s�val akad�lyozhatjuk
meg. Vagyis
egy explicit-k�nt megadott konstruktort csak k�zvetlen m�don lehet megh�vni. �gy
ahol elvileg egy m�sol� konstruktorra van sz�ks�g (�11.3.4), ott az explicit
konstruktor nem
h�v�dik meg automatikusan:
class String {
// ...
explicit String(int n); // n b�jt lefoglal�sa
String(const char* p);// a kezdo�rt�k (p) egy C st�lus� karakterl�nc
};
String s1 = 'a'; // hiba: nincs automatikus char->String �talak�t�s
String s2(10); // rendben: String 10 karakternyi hellyel
String s3 = String(10); // rendben: String 10 karakternyi hellyel
String s4 = "Brian"; // rendben: s4 = String("Brian")
String s5("Fawlty");
void f(String);
String g()
{
374 Absztrakci�s m�dszerek
f(10); // hiba: nincs automatikus int ->String �talak�t�s
f(String(10));
f("Arthur"); // rendben: f(String("Arthur"))
f(s1);
String* p1 = new String("Eric");
String* p2 = new String(10);
return 10; // hiba: nincs automatikus int ->String �talak�t�s
}
A k�l�nbs�g ak�z�tt, hogy
String s1 = 'a'; // hiba: nincs automatikus char ->String �talak�t�s
�s ak�z�tt, hogy
String s2(10); // rendben: karakterl�nc 10 karakternyi hellyel
csek�lynek tunhet, de igazi k�dban kev�sb� az, mint kital�lt p�ld�kban.
A Date oszt�lyban egy sima int-et haszn�ltunk az �v �br�zol�s�ra (�10.3). Ha a
Date oszt�ly
l�tfontoss�g� szerepet j�tszott volna, akkor bevezethett�k volna a Year oszt�lyt,
hogy ford
�t�si idoben szigor�bb ellenorz�sek t�rt�njenek:
class Year {
int y;
public:
explicit Year(int i) : y(i) { } // Year l�trehoz�sa int-bol
operator int() const { return y; } // �talak�t�s Year-rol int-re
};
class Date {
public:
Date(int d, Month m, Year y);
// ...
};
Date d3(1978,feb,21); // hiba: a 21 nem Year t�pus�
Date d4(21,feb,Year(1978)); // rendben
A Year egy egyszeru .csomagol�. (beburkol�, wrapper) oszt�ly az int k�r�l. Az
operator
int()-nek k�sz�nhetoen a Year automatikusan mindenhol int-t� alakul, ahol
sz�ks�ges. Az-
�ltal, hogy a konstruktort explicit-k�nt adtuk meg, biztos�tottuk, hogy az int-nek
Year-r� va-
11. Oper�torok t�lterhel�se 375
l� alak�t�sa csak ott t�rt�nik meg, ahol ezt k�rj�k �s a .v�letlen. �rt�kad�sok a
ford�t�skor
kider�lnek. Minthogy a Year tagf�ggv�nyeit k�nnyu helyben kifejtve (inline)
ford�tani, a fut
�si ido �s a sz�ks�ges t�rhely n�veked�s�tol sem kell tartanunk.
Hasonl� m�dszer tartom�ny (intervallum) t�pusokra (�25.6.1) is alkalmazhat�.
11.8. Indexel�s
Oszt�ly t�pus� objektumoknak az operator [ ] (subscripting) f�ggv�ny seg�ts�g�vel
adhatunk
.sorsz�mot. (indexet). Az operator[ ] m�sodik param�tere (az index) b�rmilyen
t�pus�
lehet, �gy azt�n vektorokat, asszociat�v t�mb�ket stb. is defini�lhatunk.
P�ldak�nt �rjuk most �jra a �5.5-beli p�ld�t, amelyben egy asszociat�v t�mb
seg�ts�g�vel �rtunk
egy f�jlban a szavak elofordul�s�t megsz�mol� kis programot. Akkor egy f�ggv�nyt
haszn�ltunk, most egy asszociat�v t�mb t�pust:
class Assoc {
struct Pair {
string name;
double val;
Pair(string n ="", double v =0) :name(n), val(v) { }
};
vector<Pair> vec;
Assoc(const Assoc&); // a m�sol�st megakad�lyozand� priv�t
Assoc& operator=(const Assoc&); // a m�sol�st megakad�lyozand� priv�t
public:
Assoc() {}
const double& operator[ ](const string&);
double& operator[ ](string&);
void print_all() const;
};
Az Assoc t�pus� objektumok Pair-ek vektor�t tartalmazz�k. A megval�s�t�sban
ugyanazt az
egyszeru �s nem t�l hat�kony keres�si m�dszert haszn�ljuk, mint az �5.5 pontban:
double& Assoc::operator[ ](string& s)
// megkeress�k s-t; ha megtal�ltuk, visszaadjuk az �rt�k�t; ha nem, �j Pair-t
hozunk
// l�tre �s az alap�rtelmezett 0 �rt�ket adjuk vissza
{
376 Absztrakci�s m�dszerek
for (vector<Pair>::iterator p = vec.begin(); p!=vec.end(); ++p)
if (s == p->name) return p->val;
vec.push_back(Pair(s,0)); // kezdo�rt�k: 0
return vec.back().val; // az utols� elem visszaad�sa (�16.3.3)
}
Minthogy az Assoc objektum �br�zol�sa k�v�lrol nem �rheto el, sz�ks�g van egy
kimeneti
f�ggv�nyre:
void Assoc::print_all() const
{
for (vector<Pair>::const_iterator p = vec.begin(); p!=vec.end(); ++p)
cout << p->name << ": " << p->val << '\n';
}
V�g�l meg�rhatjuk a foprogram egyszeru v�ltozat�t:
int main() // szavak elofordul�s�nak megsz�ml�l�sa a bemeneten
{
string buf;
Assoc vec;
while (cin>>buf) vec[buf]++;
vec.print_all();
}
Az asszociat�v t�mb �tlet�t tov�bbfejleszti a �17.4.1 pont.
Az operator[ ]() f�ggv�nyeknek tagf�ggv�nynek kell lenni�k.
11.9. F�ggv�nyh�v�s
A f�ggv�nyh�v�s (function call), vagyis a kifejez�s(kifejez�s-lista) jel�l�s �gy
tekintheto,
mint egy k�toperandus� muvelet, ahol a kifejez�s a bal oldali, a kifejez�s-lista
pedig a jobb
oldali operandus. A () h�v� oper�tor a t�bbi oper�torhoz hasonl� m�don
t�lterhelheto.
Az operator()() param�terlist�j�nak ki�rt�kel�se �s ellenorz�se a szok�sos
param�ter-�tad�-
si szab�lyok szerint t�rt�nik. A f�ggv�nyh�v� oper�tor t�lterhel�se elsosorban
olyan t�pusok
l�trehoz�sakor hasznos, amelyeknek csak egy muvelet�k van vagy �ltal�ban csak egy
muvelet�k haszn�latos.
11. Oper�torok t�lterhel�se 377
A ( ) h�v� muvelet legnyilv�nval�bb �s tal�n legfontosabb alkalmaz�sa az, hogy a
valamik
�ppen f�ggv�nyk�nt viselkedo objektumokat f�ggv�nyk�nt h�vhassuk meg. Egy f�ggv
�nyk�nt viselkedo objektumot f�ggv�nyszeru vagy egyszeruen f�ggv�nyobjektumnak h�-

vunk (�18.4). Az ilyen f�ggv�nyobjektumok fontosak, mert lehetov� teszik, hogy


olyan k�-
dot �rjunk, amelyben valamilyen nem mag�t�l �rtetodo muveletet param�terk�nt adunk
�t.
A standard k�nyvt�rban p�ld�ul sok olyan algoritmus tal�lhat�, melyek egy
f�ggv�nyt h�vnak
meg egy t�rol� minden elem�re. Vegy�k az al�bbi p�ld�t:
void negate(complex& c) { c = -c; }
void f(vector<complex>& aa, list<complex>& ll)
{
for_each(aa.begin(),aa.end(),negate); // a vektor �sszes elem�nek neg�l�sa
for_each(ll.begin(),ll.end(),negate); // a lista �sszes elem�nek neg�l�sa
}
Ez a vektor �s a lista minden elem�t neg�lja.
Mi lenne, ha a lista minden elem�hez complex(2,3)-at akarn�nk hozz�adni? Ezt
k�nnyen
megtehetj�k:
void add23(complex& c)
{
c += complex(2,3);
}
void g(vector<complex>& aa, list<complex>& ll)
{
for_each(aa.begin(),aa.end(),add23);
for_each(ll.begin(),ll.end(),add23);
}
Hogyan tudn�nk egy olyan f�ggv�nyt �rni, melyet t�bbsz�r megh�vva egy-egy
tetszoleges
�rt�ket adhatunk az elemekhez? Olyasmire van sz�ks�g�nk, aminek megadhatjuk a
k�v�nt
�rt�ket �s ut�na ezt az �rt�ket haszn�lja fel minden h�v�sn�l. Ez a f�ggv�nyeknek
nem term
�szetes tulajdons�ga. Jellemzo megold�sk�nt valahova a f�ggv�nyt k�r�lvevo
k�rnyezetbe
helyezve adjuk �t az �rt�ket, ami nem .tiszta. megold�s. Viszont �rhatunk egy
oszt�lyt,
amely a megfelelo m�don muk�dik:
class Add {
complex val;
public:
Add(complex c) { val = c; } // az �rt�k ment�se
Add(double r, double i) { val = complex(r,i); }
void operator()(complex& c) const { c += val; } // a param�ter n�vel�se az
�rt�kkel
};
378 Absztrakci�s m�dszerek
Egy Add oszt�ly� objektum kezdo�rt�k�nek egy komplex sz�mot adunk, majd a ( )
muveletet
v�grehajtatva ezt a sz�mot hozz�adjuk a param�terhez:
void h(vector<complex>& aa, list<complex>& ll, complex z)
{
for_each(aa.begin(),aa.end(),Add(2,3));
for_each(ll.begin(),ll.end(),Add(z));
}
Ez a t�mb minden elem�hez complex(2,3)-at fog adni, a lista elemeihez pedig z-t.
Vegy�k
�szre, hogy Add(z) egy olyan objektumot hoz l�tre, amelyet azt�n a for_each
ism�telten felhaszn
�l. Nem egyszeruen egy egyszer vagy t�bbsz�r megh�vott f�ggv�nyrol van sz�.
A t�bbsz�r megh�vott f�ggv�ny az Add(z) operator()() f�ggv�nye.
Mindez az�rt muk�dik, mert a for_each egy sablon (template), amely a ( ) muveletet
alkalmazza
a harmadik param�ter�re, an�lk�l, hogy t�rodne vele, mi is igaz�b�l a harmadik
param�ter:
template<class Iter, class Fct> Fct for_each(Iter b, Iter e, Fct f)
{
while (b != e) f(*b++);
return f;
}
Elso pillant�sra ez a m�dszer furcs�nak tunhet, de egyszeru, hat�kony, �s nagyon
hasznos
(l�sd �3.8.5, �18.4).
Az operator()() tov�bbi n�pszeru alkalmaz�sai a r�szl�ncok k�pz�s�re vagy t�bb
dimenzi-
�s t�mb�k indexel�s�re (�22.4.5) val� haszn�lat.
Az operator()()-nak tagf�ggv�nynek kell lennie.
11.10. Indirekci�
A -> indirekci� (.hivatkoz�stalan�t�s., dereferencing) oper�tort egyparam�teru,
ut�tagk�nt
haszn�lt oper�tork�nt defini�lhatjuk. Legyen adott egy oszt�ly:
class Ptr {
// ...
X* operator->();
};
11. Oper�torok t�lterhel�se 379
Ekkor a Ptr oszt�ly� objektumokat az X oszt�ly tagjainak el�r�s�re haszn�lhatjuk,
a mutat
�khoz nagyon hasonl� m�don:
void f(Ptr p)
{
p->m = 7; // (p.operator->())->m = 7
}
A p objektumnak a p.operator->() mutat�v� val� �talak�t�sa nem f�gg att�l, hogy
milyen m
tagra mutat. Az operator->() ebben az �rtelemben egyoperandus� ut�tag-oper�tor,
formai
k�vetelm�nyei viszont nem �jak, �gy a tagnevet ki kell �rni ut�na:
void g(Ptr p)
{
X* q1 = p->; // szintaktikus hiba
X* q2 = p.operator->(); // rendben
}
A ->() oper�tor t�lterhel�s�nek fo alkalmaz�sa az okos vagy intelligens mutat�
(smart pointer)
t�pusok l�trehoz�sa, azaz olyan objektumok�, amelyek mutat�k�nt viselkednek, de
r�ad�sul valamilyen tennival�t v�geznek, valah�nyszor egy objektumot �rnek el
rajtuk kereszt
�l. P�ld�ul l�trehozhatunk egy Rec_ptr oszt�lyt, amellyel a lemezen t�rolt Rec
oszt�ly�
objektumok �rhetoek el. A Rec_ptr konstruktora egy nevet v�r, melynek seg�ts�g�vel
a keresett
objektum a lemezen megkeresheto, a Rec_ptr::operator->() f�ggv�ny a mem�ri�ba
t�lti az objektumot, amikor azt a Rec_ptr-en kereszt�l el akarjuk �rni, a Rec_ptr
destruktora
pedig sz�ks�g eset�n a megv�ltozott objektumot a lemezre �rja:
class Rec_ptr {
const char* identifier;
Rec* in_core_address;
// ...
public:
Rec_ptr(const char* p) : identifier(p), in_core_address(0) { }
~Rec_ptr() { write_to_disk(in_core_address,identifier); }
Rec* operator->();
};
Rec* Rec_ptr::operator->()
{
if (in_core_address == 0) in_core_address = read_from_disk(identifier);
return in_core_address;
}
380 Absztrakci�s m�dszerek
A Rec_ptr-t �gy haszn�lhatjuk:
struct Rec { // a Rec t�pus, amire Rec_ptr mutat
string name;
// ...
};
void update(const char* s)
{
Rec_ptr p(s); // Rec_ptr elo�ll�t�sa s-bol
p->name = "Roscoe"; // s m�dos�t�sa; ha sz�ks�ges, elosz�r beolvassa a lemezrol
// ...
}
Term�szetesen az igazi Rec_ptr egy sablon lenne, a Rec t�pus pedig param�ter. Egy
val�s�-
gos program hibakezel�st is tartalmazna �s kev�sb� na�v m�don kezeln� a lemezt.
K�z�ns�ges mutat�k eset�ben a -> haszn�lata egyen�rt�ku az egyv�ltoz�s * �s [ ]
haszn�-
lat�val. Ha adott egy t�pus:
Y* p;
akkor teljes�l a k�vetkezo:
p->m == (*p).m == p[0].m
Ahogy m�r megszokhattuk, a felhaszn�l�i oper�torokra n�zve ez nem biztos�tott.
Sz�ks�g
eset�n persze gondoskodhatunk errol:
class Ptr_to_Y {
Y* p;
public:
Y* operator->() { return p; }
Y& operator*() { return *p; }
Y& operator[ ](int i) { return p[i]; }
};
Ha egy oszt�lyban t�bb ilyen oper�tort hat�rozunk meg, akkor tan�csos lehet ezt
�gy tenni,
hogy a fenti egyen�rt�kus�g teljes�lj�n, ugyan�gy, mint ahogy ++x �s x+=1 is j�,
ha
x=x+1-gyel azonos hat�ssal j�r, ha x egy olyan oszt�ly� v�ltoz�, amelyben a ++,
+=, + mu-
veletek �rtelmezettek.
11. Oper�torok t�lterhel�se 381
A -> oper�tor t�lterhelhetos�ge nem csak kis k�l�nlegess�g, hanem �rdekes
programok
egy oszt�lya sz�m�ra fontos is, azon okn�l fogva, hogy az indirekci�
(dereferencing) kulcsfogalom,
a -> oper�tor t�lterhel�se pedig tiszta, k�zvetlen �s hat�kony m�dja annak egy
programban val� megjelen�t�s�re. A bej�r�k (iter�torok) (19. fejezet) jellemzo �s
l�nyegi
p�ld�t adnak erre. A -> oper�tor m�sik haszna, hogy korl�tozott, de hasznos m�don
lehet
ov� teszi a C++ nyelvben a deleg�ci�t (�24.2.4).
Az operator-> tagf�ggv�ny kell, hogy legyen. Csak �gy haszn�lhat�, ha mutat�t vagy
olyan
t�pust ad vissza, amelyre a -> alkalmazhat�. Ha egy sablon oszt�ly sz�m�ra adjuk
meg, sokszor
elofordul, hogy nem is ker�l t�nyleges felhaszn�l�sra, ez�rt �sszeru e megszor�t�s
ellen
orz�s�t a t�nyleges haszn�latig elhalasztani.
11.11. N�vel�s �s cs�kkent�s
Amint a programoz� kital�l egy .intelligens mutat�t., sokszor d�nt �gy, hogy ehhez
a ++
n�velo (increment) �s -- cs�kkento (decrement) muvelet is hozz�tartozik, a
be�p�tett t�pusokra
�rtelmezett n�vel�s �s cs�kkent�s mint�j�ra. Ez k�l�n�sen nyilv�nval� �s sz�ks�ges

olyankor, amikor a c�l egy k�z�ns�ges mutat�nak egy okosra val� kicser�l�se, amely
azonos
jelent�s mellett csak n�mi fut�si ideju hiba-ellenorz�ssel van kieg�sz�tve. Vegy�k
p�ld
�ul az al�bbi . egy�bk�nt problematikus . hagyom�nyos programot:
void f1(T a) // hagyom�nyos haszn�lat
{
T v[200];
T* p = &v[0];
p--;
*p = a; // hopp�: 'p' tartom�nyon k�v�li �s nem kaptuk el
++p;
*p = a; // rendben
}
A p mutat�t ki szeretn�nk cser�lni valamilyen Ptr_to_T oszt�ly� objektumra,
amelyre csak akkor
tudjuk alkalmazni az indirekci� oper�tort, ha t�nyleg egy objektumra mutat. Azt is
el szeretn
�nk �rni, hogy p-t csak �gy lehessen n�velni vagy cs�kkenteni, ha t�mb�n bel�li
objektumra
mutat, m�g a n�vel�s vagy cs�kkent�s hat�s�ra is. Valami ilyesmit szeretn�nk
teh�t:
class Ptr_to_T {
// ...
};
382 Absztrakci�s m�dszerek
void f2(T a) // ellenorz�tt
{
T v[200];
Ptr_to_T p(&v[0],v,200);
p--;
*p = a; // fut�si ideju hiba: 'p' tartom�nyon k�v�li
++p;
*p = a; // rendben
}
A n�velo �s cs�kkento oper�torok az egyetlenek a C++ nyelv oper�torai k�z�tt,
amelyek
elotagk�nt (prefix) �s ut�tagk�nt (postfix) egyar�nt haszn�lhat�k. Ez�rt a
Ptr_to_T t�pus
sz�m�ra mindk�t fajta n�velo �s cs�kkento oper�tort defini�lnunk kell:
class Ptr_to_T {
T* p;
T* array;
int size;
public:
Ptr_to_T(T* p, T* v, int s); // csatol�s s m�retu v t�mbh�z, a kezdo�rt�k p
Ptr_to_T(T* p); // csatol�s �n�ll� objektumhoz, a kezdo�rt�k p
Ptr_to_T& operator++(); // elotag
Ptr_to_T operator++(int); // ut�tag
Ptr_to_T& operator--(); // elotag
Ptr_to_T operator--(int); // ut�tag
T& operator*(); // elotag
};
Az int param�terrel jelezz�k a ++ ut�tagk�nt val� alkalmaz�s�t. Mag�t az int-et
nem haszn
�ljuk, csak �l-param�ter, amely az elo- �s ut�tagk�nt val� haszn�lat k�z�tt tesz
k�l�nbs�-
get. K�nnyen megjegyezhetj�k, melyik melyik, ha arra gondolunk, hogy a t�bbi
(aritmetikai
�s logikai) egy param�teru oper�torhoz hasonl�an az �l-param�ter n�lk�li ++ �s --
az
elotagk�nt, a param�teres v�ltozat a .furcsa. ut�tagk�nt val� muk�d�shez kell.
A Prt_to_T oszt�lyt haszn�lva a p�lda egyen�rt�ku az al�bbival:
void f3(T a) // ellenorz�tt
{
T v[200];
Ptr_to_T p(&v[0],v,200);
p.operator--(0);
11. Oper�torok t�lterhel�se 383
p.operator*() = a; // fut�si ideju hiba: 'p' tartom�nyon k�v�li
p.operator++();
p.operator*() = a; // rendben
}
A Prt_to_T oszt�ly kieg�sz�t�se gyakorlatnak marad (�11.14[19]). �tdolgoz�sa olyan
sablonn
�, amely kiv�teleket is haszn�l a fut�si idoben fell�po hib�k jelz�s�re, egy m�sik
gyakorlat
(�14.12[12]). A �13.6.3 egy mutat�sablont mutat be, amely �r�klod�s haszn�lata
mellett
is j�l muk�dik.
11.12. Egy karakterl�nc oszt�ly
�me a String oszt�ly egy val�s�gosabb v�ltozata, amely a c�ljainknak m�g �ppen
megfelel.
Ez a karakterl�nc-oszt�ly t�mogatja az �rt�k szerinti muk�d�st (value semantics,
�rt�k-szemantika),
a karakter�r� �s -olvas� muveleteket, az ellenorz�tt �s ellenorizetlen el�r�st, az

adatfolyam ki- �s bemenetet, a karakterliter�lokat, az egyenlos�gvizsg�l� �s


�sszefuzo mu-
veleteket. A karakterl�ncokat C st�lus�, null�val lez�rt karaktert�mbk�nt t�rolja,
a m�sol�sok
sz�m�nak cs�kkent�s�re pedig hivatkoz�ssz�ml�l�t haszn�l. Egy t�bbet tud� �s/vagy
t�bb
szolg�ltat�st ny�jt� string oszt�ly �r�sa j� gyakorlat (�11.14[7-12]). Ha
megvagyunk vele, eldobhatjuk
a gyakorlatainkat �s haszn�lhatjuk a standard k�nyvt�rbeli string-et (20.
fejezet).
Az �n majdnem val�s�gos String oszt�lyom h�rom seg�doszt�lyt haszn�l: az Srep-et,
hogy
t�bb azonos �rt�ku String is haszn�lhassa ugyanazt az elt�rolt adatot, ha azonos
az �rt�k�k;
a Range-et az �rt�ktartom�ny-megs�rt�si hib�kat jelzo kiv�telek kiv�lt�s�hoz; �s a
Cref-et,
hogy egy �r�s �s olvas�s k�z�tt k�l�nbs�get tevo index-oper�tort t�mogasson:
class String {
struct Srep; // adat�br�zol�s
Srep *rep;
public:
class Cref; // referencia char-ra
class Range { }; // kiv�telkezel�shez
// ...
};
384 Absztrakci�s m�dszerek
A t�bbi taghoz hasonl�an a tagoszt�lyokat (member class, amit gyakran h�vnak
be�gyazott
oszt�lynak, nested class-nak is) deklar�lhatjuk az oszt�lyban, majd k�sobb
kifejthetj�k:
struct String::Srep {
char* s; // mutat� az elemekre
int sz; // karakterek sz�ma
int n; // hivatkoz�ssz�ml�l�
Srep(int nsz, const char* p)
{
n = 1;
sz = nsz;
s = new char[sz+1]; // hely a lez�r� nulla sz�m�ra is
strcpy(s,p);
}
~Srep() { delete[ ] s; }
Srep* get_own_copy() // m�sol�s, ha sz�ks�ges
{
if (n==1) return this;
n--;
return new Srep(sz,s);
}
void assign(int nsz, const char* p)
{
if (sz != nsz) {
delete[ ] s;
sz = nsz;
s = new char[sz+1];
}
strcpy(s,p);
}
private: // a m�sol�s megakad�lyoz�sa
Srep(const Srep&);
Srep& operator=(const Srep&);
};
A String oszt�lynak megvannak a szok�sos konstruktorai, destruktora �s �rt�kad�
muveletei
is:
class String {
// ...
11. Oper�torok t�lterhel�se 385
String(); // x = ""
String(const char*); // x = "abc"
String(const String&); // x = m�sik_karakterl�nc
String& operator=(const char *);
String& operator=(const String&);
~String();
// ...
};
A String oszt�ly �rt�k szerint muk�dik, azaz egy s1=s2 �rt�kad�s ut�n s1 �s s2 k�t
teljesen
k�l�nb�zo karakterl�nc lesz, vagyis ha k�sobb az egyiket m�dos�tjuk, akkor annak
nem
lesz hat�sa a m�sikra. A m�sik megold�s az lenne, ha a String oszt�ly mutat�kkal
dolgozna.
Ekkor az s1=s2 �rt�kad�s ut�n s2 megv�ltoztat�sa s1-et is �rinten�. Ha egy
oszt�lynak
megvannak a hagyom�nyos aritmetikai muveletei, mint a komplex sz�mokkal,
vektorokkal,
m�trixokkal, karakterl�ncokkal v�gzettek, �n elonyben r�szes�tem az �rt�k szerinti

muk�d�st. Ahhoz viszont, hogy ennek t�mogat�sa ne ker�lj�n t�l sokba, a String-et
le-
�r�k�nt �br�zolom, amely az adat�br�zol�sra mutat, amit csak sz�ks�g eset�n kell
m�solni:
String::String() // az alap�rtelmezett �rt�k egy �res karakterl�nc
{
rep = new Srep(0,"");
}
String::String(const String& x) // m�sol� konstruktor
{
x.rep->n++;
rep = x.rep; // az �br�zol�s megoszt�sa
}
String::~String()
{
if (--rep->n == 0) delete rep;
}
String& String::operator=(const String& x) // m�sol� �rt�kad�s
{
x.rep->n++; // v�delem az "st = st" ellen
if (--rep->n == 0) delete rep;
rep = x.rep; // az �br�zol�s megoszt�sa
return *this;
}
A const char* param�teru �l-m�sol� muveletek bevezet�s�vel a karakterliter�lokat
is megengedj
�k:
386 Absztrakci�s m�dszerek
String::String(const char* s)
{
rep = new Srep(strlen(s),s);
}
String& String::operator=(const char* s)
{
if (rep->n == 1) // Srep �jrahasznos�t�sa
rep->assign(strlen(s),s);
else { // �j Srep haszn�lata
rep->n--;
rep = new Srep(strlen(s),s);
}
return *this;
}
Az egyes karakterl�ncokat el�ro oper�torok megtervez�se neh�z, mert az ide�lis
megold�s
az lenne, ha ezek a szok�sos jel�l�st (azaz a [ ]-t) haszn�ln�k, a leheto
leghat�konyabbak
lenn�nek �s a param�ter �rt�k�t is ellenorizn�k. Sajnos, ez a h�rom k�vetelm�ny
nem teljes
�theto egyszerre. �n �gy k�sz�tettem el az oszt�lyt, hogy hat�kony ellenorizetlen
muveleteket
adtam meg (egy kicsit k�nyelmetlenebb jel�l�ssel), illetve kev�sb� hat�kony ellen-

orz�tt elj�r�sokat (a hagyom�nyos jel�l�ssel):


class String {
// ...
void check(int i) const { if (i<0 || rep->sz<=i) throw Range(); }
char read(int i) const { return rep->s[i]; }
void write(int i, char c) { rep=rep->get_own_copy(); rep->s[i]=c; }
Cref operator[ ](int i) { check(i); return Cref(*this,i); }
char operator[ ](int i) const { check(i); return rep->s[i]; }
int size() const { return rep->sz; }
// ...
};
Az �tlet az, hogy a hagyom�nyos [ ] jel�l�ssel az ellenorz�tt el�r�s legyen
biztos�tott a k�-
z�ns�ges felhaszn�l�s sz�m�ra, de a felhaszn�l�nak legyen m�dja egyszerre
v�gign�zni
a teljes tartom�nyt �s a gyorsabb, ellenorizetlen el�r�st haszn�lni:
11. Oper�torok t�lterhel�se 387
int hash(const String& s)
{
int h = s.read(0);
const int max = s.size();
for (int i = 1; i<max; i++) h ^= s.read(i)>>1; // ellenorz�s n�lk�li hozz�f�r�s s-
hez
return h;
}
Neh�z dolog egy oper�tort, p�ld�ul a [ ]-t �gy meghat�rozni, hogy az az �r� �s az
olvas� jelleg
u hozz�f�r�st is t�mogassa, ha nem fogadhat� el az a megold�s, hogy egyszeruen egy

referenci�t adunk vissza, amit azt�n a felhaszn�l� kedve szerint felhaszn�lhat.


Itt p�ld�ul ez
nem lehets�ges, mert a String-et �gy hat�roztam meg, hogy az egyes �rt�kad�ssal,
param�ter-�tad�ssal stb. megadott �rt�ku String-ek ugyanazt a belso �br�zol�st
haszn�lj�k,
m�g az egyik String-et t�nylegesen nem �rj�k: az �rt�k m�sol�sa csak ekkor
t�rt�nik meg.
Ezt a m�dszert �ltal�ban �r�skori m�sol�snak vagy .m�sol�s �r�skor.-nak (copy-on-
write)
h�vj�k. A t�nyleges m�sol�st a String::get_own_copy() v�gzi.
Abb�l a c�lb�l, hogy az el�ro f�ggv�nyeket helyben kifejtve (inline) lehessen
ford�ttatni,
olyan helyre kell elhelyezni definici�jukat, ahonnan az Srep oszt�ly� el�rheto.
Teh�t vagy
az Srep-et kell a String oszt�lyon bel�l megadni, vagy pedig az el�ro f�ggv�nyeket
kell
inline-k�nt meghat�rozni a String-en k�v�l �s az String::Srep ut�n (�11.14[2]).
Megk�l�nb�ztetendo az �r�st �s az olvas�st, a String::operator[ ]() egy Cref-et ad
vissza, ha
nem const objektumra h�vt�k meg. A Cref �gy viselkedik, mint a char&, azzal a
k�l�nbs�ggel,
hogy �r�sakor megh�vja a String::Sref::get_own_copy()-t:
class String::Cref { // hivatkoz�s s[i]-re
friend class String;
String& s;
int i;
Cref(String& ss, int ii) : s(ss), i(ii) { }
public:
operator char() const { return s.read(i); } // �rt�k kijel�l�se
void operator=(char c) { s.write(i,c); } // �rt�k m�dos�t�sa
};
P�ld�ul:
void f(String s, const String& r)
{
char c1 = s[1]; // c1 = s.operator[ ](1).operator char()
s[1] = 'c'; // s.operator[ ](1).operator=('c')
388 Absztrakci�s m�dszerek
char c2 = r[1]; // c2 = r.operator[ ](1)
r[1] = 'd'; // hiba: char �rt�kad�s, r.operator[ ](1) = 'd'
}
Vegy�k �szre, hogy egy nem const objektumra az s.operator[ ](1) �rt�ke Cref(s,1)
lesz.
Ahhoz, hogy teljess� tegy�k a String oszt�lyt, meghat�rozunk m�g egy sor hasznos
f�ggv�nyt:
class String {
// ...
String& operator+=(const String&);
String& operator+=(const char*);
friend ostream& operator<<(ostream&, const String&);
friend istream& operator>>(istream&, String&);
friend bool operator==(const String& x, const char* s)
{ return strcmp(x.rep->s, s) == 0; }
friend bool operator==(const String& x, const String& y)
{ return strcmp(x.rep->s, y.rep->s) == 0; }
friend bool operator!=(const String& x, const char* s)
{ return strcmp(x.rep->s, s) != 0; }
friend bool operator!=(const String& x, const String& y)
{ return strcmp(x.rep->s, y.rep->s) != 0; }
};
String operator+(const String&, const String&);
String operator+(const String&, const char*);
Hely-megtakar�t�s c�lj�b�l a ki- �s bemeneti oper�torokat, illetve az �sszefuz�st
meghagytam
gyakorlatnak.
A foprogram puszt�n egy kiss� megdolgoztatja a String oper�torokat:
String f(String a, String b)
{
a[2] = 'x';
char c = b[3];
cout << "Az f-ben: " << a << ' ' << b << ' ' << c << '\n';
return b;
}
11. Oper�torok t�lterhel�se 389
int main()
{
String x, y;
cout << "Adjon meg k�t karakterl�ncot!\n";
cin >> x >> y;
cout << "Bemenet: " << x << ' ' << y << '\n';
String z = x;
y = f(x,y);
if (x != z) cout << "Az x s�r�lt!\n";
x[0] = '!';
if (x == z) cout << "Az �r�s nem siker�lt!\n";
cout << "Kil�p�s: " << x << ' ' << y << ' ' << z << '\n';
}
Ebbol a String oszt�lyb�l m�g hi�nyoznak fontosnak vagy ak�r alapvetonek
tekintheto dolgok,
p�ld�ul nincs az �rt�ket C st�lus� adatk�nt visszaad� muvelet (11.14[10], 20.
fejezet).
11.13. Tan�csok
[1] Oper�torokat elsosorban az�rt adjunk meg, hogy a szok�sos haszn�lati m�dot
t�mogassuk. �11.1.
[2] Nagy operandusok eset�ben haszn�ljunk const referencia param�tereket. �11.6.
[3] Nagy �rt�keket ad� eredm�nyekn�l fontoljuk meg az eredm�ny-visszaad�s
optimaliz
�l�s�t. 11.6.
[4] Hagyatkozzunk az alap�rtelmezett m�sol� muveletekre, ha azok megfeleloek az
oszt�lyunk sz�m�ra. 11.3.4.
[5] B�r�ljuk fel�l vagy tiltsuk meg az alap�rtelmezett m�sol�st, ha az egy adott
t�pus
sz�m�ra nem megfelelo. 11.2.2.
[6] Ha egy f�ggv�nynek sz�ks�ge van az adat�br�zol�s el�r�s�re, ink�bb tagf�ggv
�ny legyen. 11.5.2.
[7] Ha egy f�ggv�nynek nincs sz�ks�ge az adat�br�zol�s el�r�s�re, ink�bb ne
legyen tagf�ggv�ny. 11.5.2.
[8] Haszn�ljunk n�vteret, hogy a seg�df�ggv�nyeket oszt�lyukhoz rendelj�k.
�11.2.4.
[9] Szimmetrikus muveletekre haszn�ljunk nem tag f�ggv�nyeket. �11.3.2.
[10] T�bbdimenzi�s t�mb indexel�s�re haszn�ljunk ()-t. �11.9.
[11] Az egyetlen .m�ret. param�teru konstruktorok legyenek explicit-ek. �11.7.1.
390 Absztrakci�s m�dszerek
[12] �ltal�nos c�lra haszn�ljuk a szabv�nyos string-et (20. fejezet), ne a
gyakorlatok
megold�sa r�v�n kapott saj�t v�ltozatot. �11.12.
[13] Legy�nk �vatosak az automatikus konverzi�k bevezet�sekor. �11.4.
[14] Bal oldali operandusk�nt bal�rt�ket v�r� muveleteket tagf�ggv�nyekkel
val�s�tsunk
meg. �11.3.5.
11.14. Gyakorlatok
1. (*2) Milyen konverzi�kat haszn�lunk az al�bbi program egyes kifejez�seiben:
struct X {
int i;
X X(int);
operator+(int);
};
struct Y {
int i;
Y(X);
Y operator+(X);
operator int();
};
extern X operator*(X, Y);
extern int f(X);
X x = 1;
Y y = x;
int i = 2;
int main()
{
i + 10; y + 10; y + 10 * y;
x + y + i; x * x + i; f(7);
f(y); y + y; 106 + y;
}
M�dos�tsuk a programot �gy, hogy fut�s k�zben ki�rjon minden megengedett
kifejez�st.
2. (*2) Fejezz�k be �s tesztelj�k a �11.12-beli String oszt�lyt.
11. Oper�torok t�lterhel�se 391
3. (*2) Defini�ljuk az INT oszt�lyt, amely pontosan �gy viselkedik, mint egy int.
(Seg�ts�g: defini�ljuk az INT::operator int()-et).
4. (*1) Defini�ljuk a RINT oszt�lyt, amely pontosan �gy viselkedik, mint egy int,
azzal a k�l�nbs�ggel, hogy csak a k�vetkezo muveletek enged�lyezettek: (egy
�s k�t param�teru) +, (egy �s k�t param�teru) -, *, / �s %. (Seg�ts�g: ne
defini�ljuk a RINT::operator int()-et).
5. (*3) Defini�ljuk a LINT oszt�lyt, amely pontosan �gy viselkedik, mint a RINT,
de
legal�bb 64 bites pontoss�g�.
6. (*4) Defini�ljunk egy tetszoleges pontoss�g� aritmetik�t t�mogat� oszt�lyt.
Tesztelj�k az 1000 faktori�lis�nak kisz�m�ttat�s�val. (Seg�ts�g: a String
oszt�ly�-
hoz hasonl� t�rszervez�sre lesz sz�ks�g.)
7. (*2) Hat�rozzunk meg a String oszt�ly sz�m�ra egy k�lso bej�r�t (iter�tort):
class String_iter {
// hivatkoz�s karakterl�ncra �s annak elem�re
public:
String_iter(String& s); // bej�r� s sz�m�ra
char& next(); // hivatkoz�s a k�vetkezo elemre
// ig�ny szerint tov�bbi muveletek
};
Hasonl�tsuk ezt �ssze hasznoss�g, st�lus �s hat�konys�g szempontj�b�l a String
egy belso bej�r�j�val. (Vagyis adott egy kurrens elem�nk a String-ben, �s a vele
kapcsolatos muveletek.)
8. (*1.5) A () oper�tor t�lterhel�s�vel hat�rozzunk meg egy r�szl�nc-muveletet
egy karakterl�nc-oszt�ly sz�m�ra. Milyen m�s muveletet szeretn�nk egy karakterl
�ncon v�gezni?
9. (*3) Tervezz�k meg �gy a String oszt�lyt, hogy a r�szl�nc-oper�tort egy �rt�kad
�s bal oldal�n is fel lehessen haszn�lni. Elosz�r egy olyan v�ltozatot �rjunk,
amelyikn�l egy r�szl�ncot egy azonos hossz�s�g� teljes karakterl�ncra lehet
cser�lni, azt�n egy olyat, amelyikn�l elt�rore.
10. (*2) Defini�ljuk a String oszt�ly sz�m�ra az �rt�ket C st�lus� adatk�nt
visszaad�
muveletet. Vitassuk meg annak elonyeit �s h�tr�nyait, hogy ez egy konverzi�s
oper�tor. Vitassuk meg a C st�lus� adat sz�m�ra sz�ks�ges mem�ria lefoglal�s�-
nak k�l�nf�le m�djait.
11. (*2.5) Tervezz�nk �s k�sz�ts�nk egy egyszeru regul�ris kifejez�s illeszto
eszk�zt
a String oszt�ly sz�m�ra.
12. (*1.5) M�dos�tsuk �gy a �11.14[11]-beli eszk�zt, hogy az muk�dj�n a standard
k�nyvt�rbeli string-gel. A string defin�ci�j�t nem v�ltoztathatjuk meg.
392 Absztrakci�s m�dszerek
13. (*2) �rjunk egy programot, amit oper�tor-t�lterhel�ssel �s a makr�k
haszn�lat�-
val olvashatatlann� tesz�nk. Egy �tlet: hat�rozzuk meg + -t �gy az INT-ekre,
hogy - -t jelentsen �s ford�tva. Ezut�n egy makr�val hat�rozzuk meg �gy az intet,
hogy INT-et jelentsen. B�r�ljuk fel�l a .n�pszeru. f�ggv�nyeket referencia
t�pus� param�tereket haszn�l� f�ggv�nyekk�nt. N�h�ny f�lrevezeto megjegyz
�ssel is nagy zavart lehet kelteni.
14. (*3) Cser�lj�k ki egy bar�tunkkal a �11.14[13] feladatra adott megold�sunkat,
�s
pr�b�ljuk meg futtat�sa n�lk�l kider�teni, mit csin�l. A gyakorlat v�g�re meg
fogjuk tanulni, hogy mit ne tegy�nk t�bb�.
15. (*2) Defini�ljuk a Vec4 t�pust, mint n�gy float-b�l �ll� vektort. Defini�ljuk
a [ ]
muveletet. Adjuk meg a +, -, *, /, =, +, +=, -=, *= �s /= muveleteket a vektorok
�s float-ok egy�ttes haszn�lat�ra.
16. (*3) Defini�ljuk a Mat4 t�pust, mint n�gy Vec4-bol �ll� vektort. Defini�ljuk a
[ ]
muveletet, mint ami Vec4-et ad vissza, ha a Mat4-re alkalmazzuk. Adjuk meg
a szok�sos m�trix-muveleteket. K�sz�ts�nk f�ggv�nyt, amely a Gauss-f�le kik�-
sz�b�l�s m�dszer�t alkalmazza egy Mat4-re.
17. (*2) Defini�ljunk egy Vector t�pust, amely a Vec4-hez hasonl�t, de
Vector::Vector(int) konstruktor�nak param�terk�nt megadhatjuk a m�retet.
18. (*3) Defini�ljunk egy Matrix t�pust, amely a Mat4-hez hasonl�t, de
Matrix::Matrix(int,int) konstruktor�nak param�terk�nt megadhatjuk
a dimenzi�kat.
19. (*2) Fejezz�k be a �11.11 pont Ptr_to_T oszt�ly�t �s ellenorizz�k. Legyenek
meg legal�bb a *, ->, =, ++ �s -- muveletek. Ne okozzunk fut�si ideju hib�t,
csak ha egy hib�s mutat�t t�nylegesen felhaszn�lnak.
20. (*1) Adott k�t strukt�ra:
struct S { int x, y; };
struct T { char* p; char* q; };
�rjunk egy C oszt�lyt, melynek seg�ts�g�vel majdnem �gy haszn�lhatjuk valamely
S �s T x-�t �s p-j�t, mint ha x �s p C tagja lenne.
21. (*1.5) Defini�ljuk az Index oszt�lyt a mypow(double,Index) hatv�nyoz� f�ggv
�ny kitevoje sz�m�ra. Tal�ljunk m�dot arra, hogy 2**I megh�vja mypow(2,I)-t.
22. (*2) Defini�ljuk az Imaginary oszt�lyt k�pzetes sz�mok �br�zol�s�ra.
Defini�ljuk a Complex oszt�lyt ennek alapj�n. K�sz�ts�k el az alapveto
aritmetikai muveleteket.
11. Oper�torok t�lterhel�se 393
Sz�rmaztatott oszt�lyok
.Ne szapor�tsuk az
objektumokat,
ha nem sz�ks�ges..
(W. Occam)
Fogalmak �s oszt�lyok . Sz�rmaztatott oszt�lyok . Tagf�ggv�nyek . L�trehoz�s �s
megsemmis
�t�s . Oszt�lyhierarchi�k . T�pusmezok . Virtu�lis f�ggv�nyek . Absztrakt oszt�-
lyok . Hagyom�nyos oszt�lyhierarchi�k . Absztrakt oszt�lyok mint fel�letek . Az
objektumok
l�trehoz�s�nak adott helyre korl�toz�sa . Absztrakt oszt�lyok �s
oszt�lyhierarchi�k
. Tan�csok . Gyakorlatok
12.1. Bevezet�s
A C++ a Simula nyelvtol k�lcs�n�zte az oszt�ly, mint felhaszn�l�i t�pus, illetve
az oszt�lyhierarchia
fogalm�t, valamint a rendszertervez�s azon elv�t, hogy a programban haszn�lt
fogalmak
modellez�s�re oszt�lyokat haszn�ljon. A C++ ny�jtotta nyelvi szerkezetek k�zvetlen
�l t�mogatj�k ezeket a tervez�si elveket. Megford�tva is igaz: akkor haszn�ljuk a
C++
nyelvet hat�konyan, ha a nyelvi lehetos�geket a tervez�si elvek t�mogat�s�ra
haszn�ljuk.
Aki a nyelvi elemeket csak a hagyom�nyosabb programoz�s jel�l�sbeli
al�t�maszt�s�ra
haszn�lja, a C++ val�di eross�g�nek haszn�lat�r�l mond le.
12
Egy fogalom sohasem �nmag�ban l�tezik, hanem m�s fogalmakkal egy�tt �s erej�nek
egy
r�sz�t is a rokon fogalmakkal val� kapcsolatb�l mer�ti. Pr�b�ljuk csak
megmagyar�zni, mi
az, hogy aut�. Hamarosan bevezetj�k a k�vetkezo fogalmakat: ker�k, motor, vezeto,
gyalogos,
teheraut�, mentok, utak, olaj, gyorshajt�s, b�rs�g, motel stb. Minthogy a
fogalmakat
oszt�lyokk�nt �br�zoljuk, felmer�l a k�rd�s: hogyan �br�zoljuk a fogalmak k�z�tti
kapcsolatokat?
Persze tetszoleges kapcsolatot egy programoz�si nyelvben nem tudunk k�zvetlen
�l kifejezni. De ha tudn�nk, akkor sem akarn�nk, hiszen oszt�lyainkat a mindennapi

�letben haszn�lt fogalmakn�l szukebben �s prec�zebben akarjuk meghat�rozni. A


sz�rmaztatott
oszt�ly fogalma �s a vele kapcsolatos nyelvi elj�r�sok c�lja a viszonyok
kifejez�se,
azaz hogy kifejezz�k, mi a k�z�s az oszt�lyokban. A k�r �s a h�romsz�g fogalm�ban
p�ld
�ul k�z�s, hogy mindketto s�kg�rbe-alakzat, �gy a Circle (K�r) �s Triangle
(H�romsz�g)
oszt�lyokat �gy �rhatjuk le, hogy pontosan meghat�rozott (explicit) m�don
megmondjuk,
hogy a Shape (Alakzat) oszt�ly a k�z�s benn�k. Ha egy programban �gy
szerepeltet�nk k�-
r�ket �s h�romsz�geket, hogy nem vonjuk be a s�kidom fogalm�t, akkor valami
l�nyegeset
mulasztunk el. Ez a fejezet azt feszegeti, mi k�vetkezik ebbol az egyszeru
elvbol . ami val
�j�ban az �ltal�ban objektumorient�ltnak nevezett programoz�si elv alapja.
A nyelvi lehetos�gek �s m�dszerek bemutat�sa az egyszerutol �s konkr�tt�l a
bonyolultabb,
kifinomultabb, elvontabb fel� halad. Sokak sz�m�ra ez a megszokott�l a kev�sb�
ismert
fel� val� halad�st is fogja jelenti. De ez nem csup�n egyszeru utaz�s a .r�gi,
rossz m�dszerekt
ol. az .egyed�li igaz �t. fel�. Amikor r�mutatok egy megk�zel�t�s korl�taira, hogy

a programoz�t az �j fel� tereljem, mindig adott probl�m�k kapcs�n teszem; m�s


probl�m�k
kapcs�n vagy m�s �sszef�gg�sben lehets�ges, hogy a kor�bbi m�dszer alkalmaz�sa a
jobb
v�laszt�s. Haszn�lhat� programokat az itt t�rgyalt m�dszerek mindegyik�nek
felhaszn�l�-
s�val �rtak m�r. A c�l az, hogy az olvas� megismerje az �sszes elj�r�st, hogy
azt�n okos �s
kiegyens�lyozott m�don tudjon majd v�lasztani k�z�l�k, amikor igazi feladatokat
kell
megoldania.
A fejezetben elosz�r az objektumorient�lt programoz�st t�mogat� alapveto nyelvi
eszk�z�-
ket mutatom be, majd egy hosszabb p�lda kapcs�n azt t�rgyalom, hogyan lehet ezek
alkalmaz
�s�val j�l szerkesztett programot �rni. Az objektumorient�lt programoz�st t�mogat�
tov
�bbi nyelvi eszk�z�ket, p�ld�ul a t�bbsz�r�s �r�klod�st vagy a fut�si ideju
t�pusazonos�-
t�st a 15. fejezet t�rgyalja.
396 Absztrakci�s m�dszerek
12.2. Sz�rmaztatott oszt�lyok
Vegy�nk egy programot, amely egy c�g dolgoz�it kezeli. Egy eff�le programban lehet
egy
ilyen adatszerkezet:
struct Employee { // alkalmazott
string first_name, family_name;
char middle_initial;
Date hiring_date;
short department;
// ...
};
Ezut�n .meghat�rozhatunk. egy fon�k�t is:
struct Manager { // fon�k
Employee emp; // a fon�k mint alkalmazott
set<Employee*> group; // beosztottak
short level;
// ...
};
A fon�k egyben alkalmazott is, ez�rt az Employee (Alkalmazott) adatokat a Manager
(Fo-
n�k, vezeto) objektum emp tagj�ban t�roljuk. Ez nyilv�nval� lehet a programoz�
(k�l�n�-
sen egy figyelmes programoz�) sz�m�ra, de a ford�t�program �s az egy�b eszk�z�k
sehonnan
nem fogj�k tudni, hogy a Manager egyben Employee is. Egy Manager* nem Employee*
is egyben, �gy a ketto nem cser�lheto fel. Egy Employee-ket tartalmaz� list�ra nem
vehet�nk
fel egy Manager-t a megfelelo k�d meg�r�sa n�lk�l. Vagy t�pusk�nyszer�t�st kellene
alkalmaznunk
a Manager*-ra, vagy az emp tag c�m�t kellene az alkalmazottak list�j�ra tenn�nk.
Egyik megold�s sem eleg�ns �s zavar� is lehet. A helyes megk�zel�t�s az, hogy
kifejezetten
megmondjuk, a Manager-ek egyben Employee-k is, csak tov�bbi adatokat is
tartalmaznak:
struct Manager : public Employee {
set<Employee*> group;
short level;
// ...
};
A Manager az Employee-b�l sz�rmazik, �s ford�tva, az Employee a Manager
b�zisoszt�lya.
A Manager oszt�lynak megvannak azok a tagjai, amelyek az Employee-nek is
(first_name,
department stb.) �s ezekhez j�nnek hozz� a saj�t tagok (group, level stb.).
12. Sz�rmaztatott oszt�lyok 397
A sz�rmaztat�st gyakran �gy �br�zolj�k grafikusan, hogy a sz�rmaztatott oszt�lyb�l
egy nyilat
rajzolnak a b�zisoszt�ly fel�, jelezve, hogy a sz�rmaztatott oszt�ly a
b�zisoszt�lyra hivatkozik
(�s nem ford�tva):
�ltal�ban �gy mondj�k, a sz�rmaztatott oszt�ly tulajdons�gokat �r�k�l a
b�zisoszt�lyt�l.
Ennek alapj�n ezt a kapcsolatot �r�klod�snek (�r�kl�s, inheritance) is h�vj�k. Az
angol kifejez
�sek a b�zisposzt�lyra �s a sz�rmaztatott oszt�lyra: base class (vagy superclass),
illetve
derived class (subclass). Az ut�bbi sz�haszn�lat (superclass . fooszt�ly, subclass
. aloszt
�ly) azonban zavar� lehet, hiszen a sz�rmaztatott oszt�ly bizonyos �rtelemben
.sz�lesebb.
a b�zisoszt�lyn�l, mivel ann�l t�bb adatot t�rol �s t�bb f�ggv�nyt biztos�t.
A sz�rmaztat�s n�pszeru �s hat�kony megval�s�t�sa a sz�rmaztatott oszt�ly�
objektumot
a b�zisoszt�ly olyan objektumak�nt �br�zolja, amely kieg�sz�l a sz�rmaztatott
oszt�lyra
egyedileg jellemzo adatokkal is:
398 Absztrakci�s m�dszerek
Manager
Employee
first_name
family_name
...
first_name
family_name
...
group
level
...
Emplyee: Manager:
A Manager oszt�lynak az Employee-b�l ilyen m�don val� sz�rmaztat�sa a Manager
t�pust
az Employee alt�pus�v� teszi, �gy teh�t mindenhol, ahol Employee objektum
haszn�lhat�,
egy Manager is megfelel. Most m�r k�sz�thet�nk egy list�t az alkalmazottakr�l
(Employee),
akiknek egy r�sze vezeto beoszt�s� (Manager):
void f(Manager m1, Employee e1)
{
list<Employee*> elist;
elist.push_front(&m1);
elist.push_front(&e1);
// ...
}
Ne feledj�k, egy Manager egyben Employee is, �gy egy Manager*-ot haszn�lhatunk
Employee*-k�nt is. Az Employee viszont nem felt�tlen�l Manager, �gy Employee*-ot
nem
haszn�lhatunk Manager*-k�nt. �ltal�ban, ha egy Derived (sz�rmaztatott) oszt�lynak
egy
Base (b�zis) oszt�ly nyilv�nos b�zisoszt�lya (�15.3), akkor egy Base* v�ltoz�
t�pusk�nyszer�t�s n�lk�l kaphat Derived* t�pus� �rt�ket. A m�sik ir�nyban (Base*-
r�l
Derived*-ra) explicit konverzi� sz�ks�ges:
void g(Manager mm, Employee ee)
{
Employee* pe = &mm; // rendben: minden Manager egyben Employee is
Manager* pm = &ee; // hiba: nem minden Employee fon�k
pm->level = 2; // katasztr�fa: ee nem rendelkezik 'level' taggal
pm = static_cast<Manager*>(pe); // "nyers erovel": muk�dik, mert pe
// a Manager t�pus� mm-re mutat
pm->level = 2; // ez is j�: pm a Manager t�pus� mm-re mutat,
// amelynek van 'level' tagja
}
Vagyis mutat�k �s referenci�k haszn�latakor a sz�rmaztatott oszt�ly objektumait
�gy kezelhetj
�k, mint a b�zisoszt�ly objektumait. A m�sik ir�nyban ez nem �ll. A static_cast �s

a dynamic_cast haszn�lat�t a �15.4.2 pont �rja le.


Egy oszt�ly b�zisoszt�lyk�nt val� haszn�lata egyen�rt�ku az oszt�ly egy (n�vtelen)
objektum
�nak deklar�l�s�val. K�vetkez�sk�ppen egy oszt�lyt csak akkor haszn�lhatunk
b�zisoszt
�lyk�nt, ha defini�ltuk (�5.7):
12. Sz�rmaztatott oszt�lyok 399
class Employee; // csak deklar�ci�, nem defin�ci�
class Manager : public Employee { // hiba: Employee nem defini�lt
// ...
};
12.2.1. Tagf�ggv�nyek
Az egyszeru adatszerkezetek . mint a Manager �s az Employee . nem t�l �rdekesek �s
sokszor
nem is k�l�n�sebben hasznosak. Az inform�ci�t megfelelo t�pusk�nt kell megadnunk,
melyhez az elv�gezheto muveletek is hozz�tartoznak, �s ezt �gy kell megtenn�nk,
hogy
k�zben nem k�tod�nk az adott �br�zol�shoz:
class Employee {
string first_name, family_name;
char middle_initial;
// ...
public:
void print() const;
string full_name() const
{ return first_name + ' ' + middle_initial + ' ' + family_name; }
// ...
};
class Manager : public Employee {
// ...
public:
void print() const;
// ...
};
A sz�rmaztatott oszt�lyok tagf�ggv�nyei ugyan�gy el�rhetik a b�zisoszt�ly
nyilv�nos
(public) . �s v�dett (protected, �15.3) . tagjait, mintha maguk vezett�k volna be
azokat:
void Manager::print() const
{
cout << "A keresett n�v " << full_name() << '\n';
// ...
}
A sz�rmaztatott oszt�ly azonban nem �ri el a b�zisoszt�ly priv�t (private)
tagjait:
void Manager::print() const
{
cout << "A keresett n�v " << family_name << '\n'; // hiba!
// ...
}
400 Absztrakci�s m�dszerek
A Manager::print() m�sodik v�ltozat�t a ford�t� nem fogja leford�tani. A
sz�rmaztatott oszt
�lynak nincs k�l�nleges enged�lye a b�zisoszt�ly priv�t tagjainak el�r�s�re, �gy
a Manager::print() sz�m�ra a family_name nem �rheto el.
N�melyek meglepodnek ezen, de gondoljuk el, mi lenne ford�tott esetben: ha a
sz�rmaztatott
oszt�ly tagf�ggv�nye el�rhetn� a b�zisoszt�ly priv�t tagjait. A priv�t tag fogalma
�rtelmetlenn
� v�lna az�ltal, hogy a programoz� hozz�f�rhetne az oszt�ly priv�t r�sz�hez egy
oszt�lyt sz�rmaztatva belole. Tov�bb� nem lehetne t�bb� egy priv�t tag haszn�lat�t
a tag-
�s bar�t (friend) f�ggv�nyek �tn�z�s�vel megkeresni. Az eg�sz program minden
forr�s�llom
�ny�t �t k�ne n�zni: a sz�rmaztatott oszt�lyokat �s azok f�ggv�nyeit keresni, majd
a sz�rmaztatott
oszt�lyokb�l sz�rmaztatott tov�bbi oszt�lyokat �s azok f�ggv�nyeit �s �gy tov�bb.
Ez legjobb esetben is f�raszt� �s sokszor kivitelezhetetlen is. Ott, ahol ez
elfogadhat�, ink
�bb v�dett (protected) �s ne priv�t (private) tagokat haszn�ljunk. Egy v�dett tag
a sz�rmaztatott
oszt�lyok sz�m�ra olyan, mint egy nyilv�nos (public), a t�bbiek sz�m�ra azonban
priv�tnak minos�l (�15.3).
A legtiszt�bb megold�s �ltal�ban az, ha a sz�rmaztatott oszt�ly a b�zisoszt�lynak
csak
a nyilv�nos tagjait haszn�lja:
void Manager::print() const
{
Employee::print(); // alkalmazottak adatainak ki�r�sa
cout << level; // a fon�k�kre vonatkoz� adatok ki�r�sa
// ...
}
Vegy�k �szre, hogy a :: hat�k�r oper�tort kellett haszn�lni, mert a print()
f�ggv�nyt
a Manager oszt�ly �jradefini�lja. A f�ggv�nynevek ilyen m�don val�
�jrafelhaszn�l�sa igen
�ltal�nos. Ha �vatlanul ilyet �runk:
void Manager::print() const
{
print(); // hopp�!
// a fon�k�kre vonatkoz� adatok ki�r�sa
}
a program v�ratlan m�don �jra �s �jra meg fogja h�vni �nmag�t.
12. Sz�rmaztatott oszt�lyok 401
12.2.2. Konstruktorok �s destruktorok
Egyes sz�rmaztatott oszt�lyoknak konstruktorokra van sz�ks�g�k. Ha a
b�zisoszt�lynak
vannak ilyen f�ggv�nyei, akkor az egyiket meg is kell h�vni. Az alap�rtelmezett
konstruktorokat
automatikusan is megh�vhatjuk, de ha a b�zisoszt�ly minden konstruktora param�-
tert ig�nyel, akkor a megfelelo konstruktort csak explicit m�don lehet megh�vni.
Vegy�k
a k�vetkezo p�ld�t:
class Employee {
string first_name, family_name;
short department;
// ...
public:
Employee(const string& n, int d);
// ...
};
class Manager : public Employee {
set<Employee*> group; // beosztottak
short level;
// ...
public:
Manager(const string& n, int d, int lvl);
// ...
};
A b�zisoszt�ly konstruktora a sz�rmaztatott oszt�ly konstruktor�nak definici�j�ban
kap param
�tereket. Ebbol a szempontb�l a b�zisoszt�ly konstruktora �gy viselkedik, mintha
a sz�rmaztatott oszt�ly tagja lenne (�10.4.6):
Employee::Employee(const string& n, int d)
: family_name(n), department(d) // tagok kezdeti �rt�kad�sa
{
// ...
}
Manager::Manager(const string& n, int d, int lvl)
: Employee(n,d), // a b�zisoszt�ly kezdeti �rt�kad�sa
level(lvl) // tagok kezdeti �rt�kad�sa
{
// ...
}
402 Absztrakci�s m�dszerek
Egy sz�rmaztatott oszt�ly konstruktora csak a saj�t tagjai �s a b�zisoszt�ly
konstruktora sz�-
m�ra adhat meg kezdo�rt�ket; a b�zisoszt�ly tagjainak nem:
Manager::Manager(const string& n, int d, int lvl)
: family_name(n), // hiba: family_name nem deklar�lt a Manager oszt�lyban
department(d), // hiba: department nem deklar�lt a Manager oszt�lyban
level(lvl)
{
// ...
}
A fenti defin�ci� h�rom hib�t tartalmaz: nem h�vja meg az Employee konstruktor�t,
�s k�t �zben
is megpr�b�l k�zvetlen�l kezdo�rt�ket adni az Employee tagjainak.
Az oszt�lyba tartoz� objektumok .alulr�l felfel�. �p�lnek fel; elosz�r a
b�zisoszt�ly, azt�n
a tagok, v�g�l maga a sz�rmaztatott oszt�ly. A megsemmis�t�s ford�tott sorrendben
t�rt�nik:
elosz�r a sz�rmaztatott oszt�ly, azt�n a tagok, v�g�l a b�zisoszt�ly. A tagok a
deklar�ci� sorrendj
�ben j�nnek l�tre �s ford�tott sorrendben semmis�lnek meg (�10.4.6 �s �15.2.4.1).
12.2.3. M�sol�s
Egy oszt�lyba tartoz� objektum m�sol�s�t a m�sol� konstruktor �s az �rt�kad�sok
hat�rozz
�k meg (�10.4.4.1):
class Employee {
// ...
Employee& operator=(const Employee&);
Employee(const Employee&);
};
void f(const Manager& m)
{
Employee e = m; // e l�trehoz�sa m Employee r�sz�bol
e = m; // m Employee r�sz�nek m�sol�sa e-be
}
Minthogy az Employee oszt�ly m�sol� f�ggv�nyei nem tudnak a Manager oszt�lyr�l, a
Manager
objektumnak csak az Employee r�sze fog lem�sol�dni. Az objektumnak ez a
.felszeletel
od�se. (slicing), azaz a t�ny, hogy ekkor az objektumnak csak egy szelete
m�sol�dik
le, meglepo lehet �s hib�khoz vezethet. A felszeletelod�s megakad�lyoz�sa az egyik
oka
annak, hogy oszt�lyhierarchi�ba tartoz� objektumok eset�ben c�lszerubb mutat�kat
�s
referenci�kat haszn�lnunk. A hat�konys�gi megfontol�sok mellett tov�bbi ok, hogy
meg-
orizz�k a t�bbalak� (polimorfikus) viselked�st (�2.5.4 �s �12.2.6).
12. Sz�rmaztatott oszt�lyok 403
Jegyezz�k meg, hogy ha nem hat�rozunk meg m�sol� �rt�kad� oper�tort, akkor a
ford�t�-
program fog l�trehozni egyet. Ebbol k�vetkezik, hogy az �rt�kad� oper�torok nem
�r�kl
odnek. (A konstruktorok soha.)
12.2.4. Oszt�lyhierarchi�k
Egy sz�rmaztatott oszt�ly lehet maga is b�zisoszt�ly:
class Employee { /* ... */ };
class Manager : public Employee { /* ... */ };
class Director : public Manager { /* ... */ };
Az egym�ssal kapcsolatban �ll� oszt�lyok ilyen halmaz�t hagyom�nyosan
oszt�lyhierarchi�-
nak h�vjuk. A hierarchia leggyakrabban fa szokott lenni, de lehet enn�l
�ltal�nosabb gr�f is.:
class Temporary { /* ... */ };
class Secretary : public Employee { /* ... */ };
class Tsec : public Temporary, public Secretary { /* ... */ };
class Consultant : public Temporary, public Manager { /* ... */ };
�br�val:
Vagyis ahogy a �15.2 pont r�szletesen elmagyar�zza, a C++ nyelv k�pes az
oszt�lyoknak
egy ir�ny�tott k�rmentes gr�fj�t kifejezni.
404 Absztrakci�s m�dszerek
Employee
Secretary Manager
Consultant
Tsec
Director
Temporary
12.2.5. T�pusmezok
Ha a deklar�ci�kban alkalmazott k�nyelmes r�vid�t�sn�l t�bbre akarjuk haszn�lni az
oszt�-
lyok sz�rmaztat�s�t, meg kell v�laszolnunk a k�vetkezo k�rd�st: ha adott egy Base*
mutat
�, akkor milyen sz�rmaztatott oszt�lyba tartozik az objektum, amelyre mutat? A
probl�m�-
nak n�gy alapveto megold�sa van:
1. �rj�k el, hogy csak egyf�le objektum j�hessen sz�ba (�2.7, 13. fejezet).
2. Helyezz�nk egy t�pusmezot a b�zisoszt�lyba �s a f�ggv�nyek ezt k�rdezz�k le.
3. Haszn�ljuk a dynamic_cast-ot (dinamikus t�puskonverzi�, �15.4.2, �15.4.5).
4. Haszn�ljunk virtu�lis f�ggv�nyeket (�2.5.5, �12.2.6).
B�zisoszt�lyra hivatkoz� mutat�kat gyakran haszn�lunk olyan t�rol� oszt�lyokban
(container class), mint a halmaz (set), a vektor (vector) �s a lista (list). Ekkor
az elso megold
�s homog�n list�kat, azaz azonos t�pus� objektumokat eredm�nyez. A t�bbi megold�s
lehet
ov� tesz heterog�n list�kat is, azaz olyanokat, ahol k�l�nb�zo t�pus� objektumok
(vagy
ilyenekre hivatkoz� mutat�k) lehetnek. A 3. megold�s a 2. megold�snak a nyelv
�ltal t�mogatott
v�ltozata, a 4. pedig a 2.-nak egyedi, t�pusbiztos �talak�t�sa. Az 1. �s a 4.
megold�s
p�ros�t�sai k�l�n�sen �rdekesek �s erosek; majdnem mindig vil�gosabb k�dot eredm�-

nyeznek, mint a 2. vagy a 3. megold�s.


N�zz�nk meg elosz�r egy t�pusmezos megold�st, hogy l�ssuk, legt�bbsz�r mi�rt
ker�lend
o. A .fon�k . alkalmazott. p�ld�t �gy �rhatn�nk �t:
struct Employee {
enum Empl_type { M, E };
Empl_type type;
Employee() : type(E) { }
string first_name, family_name;
char middle_initial;
Date hiring_date;
short department;
// ...
};
struct Manager : public Employee {
Manager() { type = M; }
set<Employee*> group; // beosztottak
short level;
// ...
};
12. Sz�rmaztatott oszt�lyok 405
Most m�r �rhatunk egy f�ggv�nyt, amely minden Employee-rol ki tudja �rni az
inform�ci�t:
void print_employee(const Employee* e)
{
switch (e->type) {
case Employee::E:
cout << e->family_name << '\t' << e->department << '\n';
// ...
break;
case Employee::M:
{ cout << e->family_name << '\t' << e->department << '\n';
// ...
const Manager* p = static_cast<const Manager*>(e);
cout << " szint " << p->level << '\n';
// ...
break;
}
}
}
Az alkalmazottak list�ja �gy �rhat� ki:
void print_list(const list<Employee*>& elist)
{
for (list<Employee*>::const_iterator p = elist.begin(); p!=elist.end(); ++p)
print_employee(*p);
}
Ez j�l muk�dik, k�l�n�sen az egyetlen programoz� �ltal fenntartott kis
programokban.
Alapveto gyeng�je, hogy az a felt�tele, hogy a programoz� a megfelelo (�s a
ford�t�program
�ltal nem ellenorizheto m�don) kell, hogy kezelje a t�pusokat. A probl�m�t
�ltal�ban
s�lyosb�tja, hogy az olyan f�ggv�nyek, mint a print_employee, a sz�ba j�heto
oszt�lyok k�-
z�s von�sait haszn�lj�k ki:
void print_employee(const Employee* e)
{
cout << e->family_name << '\t' << e->department << '\n';
// ...
if (e->type == Employee::M) {
const Manager* p = static_cast<const Manager*>(e);
cout << " szint " << p->level << '\n';
// ...
}
}
406 Absztrakci�s m�dszerek
Egy nagy f�ggv�nyben, ahol sok sz�rmaztatott t�pust kell kezelni, neh�z lehet az
�sszes
ilyen t�pusmezo-ellenorz�st megtal�lni. De ha megtal�ltuk is, neh�z lehet
meg�rteni, hogy
mi is t�rt�nik. Tov�bb�, ha a rendszer �j Employee-vel bov�l, az �sszes fontos
f�ggv�nyt
m�dos�tani kell . vagyis az �sszes olyat, amelyik ellenorzi a t�pusmezot. Minden
olyan
f�ggv�nyt meg kell vizsg�lni, amelyiknek egy v�ltoztat�s ut�n sz�ks�ge lehet a
t�pusmezo
ellenorz�s�re. Ez azt jelenti, hogy hozz� kell f�rni a kritikus forr�sk�dhoz �s
k�l�n munk�t
jelent a v�ltoztat�s ut�ni teszt is. A t�pusk�nyszer�t�s �rulkod� jele annak, hogy
jav�tani lehetne
a k�don.
Vagyis a t�pusmezos megold�s hib�kra ad lehetos�get �s nehezen m�dos�that� k�dot
eredm
�nyez. Ahogy a rendszer m�rete no, a probl�ma s�lyosbodik, mert a t�pusmezo
alkalmaz
�sa ellentmond a modularit�s �s az adatrejt�s elv�nek. Minden t�pusmezot haszn�l�
f�ggv�nynek ismernie kell az �sszes olyan oszt�ly �br�zol�s�t (�s megval�s�t�suk
egy�b
r�szleteit), amely a t�pusmezos oszt�ly lesz�rmazottja.
Ezenk�v�l ha van egy olyan adat (p�ld�ul egy t�pusmezo), amely minden
sz�rmaztatott oszt
�lyb�l el�rheto, akkor a programoz� hajlamos arra, hogy tov�bbi ilyen mezoket
hozzon
l�tre. A k�z�s b�zisoszt�ly �gy mindenf�le .hasznos inform�ci�k. gyujtem�ny�v�
v�lik.
Ez azt�n a b�zisoszt�ly �s a sz�rmaztatott oszt�lyok megval�s�t�s�nak legkev�sb�
k�v�natos
�sszefon�d�s�hoz vezet. A tiszt�bb fel�p�t�s �s k�nnyebb m�dos�that�s�g kedv��rt a
k�-
l�n�ll� dolgokat kezelj�k k�l�n, a k�lcs�n�s f�gg�seket pedig ker�lj�k el.
12.2.6. Virtu�lis f�ggv�nyek
A virtu�lis f�ggv�nyek az�ltal ker�lik el a t�pusmezos megold�s probl�m�it, hogy
seg�ts�-
g�kkel a programoz� olyan f�ggv�nyeket deklar�lhat a b�zisoszt�lyban, amelyeket a
sz�rmaztatott
oszt�lyok fel�lb�r�lhatnak. A ford�t�- �s bet�ltoprogram gondoskodik az objektumt
�pusok �s az alkalmazott f�ggv�nyek �sszhangj�r�l:
class Employee {
string first_name, family_name;
short department;
// ...
public:
Employee(const string& name, int dept);
virtual void print() const;
// ...
};
12. Sz�rmaztatott oszt�lyok 407
A virtual kulcssz� azt jelenti, hogy a print() f�ggv�ny fel�letk�nt szolg�l az
ebben az oszt
�lyban defini�lt print() f�ggv�nyhez, illetve a sz�rmaztatott oszt�lyokban
defini�lt print()
f�ggv�nyekhez. Ha a sz�rmaztatott oszt�lyokban szerepelnek ilyenek, a
ford�t�program
mindig az adott Employee objektumnak megfelelo f�ggv�nyt fogja megh�vni.
Egy virtu�lis f�ggv�ny akkor szolg�lhat fel�letk�nt a sz�rmaztatott oszt�lyokban
defini�lt
f�ggv�nyekhez, ha azoknak ugyanolyan t�pus� param�tereik vannak, mint a
b�zisoszt�lybelinek,
�s a visszat�r�si �rt�k is csak nagyon csek�ly m�rt�kben k�l�nb�zik (�15.6.2).
A virtu�lis tagf�ggv�nyeket n�ha met�dusoknak (method) is h�vj�k.
A virtu�lis f�ggv�nyt mindig defini�lnunk kell abban az oszt�lyban, amelyben
elosz�r
deklar�ltuk, hacsak nem tiszt�n virtu�lis (pure virtual) f�ggv�nyk�nt adtuk meg
(�12.3):
void Employee::print() const
{
cout << family_name << '\t' << department << '\n';
// ...
}
Virtu�lis f�ggv�nyt akkor is haszn�lhatunk, ha oszt�ly�b�l nem is sz�rmaztatunk
tov�bbi
oszt�lyt; ha pedig sz�rmaztatunk, annak a f�ggv�nybol nem kell felt�tlen�l saj�t
v�ltozat.
Oszt�ly sz�rmaztat�sakor csak akkor �rjunk egy megfelelo v�ltozatot a f�ggv�nybol,
ha val
�ban sz�ks�ges:
class Manager : public Employee {
set<Employee*> group;
short level;
// ...
public:
Manager(const string& name, int dept, int lvl);
void print() const;
// ...
};
void Manager::print() const
{
Employee::print();
cout << "\tszint " << level << '\n';
// ...
}
408 Absztrakci�s m�dszerek
A sz�rmaztatott oszt�ly azonos nevu �s azonos t�pus� param�terekkel b�r� f�ggv�nye
fel�l-
�rja vagy fel�lb�r�lja (override) a virtu�lis f�ggv�ny b�zisoszt�lybeli
v�ltozat�t. Hacsak
k�zvetlen m�don meg nem mondjuk, hogy a virtu�lis f�ggv�ny melyik v�ltozat�t
akarjuk
haszn�lni . mint az Employee::print() h�v�sn�l ., az objektumhoz legink�bb illo
fel�l�r�
f�ggv�ny lesz megh�vva.
A glob�lis print_employee() f�ggv�ny (�12.2.5) sz�ks�gtelen, mert a hely�be a
print() tagf
�ggv�nyek l�ptek. Az alkalmazottak (Employee) list�j�t �gy �rathatjuk ki:
void print_list(const list<Employee*>& s)
{
for (list<Employee*>::const_iterator p = s.begin(); p!=s.end(); ++p) // l�sd
�2.7.2
(*p)->print();
}
De ak�r �gy is:
void print_list(const list<Employee*>& s)
{
for_each(s.begin(),s.end(),mem_fun(&Employee::print)); // l�sd �3.8.5
}
Minden Employee a t�pus�nak megfeleloen �r�dik ki. A
int main()
{
Employee e("Brown",1234);
Manager m("Smith",1234,2);
list<Employee*> empl;
empl.push_front(&e); // �2.5.4
empl.push_front(&m);
print_list(empl);
}
p�ld�ul az al�bbi kimenetet eredm�nyezi:
Smith 1234
szint 2
Brown 1234
Ez akkor is muk�dik, ha a print_list() f�ggv�nyt azelott �rtuk meg �s ford�tottuk
le, mielott
a Manager oszt�lyt egy�ltal�n kital�ltuk volna! Ez az oszt�lyoknak egy
kulcsfontoss�g� tulajdons
�ga. Ha helyesen alkalmazzuk, az objektumorient�lt tervez�s sarokk�ve lesz �s
a programok fejleszt�s�n�l bizonyos fok� stabilit�st ad.
12. Sz�rmaztatott oszt�lyok 409
Azt, hogy az Employee f�ggv�nyei att�l f�ggetlen�l .helyesen. viselkednek, hogy
pontosan
milyen fajta Employee-re h�vtuk meg azokat, t�bbalak�s�gnak (polimorfizmus,
polymorphism) nevezz�k. A virtu�lis f�ggv�nyekkel b�r� t�pus neve t�bbalak� t�pus
(polimorfikus t�pus). A C++ nyelvben a t�bbalak� viselked�st virtu�lis f�ggv�nyek
haszn�-
lat�val vagy az objektumoknak mutat�kon vagy referenci�kon �t val� kezel�s�vel
�rhetj�k
el. Ha k�zvetlen�l kezel�nk egy objektumot �s nem mutat� vagy referencia
seg�ts�g�vel,
a ford�t�program felismeri annak pontos t�pus�t, �gy a fut�si ideju t�bbalak�s�gra
nincs
sz�ks�g.
Vil�gos, hogy a t�bbalak�s�g t�mogat�sa �rdek�ben a ford�t�programnak minden
Employee
t�pus� objektumban valamilyen, a t�pusra vonatkoz� inform�ci�t (t�pusinform�ci�t)
kell
nyilv�ntartania, melynek seg�ts�g�vel k�pes a megfelelo print() f�ggv�nyt
megh�vni. Ehhez
rendszerint egyetlen mutat�nyi hely is el�g, �s erre is csak azon oszt�lyokban van
sz�ks�g,
amelyeknek van virtu�lis f�ggv�ny�k; teh�t nem minden oszt�lyban �s m�g csak nem
is
minden sz�rmaztatott oszt�lyban. A t�pusmezos megold�s v�laszt�sa eset�n ehhez
k�pest jelent
os mennyis�gu t�rter�letet kellett volna a t�pusmezo sz�m�ra biztos�tanunk.
Ha egy f�ggv�nyt (mik�nt a Manager::print()-et is) a :: hat�k�r-felold� oper�tor
seg�ts�g�-
vel h�vunk meg, akkor ez�ltal kikapcsoljuk a virtualit�st. M�sk�l�nben a
Manager::print()
v�gtelen rekurzi�t id�zne elo. A minos�tett n�v haszn�lat�nak van m�g egy elonye:
ha egy
virtu�lis f�ggv�ny inline (ami elo szokott fordulni), akkor a ford�t�program a ::
minos�tovel
jelzett h�v�sokat k�pes helyben kifejteni. Ennek seg�ts�g�vel a programoz�
hat�konyan k�-
pes azokat az egyedi eseteket kezelni, amikor mondjuk egy virtu�lis f�ggv�ny
ugyanarra az
objektumra egy m�sik f�ggv�nyt is megh�v. A Manager::print() f�ggv�ny ennek
p�ld�ja.
Minthogy a Manager::print() megh�v�sakor meghat�rozzuk az objektum t�pus�t, az
Employee::print() ezt k�veto megh�v�sakor a t�pusr�l m�r nem kell �jra d�nteni.
�rdemes megeml�teni, hogy a virtu�lis f�ggv�nyh�v�s hagyom�nyos �s nyilv�nval�
megval
�s�t�sa az egyszeru k�zvetett f�ggv�nyh�v�s (indirekci�) (�2.5.5), �gy a
hat�konys�g elveszt
�s�tol val� f�lelem ne riasszon vissza senkit a virtu�lis f�ggv�nyek haszn�lat�t�l
ott, ahol
egy k�z�ns�ges f�ggv�nyh�v�s elfogadhat�an hat�kony.
410 Absztrakci�s m�dszerek
12.3. Absztrakt oszt�lyok
Sok oszt�ly hasonl�t az Employee oszt�lyra annyiban, hogy �nmag�ban �s
sz�rmaztatott
oszt�lyok b�zisoszt�lyak�nt is hasznos. Az ilyen oszt�lyok sz�m�ra elegendoek az
elozo
pontban bemutatott m�dszerek. De nem minden oszt�ly ilyen. Bizonyos oszt�lyok,
p�ld�-
ul a Shape (Alakzat), olyan elvont fogalmakat jelen�tenek meg, amelyekhez nem
l�tezhetnek
objektumok. A Shape-nek csak mint b�zisoszt�lynak van �rtelme. Ez abb�l is
l�that�,
hogy nem tudunk hozz� virtu�lis f�ggv�nyeket �rtelmesen defini�lni:
class Shape {
public:
virtual void rotate(int) { error("Shape::rotate"); } // nem "eleg�ns"
virtual void draw() { error("Shape::draw"); }
// ...
};
Egy ilyen meghat�rozatlan alakzatot meg tudunk ugyan adni (a nyelv megengedi), de
nem
sok �rtelme van:
Shape s; // butas�g: "alak n�lk�li alakzat"
A dolog az�rt �rtelmetlen, mert az s minden muvelete hib�t fog eredm�nyezni.
Jobb megold�s, ha a Shape oszt�ly virtu�lis f�ggv�nyeit tiszt�n virtu�lis (pure
virtual) f�ggv
�nyk�nt deklar�ljuk. A virtu�lis f�ggv�nyek az =0 .kezdeti �rt�kad�st�l. lesznek
tiszt�n
virtu�lisak:
class Shape { // absztrakt oszt�ly
public:
virtual void rotate(int) = 0; // tiszt�n virtu�lis f�ggv�ny
virtual void draw() = 0; // tiszt�n virtu�lis f�ggv�ny
virtual bool is_closed() = 0; // tiszt�n virtu�lis f�ggv�ny
// ...
};
Ha egy oszt�ly legal�bb egy tiszt�n virtu�lis f�ggv�nnyel rendelkezik, akkor
absztrakt oszt
�lynak (elvont oszt�ly, abstract class) h�vjuk, ilyen oszt�lyba tartoz� objektumot
pedig nem
hozhatunk l�tre:
Shape s; // hiba: s az absztrakt Shape oszt�ly v�ltoz�ja lenne
12. Sz�rmaztatott oszt�lyok 411
Az absztrakt oszt�lyokat csak fel�letk�nt (interface), illetve m�s oszt�lyok
b�zisoszt�lyak�nt
haszn�lhatjuk:
class Point { /* ... */ };
class Circle : public Shape {
public:
void rotate(int) { } // a Shape::rotate fel�l�r�sa
void draw(); // a Shape::draw fel�l�r�sa
bool is_closed() { return true; } // a Shape::is_closed fel�l�r�sa
Circle(Point p, int r);
private:
Point center;
int radius;
};
Ha egy tiszt�n virtu�lis f�ggv�nyt a sz�rmaztatott oszt�lyban nem defini�lunk,
akkor az tiszt
�n virtu�lis f�ggv�ny marad, sot, a sz�rmaztatott oszt�ly is absztrakt oszt�ly
lesz. Ez a megval
�s�t�s l�pcsozetes fel�p�t�s�t teszi lehetov�:
class Polygon : public Shape { // absztrakt oszt�ly
public:
bool is_closed() { return true; } // a Shape::is_closed fel�l�r�sa
// ... a draw �s a rotate nincs fel�l�rva ...
};
Polygon b; // hiba: a Polygon oszt�lynak nem lehet objektuma
class Irregular_polygon : public Polygon {
list<Point> lp;
public:
void draw(); // a Shape::draw fel�l�r�sa
void rotate(int); // a Shape::rotate fel�l�r�sa
// ...
};
Irregular_polygon poly(some_points); // j� (megfelelo konstrukort felt�telezve)
Az absztrakt oszt�lyok fontos k�pess�ge, hogy seg�ts�g�kkel a megval�s�t�s egy�b
r�szeinek
el�rhetov� t�tele n�lk�l biztos�thatunk fel�letet. Egy oper�ci�s rendszer p�ld�ul
egy
absztrakt oszt�ly m�g� rejtheti eszk�zmeghajt�inak tulajdons�gait:
class Character_device {
public:
virtual int open(int opt) = 0;
virtual int close(int opt) = 0;
412 Absztrakci�s m�dszerek
virtual int read(char* p, int n) = 0;
virtual int write(const char* p, int n) = 0;
virtual int ioctl(int ...) = 0;
virtual ~Character_device() { } // virtu�lis destruktor
};
Az egyes eszk�zmeghajt�kat a Character_device-b�l sz�rmaztatott oszt�lyk�nt
defini�lhatjuk, �s sokf�le eszk�zmeghajt�t kezelhet�nk ezen fel�leten kereszt�l. A
virtu�lis
destruktorok fontoss�g�t a �12.4.2 pont magyar�zza el.
Az absztrakt oszt�lyok bevezet�s�vel imm�r minden eszk�z a kez�nkben van arra,
hogy
modul�ris m�don, �p�tok�vekk�nt oszt�lyokat haszn�lva egy teljes programot �rjunk.

12.4. Oszt�lyhierarchi�k tervez�se


Vegy�k a k�vetkezo egyszeru tervez�si probl�m�t: hogyan lehet egy program sz�m�ra
lehet
ov� tenni egy eg�sz �rt�k bek�r�s�t a felhaszn�l�i fel�letrol? Zavarbaejtoen
sokf�le m�don.
Ahhoz, hogy elszigetelj�k programunkat ettol a sokf�les�gtol �s felder�thess�k a
k�l�nb�zo
tervez�si m�dokat, kezdj�k a munk�t ezen egyszeru adatbeviteli muvelet modellj�nek
fel�ll
�t�s�val. A t�nyleges felhaszn�l�i fel�let elk�sz�t�s�nek r�szleteit k�sobbre
halasztjuk.
Az alap�tlet az, hogy lesz egy Ival_box (�rt�kmezo) oszt�lyunk, amely tudja, hogy
milyen
�rt�keket fogadhat el. A program elk�rheti egy Ival_box objektum �rt�k�t �s
felsz�l�thatja
arra is, hogy k�rje be ezt az �rt�ket a felhaszn�l�t�l, ha m�g nem �ll
rendelkez�sre. Azt is
megk�rdezheti, hogy az �rt�k megv�ltozott-e a legut�bbi k�r�s �ta.
Minthogy ez az alap�tlet sokf�lek�ppen megval�s�that�, abb�l kell kiindulnunk,
hogy sokf
�le k�l�nb�zo Ival_box lesz: cs�szk�k, sz�veges adatbeviteli mezok, ahov� a
felhaszn�l�
be�rhatja az �rt�ket, sz�mt�rcs�k, hanggal vez�relheto eszk�z�k.
Azt az �ltal�nos megk�zel�t�st alkalmazzuk, hogy egy virtu�lis felhaszn�l�i
fel�letet. bocs�-
tunk az alkalmaz�s rendelkez�s�re, amely a l�tezo felhaszn�l�i fel�letek
szolg�ltat�sainak
egy r�sz�t biztos�tja. E fel�let sz�mos rendszeren elk�sz�theto, �gy k�dja
.hordozhat�. lesz.
Term�szetesen vannak m�s m�dok is arra, hogy egy alkalmaz�st elv�lasszunk a
felhaszn�-
l�i fel�lettol. Az�rt v�lasztottam ezt, mert �ltal�nos, mert a kapcs�n egy sor
elj�r�st �s tervez
�si szempontot lehet bemutatni, mert ezeket a m�dszereket alkalmazz�k a val�di
felhasz-
12. Sz�rmaztatott oszt�lyok 413
n�l�i fel�leteteket kezelo rendszerekben, �s v�g�l . a legl�nyegesebb ok ., mert
ezek
a m�dszerek a felhaszn�l�i fel�letetek szuk tartom�ny�n�l j�val sz�lesebb k�rben
is alkalmazhat
�k.
12.4.1. Hagyom�nyos oszt�lyhierarchia
Elso megold�sunk egy hagyom�nyos oszt�lyhierarchia; ilyennel a Simula, Smalltalk
�s r�-
gebbi C++-programokban tal�lkozhatunk.
Az Ival_box oszt�ly az �sszes Ival_box �ltal haszn�latos fel�letet �rja le �s egy
olyan alap�rtelmezett
megval�s�t�st ad, melyet az egyes Ival_box-ok saj�tjaikkal fel�lb�r�lhatnak. Ezenk
�v�l megadjuk az alapmegold�shoz sz�ks�ges adatokat is:
class Ival_box {
protected:
int val;
int low, high;
bool changed;
public:
Ival_box(int ll, int hh) { changed = false; val = low = ll; high = hh; }
virtual int get_value() { changed = false; return val; }
virtual void set_value(int i) { changed = true; val = i; } // felhaszn�l�k sz�m�ra

virtual void reset_value(int i) { changed = false; val = i; } // alkalmaz�sok


sz�m�ra
virtual void prompt() { }
virtual bool was_changed() const { return changed; }
};
A f�ggv�nyek alap�rtelmezett v�ltozatai meglehetosen v�zlatosak, .pongyol�k.;
c�ljuk legink
�bb az, hogy illusztr�lj�k a megk�zel�t�st. (Egy .val�di. oszt�ly p�ld�ul
�rt�kellenorz�st
is v�gezne.)
Az .ival oszt�lyokat. egy programoz� �gy haszn�lhatn� fel:
void interact(Ival_box* pb)
{
pb->prompt(); // jelz�s a felhaszn�l�nak
// ...
int i = pb->get_value();
if (pb->was_changed()) {
// �j �rt�k; valamit csin�lunk vele
}
414 Absztrakci�s m�dszerek
else {
// a r�gi �rt�k j� volt; ezt is felhaszn�ljuk valahogy
}
// ...
}
void some_fct()
{
Ival_box* p1 = new Ival_slider(0,5); // az Ival_slider az Ival_box oszt�lyb�l
sz�rmazik
interact(p1);
Ival_box* p2 = new Ival_dial(1,12);
interact(p2);
}
A programk�d legnagyobb r�sze az interact() f�ggv�ny st�lus�ban �r�dna, �s
egyszeru
Ival_box-okat, illetve azokra hivatkoz� mutat�kat haszn�lna. �gy a programnak nem
kellene
tudnia az esetleg nagy sz�m� k�l�nb�zo Ival_box-v�ltozatokr�l, csak annak a
viszonylag
kis sz�m� f�ggv�nynek kellene ismernie azokat, amelyek ilyen objektumokat
l�trehoznak.
Ez a felhaszn�l�kat elszigeteli a sz�rmaztatott oszt�lyok esetleges
m�dos�t�sait�l.
A k�d legnagyobb r�sz�nek m�g arr�l sem kell tudnia, hogy egy�ltal�n k�l�nb�zo
Ival_box-ok l�teznek.
Hogy egyszerus�tsem a t�rgyal�st, eltekintek att�l a k�rd�stol, hogyan v�r a
program bemenetre.
Lehets�ges megold�s, hogy a program a get_value() f�ggv�nyben t�nylegesen v�r
a felhaszn�l�i bemenetre, megoldhat� �gy is, hogy az Ival_box-ot egy esem�nyhez
kapcsoljuk
�s egy visszah�v�s (callback) seg�ts�g�vel v�laszolunk, esetleg a programmal k�l�n

v�grehajt�si sz�lat ind�ttatunk el az Ival_box sz�m�ra, majd a sz�l �llapot�t


k�rdezz�k le.
Az ilyen d�nt�sek alapveto fontoss�g�ak a felhaszn�l�i fel�letet kezelo rendszerek
tervez
�sekor, de ha itt a val�s�got ak�r csak megk�zel�to r�szletess�ggel t�rgyaln�nk
ezeket, elvonn
�nk a figyelmet a programoz�si elj�r�sok �s nyelvi eszk�z�k t�rgyal�s�t�l. Az itt
bemutatott
tervez�si m�dszerek �s az azokat t�mogat� nyelvi eszk�z�k nem k�todnek adott
felhaszn�l�i fel�lethez; j�val sz�lesebb k�rben is alkalmazhat�k.
A k�l�nb�zo Ival_box-okat az Ival_box-b�l sz�rmaztatott oszt�lyokk�nt
hat�rozhatjuk meg:
class Ival_slider : public Ival_box {
// a cs�szka kin�zet�t, viselked�s�t meghat�roz� grafikai elemek
public:
Ival_slider(int, int);
int get_value();
void prompt();
};
Az Ival_box adattagjait v�dettk�nt (protected) vezett�k be, hogy a sz�rmaztatott
oszt�lyok-
12. Sz�rmaztatott oszt�lyok 415
b�l el�rhetoek legyenek. �gy azt�n az Ival_slider::get_value() f�ggv�ny
elhelyezheti az �rt
�ket az Ival_box::val adattagban. A v�dett tagok el�rhetok az oszt�ly �s a
sz�rmaztatott oszt
�lyok f�ggv�nyei sz�m�ra is, de az �ltal�nos felhaszn�l� sz�m�ra nem (�15.3).
Az Ival_box-b�l az Ival_slider mellett m�s v�ltozatokat is sz�rmaztathatunk. Ezek
k�z�tt ott
lehet az Ival_dial, amelyn�l egy gomb forgat�s�val adhatunk meg egy �rt�ket,
a Flashing_ival_slider, amely felvillan, ha a prompt() f�ggv�nnyel erre k�rj�k, �s

a Popup_ival_slider, amely a prompt() hat�s�ra valamilyen feltuno helyen jelenik


meg,
a felhaszn�l�t�l szinte kik�vetelve egy �rt�k megad�s�t.
De vajon honnan vegy�k a grafikus elemeket? A legt�bb felhaszn�l�i fel�letet
kezelo rendszer
biztos�t egy oszt�lyt, amely le�rja a k�pernyon levo objektumok alapveto
tulajdons�gait.
Ha p�ld�ul a .Big Bucks Inc.. (.Sok P�nz Rt..) rendszer�t haszn�ljuk, akkor az
Ival_slider, az Ival_dial stb. oszt�lyok mindegyike egy-egy fajta BBwindow (Big
Bucks
window) kell, hogy legyen. Ezt a legegyszerubben �gy �rhetj�k el, ha Ival_box-
unkat �gy
�rjuk �t, hogy a BBwindow-b�l sz�rmaztatott oszt�ly legyen. �gy azt�n az �sszes
oszt�lyunk
a BBwindow-b�l sz�rmaztatott lesz, teh�t elhelyezheto lesz a k�pernyon,
megjelen�se igazodik
majd a rendszer t�bbi grafikus elem�nek megjelen�s�hez, �tm�retezheto, �thelyezhet
o lesz stb., a BBwindow rendszer szab�lyainak megfeleloen. Oszt�lyhierarchi�nk
teh�t
�gy fog kin�zni:
class Ival_box : public BBwindow { /* ... */ }; // �jra�rva a BBwindow
haszn�lat�ra
class Ival_slider : public Ival_box { /* ... */ };
class Ival_dial : public Ival_box { /* ... */ };
class Flashing_ival_slider : public Ival_slider { /* ... */ };
class Popup_ival_slider : public Ival_slider { /* ... */ };
�br�val:
416 Absztrakci�s m�dszerek
BBwindow
Ival_box
Ival_slider Ival_dial
Popup_ival_slider Flashing_ival_slider
12.4.1.1. B�r�lat
Ez �gy sok tekintetben j�l fog muk�dni �s az ilyesfajta oszt�lyfel�p�t�s sz�mos
probl�m�ra
j� megold�s. �m van n�h�ny h�tul�toje, melyek miatt m�s tervez�si lehetos�gek ut�n
fogunk
n�zni.
A BBwindow oszt�lyt ut�lag tett�k az Ival_box b�zisoszt�ly�v�, ami nem eg�szen
helyes.
A BBwindow oszt�ly nem alapveto r�sze az Ival_box-ra �p�tett rendszernek, megl�te
csup
�n r�szletk�rd�s. Az, hogy az Ival_box a BBwindow oszt�ly lesz�rmazottja, ezt a
r�szletk
�rd�st elsorendu tervez�si d�nt�ss� emeli. Ez abban az esetben helyes, ha c�g�nk
kulcsfontoss
�g� �zleti d�nt�se, hogy a .Big Bucks Inc.. �ltal biztos�tott k�rnyezetet
haszn�ljuk.
De mi t�rt�nik, ha Ival_box-unkat olyan rendszerekre is �t szeretn�nk �ltetni,
melyek az
.Imperial Bananas., a .Liberated Software. vagy a .Compiler Whizzles.-tol
sz�rmaznak? Ekkor
programunkb�l n�gy v�ltozatot kellene k�sz�ten�nk:
class Ival_box : public BBwindow { /* ... */ }; // BB v�ltozat
class Ival_box : public CWwindow { /* ... */ }; // CW v�ltozat
class Ival_box : public IBwindow { /* ... */ }; // IB v�ltozat
class Ival_box : public LSwindow { /* ... */ }; // LS v�ltozat
Ha ennyi v�ltozatunk van, m�dos�t�suk, v�ltozatk�vet�s�k r�m�lomm� v�lhat.
Egy m�sik probl�ma, hogy az Ival_box-ban deklar�lt adatok minden sz�rmaztatott
oszt�ly
rendelkez�s�re �llnak. Ezek az adatok megint csak egy .apr�. r�szletet jelentenek,
m�gis
beker�ltek az Ival_box fel�letbe. Ez gyakorlati szempontb�l azt is jelenti, hogy
nem biztos
�tott, hogy mindig a megfelelo adatot kapjuk. Az Ival_slider eset�ben p�ld�ul nem
sz�ks�-
ges az adat k�l�n t�rol�sa, minthogy ez a cs�szka �ll�s�b�l meghat�rozhat�,
valah�nyszor
v�grehajtj�k a get_value()-t. �ltal�ban is problematikus k�t rokon, de elt�ro
adathalmaz t�-
rol�sa. Elobb-ut�bb valaki el�ri, hogy ne legyenek t�bb� �sszhangban. A
tapasztalat is azt
mutatja, hogy kezdo programoz�k sz�ks�gtelen �s nehezebb m�dos�that�s�got eredm�-
nyezo m�don szeretnek a v�dett (protected) adattagokkal �gyeskedni. Jobb, ha az
adattagok
priv�tok, mert �gy a sz�rmaztatott oszt�lyok �r�i nem zavarhatj�k �ssze azokat.
M�g
jobb, ha az adatok a sz�rmaztatott oszt�lyokban vannak, mert akkor pontosan meg
tudnak
felelni a k�vetelm�nyeknek �s nem keser�thetik meg az egym�ssal nem rokon
sz�rmaztatott
oszt�lyok �let�t. A v�dett fel�let szinte mindig csak f�ggv�nyeket, t�pusokat �s
konstansokat
tartalmazzon.
Ha az Ival_box a BBwindow-b�l sz�rmazik, ez azzal az elonnyel j�r, hogy az
Ival_box felhaszn
�l�i a BBwindow minden szolg�ltat�s�t ig�nybe vehetik, ami sajnos azt is jelenti,
hogy
a BBwindow oszt�ly v�ltoz�sakor az Ival_box felhaszn�l�inak �jra kell ford�taniuk,
esetleg
�jra kell �rniuk a k�djukat. A legt�bb C++-v�ltozat �gy muk�dik, hogy ha egy
b�zisoszt�ly
m�rete megv�ltozik, akkor az �sszes sz�rmaztatott oszt�lyt �jra kell ford�tani.
12. Sz�rmaztatott oszt�lyok 417
V�g�l lehets�ges, hogy programunknak olyan vegyes k�rnyezetben kell futnia, ahol
k�l�nb
�zo felhaszn�l�i fel�letek ablakai l�teznek egyidejuleg. Vagy az�rt, mert valahogy
ezek
egy k�pernyon tudnak osztozni, vagy mert programunknak k�l�nb�zo rendszerek
felhaszn
�l�ival kell kapcsolatot tartania. Ehhez pedig nem el�g rugalmas megold�s, ha a
felhaszn
�l�i fel�letet az egyetlen Ival_box fel�let�nk b�zisoszt�lyak�nt .bedr�tozzuk..
12.4.2. Absztrakt oszt�lyok
Nos, kezdj�k �jra a tervez�st, hogy megoldjuk a hagyom�nyos fel�p�t�s b�r�lat�ban
felvetett
probl�m�kat:
1. A felhaszn�l�i fel�let val�ban olyan r�szletk�rd�s legyen, amelyrol nem kell
tudom�st venni�k azon felhaszn�l�knak, akiket nem �rdekel.
2. Az Ival_box oszt�ly ne tartalmazzon adatokat.
3. Ha megv�ltozik a felhaszn�l�i fel�letet kezelo rendszer, ne legyen sz�ks�ges
az Ival_box csal�dot felhaszn�l� k�d �jraford�t�sa.
4. K�l�nb�zo felhaszn�l�i fel�letekhez tartoz� Ival_box-ok tudjanak egyszerre
l�tezni a programban.
T�bbf�le megold�s k�n�lkozik erre; most egy olyat mutatok be, amely tiszt�n
megval�s�that
� a C++ nyelvvel.
Elosz�r is, az Ival_box oszt�lyt puszta fel�letk�nt (pure interface) hat�rozzuk
meg:
class Ival_box {
public:
virtual int get_value() = 0;
virtual void set_value(int i) = 0;
virtual void reset_value(int i) = 0;
virtual void prompt() = 0;
virtual bool was_changed() const = 0;
virtual ~Ival_box() { }
};
Ez sokkal vil�gosabb, mint az Ival_box oszt�ly eredeti deklar�ci�ja volt.
Elhagytuk az adattagokat
�s a tagf�ggv�nyek egyszerus�tett kifejt�s�t is. Elmaradt a konstruktor is, mivel
nincs kezdo�rt�kre v�r� adat. Ehelyett egy virtu�lis destruktorunk van, amely
biztos�tja az
�r�klo oszt�lyok adatainak helyes .eltakar�t�s�t..
418 Absztrakci�s m�dszerek
Az Ival_slider defin�ci�ja �gy alakulhat:
class Ival_slider : public Ival_box, protected BBwindow {
public:
Ival_slider(int,int);
~Ival_slider();
int get_value();
void set_value(int i);
// ...
protected:
// a BBwindow virtu�lis f�ggv�nyeit fel�l�r� f�ggv�nyek
// pl. BBwindow::draw(), BBwindow::mouse1hit()
private:
// a cs�szka adatai
};
Mivel az Ival_slider oszt�ly az absztrakt Ival_box oszt�lyb�l sz�rmazik, meg kell
val�s�tania
annak tiszt�n virtu�lis (pure virtual) f�ggv�nyeit. A BBwindow oszt�lyb�l is
sz�rmazik, ez�rt
onnan val�k az eszk�zei, melyekkel ezt megteheti. Az Ival_box adja a sz�rmaztatott
oszt�ly
fel�let�t, ez�rt nyilv�nos (public) m�don sz�rmazik onnan. Mivel a BBwindow
oszt�lyb�l
val� sz�rmaz�sa mind�ssze seg�ts�get ny�jt a megval�s�t�shoz, onnan v�dett
(protected)
m�don sz�rmazik (�15.3.2). Ebbol k�vetkezik, hogy az Ival_slider-t felhaszn�l�
programoz�
nem haszn�lhatja k�zvetlen�l a BBwindow �ltal ny�jtott eszk�z�ket. Az Ival_slider
fel�lete
az Ival_box-t�l �r�k�lt r�szbol �ll, illetve abb�l, amit maga az Ival_slider
kifejezetten
deklar�l. Az�rt haszn�lunk v�dett sz�rmaztat�st a szigor�bb megk�t�st jelento (�s
�ltal�ban
biztons�gosabb) priv�t helyett, hogy az Ival_slider-bol sz�rmaztatott oszt�lyok
sz�m�ra
a BBwindow-t el�rhetov� tegy�k.
A t�bb oszt�lyb�l val� k�zvetlen �r�klod�st �ltal�ban t�bbsz�r�s �r�klod�snek
(multiple
inheritance) h�vj�k (�15.2). Vegy�k �szre, hogy Ival_slider-nek mind az Ival_box,
mind
a BBwindow f�ggv�nyei k�z�l fel�l kell �rnia n�h�nyat, ez�rt k�zvetve vagy
k�zvetlen�l
mindk�t oszt�lyb�l sz�rmaznia kell. Mint a �12.4.1.1 pontban l�ttuk, lehets�ges
ugyan az
Ival_slider k�zvetett sz�rmaztat�sa a BBwindow-b�l (az�ltal, hogy az Ival_box
a BBwindow-b�l sz�rmazik), de ez nemk�v�natos mell�khat�sokkal j�r. Hasonl�an, az
az
�t, hogy a BBwindow .megval�s�t�si oszt�ly. tagja legyen az Ival_box-nak, nem
j�rhat�,
mert egy oszt�ly nem �rhatja fel�l tagjainak virtu�lis f�ggv�nyeit (�24.3.4). Az
ablaknak az
Ival_box oszt�ly egy BBwindow* t�pus� tagjak�nt val� �br�zol�sa teljesen elt�ro
szerkezethez
vezet, melynek megvannak a maga elonyei �s h�tr�nyai (�12.7[14], �25.7).
�rdekes m�don az Ival_slider ilyen m�don val� deklar�l�sa eset�n ugyanolyan k�dot
�rhatunk,
mint azelott. Csak az�rt v�ltoztattunk, hogy a szerkezet logikusabb m�don t�kr�zze
a megval�s�t�st.
12. Sz�rmaztatott oszt�lyok 419
Sz�mos oszt�lynak sz�ks�ge van valamilyen .rendrak�sra., mielott egy objektuma
megsemmis
�l. Mivel az absztrakt Ival_box oszt�ly nem tudhatja, hogy egy sz�rmaztatott
oszt�lynak
nincs-e sz�ks�ge erre, fel kell t�teleznie, hogy igenis sz�ks�g van r�. A
rendrak�st �gy
biztos�tjuk, hogy a b�zisoszt�lyban defini�ljuk az Ival_box::~Ival_box() virtu�lis
destruktort
�s a sz�rmaztatott oszt�lyokban megfelelo m�don fel�l�rjuk azt:
void f(Ival_box* p)
{
// ...
delete p;
}
A delete oper�tor megsemmis�ti az objektumot, amelyre p mutat. Nem tudhatjuk, hogy
pontosan
milyen oszt�ly� objektumr�l van sz�, de mivel az Ival_box-nak virtu�lis
destruktora
van, a megfelelo destruktor fog megh�v�dni, (ha az adott oszt�lynak van ilyen).
Az Ival_box hierarchi�t most �gy �rhatjuk le:
class Ival_box { /* ... */ };
class Ival_slider : public Ival_box, protected BBwindow { /* ... */ };
class Ival_dial : public Ival_box, protected BBwindow { /* ... */ };
class Flashing_ival_slider : public Ival_slider { /* ... */ };
class Popup_ival_slider : public Ival_slider { /* ... */ };
Egyszeru r�vid�t�sekkel pedig �gy �br�zolhatjuk:
A szaggatott nyilak a v�dett (protected) m�d� �r�klod�st jel�lik. Az �ltal�nos
felhaszn�l�k
sz�m�ra ezek csak r�szletk�rd�sek.
420 Absztrakci�s m�dszerek
BBwindow
Ival_slider Ival_dial
Popup_slider Flashing_slider
Ival_box BBwindow
12.4.3. Egy�b megval�s�t�sok
Ez a szerkezet tiszt�bb �s k�nnyebben m�dos�that�, mint a hagyom�nyos, de nem
kev�sb
� hat�kony. A v�ltozatk�vet�si probl�m�t azonban nem oldja meg:
class Ival_box { /* ... */ }; // k�z�s
class Ival_slider : public Ival_box, protected BBwindow { /* ... */ }; // BB
class Ival_slider : public Ival_box, protected CWwindow { /* ... */ }; // CW
// ...
R�ad�sul a BBwindow-hoz �s a CWwindow-hoz �rt Ival_slider-ek nem l�tezhetnek
egy�tt,
m�g akkor sem, ha egy�bk�nt maguk a BBwindow �s CWwindow felhaszn�l�i fel�letek
igen.
A nyilv�nval� megold�s az, hogy k�l�nb�zo nevu Ival_slider oszt�lyokat hozunk
l�tre:
class Ival_box { /* ... */ };
class BB_ival_slider : public Ival_box, protected BBwindow { /* ... */ };
class CW_ival_slider : public Ival_box, protected CWwindow { /* ... */ };
// ...
�br�val:
Hogy programunk Ival_box oszt�lyait jobban elszigetelj�k a megval�s�t�s egy�b
r�szleteit
ol, sz�rmaztathatunk egy absztrakt Ival_slider oszt�lyt az Ival_box-b�l, majd
ebbol �r�k�ltethetj
�k az egyes rendszerf�ggo Ival_slider-eket:
class Ival_box { /* ... */ };
class Ival_slider : public Ival_box { /* ... */ };
class BB_ival_slider : public Ival_slider, protected BBwindow { /* ... */ };
class CW_ival_slider : public Ival_slider, protected CWwindow { /* ... */ };
// ...
12. Sz�rmaztatott oszt�lyok 421
BBwindow
BB_ival_slider CW_ival_slider
Ival_box CWwindow
�br�val:
�ltal�ban m�g enn�l is jobban j�runk, ha a hierarchi�ban egyedibb oszt�lyokat
haszn�lunk.
Ha p�ld�ul a .Big Bucks Inc.. rendszer�ben van egy cs�szka (slider) oszt�ly, akkor
a mi
Ival_slider-�nket k�zvetlen�l a BBslider-bol sz�rmaztathatjuk:
class BB_ival_slider : public Ival_slider, protected BBslider { /* ... */ };
class CW_ival_slider : public Ival_slider, protected CWslider { /* ... */ };
�br�val:
Ez a jav�t�s jelentos lehet abban a (surun elofordul�) esetben, ha a mi fogalmaink
nem esnek
t�vol a megval�s�t�s c�lj�b�l felhaszn�lt rendszer fogalmait�l. Ekkor a
programoz�s tulajdonk
�ppen a rokon fogalmak k�z�tti lek�pez�sre egyszerus�dik, �s a BBwindow-hoz
hasonl� �ltal�nos b�zisoszt�lyokb�l val� �r�klod�s ritk�n fordul elo. A teljes
hierarchia
egyr�szt az eredeti, alkalmaz�sk�zpont� rendszer sz�rmaztatott oszt�lyokk�nt
megval�s�-
tott fel�leteinek viszonyrendszer�bol fog �llni:
class Ival_box { /* ... */ };
class Ival_slider : public Ival_box { /* ... */ };
class Ival_dial : public Ival_box { /* ... */ };
class Flashing_ival_slider : public Ival_slider { /* ... */ };
class Popup_ival_slider : public Ival_slider { /* ... */ };
422 Absztrakci�s m�dszerek
BBwindow
BB_ival_slider CW_ival_slider
Ival_slider
Ival_box
CWwindow
BBslider
BB_ival_slider CW_ival_slider
Ival_slider CWslider
BBwindow Ival_box CWwindow
Illetve a hierarchi�t . szint�n az �r�klod�s seg�ts�g�vel . t�bbf�le grafikus
felhaszn�l�i fel�-
letre lek�pezo sz�rmaztatott oszt�lyokb�l:
class BB_ival_slider : public Ival_slider, protected BBslider { /* ... */ };
class BB_flashing_ival_slider : public Flashing_ival_slider,
protected BBwindow_with_bells_and_whistles { /* ... */ };
class BB_popup_ival_slider : public Popup_ival_slider, protected BBslider { /* ...
*/ };
class CW_ival_slider : public Ival_slider, protected CWslider { /* ... */ };
// ...
A kapott fel�p�tm�nyt egyszeru r�vid�t�sek seg�ts�g�vel �gy �br�zolhatjuk:
Az eredeti Ival_box hierarchia v�ltozatlan marad, csak a konkr�t megval�s�t�st
v�gzo oszt
�lyok veszik k�r�l.
12.4.3.1. B�r�lat
Az absztrakt oszt�lyokat haszn�l� oszt�lyszerkezet rugalmas �s majdnem ugyanolyan
egyszer
uen kezelheto, mint a konkr�t felhaszn�l�i fel�letet b�zisoszt�lyk�nt
szerepelteto.
Az ut�bbiban a fa gy�kere a megfelelo ablakoszt�ly, az elobbiben viszont
v�ltozatlanul az
alkalmaz�s oszt�lyhierarchi�ja marad a t�nyleges megval�s�t�st v�gzo oszt�lyok
alapja.
A program szempontj�b�l ezek a szerkezetek egyen�rt�kuek abban az �rtelemben, hogy

majdnem az eg�sz k�d v�ltoztat�s n�lk�l �s ugyan�gy muk�dik mindk�t esetben, �s


mindkett
on�l az alkalmazott felhaszn�l�i fel�lettol f�ggo elemekre val� tekintet n�lk�l
vizsg�lhatjuk
az Ival_box csal�d oszt�lyait. A �12.4.1-beli interact() f�ggv�nyt p�ld�ul nem
kell �jra
�rnunk, ha az egyik szerkezetrol a m�sikra v�ltunk.
12. Sz�rmaztatott oszt�lyok 423
Ival_box
Ival_slider Ival_dial
ipopup iflash
BBislider CWipop
BBslider
CWislider
BBslider CWsl CWsl BBb&w CWsl
BBipop CWifl BBifl
Mindk�t esetben �jra kell �rnunk az egyes Ival_box oszt�lyokat, ha a felhaszn�l�i
fel�let
nyilv�nos fel�lete megv�ltozik, de az absztrakt oszt�lyokat haszn�l� szerkezet
eset�ben
szinte az eg�sz k�d v�dett a megval�s�t�s v�ltoz�s�t�l �s egy ilyen v�ltoz�s ut�n
nem kell
�jraford�tani. Ez k�l�n�sen akkor fontos, ha a megval�s�t�st v�gzo elemek
k�sz�toje egy �j,
.majdnem kompatibilis. v�ltozatot bocs�t ki. R�ad�sul az absztrakt oszt�lyos
megold�st v�-
laszt�k a klasszikus hierarchia h�vein�l kev�sb� vannak kit�ve az egyedi, m�shol
nem haszn
�lhat� megval�s�t�s csapd�j�ba val� bez�r�d�s vesz�ly�nek. Az elvont Ival_box
oszt�-
lyokra �p�tett programot v�lasztva nem haszn�lhatjuk .v�letlen�l. a megval�s�t�
oszt�lyok
ny�jtotta lehetos�geket, mert csak az Ival_box hierarchi�ban kifejezetten megadott
leheto-
s�gek �rhetok el, semmi sem �r�klodik automatikusan egy rendszerf�ggo
b�zisoszt�lyt�l.
12.4.4. Az objektumok l�trehoz�s�nak adott helyre korl�toz�sa
A program legnagyobb r�sze meg�rhat� az Ival_box fel�let felhaszn�l�s�val. Ha a
sz�rmaztatott
fel�letek tov�bbfejlodnek �s t�bb szolg�ltat�st ny�jtanak, mint a sima Ival_box,
akkor
nagyr�szt haszn�lhatjuk az Ival_box, Ival_slider stb. fel�leteket. Az objektumokat
azonban
az adott rendszerre jellemzo nevek (p�ld�ul CW_ival_dial �s
BB_flashing_ival_slider) felhaszn
�l�s�val kell l�trehozni. J� lenne, ha az ilyen rendszerf�ggo nevek min�l kevesebb

helyen forduln�nak elo, mivel az objektumok l�trehoz�sa nehezen k�theto helyhez,


hacsak
nem szisztematikusan j�runk el.
Szok�s szerint az indirekci� (k�zvetett hivatkoz�s) bevezet�se a megold�s. Ezt
t�bbf�lek�ppen
is megtehetj�k. Egyszeru megold�s lehet p�ld�ul egy olyan oszt�ly bevezet�se,
amely
az objektumokat l�trehoz� muveletek�rt felelos:
class Ival_maker {
public:
virtual Ival_dial* dial(int, int) =0; // t�rcsa (dial) k�sz�t�se
virtual Popup_ival_slider* popup_slider(int, int) =0; // elougr� cs�szka (popup
slider)
// k�sz�t�se
// ...
};
Az Ival_maker oszt�ly az Ival_box hierarchia minden olyan fel�lete sz�m�ra
rendelkezik az
adott t�pus� objektumot l�trehoz� f�ggv�nnyel, mely fel�letrol a felhaszn�l�k
tudhatnak.
Az ilyen oszt�lyokat gy�rnak (factory) h�vj�k, f�ggv�nyeiket pedig . n�mik�pp
f�lrevezet
o m�don . virtu�lis konstruktoroknak (�15.6.2).
424 Absztrakci�s m�dszerek
Az egyes k�l�nb�zo felhaszn�l�i fel�leteket kezelo rendszereket most az Ival_maker
oszt
�lyb�l sz�rmaztatott oszt�lyokk�nt �br�zoljuk:
class BB_maker : public Ival_maker { // BB-v�ltozatok k�sz�t�se
public:
Ival_dial* dial(int, int);
Popup_ival_slider* popup_slider(int, int);
// ...
};
class LS_maker : public Ival_maker { // LS-v�ltozatok k�sz�t�se
public:
Ival_dial* dial(int, int);
Popup_ival_slider* popup_slider(int, int);
// ...
};
Minden f�ggv�ny a k�v�nt fel�letu �s megval�s�t�si t�pus� objektumot hozza l�tre:
Ival_dial* BB_maker::dial(int a, int b)
{
return new BB_ival_dial(a,b);
}
Ival_dial* LS_maker::dial(int a, int b)
{
return new LS_ival_dial(a,b);
}
Ha adott egy mutat� egy Ival_maker objektumra, akkor a programoz� ennek
seg�ts�g�vel
�gy hozhat l�tre objektumokat, hogy nem kell tudnia, pontosan milyen rendszeru
felhaszn
�l�i fel�let van haszn�latban:
void user(Ival_maker* pim)
{
Ival_box* pb = pim->dial(0,99); // megfelelo t�rcsa l�trehoz�sa
// ...
}
BB_maker BB_impl; // BB-felhaszn�l�knak
LS_maker LS_impl; // LS-felhaszn�l�knak
void driver()
{
user(&BB_impl); // BB haszn�lata
user(&LS_impl); // LS haszn�lata
}
12. Sz�rmaztatott oszt�lyok 425
12.5. Oszt�lyhierarchi�k �s absztrakt oszt�lyok
Az absztrakt oszt�lyok fel�letek (interface). Az oszt�lyhierarchia annak eszk�ze,
hogy fokozatosan
�p�ts�nk fel oszt�lyokat. Term�szetesen minden oszt�ly ad egy fel�letet a
programoz
� sz�m�ra, n�mely absztrakt oszt�ly pedig jelentos szolg�ltat�sokat k�n�l,
amelyekre
�p�thet�nk, de .fel�let. �s .�p�toko. szerep�k alapvetoen az absztrakt
oszt�lyoknak �s az
oszt�lyhierarchi�knak van.
Klasszikus hierarchi�nak azt a fel�p�t�st nevezz�k, amelynek egyes oszt�lyai
hasznos szolg
�ltat�sokat k�n�lnak a felhaszn�l�knak, illetve egyben a fejlettebb vagy egyedi
feladatot
v�gzo oszt�lyok sz�m�ra �p�toko�l szolg�lnak. Az ilyen fel�p�t�s ide�lisan
t�mogatja a l�-
p�senk�nti finom�t�ssal val� fejleszt�st, illetve az �j oszt�lyok l�trehoz�s�t,
amennyiben
ezek megfeleloen illeszkednek a hierarchi�ba.
A klasszikus fel�p�t�s a t�nyleges megval�s�t�st sokszor �sszekapcsolja a
felhaszn�l�knak
ny�jtott fel�lettel. Ez �gyben az absztrakt oszt�lyok seg�thetnek. Az absztrakt
oszt�lyok seg
�ts�g�vel fel�p�tett rendszer tiszt�bb �s hat�konyabb m�dot ad a fogalmak
kifejez�s�re,
an�lk�l hogy a megval�s�t�s r�szleteivel keveredne vagy jelentosen n�veln� a
program fut
�si idej�t. A virtu�lis f�ggv�nyek megh�v�sa egyszeru �s f�ggetlen att�l, hogy
mif�le elvonatkoztat
�si r�teg hat�r�t l�pi �t. Egy absztrakt oszt�ly virtu�lis f�ggv�ny�t megh�vni
semmivel
sem ker�l t�bbe, mint b�rmely m�s virtu�lis f�ggv�nyt.
A fentiekbol ad�d� v�gk�vetkeztet�s az, hogy egy rendszert a felhaszn�l�k fel�
mindig
absztrakt oszt�lyok hierarchi�jak�nt mutassunk, de klasszikus hierarchiak�nt
�p�ts�nk fel.
12.6. Tan�csok
[1] Ker�lj�k a t�pusmezok alkalmaz�s�t. �12.2.5.
[2] Az objektumok felszeletelod�s�t (slicing) elker�lendo haszn�ljunk mutat�kat �s

referenci�kat. �12.2.3.
[3] Haszn�ljunk absztrakt oszt�lyokat, hogy a vil�gos fel�letek elk�sz�t�s�re
�sszpontos
�thassunk. �12.3.
[4] Haszn�ljunk absztrakt oszt�lyokat, hogy min�l kisebb fel�leteket
haszn�lhassunk.
�12.4.2.
[5] Haszn�ljunk absztrakt oszt�lyokat, hogy a fel�leteket elv�lasszuk a
megval�s�t�-
si r�szletektol. �12.4.2.
426 Absztrakci�s m�dszerek
[6] Haszn�ljunk virtu�lis f�ggv�nyeket, hogy k�sobb �j megval�s�t�st k�sz�thess�nk

a meglevo felhaszn�l�i k�d befoly�sol�sa n�lk�l. �12.4.1.


[7] Haszn�ljunk absztrakt oszt�lyokat, hogy min�l kevesebbszer kelljen a
felhaszn�-
l�i k�dot �jraford�tani. �12.4.2.
[8] Haszn�ljunk absztrakt oszt�lyokat, hogy a program t�bbf�le rendszeren is mu-
k�dj�n. �12.4.3.
[9] Ha egy oszt�lynak van virtu�lis f�ggv�nye, akkor legyen virtu�lis destruktora
is.
�12.4.2.
[10] Az absztrakt oszt�lyoknak �ltal�ban nincs sz�ks�g�k konstruktorra. 12.4.2.
[11] Az �n�ll� fogalmakat k�l�n �br�zoljuk. �12.4.1.1.
12.7. Gyakorlatok
1. (*1) Ha adott a k�vetkezo:
class Base {
public:
virtual void iam() { cout << "B�zisoszt�ly\n"; }
};
Sz�rmaztassunk k�t oszt�lyt a Base-bol, mindegyiknek legyen egy iam() f�ggv
�nye, amely ki�rja az oszt�ly nev�t. Hozzunk l�tre egy-egy ilyen oszt�ly�
objektumot
�s h�vjuk meg r�juk az iam() f�ggv�nyt. Rendelj�nk a sz�rmaztatott
oszt�lyok objektumaira hivatkoz� mutat�kat Base* t�pus� mutat�khoz �s h�vjuk
meg ezeken kereszt�l az iam() f�ggv�nyt.
2. (*3.5) K�sz�ts�nk egy egyszeru grafikus rendszert a rendelkez�s�nk �ll�
grafikus
felhaszn�l�i fel�let felett. (Ha nincs ilyen vagy nincs tapasztalatunk ilyesmivel,

akkor k�sz�thet�nk egy egyszeru, ASCII karakterekbol fel�p�tett megval�s�-


t�st, ahol egy pont egy karakterpoz�ci�nak felel meg, �s az �r�s a megfelelo
karakter, mondjuk a * megfelelo poz�ci�ra val� helyez�s�t jelenti.)
Ebben a feladatban �s a tov�bbiakban a k�vetkezo oszt�lyokat haszn�ljuk:
Window (Ablak), Point (Pont), Line (Vonal), Dot (K�pernyopont), Rectangle
(T�glalap), Circle (K�r), Shape (Alakzat, Idom), Square (N�gyzet) �s Triangle
(H�romsz�g).
A Window(n,m) hozzon l�tre egy n-szer m m�retu ter�letet a k�pernyon.
A k�pernyo pontjait az (x,y) der�ksz�gu (descartes-i) koordin�t�k seg�ts�g�vel
c�mezz�k meg. A Window oszt�lyba tartoz� w aktu�lis helye . w.current() .
12. Sz�rmaztatott oszt�lyok 427
kezdetben Point(0,0). A poz�ci�t a w.current(p) h�v�ssal �ll�thatjuk be, ahol p
egy Point. A Point objektumokat egy koordin�ta-p�r adja meg: Point(x,y);
a Line objektumokat egy Point p�r . Line(w.current(),p2) .; a Shape oszt�ly
a Dot, a Line, a Rectangle, a Circle stb. k�z�s fel�lete. Egy Point nem Shape is
egyben. A Dot(p)-k�nt l�trehozott Dot egy Point p-t jelent a k�pernyon.
A Shape-ek nem l�that�k, am�g a draw() f�ggv�nyt meg nem h�vjuk; p�ld�ul:
w.draw(Circle(w.current(),10)). Minden Shape-nek 9 �rintkez�si pontja van: e
(east . kelet), w (west . nyugat), n (north . �szak), s (south . d�l), ne
(�szakkelet),
nw (�szaknyugat), se (d�lkelet), sw (d�lnyugat) �s c (center . k�z�ppont).
A Line(x.c(),y.nw()) p�ld�ul egy vonalat h�z az x k�zep�tol az y bal felso sark
�hoz. Ha egy Shape-re alkalmaztuk a draw() f�ggv�nyt, az aktu�lis poz�ci�
a Shape se()-je lesz. Egy Rectangle-t a bal als� �s a jobb felso cs�cs�val adunk
meg; Rectangle(w.current(),Point(10,10)). Egyszeru tesztk�nt jelen�ts�nk meg
egy gyermekrajzot, amely egy h�zat �br�zol tetovel, k�t ablakkal, �s egy ajt�val.
3. (*2) Egy Shape fontos r�szei szakaszokk�nt jelennek meg a k�pernyon. Adjunk
meg olyan muveleteket, amelyek seg�ts�g�vel meg tudjuk v�ltoztatni ezen szakaszok
kin�zet�t. Az s.thickness(n) a 0,1,2,3 �rt�kek valamelyik�re �ll�tsa be
a vonalsz�less�get, ahol a 2 az alap�rtelmezett �rt�k �s a 0 �rt�k azt jelenti,
hogy a vonal l�thatatlan. A vonal lehessen t�m�r, szaggatott vagy pontokb�l
�ll� is. Ezt a Shape::outline() f�ggv�ny �ll�tsa be.
4. (*2.5) �rjuk meg a Line::arrowhead() f�ggv�nyt, amely egy vonal v�g�re egy
nyilat rajzol. Minthogy egy vonalnak k�t v�ge van �s a ny�l a vonalhoz k�pest
k�tf�le ir�nyba mutathat, �gy az arrowhead() f�ggv�ny param�tere vagy param
�terei ki kell, hogy tudj�k fejezni ezt a n�gyf�le lehetos�get.
5. (*3.5) Gondoskodjunk arr�l, hogy azon pontok �s vonalszakaszok, amelyek
k�v�l esnek egy Window-n, ne jelenjenek meg. Ezt a jelens�get gyakran h�vj�k
.lev�g�snak. (clipping). E c�lb�l . gyakorlatk�nt . ne hagyatkozzunk a felhaszn
�lt grafikus felhaszn�l�i fel�letre.
6. (*2.5) Eg�sz�ts�k ki grafikai rendszer�nket a Text t�pussal. A Text legyen egy
t�glalap alak� Shape, amely karaktereket tud megjelen�teni. Alap�rtelmez�s szerint

egy karakter a koordin�ta-tengelyen minden ir�nyban egy egys�gnyi helyet


foglaljon el.
7. (*2) Hat�rozzunk meg egy f�ggv�nyt, amely megtal�lja k�t Shape egym�shoz
legk�zelebbi pontjait �s �sszek�ti azokat.
8. (*3) Vezess�k be grafikai rendszer�nkbe a sz�n fogalm�t. H�romf�le dolog lehet
sz�nes: a h�tt�r, egy z�rt Shape belseje �s egy Shape hat�ra.
428 Absztrakci�s m�dszerek
9. (*2) Vegy�k az al�bbi oszt�lyt:
class Char_vec {
int sz;
char element[1];
public:
static Char_vec* new_char_vec(int s);
char& operator[ ](int i) { return element[i]; }
// ...
};
Defini�ljuk a new_char_vec()-t, hogy egybef�ggo mem�riater�letet foglalhassunk
le egy Char_vec objektum sz�m�ra, �gy elemeit az element() f�ggv�nnyel
indexelhetj�k. Milyen k�r�lm�nyek k�z�tt okoz ez a tr�kk komoly probl�m�-
kat?
10. (*2.5) Ha adottak a Shape oszt�lyb�l sz�rmaz� Circle, Square �s Triangle
oszt�-
lyok, hat�rozzuk meg az intersect() f�ggv�nyt, amely k�t Shape* param�tert
vesz �s a megfelelo f�ggv�nyek megh�v�s�val meg�llap�tja, hogy a k�t Shape �tfed
o-e, metszi-e egym�st. Ehhez sz�ks�ges lesz az oszt�lyok megfelelo (virtu�-
lis) f�ggv�nyekkel val� bov�t�se. Ne �rjuk meg az �tfed�s t�nyleges meg�llap�t�-
s�ra szolg�l� k�dot, csak arra �gyelj�nk, hogy a megfelelo f�ggv�nyeket h�vjuk
meg. Ezt az elj�r�st angolul �ltal�ban .double dispatch. vagy .multi-method.
n�ven emlegetik.
11. (*5) Tervezz�nk �s �rjunk meg egy esem�nyvez�relt szimul�ci�kat v�gzo
k�nyvt�rat. Seg�ts�g: n�zz�k meg a <task.h> fej�llom�nyt. Ez egy r�gi program,
az olvas� jobbat tud �rni. Legyen egy task nevu oszt�ly. A task oszt�ly�
objektumok
legyenek k�pesek �llapotuk ment�s�re �s vissza�ll�t�s�ra (mondjuk
a task::save() �s a task::restore() f�ggv�nyekkel), hogy kieg�sz�to elj�r�sk�nt
(co-routine) muk�dhessenek. Az egyes elv�gzendo feladatokat a task oszt�lyb�l
�r�klo oszt�lyok objektumaik�nt adhassuk meg. A task-ok �ltal v�grehajtand�
programokat virtu�lis f�ggv�nyekkel hat�rozzuk meg. Egy �j task sz�m�ra legyen
lehets�ges param�tereket megadni konstruktora(i)nak param�terek�nt.
Legyen egy �temezo, amely megval�s�tja a virtu�lis ido fogalm�t. Legyen egy
task::delay(long) f�ggv�ny, amely .fogyasztja. ezt a virtu�lis idot. Az, hogy ez
az �temezo a task r�sze vagy �n�ll� oszt�ly lesz-e, a fo tervez�si d�nt�sek
egyike.
A task-oknak kapcsolatot kell tartaniuk egym�ssal. Erre a c�lra tervezz�nk
egy queue oszt�lyt. Egy task-nak legyen lehetos�ge t�bb forr�s felol �rkezo
bemenetre
v�rakozni. Kezelj�k a fut�si ideju hib�kat azonos m�don. Hogyan lehetne
egy ilyen k�nyvt�rat haszn�l� programban hibakeres�st v�gezni?
12. (*2) Hat�rozzuk meg egy kalandj�t�k sz�m�ra a Warrior (harcos), Monster
(sz�rny) �s Object (t�rgy; olyasmi, amit fel lehet kapni, el lehet dobni,
haszn�lni
lehet stb.) oszt�lyok fel�let�t.
12. Sz�rmaztatott oszt�lyok 429
13. (*1.5) Mi�rt van a �12.7[2]-ben Point �s Dot oszt�ly is? Milyen k�r�lm�nyek
k�-
z�tt lenne j� �tlet a Shape oszt�lyokat a kulcsoszt�lyok, p�ld�ul a Line konkr�t
v�ltozataival bov�teni?
14. (*3) V�zoljuk az Ival_box p�lda (�12.4) egy elt�ro megval�s�t�si m�dj�t:
minden,
a program �ltal el�rheto oszt�ly egyszeruen egy mutat�t tartalmazzon a megval�-
s�t� oszt�lyra. Ilyen m�don minden .fel�letoszt�ly. egy megval�s�t� oszt�ly le-
�r�ja (handle) lesz, �s k�t hierarchi�val fogunk rendelkezni: egy fel�let- �s egy
megval�s�t�si hierarchi�val. �rjunk olyan r�szk�dokat, amelyek el�g r�szletesek
ahhoz, hogy bemutass�k a t�puskonverzi�kb�l ad�d� lehets�ges probl�m�kat.
Gondoljuk �t a k�vetkezo szempontokat: a haszn�lat k�nnyus�ge; a programoz
�s k�nnyus�ge; mennyire k�nnyu a megval�s�t� oszt�lyok �s a fel�letek �jrahasznos
�t�sa, ha �j fogalmat vezet�nk be a hierarchi�ba; mennyire k�nnyu
v�ltoztat�sokat eszk�z�lni a fel�letekben vagy a megval�s�t�sban; �s sz�ks�g
van-e �jraford�t�sra, ha v�ltozott a rendszerf�ggo elemek megval�s�t�sa.
430 Absztrakci�s m�dszerek
Sablonok
.Az Olvas� id�zet�nek helye..
(B. Stroustrup)
Sablonok . Egy karakterl�nc sablon . P�ld�nyos�t�s . Sablonparam�terek .
T�pusellenorz
�s . F�ggv�nysablonok . Sablonparam�terek levezet�se . Sablonparam�terek meghat�-
roz�sa . F�ggv�nysablonok t�lterhel�se . Elj�r�sm�d megad�sa sablonparam�terekkel
. Alap�rtelmezett sablonparam�terek . Specializ�ci� . �r�klod�s �s sablonok . Tag
sablonok . Konverzi�k . A forr�sk�d szerkezete . Tan�csok . Gyakorlatok
13.1. Bevezet�s
F�ggetlen fogalmakat f�ggetlen�l �br�zoljunk �s csak sz�ks�g eset�n haszn�ljunk
egy�tt.
Ha megs�rtj�k ezt az elvet, akkor vagy nem rokon fogalmakat kapcsolunk �ssze vagy
sz�ks
�gtelen f�gg�seket teremt�nk, �gy kev�sb� rugalmas r�szekbol vagy �sszetevokbol
kell
majd a programokat �ssze�ll�tanunk. A sablonok (template) egyszeru m�dot adnak
arra,
hogy �ltal�nos fogalmak sz�les k�r�t �br�zoljuk �s egyszeru m�don haszn�ljuk
egy�tt.
Az �gy l�trej�vo oszt�lyok fut�si ido �s t�rig�ny tekintet�ben felveszik a
versenyt a k�zzel
�rott �s egyedibb feladatot v�gzo k�ddal.
13
A sablonok k�zvetlen�l t�mogatj�k az �ltal�nos�tott (generikus) programoz�st
(�2.7.), azaz
a t�pusoknak param�terk�nt val� haszn�lat�t. A C++ sablonjai lehetov� teszik, hogy
egy
oszt�ly vagy f�ggv�ny defini�l�sakor egy t�pust param�terk�nt adjunk meg. A sablon
a felhaszn
�lt t�pusnak csak azon tulajdons�gait�l f�gg, amelyeket t�nylegesen ki is haszn�l.

A sablon �ltal felhaszn�lt param�tert�pusok nem kell, hogy rokons�gban �lljanak


egym�ssal,
�gy nem sz�ks�ges az sem, hogy egyazon �r�klod�si hierarchia tagjai legyenek.
Ebben a fejezetben a sablonokat �gy mutatjuk be, hogy az elsodleges hangs�ly a
standard
k�nyvt�r tervez�s�hez, megval�s�t�s�hoz �s haszn�lat�hoz sz�ks�ges m�dszerekre
esik.
A standard k�nyvt�r nagyobb m�rt�ku �ltal�noss�got, rugalmass�got �s hat�konys�got
k�-
vetel, mint a legt�bb program. K�vetkez�sk�ppen a t�rgyaland� elj�r�sok sz�les
k�rben
haszn�lhat�ak �s igen sokf�le probl�ma megold�s�hoz biztos�tanak hat�kony
seg�ts�get.
Lehetov� teszik, hogy egyszeru fel�letek m�g� kifinomult megval�s�t�sokat rejts�nk
�s
csak akkor .mutassuk be. a bonyolult r�szleteket a felhaszn�l�nak, ha val�ban
sz�ks�ge
van r�juk. A sort(v) p�ld�ul sokf�le t�rol� objektum tartalmazta sokf�le t�pus�
elemnek sokf
�le rendezo algoritmus�hoz adhat fel�letet. Egy adott v-hez a ford�t�program
automatikusan
v�lasztja ki a legalkalmasabb rendezo f�ggv�nyt.
A standard k�nyvt�r minden fobb fogalmat egy-egy sablonk�nt �br�zol (p�ld�ul
string,
ostream, complex, list �s map), de a legfobb muveleteket is, p�ld�ul a
karakterl�ncok
(string-ek) �sszehasonl�t�s�t, a << kimeneti muveletet, a komplex sz�mok (complex)
�sszead
�s�t, egy lista (list) k�vetkezo elem�nek v�tel�t, vagy a rendez�st (sort()).
Ez�rt azt�n e
k�nyvnek az eml�tett k�nyvt�rral foglalkoz� fejezetei (a III. r�sz) gazdag
forr�sai a sablonokra
�s az azokra �p�to programoz�si m�dszerekre vonatkoz� p�ld�knak. K�vetkez�sk
�ppen ez a fejezet a sablonok fogalm�t j�rja k�r�l �s csup�n a haszn�latuk
alapveto m�djait
bemutat� kisebb p�ld�kra �sszpontos�t:
�13.2 Az oszt�lysablonok l�trehoz�s�ra �s haszn�lat�ra szolg�l� alapveto elj�r�sok

�13.3 F�ggv�nysablonok, f�ggv�nyek t�lterhel�se, t�pusok levezet�se


�13.4 �ltal�nos�tott algoritmusok elj�r�sm�dj�nak megad�sa sablonparam�terekkel
�13.5 Sablon t�bbf�le megval�s�t�sa k�l�nb�zo definici�kkal
�13.6 �r�klod�s �s sablonok (fut�si �s ford�t�si ideju t�bbalak�s�g)
�13.7 A forr�sk�d szerkezete
A sablon (template) fogalm�t a �2.7.1 �s a �3.8 pont vezette be. A sablonnevek
felold�s�ra,
illetve a sablonok formai k�vetelm�nyeire vonatkoz� r�szletes szab�lyok a �C.13
pontban
vannak.
432 Absztrakci�s m�dszerek
13.2. Egy egyszeru karakterl�nc sablon
Vegy�nk egy karakterl�ncot. A string (karakterl�nc) olyan oszt�ly, amely
karaktereket t�rol
�s olyan indexel�si, �sszefuz�si �s �sszehasonl�t�si muveleteket ny�jt, amelyeket
rendesen
a .karakterl�nc. fogalm�hoz k�t�nk. Ezeket k�l�nf�le karakterk�szletek sz�m�ra
szeretn
�nk biztos�tani. P�ld�ul az elojeles �s elojel n�lk�li, k�nai vagy g�r�g stb.
karakterekbol �ll
� l�ncok sz�mos �sszef�gg�sben hasznosak lehetnek. Ez�rt �gy szeretn�nk a
karakterl�nc
fogalm�t �br�zolni, hogy min�l kev�sb� f�ggj�nk egy adott karakterk�szlettol. A
karakterl
�nc definici�ja arra �p�t, hogy egy karaktert le lehet m�solni, ezen k�v�l nem sok
egy�bre.
Ez�rt ha a �11.2-beli char-okb�l fel�p�lo string oszt�lyban a karakterek t�pus�t
param�terr
� tessz�k, �ltal�nosabb karakterl�nc-oszt�lyt kapunk:
template<class C> class String {
struct Srep;
Srep *rep;
public:
String();
String(const C*);
String(const String&);
C read(int i) const;
// ...
};
A template<class C> elotag azt jelenti, hogy egy sablon deklar�ci�ja k�vetkezik �s
abban
a C t�pusparam�tert fogjuk haszn�lni. Bevezet�se ut�n a C-t ugyan�gy
haszn�lhatjuk, mint
b�rmely m�s t�pusnevet. A C hat�k�re a template<class C> elotaggal bevezetett
deklar�ci�
v�g�ig terjed. Jegyezz�k meg, hogy a template<class C> elotag azt jelenti, hogy C
egy t�pusn
�v; nem felt�tlen�l kell oszt�lyn�vnek lennie. Az oszt�lysablon neve a <> jelp�r
k�z� �rott
t�pusn�vvel egy�tt egy, a sablon �ltal meghat�rozott oszt�ly nev�t adja �s
ugyan�gy haszn
�lhat�, mint b�rmely m�s oszt�lyn�v:
String<char> cs;
String<unsigned char> us;
String<wchar_t> ws;
class Jchar {
// jap�n karakter
};
String<Jchar> js;
13. Sablonok 433
A n�vre vonatkoz� saj�tos formai k�vetelm�nyektol eltekintve a String<char>
pontosan
ugyan�gy muk�dik, mintha a �11.12-beli String-defin�ci�val defini�ltuk volna. A
String sablonn
� t�tele lehetov� teszi, hogy a char-okb�l �ll� karakterl�ncok szolg�ltat�sait m�s
t�pus
� karakterekbol �ll� String-ek sz�m�ra is el�rhetov� tegy�k. P�ld�ul ha a standard
k�nyvt
�rbeli map �s String sablonokat haszn�ljuk, a �11.8 pont sz�sz�ml�l� p�ld�ja �gy
�rhat� �t:
int main() // szavak elofordul�s�nak megsz�ml�l�sa a bemeneten
{
String<char> buf;
map<String<char>,int> m;
while (cin>>buf) m[buf]++;
// eredm�ny ki�r�sa
}
A Jchar jap�n karaktereket haszn�l� v�ltozat ez lenne:
int main() // szavak elofordul�s�nak megsz�ml�l�sa a bemeneten
{
String<Jchar> buf;
map<String<Jchar>,int> m;
while (cin>>buf) m[buf]++;
// eredm�ny ki�r�sa
}
A standard k�nyvt�rban szerepel a sablonn� alak�tott String-hez hasonl�
basic_string sablon
is (�11.12, �20.3). A standard k�nyvt�rban a string mint a basic_string<char>
szinonim
�ja szerepel:
typedef basic_string<char> string;
Ez lehetov� teszi, hogy a sz�sz�ml�l� p�ld�t �gy �rjuk �t:
int main() // szavak elofordul�s�nak megsz�ml�l�sa a bemeneten
{
string buf;
map<string,int> m;
while (cin>>buf) m[buf]++;
// eredm�ny ki�r�sa
}
A typedef-ek �ltal�ban is hasznosak a sablonokb�l l�trehozott oszt�lyok hossz�
neveinek
ler�vid�t�s�re. R�ad�sul, ha nem �rdekel benn�nket egy t�pus pontos definici�ja,
akkor egy
typedef elrejti elol�nk, hogy sablonb�l l�trehozott t�pusr�l van sz�.
434 Absztrakci�s m�dszerek
13.2.1. Sablonok meghat�roz�sa
A sablonb�l l�trehozott oszt�lyok teljesen k�z�ns�ges oszt�lyok, ez�rt a sablonok
haszn�-
lata semmivel sem ig�nyel hosszabb fut�si idot, mint egy egyen�rt�ku .k�zzel
�rott. oszt�-
ly�, de nem felt�tlen�l jelenti a l�trehozott k�d mennyis�g�nek cs�kken�s�t sem.
�ltal�ban j� �tlet hibakeres�ssel ellenorizni egy oszt�lyt, p�ld�ul a String-et,
mielott sablont
k�sz�t�nk belole (String<C>). Ez�ltal sz�mos tervez�si hib�t, a k�dhib�knak pedig
a legt
�bbj�t egy adott oszt�ly �sszef�gg�s�ben kezelhet�nk. Ezt a fajta hibakeres�st
(debugging)
a legt�bb programoz� j�l ismeri, �s a legt�bben jobban boldogulnak egy konkr�t
p�ld
�val, mint egy elvonttal. K�sobb azt�n an�lk�l foglalkozhatunk a t�pus
�ltal�nos�t�s�b�l
esetleg ad�d� probl�m�kkal, hogy a hagyom�nyosabb hib�k elvonn�k a figyelm�nket.
Hasonl
�an, ha meg akarunk �rteni egy sablont, akkor hasznos annak viselked�s�t elosz�r
egy
konkr�t t�pus� param�terrel (p�ld�ul a char-ral) elk�pzelni, mielott megpr�b�ljuk
a viselked
�s�t teljes �ltal�noss�g�ban meg�rteni.
Egy sablon oszt�ly (template class) tagjait ugyan�gy deklar�ljuk �s defini�ljuk,
mint a k�-
z�ns�ges oszt�lyok�t. Egy tagot nem sz�ks�ges mag�ban az oszt�lyban defini�lni;
valahol
m�shol is el�g, ugyan�gy, mint egy nem sablon oszt�lytag eset�ben (�C.13.7.). A
sablon
oszt�lyok tagjai maguk is sablonok, param�tereik pedig ugyanazok, mint a sablon
oszt�ly�i.
Ha egy ilyen tagot az oszt�ly�n k�v�l �runk le, kifejezetten sablonk�nt kell
megadnunk:
template<class C> struct String<C>::Srep {
C* s; // mutat� az elemekre
int sz; // elemek sz�ma
int n; // hivatkoz�ssz�ml�l�
// ...
};
template<class C> C String<C>::read(int i) const { return rep->s[i]; }
template<class C> String<C>::String()
{
rep = new Srep(0,C());
}
A sablonparam�terek . mint a C . ink�bb param�terek, mint a sablonon k�v�l
defini�lt t�-
pusok, de ez nem �rinti azt a m�dot, ahogyan az azokat haszn�l� sablonk�dot �rjuk.

A String<C> hat�k�r�n bel�l a <C>-vel val� minos�t�s felesleges, hiszen a sablon


neve m�r
tartalmazza azt, �gy a konstruktor neve String<C>::String lesz. De ha jobban
tetszik, meg is
adhatjuk a minos�t�st:
13. Sablonok 435
template<class C> String<C>::String<C>()
{
rep = new Srep(0,C());
}
Egy programban egy tagf�ggv�nyt csak egyetlen f�ggv�ny defini�lhat. Ugyan�gy a
sablon oszt
�lyok tagf�ggv�nyeit is csak egy f�ggv�nysablon defini�lhatja. De am�g a
f�ggv�nyeket csak
t�lterhelni lehet (�13.3.2), addig a specializ�ci�k (�13.5) haszn�lata lehetov�
teszi, hogy egy
sablonnak t�bb v�ltozat�t is elk�sz�thess�k.
Az oszt�lysablonok neve nem terhelheto t�l, �gy ha egy hat�k�rben m�r megadtunk
egy
oszt�lysablont, ott nem lehet ugyanolyan n�ven m�sik egyedet bevezetni (l�sd m�g
�13.5):
template<class T> class String { /* ... */ };
class String { /* ... */ }; // hiba: k�t meghat�roz�s
A sablonparam�terk�nt haszn�lt t�pusnak biztos�tania kell a sablon �ltal v�rt
fel�letet.
A String sablon param�terek�nt haszn�lt t�pusnak p�ld�ul t�mogatnia kell a
szok�sos m�-
sol� muveleteket (�10.4.4.1, �20.2.1). Jegyezz�k meg: az nem k�vetelm�ny, hogy egy
sablon
k�l�nb�zo param�terei �r�klod�si viszonyban �lljanak egym�ssal.
13.2.2. Sablonok p�ld�nyos�t�sa
Az elj�r�st, melynek sor�n egy sablon oszt�lyb�l �s egy sablonparam�terbol egy
oszt�lydeklar
�ci� keletkezik, gyakran sablon-p�ld�nyos�t�snak (template instantiation) h�vj�k
(�C.13.7.). Ha f�ggv�nyt hozunk l�tre egy sablon f�ggv�nybol �s egy
sablonparam�terbol,
az a f�ggv�ny-p�ld�nyos�t�s. A sablon adott param�tert�pus sz�m�ra megadott
v�ltozat�t
specializ�ci�nak (specialization) nevezz�k.
�ltal�ban az adott C++ ford�t� �s nem a programoz� dolga, hogy minden felhaszn�lt
param
�tert�pus sz�m�ra l�trehozza a megfelelo sablon f�ggv�nyt (�C.13.7):
String<char> cs;
void f()
{
String<Jchar> js;
cs = "Az adott nyelvi v�ltozat feladata, hogy kital�lja, milyen k�dot kell
l�trehozni.";
}
436 Absztrakci�s m�dszerek
A fenti esetben a String<char> �s a String<Jchar>, a megfelelo Srep t�pusok, a
destruktorok
�s az alap�rtelmezett konstruktorok, illetve a String<char>::operator=(char *)
deklar�ci�it
a ford�t� hozza l�tre. M�s tagf�ggv�nyeket nem haszn�lunk, �gy ilyeneket nem kell
k�sz�-
tenie (rem�lhetoleg nem is teszi). A l�trehozott oszt�lyok k�z�ns�ges oszt�lyok,
�gy az oszt
�lyokra vonatkoz� szok�sos szab�lyok �rv�nyesek r�juk. Ugyan�gy a l�trehozott
f�ggv�-
nyek is k�z�ns�ges f�ggv�nyek �s a f�ggv�nyekre vonatkoz� szok�sos szab�lyok
szerint
viselkednek.
Nyilv�nval�, hogy a sablonok hat�kony eszk�zt adnak arra, hogy viszonylag r�vid
defin�-
ci�kb�l hozzunk l�tre k�dot. Ez�rt azt�n nem �rt n�mi �vatoss�g, hogy elker�lj�k a
mem�-
ri�nak csaknem azonos f�ggv�ny-definici�kkal val� el�raszt�s�t (�13.5).
13.2.3. Sablonparam�terek
A sablonoknak lehetnek t�pust meghat�roz�, k�z�ns�ges t�pus� (pl. int), �s sablon
t�pus�
param�tereik (�C.13.3). Term�szetesen egy sablonnak t�bb param�tere is lehet:
template<class T, T def_val> class Cont { /* ... */ };
Ahogy a p�lda mutatja, egy sablonparam�tert felhaszn�lhatunk a tov�bbi
sablonparam�terek
meghat�roz�s�ban is.
Az eg�sz t�pus� param�terek m�retek �s korl�tok megad�s�n�l hasznosak:
template<class T, int i> class Buffer {
T v[i];
int sz;
public:
Buffer() : sz(i) {}
// ...
};
Buffer<char,127> cbuf;
Buffer<Record,8> rbuf;
A Buffer-hez hasonl� egyszeru �s korl�tozott t�rol�k ott lehetnek fontosak, ahol a
fut�si
ideju hat�konys�g �s a program t�m�rs�ge elsodleges szempont, �s ahol ez�rt nem
lehet
az �ltal�nosabb string-et vagy vector-t haszn�lni. Mivel a sablon a m�retet
param�terk�nt
megkapja, a kifejt�sben el lehet ker�lni a szabad t�r haszn�lat�t. Egy m�sik p�lda
erre
a Range oszt�ly a �25.6.1-ben.
13. Sablonok 437
A sablon param�tere lehet konstans kifejez�s (�C.5), k�lso szerkeszt�su objektum
vagy
f�ggv�ny c�me (�9.2), illetve egy tagra hivatkoz�, t�l nem terhelt mutat� (�15.5).
A mutat�,
ha sablon param�terek�nt akarjuk haszn�lni, &of alak� kell, hogy legyen, ahol of
egy objektum
vagy f�ggv�ny neve, illetve f alak�, ahol f egy f�ggv�ny neve. A tagra hivatkoz�
mutat
�kat &X::of alakban kell megadni, ahol of a tag neve. Karakterl�nc liter�lt nem
haszn�lhatunk
sablonparam�terk�nt.
Az eg�sz t�pus� param�tereknek konstansnak kell lenni�k:
void f(int i)
{
Buffer<int,i> bx; // hiba: konstans kifejez�s sz�ks�ges
}
Megford�tva, a nem t�pusba tartoz� param�terek a sablonon bel�l �lland�k, �gy a
param�-
ter �rt�k�nek m�dos�t�s�ra tett k�s�rlet hib�nak sz�m�t.
13.2.4. T�pusok egyen�rt�kus�ge
Ha adott egy sablon, akkor k�l�nf�le param�tert�pusok megad�s�val k�l�nf�le
t�pusokat
hozhatunk l�tre belole:
String<char> s1;
String<unsigned char> s2;
String<int> s3;
typedef unsigned char Uchar;
String<Uchar> s4;
String<char> s5;
Buffer<String<char>,10> b1;
Buffer<char,10> b2;
Buffer<char,20-10> b3;
Ha azonos param�terekkel adunk meg sablonokat, azok ugyanarra a l�trehozott
t�pusra
fognak hivatkozni. De mit is jelent itt az, hogy .azonos.? Szok�s szerint, a
typedef-ek nem
vezetnek be �j t�pust, �gy a String<Uchar> ugyanaz, mint a String<unsigned char>.
Megford
�tva, mivel a char �s az unsigned char k�l�nb�zo t�pusok (�4.3), a String<char> �s

a String<unsigned char> is k�l�nb�zoek lesznek.


A ford�t�program ki tudja �rt�kelni a konstans kifejez�seket is (�C.5), �gy a
Buffer<char,20-
10>-rol felismeri, hogy a Buffer<char,10>-zel azonos t�pus.
438 Absztrakci�s m�dszerek
13.2.5. T�pusellenorz�s
A sablonokat param�terekkel defini�ljuk �s k�sobb �gy is haszn�ljuk. A
sablondefin�ci�ban
a ford�t�program ellenorzi a formai hib�kat, illetve az olyanokat, amelyek a
konkr�t param
�terek ismerete n�lk�l felder�thetoek:
template<class T> class List {
struct Link {
Link* pre;
Link* suc;
T val;
Link(Link* p, Link* s,const T& v) : pre(p), suc(s), val(v) { }
} // szintaktikus hiba: hi�nyzik a pontosvesszo
Link* head;
public:
List() : head(7) { } // hiba: kezdeti �rt�kad�s mutat�nak int-tel
List(const T& t) : head(new Link(0,o,t)) { } // hiba: 'o' nem defini�lt azonos�t�
// ...
void print_all() const { for (Link* p = head; p; p=p->suc) cout << p->val << '\n';
}
};
A ford�t�program az egyszeru nyelvi hib�kat m�r a defin�ci�n�l kiszurheti, n�ha
azonban
csak k�sobb, a haszn�latn�l. A felhaszn�l�k jobban szeretik, ha a hib�k hamar
kider�lnek,
de nem minden .egyszeru. hib�t k�nnyu felder�teni. Ebben a p�ld�ban h�rom hib�t
v�tettem
(sz�nd�kosan). A sablon param�ter�tol f�ggetlen�l egy T* t�pus� mutat�nak nem
adhatjuk
a 7 kezdo�rt�ket. Hasonl�an, az o v�ltoz� (amely persze egy hib�san �rt nulla) nem

lehet a List<T>::Link konstruktor param�tere, mert ilyen n�v az adott pontr�l nem
el�rheto.
A sablon definici�j�ban haszn�lt n�vnek vagy ismertnek kell lennie, vagy
valamilyen �sszer
u �s nyilv�nval� m�don kell f�ggnie valamelyik sablonparam�tertol (�C.13.8.1). A T
sablonparam
�tertol val� legk�z�ns�gesebb �s legk�zenfekvobb f�gg�s egy T t�pus� tag vagy
T t�pus� param�ter haszn�lata. A List<T>::print_all() p�ld�ban a cout << p->val
kifejez�s
haszn�lata n�mileg .kifinomultabb. p�lda.
A sablonparam�terek haszn�lat�val �sszef�ggo hib�k csak a sablon haszn�lat�nak
hely�n
der�thetok fel:
class Rec { /* ... */ };
void f(const List<int>& li, const List<Rec>& lr)
{
li.print_all();
lr.print_all();
}
13. Sablonok 439
Itt a li.print_all() rendben van, de a lr.print_all() t�pushib�s, mert a Rec
t�pusnak nincs <<
kimeneti muvelete. A legelso pont, ahol a sablonparam�terek haszn�lat�val
�sszef�ggo hiba
kider�lhet, a sablonnak az adott param�terrel val� elso haszn�lata. Ezt a pontot
rendszerint
elso p�ld�nyos�t�si pontnak (first point of instantiation) vagy egyszeruen
p�ld�nyos�t�si
pontnak h�vj�k (�C.13.7). Az adott C++-v�ltozat . megengedett m�don . ezt az
ellenorz�st
a program �sszeszerkeszt�s�ig elhalaszthatja. Ha ebben a ford�t�si egys�gben a
print_all()-
nak csak a deklar�ci�ja �s nem a defin�ci�ja ismert, lehets�ges, hogy az adott
ford�t�nak el
is kell halasztania a t�pusellenorz�st a program �sszeszerkeszt�s�ig (�13.7). A
t�pusellenorz
�s azonos szab�lyok szerint t�rt�nik, f�ggetlen�l att�l, hogy melyik ponton megy
v�gbe.
A felhaszn�l�k itt is a min�l kor�bbi ellenorz�st szeretik. A sablonparam�terekre
vonatkoz
� megszor�t�sokat a tagf�ggv�nyek seg�ts�g�vel is kifejezhetj�k (�13.9[16]).
13.3. F�ggv�nysablonok
A legt�bb programoz� sz�m�ra a sablonok elso sz�m� �s legnyilv�nval�bb
felhaszn�l�sa
olyasf�le t�rol� oszt�lyok l�trehoz�sa �s haszn�lata, mint a basic_string (�20.3),
a vector
(�16.3), a list (�17.2.2) vagy a map (�17.4.1). K�sobb azonban felmer�l a
sablonk�nt haszn
�lt f�ggv�nyek sz�ks�gess�ge. N�zz�k p�ld�ul egy t�mb rendez�s�t:
template<class T> void sort(vector<T>&); // deklar�ci�
void f(vector<int>& vi, vector<string>& vs)
{
sort(vi); // sort(vector<int>&);
sort(vs); // sort(vector<string>&);
}
A sablon f�ggv�nyek (template function) megh�v�sakor a f�ggv�ny param�terei
hat�rozz�k
meg, hogy a sablon melyik p�ld�ny�t haszn�ljuk, vagyis a sablonparam�tereket a
f�ggv
�nyparam�terekbol vezetj�k le (deduce) (�13.3.1).
Term�szetesen a sablon f�ggv�nyt valahol defini�lnunk kell (�C.13.7):
template<class T> void sort(vector<T>& v) // defin�ci�
// Shell rendez�s (Knuth, III. k�tet, 84. o.2)
{
const size_t n = v.size();
440 Absztrakci�s m�dszerek
2 Magyarul: D. E. Knuth: A sz�m�t�g�p-programoz�s muv�szete III. k�tet, Keres�s �s
rendez�s; Muszaki
k�nyvkiad�, Budapest, 1988; 95. oldal
for (int gap=n/2; 0<gap; gap/=2)
for (int i=gap; i<n; i++)
for (int j=i-gap; 0<=j; j-=gap)
if (v[j+gap]<v[j]) { // v[j] �s v[j+gap] felcser�l�se
T temp = v[j];
v[j] = v[j+gap];
v[j+gap] = temp;
}
}
Hasonl�tsuk �ssze a sort() ezen definici�j�t a �7.7-belivel. Ez a sablonn�
alak�tott v�ltozat vil
�gosabb �s r�videbb, mert a rendezendo elemek t�pus�ra vonatkoz�an t�bb
inform�ci�ra
t�maszkodhat. Val�sz�nuleg gyorsabb is, mert nincs sz�ks�ge az �sszehasonl�t�
f�ggv�nyre
hivatkoz� mutat�ra. Ebbol k�vetkezik, hogy nincs sz�ks�g k�zvetett
f�ggv�nyh�v�sra,
a < �sszehasonl�t�st pedig k�nnyen lehet helyben kifejtve (inline) ford�tani.
Tov�bbi egyszerus�t�st jelenthet a standard k�nyvt�rbeli swap() sablon haszn�lata
(�18.6.8),
mellyel az �rt�kcser�t term�szetes form�ra alak�thatjuk:
if (v[j+gap]<v[j]) swap(v[j],v[j+gap]);
Ez a k�d hat�konys�g�t semmilyen m�don nem rontja. Ebben a p�ld�ban a < muveletet
haszn�ltuk �sszehasonl�t�sra. Nem minden t�pusnak van azonban < oper�tora, ami
korl�-
tozza a sort() ezen v�ltozat�nak haszn�lhat�s�g�t; de ez a korl�toz�s k�nnyen
megker�lhet
o (�13.4).
13.3.1. A f�ggv�nysablonok param�terei
A f�ggv�nysablonok alapveto fontoss�g�ak a t�rol� t�pusok (�2.7.2, �3.8, 18.
fejezet) sz�les
k�r�re alkalmazhat� �ltal�nos algoritmusok �r�s�hoz. Alapveto jelentos�gu, hogy
egy f�ggv
�nyh�v�skor a sablonparam�tereket le lehet vezetni, ki lehet k�vetkeztetni
(deduce)
a f�ggv�ny param�tereibol.
A ford�t�program akkor tudja levezetni egy h�v�s t�pusos �s nem t�pusba tartoz�
param�tereit,
ha a f�ggv�ny param�terlist�ja egy�rtelmuen azonos�tja a sablonparam�terek
halmaz�t
(�C.13.4):
template<class T, int i> T& lookup(Buffer<T,i>& b, const char* p);
class Record {
const char[12];
// ...
};
13. Sablonok 441
Record& f(Buffer<Record,128>& buf, const char* p)
{
return lookup(buf,p); // lookup() haszn�lata, ahol T egy Record �s i �rt�ke 128
}
Itt T-rol azt �llap�tja meg a ford�t�program, hogy Record, az i-rol pedig azt,
hogy �rt�ke128.
Megjegyzendo, hogy a ford�t�program az oszt�lysablonok param�tereit soha nem
vezeti le
(�C.13.4). Ennek az az oka, hogy az oszt�lyok t�bbf�le konstruktora ny�jtotta
rugalmass�g
ezt sok esetben megakad�lyozn�, esetleg �ttekinthetetlenn� tenn�. Egy oszt�ly
k�l�nf�le
v�ltozatai k�z�tti v�laszt�sra a specializ�lt v�ltozatok haszn�lata ad eszk�zt
(�13.5). Ha egy
levezett t�pus� objektumot kell l�trehoznunk, ezt sokszor megtehetj�k �gy, hogy a
l�trehoz
�st egy f�ggv�ny megh�v�s�val hajtatjuk v�gre (l�sd a �17.4.1.2 pontbeli
make_pair()-t).
Ha egy param�tert nem lehet levezetni a sablon f�ggv�ny param�tereibol (�C.13.4),
akkor
k�zvetlen�l meg kell adnunk. Ezt ugyan�gy tehetj�k meg, mint ahogy egy sablon
oszt�ly
sz�m�ra k�zvetlen�l megadjuk a sablonparam�tereket:
template<class T> class vector { /* ... */ };
template<class T> T* create(); // T l�trehoz�sa �s r� hivatkoz� mutat� visszaad�sa

void f()
{
vector<int> v; // oszt�ly, sablonparam�tere 'int'
int* p = create<int>(); // f�ggv�ny, sablonparam�tere 'int'
}
A k�zvetlen meghat�roz�s (explicit specification) egyik szok�sos haszn�lata a
sablon f�ggv
�ny visszat�r�si�rt�k-t�pus�nak megad�sa:
template<class T, class U> T implicit_cast(U u) { return u; }
void g(int i)
{
implicit_cast(i); // hiba: T nem vezetheto le
implicit_cast<double>(i); // T t�pusa double, U t�pusa int
implicit_cast<char,double>(i); // T t�pusa char, U t�pusa double
implicit_cast<char*,int>(i); // T t�pusa char*, U t�pusa int; hiba: int
// nem alak�that� char*-ra
}
Az alap�rtelmezett f�ggv�nyparam�ter-�rt�kekhez hasonl�an (�7.5), az explicit
megadott
sablonparam�terek k�z�l is csak az utols�kat lehet elhagyni.
442 Absztrakci�s m�dszerek
A sablonparam�terek k�zvetlen megad�sa �talak�t� f�ggv�nycsal�dok �s objektum-
l�trehoz
� f�ggv�nyek definici�j�t teszi lehetov� (�13.3.2, �C.13.1, �C.13.5). Az
automatikus
(implicit) konverzi�k (�C.6) explicit v�ltozatai, p�ld�ul az implicit_cast()
idonk�nt igen
hasznosak lehetnek. A dynamic_cast, static_cast stb. formai k�vetelm�nyei
megfelelnek az
explicit minos�t�su sablon f�ggv�nyek�inek. A be�p�tett t�puskonverzi�s oper�torok
azonban
olyan muveleteket t�mogatnak, amelyeket nem fejezhet�nk ki m�s nyelvi elemmel.
13.3.2. F�ggv�nysablonok t�lterhel�se
Azonos n�ven t�bb f�ggv�nysablon is szerepelhet, sot ugyanolyan n�ven t�bb
k�z�ns�ges
f�ggv�ny is. A t�lterhelt (vagyis azonos n�vvel m�st �s m�st jelento) f�ggv�nyek
megh�v�-
sakor a megfelelo megh�vand� f�ggv�ny vagy f�ggv�nysablon kiv�laszt�s�hoz a
t�lterhel
�s (overloading) felold�sa sz�ks�ges:
template<class T> T sqrt(T);
template<class T> complex<T> sqrt(complex<T>);
double sqrt(double);
void f(complex<double> z)
{
sqrt(2); // sqrt<int>(int)
sqrt(2.0); // sqrt(double)
sqrt(z); // sqrt<double>(complex<double>)
}
Ahogy a sablon f�ggv�ny fogalma a f�ggv�ny fogalm�nak �ltal�nos�t�sa, ugyan�gy a
sablon
f�ggv�nyekre alkalmazand� t�lterhel�s-felold�si szab�lyok is a f�ggv�nyekre
alkalmazand
� t�lterhel�s-felold�si szab�lyok �ltal�nos�t�sai. A m�dszer alapvetoen a
k�vetkezo:
megkeress�k minden sablonhoz azt a specializ�lt v�ltozatot, amelyik a
param�tereknek
a legjobban megfelel. Ezut�n ezekre a p�ld�nyokra �s az �sszes k�z�ns�ges
f�ggv�nyre is
a szok�sos t�lterhel�s-felold�si szab�lyokat alkalmazzuk:
1. Meg kell keresni azokat a specializ�lt sablon f�ggv�ny v�ltozatokat (�13.2.2),
amelyek r�szt fognak venni a t�lterhel�s felold�s�ban. Ehhez az �sszes f�ggv
�nysablont megvizsg�ljuk, hogy ha m�s ugyanilyen nevu f�ggv�ny vagy sablon
f�ggv�ny nem lenne el�rheto, akkor lehetne-e valamilyen sablonparam�terrel
alkalmazni. Az sqrt(z) h�v�s eset�ben p�ld�ul a k�vetkezo jel�ltek ad�dnak:
sqrt<double>(complex<double>) �s sqrt<complex<double>>(complex<double>).
2. Ha k�t sablon f�ggv�ny is megh�vhat� lenne �s az egyik specializ�ltabb a m�-
sikn�l (�13.5.1), akkor a k�vetkezo l�p�sekben csak azt vessz�k figyelembe.
13. Sablonok 443
Az sqrt(z) h�v�s eset�ben az sqrt<double>(complex<double>)-t v�lasztjuk az
sqrt<complex<double>>(complex<double>) helyett: minden h�v�s, ami megfelel
sqrt<T>(complex<T>)-nek, megfelel sqrt<T>(T)-nek is.
3. Ezek ut�n v�gezz�k el a k�z�ns�ges t�lterhel�s-felold�st ezen f�ggv�nyekre �s
a k�z�ns�ges f�ggv�nyekre (�7.4.). Ha egy sablon f�ggv�ny param�ter�t a
sablonparam
�terekbol vezett�k le (�13.3.1), akkor arra nem alkalmazhatunk kiterjeszt
�st (promotion), illetve szabv�nyos vagy felhaszn�l�i konverzi�t. Az sqrt(2)
h�v�s pontosan megfelel az sqrt<int>(int)-nek, �gy azt v�lasztjuk a sqrt(double)
helyett.
4. Ha egy f�ggv�ny �s egy specializ�lt v�ltozata ugyanolyan m�rt�kben megfelelo,
akkor a f�ggv�nyt v�lasztjuk. Emiatt a sqrt(2.0)-hoz a sqrt(double)-t v�lasztjuk,
�s nem a sqrt<double>(double)-t.
5. Ha nem tal�lunk megfelelo f�ggv�nyt, akkor a h�v�s hib�s. Ha t�bb ugyanolyan
m�rt�kben megfelelo f�ggv�nyt is tal�lunk, akkor a h�v�s t�bb�rtelmu �s ez�rt
hib�s:
template<class T> T max(T,T);
const int s = 7;
void k()
{
max(1,2); // max<int>(1,2)
max('a','b'); // max<char>('a','b')
max(2.7,4.9); // max<double>(2.7,4.9)
max(s,7); // max<int>(int(s),7) (egyszeru konverzi�)
max('a',1); // hiba: t�bb�rtelmu (nincs szabv�nyos konverzi�)
max(2.7,4); // hiba: t�bb�rtelmu (nincs szabv�nyos konverzi�)
}
A fenti p�lda k�t nem egy�rtelmu h�v�s�t explicit minos�t�ssel oldhatjuk fel:
void f()
{
max<int>('a',1); // max<int>(int('a'),1)
max<double>(2.7,4); // max<double>(2.7,double(4))
}
Vagy megfelelo deklar�ci�k alkalmaz�s�val:
inline int max(int i, int j) { return max<int>(i,j); }
inline double max(int i, double d) { return max<double>(i,d); }
inline double max(double d, int i) { return max<double>(d,i); }
inline double max(double d1, double d2) { return max<double>(d1,d2); }
444 Absztrakci�s m�dszerek
void g()
{
max('a',1); // max(int('a'),1)
max(2.7,4); // max(2.7,double(4))
}
K�z�ns�ges f�ggv�nyekre a k�z�ns�ges t�lterhel�s-felold�si szab�lyok �rv�nyesek
(�7.4),
�s a helyben kifejt�s (inline) biztos�tja, hogy a h�v�s nem j�r k�l�n
.k�lts�ggel..
A max() f�ggv�ny igen egyszeru, �gy explicit m�don is �rhattuk volna, de a sablon
specializ�lt haszn�lata k�nnyu �s �ltal�nosan haszn�lhat� m�dja az ilyen
t�lterhel�s-felold
� f�ggv�nyek �r�s�nak. A t�lterhel�s-felold�si szab�lyok biztos�tj�k, hogy a
sablon f�ggv
�nyek helyesen muk�dnek egy�tt az �r�klod�ssel:
template<class T> class B { /* ... */ };
template<class T> class D : public B<T> { /* ... */ };
template<class T> void f(B<T>*);
void g(B<int>* pb, D<int>* pd)
{
f(pb); // f<int>(pb)
f(pd); // f<int>(static_cast<B<int>*>(pd)); szabv�nyos �talak�t�s D<int>*-r�l
B<int>*-ra
}
Ebben a p�ld�ban az f() sablon f�ggv�ny minden T t�pusra elfogadja B<T>*-ot. Egy
D<int>* t�pus� param�ter�nk van, �gy a ford�t�program k�nnyen jut arra a
k�vetkeztet�sre,
hogy T-t int-nek v�ve a h�v�s egy�rtelmuen feloldhat�, f(B<int>*)-k�nt. Az olyan
f�ggv�nyparam�tereket, amelyek nem vesznek r�szt a sablonparam�ter levezet�s�ben,
pontosan �gy kezelhetj�k, mint egy nem sablon f�ggv�ny param�ter�t, �gy a szok�sos
�tkonverzi
�k megengedettek:
template<class T, class C> T get_nth(C& p, int n); // az n-edik elem
Ez a f�ggv�ny felt�telezhetoen a C t�pus� t�rol� n-edik elem�t adja vissza.
Minthogy C-t
a h�v�s aktu�lis param�ter�bol kell levezetni, az elso param�terre nem
alkalmazhat�
konverzi�, a m�sodik param�ter azonban teljesen k�z�ns�ges, �gy a szok�sos
konverzi�k
mindegyike tekintetbe veheto:
class Index {
public:
operator int();
// ...
};
13. Sablonok 445
void f(vector<int>& v, short s, Index i)
{
int i1 = get_nth<int>(v,2); // pontos illeszked�s
int i2 = get_nth<int>(v,s); // szabv�nyos konverzi�: short-r�l int-re
int i3 = get_nth<int>(v,i); // felhaszn�l�i konverzi�: Index-rol int-re
}
13.4. Elj�r�sm�d megad�sa sablonparam�terekkel
Gondoljuk meg, hogyan rendezhetj�k a karakterl�ncokat. H�rom dolog j�tszik
szerepet: a karakterl
�nc, az elemek t�pusa �s a l�nc elemeinek �sszehasonl�t�sakor alkalmazott
szempont.
Nem .betonozhatjuk be. a rendez�si elvet a t�rol�ba, mert az �ltal�ban nem
szabhatja meg,
mire van sz�ks�ge az elemek t�pus�val kapcsolatban, de az elemek t�pus�ba sem,
mert az
elemeket sokf�le m�don rendezhetj�k. Ehelyett a megfelelo muvelet v�grehajt�sakor
kell
megadni az alkalmazand� felt�teleket. Milyen rendez�si elvet alkalmazzunk, ha
p�ld�ul
sv�d neveket tartalmaz� karakterl�ncokat akarunk rendezni? A sv�d nevek rendez�se
sz�-
m�ra a karakterek k�t k�l�nb�zo numerikus megfeleltet�si m�dja (collating
sequence)
haszn�latos. Term�szetesen sem egy �ltal�nos string t�pus, sem egy �ltal�nos
rendezo algoritmus
nem tudhat a nevek rendez�s�nek .sv�d szok�sair�l., ez�rt b�rmely �ltal�nos megold
�s megk�veteli, hogy a rendezo elj�r�st ne csak egy adott t�pusra adhassuk meg,
hanem
adott t�pusra val� adott alkalmaz�skor is. �ltal�nos�tsuk p�ld�ul a C standard
k�nyvt�r�nak
strcmp() f�ggv�ny�t tetszoleges T t�pusb�l �ll� String-ekre (�13.2):
template<class T, class C>
int compare(const String<T>& str1, const String<T>& str2)
{
for(int i=0; i<str1.length() && i< str2.length(); i++)
if (!C::eq(str1[i],str2[i])) return C::lt(str1[i],str2[i]) ? -1 : 1;
return str1.length()-str2.length();
}
Ha valaki azt szeretn�, hogy a compare() eltekintsen a kis- �s nagybetuk k�z�tti
k�l�nbs
�gtol vagy figyelembe vegye a program nyelvi k�rnyezet�t (locale, helyi
saj�toss�gok), akkor
ezt a C::eq() �s a C::lt() f�ggv�nyek megfelelo defini�l�s�val teheti meg. Ezzel
minden
(�sszehasonl�t�, rendezo stb.) elj�r�st le�rhatunk, ha az a t�rol� �s a .C-
muveletek. nyelv�n
megfogalmazhat�:
446 Absztrakci�s m�dszerek
template<class T> class Cmp { // szok�sos, alap�rtelmezett �sszehasonl�t�s
public:
static int eq(T a, T b) { return a==b; }
static int lt(T a, T b) { return a<b; }
};
class Literate { // sv�d nevek �sszehasonl�t�sa
public:
static int eq(char a, char b) { return a==b; }
static int lt(char,char); // kikeres�s t�bl�zatb�l karakter�rt�k alapj�n
(�13.9[14])
};
A sablonparam�terek megad�sakor most m�r pontosan megadhatjuk az �sszehasonl�t�si
szab�lyokat:
void f(String<char> swede1, String<char> swede2)
{
compare< char,Cmp<char> >(swede1,swede2);
compare< char,Literate >(swede1,swede2);
}
Az �sszehasonl�t� muveletek sablonparam�terk�nt val� megad�s�nak k�t jelentos
elonye
van az egy�b lehetos�gekhez, p�ld�ul a f�ggv�nymutat�k alkalmaz�s�hoz k�pest.
Egyr�szt
t�bb muvelet megadhat� egyetlen param�terk�nt, a fut�si ido n�veked�se n�lk�l.
M�sr�szt,
az eq() �s az lt() �sszehasonl�t� muveleteket k�nnyu helyben kifejtve (inline)
ford�tani, m�g
egy f�ggv�nymutat�n kereszt�li h�v�s ilyen m�d� ford�t�sa k�l�nleges m�rt�ku
figyelmet
k�vetel a ford�t�programt�l.
Term�szetesen �sszehasonl�t� muveleteket nemcsak a be�p�tett, hanem a felhaszn�l�i
t�pusokra
is megadhatunk. Ez alapveto fontoss�g� felt�tele annak, hogy �ltal�nos
algoritmusokat
olyan t�pusokra alkalmazhassunk, amelyeknek nem magukt�l �rtetodo �sszehasonl�t�si

felt�teleik vannak (�18.4).


Minden oszt�lysablonb�l l�trehozott oszt�ly saj�t p�ld�nyokat kap a sablon
statikus v�ltoz
�ib�l (�C.13.1).
13.4.1. Alap�rtelmezett sablonparam�terek
F�rads�gos dolog minden egyes h�v�sn�l k�zvetlen�l meghat�rozni az
�sszehasonl�t�si felt
�teleket. T�lterhel�ssel szerencs�re k�nnyen megadhatunk olyan alap�rtelmez�st,
hogy
csak a szok�sost�l elt�ro �sszehasonl�t�si szempontot kelljen megadni:
13. Sablonok 447
template<class T, class C>
int compare(const String<T>& str1, const String<T>& str2); // �sszehasonl�t�s C
// haszn�lat�val
template<class T>
int compare(const String<T>& str1, const String<T>& str2); // �sszehasonl�t�s
// Cmp<T> haszn�lat�val
De a szok�sos rendez�st megadhatjuk, mint alap�rtelmezett sablonparam�ter-�rt�ket
is:
template<class T, class C = Cmp<T> >
int compare(const String<T>& str1, const String<T>& str2)
{
for(int i=0; i<str1.length() && i< str2.length(); i++)
if (!C::eq(str1[i],str2[i])) return C::lt(str1[i],str2[i]) ? -1 : 1;
return str1.length()-str2.length();
}
�gy m�r le�rhatjuk a k�vetkezot:
void f(String<char> swede1, String<char> swede2)
{
compare(swede1,swede2); // Cmp<char> haszn�lata
compare<char,Literate>(swede1,swede2); // Literate haszn�lata
}
Egy (nem sv�dek sz�m�ra) kev�sb� ezoterikus p�lda a kis- �s nagybetuk k�z�tti
k�l�nbs�-
get figyelembe vevo, illetve elhanyagol� rendez�s:
class No_case { /* ... */ };
void f(String<char> s1, String<char> s2)
{
compare(s1,s2); // kisbetu-nagybetu k�l�nb�zik
compare<char,No_case>(s1,s2); // kisbetu-nagybetu nem k�l�nb�zik
}
A standard k�nyvt�r sz�les k�rben alkalmazza azt a m�dszert, hogy az alkalmazand�
elj�-
r�sm�dot (policy) egy sablonparam�ter adja meg, �s ennek a leg�ltal�nosabb
elj�r�sm�d az
alap�rtelmezett �rt�ke (p�ld�ul �18.4). El�gg� furcsa m�don azonban a basic_string
(�13.2,
20. fejezet) �sszehasonl�t�saira ez nem �ll. Az elj�r�sm�dot kifejezo
sablonparam�tereket
gyakran nevezik .jellemvon�soknak. (traits) is. P�ld�ul a standard k�nyvt�rbeli
string
a char_traits-re �p�l (�20.2.1), a szabv�nyos algoritmusok a bej�r�k (iter�torok)
jellemvon
�sait (�19.2.2), a standard k�nyvt�rbeli t�rol�k pedig a mem�riafoglal�k�t
(allok�tor,
�19.4.) haszn�lj�k fel.
448 Absztrakci�s m�dszerek
Egy alap�rtelmezett sablonparam�ter �rtelmi ellenorz�se ott �s csak akkor t�rt�nik
meg,
ahol �s amikor az alap�rtelmezett param�tert t�nylegesen felhaszn�ljuk. �gy ha nem
haszn
�ljuk fel az alap�rtelmezett Cmp<T> param�tert, akkor olyan X t�pusokra is
haszn�lhatjuk
a compare()-t, amelyekre a ford�t� nem ford�tan� le aCmp<X>-et, mert mondjuk az X-
re a <
nem �rtelmezett. Ez d�nto jelentos�gu a szabv�nyos t�rol�k tervez�s�n�l, hiszen
ezek sablonparam
�tert haszn�lnak az alap�rtelmezett �rt�kek megad�s�ra (�16.3.4).
13.5. Specializ�ci�
Alap�rtelmez�s szerint egy sablon (template) egyetlen defin�ci�t ad a
felhaszn�lhat� �ltal elk
�pzelheto �sszes param�ter�rt�k (vagy param�ter�rt�kek) sz�m�ra. Ez azonban nem
minden
sablon �r�sakor kedvezo. Elofordulhat, hogy olyasmit szeretn�nk kifejezni, hogy
.ha
a sablonparam�ter egy mutat�, haszn�ld ezt, ha nem, haszn�ld azt., vagy hogy
.hiba, ha
a sablonparam�ter nem a My_base oszt�ly egy lesz�rmazottj�ra hivatkoz� mutat�..
Sok hasonl
� tervez�si szempontot figyelembe lehet �gy venni, hogy a sablonnak t�bbf�le
defin�ci�t adunk �s a ford�t�program az alkalmazott param�tert�pusok szerint
v�laszt k�z�-
l�k. A sablon ilyenf�le t�bbsz�r�s meghat�roz�s�t specializ�ci�nak
(specialization, egyedi
c�l� felhaszn�l�i v�ltozatok haszn�lata, szakos�t�s) h�vjuk.
Vegy�k egy Vector sablon val�sz�nu felhaszn�l�sait:
template<class T> class Vector { // �ltal�nos vektort�pus
T* v;
int sz;
public:
Vector();
Vector(int);
T& elem(int i) { return v[i]; }
T& operator[ ](int i);
void swap(Vector&);
// ...
};
Vector<int> vi;
Vector<Shape*> vps;
Vector<string> vs;
Vector<char*> vpc;
Vector<Node*> vpn;
13. Sablonok 449
A legt�bb Vector valamilyen mutat�t�pus Vector-a lesz. T�bb okb�l is, de foleg
az�rt, mert
a t�bbalak� (polymorph) viselked�s megorz�se c�lj�b�l mutat�kat kell haszn�lnunk
(�2.5.4, �12.2.6). Ez�rt aki objektumorient�lt programoz�st folytat �s
t�pusbiztos, p�ld�ul
standard k�nyvt�rbeli t�rol�kat haszn�l, az biztosan sz�mos mutat�t tartalmaz�
t�rol�t fog
haszn�lni.
A legt�bb C++-v�ltozat alap�rtelmez�s szerint lem�solja a sablon f�ggv�nyek
k�dj�t. Ez j�
a v�grehajt�si sebess�g szempontj�b�l, de kritikus esetekben (mint az im�nti
Vector-n�l)
a k�d .felf�v�d�s�val. j�r.
Szerencs�re l�tezik egyszeru megold�s. A mutat�kat tartalmaz� t�rol�knak el�g
egyetlen
megval�s�t�s. Ezt specializ�lt v�ltozat k�sz�t�s�vel �rhetj�k el. Elosz�r
defini�ljuk a Vectornak
a void mutat�kra vonatkoz� v�ltozat�t (.specializ�ci�j�t.):
template<> class Vector<void*> {
void** p;
// ...
void*& operator[ ](int i);
};
Ezt a v�ltozatot azt�n az �sszes, mutat�t tartalmaz� vektor k�z�s
megval�s�t�sak�nt haszn
�lhatjuk. A template<> elotag azt jelenti, hogy enn�l a specializ�lt v�ltozatn�l
nem kell sablonparam
�tert megadnunk. Azt, hogy milyen t�pus� sablonparam�terre haszn�ljuk, a n�v
ut�ni <> jelp�r k�z�tt adjuk meg: vagyis a <void*> azt jelenti, hogy ezt a
defin�ci�t kell minden
olyan Vector eset�ben haszn�lni, amelyikre a T t�pusa void*.
A Vector<void*> egy teljes specializ�ci�, azaz ezen v�ltozat haszn�latakor nincs
sablonparam
�ter, amit meg kellene adni vagy le kellene vezetni; a Vector<void*>-ot a
k�vetkezo m�-
don deklar�lt Vector-ok sz�m�ra haszn�ljuk:
Vector<void*> vpv;
Ha olyan v�ltozatot akarunk megadni, ami mutat�kat tartalmaz� Vector-ok, �s csak
azok
eset�n haszn�land�, r�szleges specializ�ci�ra van sz�ks�g�nk:
template<class T> class Vector<T*> : private Vector<void*> {
public:
typedef Vector<void*> Base;
Vector() : Base() {}
explicit Vector(int i) : Base(i) {}
450 Absztrakci�s m�dszerek
T*& elem(int i) { return reinterpret_cast<T*&>(Base::elem(i)); }
T*& operator[ ](int i) { return reinterpret_cast<T*&>(Base::operator[ ](i)); }
// ...
};
A n�v ut�ni <T*> specializ�l� minta azt jelzi, hogy ezt a v�ltozatot kell minden
mutat�t�pus
eset�ben haszn�lni; azaz minden olyan sablonparam�tern�l, ami T* alakba �rhat�:
Vector<Shape*> vps; // <T*> most <Shape*>, �gy T is Shape
Vector<int**> vppi; // <T*> most <int**>, �gy T is int*
Jegyezz�k meg, hogy r�szleges specializ�ci� haszn�lata eset�n a sablonparam�ter
a specializ�ci�ra haszn�lt mint�b�l ad�dik; a sablonparam�ter nem egyszeruen az
aktu�lis
sablonparam�ter. �gy p�ld�ul a Vector<Shape*> eset�ben T t�pusa Shape �s nem
Shape*.
Ha adott a Vector ezen r�szlegesen specializ�lt v�ltozata, akkor ez az �sszes
mutat�t�pusra
vonatkoz� Vector k�z�s megval�s�t�sa. A Vector<T*> oszt�ly egyszeruen egy fel�let
a void*-os v�ltozathoz, melyet kiz�r�lag az �r�klod�s �s a helyben kifejt�s
eszk�z�vel val
�s�tottuk meg.
Fontos, hogy a Vector ezen finom�t�sa a felhaszn�l�i fel�let megv�ltoztat�sa
n�lk�l t�rt�nt.
A specializ�ci� a k�z�s fel�let t�bbf�le meghat�roz�s�nak eszk�ze. Term�szetesen
az �ltal
�nos Vector-t �s a mutat�kra vonatkoz� v�ltozatot h�vhattuk volna k�l�nb�zok�ppen
is.
Amikor ezt kipr�b�ltam, kider�lt, hogy sok felhaszn�l�, akinek tudnia kellett
volna r�la,
m�gsem a mutat�s v�ltozatot haszn�lta �s a kapott k�d a v�rtn�l sokkal nagyobb
lett. Ebben
az esetben sokkal jobb a fontos r�szleteket egy k�z�s fel�let m�g� rejteni.
Ez a m�dszer a gyakorlatban a k�d felf�v�d�s�nak megakad�lyoz�s�ban volt sikeres.
Akik
nem alkalmaznak ilyen m�dszereket (ak�r a C++-ban, ak�r egy�b t�pus-param�terez�si
lehet
os�geket tartalmaz� nyelvekben), k�nnyen azt vehetik �szre, hogy az ism�tlodo k�d
k�-
zepes m�retu programok eset�ben is megab�jtokra r�ghat. A vektormuveletek
k�l�nb�zo
v�ltozatainak leford�t�s�hoz sz�ks�ges ido megtakar�t�s�val ez a m�dszer a
ford�t�si �s
szerkeszt�si idot is dr�mai m�don cs�kkenti. Az �sszes mutat�t tartalmaz� lista
egyetlen
specializ�lt v�ltozattal val� megval�s�t�sa j� p�lda arra, hogyan lehet a
k�dfelf�v�d�st megakad
�lyozni �gy, hogy a k�z�s k�dot a leheto legjobban n�velj�k.
Az �ltal�nos sablont az �sszes specializ�lt v�ltozat elott kell megadni:
template<class T> class List<T*> { /* ... */ };
template<class T> class List { /* ... */ }; // hiba: �ltal�nos sablon a
specializ�lt ut�n
13. Sablonok 451
Az �ltal�nos sablon �ltal adott l�tfontoss�g� inform�ci� az, hogy milyen
param�tereket kell
a felhaszn�l�s vagy a specializ�ci� sor�n megadni. Ez�rt el�g az �ltal�nos sablont
a specializ
�lt v�ltozat deklar�ci�ja vagy definici�ja elott megadni:
template<class T> class List;
template<class T> class List<T*> { /* ... */ };
Ha haszn�ljuk is, akkor az �ltal�nos sablont valahol defini�lnunk kell (�13.7).
Ha valahol szerepel egy felhaszn�l�i specializ�lt v�ltozat, akkor annak
deklar�ci�ja
a specializ�lt haszn�lat minden hely�rol el�rheto kell, hogy legyen:
template<class T> class List { /* ... */ };
List<int*> li;
template<class T> class List<T*> { /* ... */ }; // hiba
Itt a List-et az int*-ra a List<int*> haszn�lata ut�n specializ�lunk.
Egy sablon minden specializ�lt v�ltozat�t ugyanabban a n�vt�rben kell megadni,
mint mag
�t a sablont. Ha haszn�lj�k, akkor egy explicit deklar�lt (azaz nem egy
�ltal�nosabb�l l�trehozott)
sablonnak valahol szint�n explicit defini�ltnak kell lennie (�13.7). Vagyis a
specializ
�lt v�ltozat explicit megad�s�b�l k�vetkezik, hogy sz�m�ra a ford�t� nem hoz l�tre

defin�ci�t.
13.5.1. Specializ�ci�k sorrendje
Az egyik v�ltozat specializ�ltabb egy m�sikn�l, ha minden olyan param�terlista,
amely illeszkedik
az egyikre, illeszkedik a m�sikra is. Ez ford�tva nem �ll fenn:
template<class T> class Vector; // �ltal�nos
template<class T> class Vector<T*>; // mutat�khoz
template<> class Vector<void*>; // void*-okhoz
Minden t�pust haszn�lhatunk a leg�ltal�nosabb Vector param�terek�nt, de a
Vector<T*> param
�terek�nt csak mutat�t, a Vector<void*> param�terek�nt pedig csak void* mutat�t.
Az objektumok �s mutat�k stb. (�13.5) deklar�ci�j�ban, illetve a t�lterhel�s
felold�sakor
(�13.3.2) a legink�bb specializ�lt v�ltozat r�szes�l elonyben.
452 Absztrakci�s m�dszerek
A specializ�l� minta megad�s�n�l a sablonparam�terek levezet�s�n�l (�13.3.1)
haszn�lt t�-
pusokb�l �ssze�ll�tott t�pusok haszn�lhat�k fel.
13.5.2. F�ggv�nysablon specializ�ci�
A specializ�ci� term�szetesen a sablon f�ggv�nyekn�l (template function) is
hasznos. Vegy
�k a �7.7 �s �13.3 p�ldabeli Shell rendez�st. Ez az elemeket a < seg�ts�g�vel
hasonl�tja
�ssze �s a r�szletezett k�d seg�ts�g�vel cser�li fel. Jobb defin�ci� lenne a
k�vetkezo:
template<class T> bool less(T a, T b) { return a<b; }
template<class T> void sort(Vector<T>& v)
{
const size_t n = v.size();
for (int gap=n/2; 0<gap; gap/=2)
for (int i=gap; i<n; i++)
for (int j=i-gap; 0<=j; j-=gap)
if (less(v[j+gap],v[j])) swap(v[j],v[j+gap]);
}
Ez nem jav�tja mag�t az algoritmust, de lehetos�get ny�jt a megval�s�t�s
jav�t�s�ra. Eredeti
form�j�ban egy Vector<char*>-ot nem rendez j�l, mert k�t char*-ot a < seg�ts�g�vel
hasonl
�t �ssze, azaz az elso karakter c�m�t fogja az �sszehasonl�t�s alapj�ul venni.
Ehelyett a mutatott
karakterek szerinti �sszehasonl�t�st szeretn�nk. Erre a less()-nek egy egyszeru,
const
char*-ra vonatkoz� specializ�ci�ja fog �gyelni:
template<> bool less<const char*>(const char* a, const char* b)
{
return strcmp(a,b)<0;
}
Mint az oszt�lyokn�l is (�13.5), a <> sablon-elotag azt jelzi, hogy ez egy
sablonparam�ter
megad�sa n�lk�li specializ�lt v�ltozat. A sablon f�ggv�ny neve ut�ni <const char*>
azt jelenti,
hogy a f�ggv�nyt azokban az esetekben kell alkalmazni, amikor a sablonparam�ter
const char*. Minthogy a sablonparam�ter k�zvetlen�l levezetheto a f�ggv�ny
param�terlist
�j�b�l, nem kell explicit megadnunk. �gy egyszerus�thet�nk a specializ�ci�
megad�s�n:
template<> bool less<>(const char* a, const char* b)
{
return strcmp(a,b)<0;
}
13. Sablonok 453
Minthogy adott a template<> elotag, a m�sodik, �res <> felesleges, hiszen nem
hordoz �j
inform�ci�t. �gy azt�n �ltal�ban �gy �rn�nk:
template<> bool less(const char* a, const char* b)
{
return strcmp(a,b)<0;
}
�n jobban kedvelem ezt a r�videbb deklar�ci�s form�t.
Vegy�k a swap() k�zenfekvo meghat�roz�s�t:
template<class T> void swap(T& x, T& y)
{
T t = x; // x m�sol�sa az ideiglenes v�ltoz�ba
x = y; // y m�sol�sa x-be
y = t; // ideiglenes v�ltoz� m�sol�sa y-ba
}
Ez nem t�l hat�kony, ha Vector-ok vektoraira h�vjuk meg; az �sszes elem
m�sol�s�val cser
�li fel a Vector-okat. De ezt is megoldhatjuk megfelelo specializ�ci�val. Maga a
Vector objektum
csak annyi adatot tartalmaz, hogy az elemeihez val� k�zvetett hozz�f�r�st
t�mogassa
(mint a string �11.12, �13.2). �gy azt�n a cser�t a megfelelo �br�zol� adatok
cser�j�vel lehet
megoldani. Hogy lehetov� tegy�k az �br�zol� adatok kezel�s�t, adjunk meg egy
swap()
f�ggv�nyt a Vector oszt�ly sz�m�ra (�13.5):
template<class T> void Vector<T>::swap(Vector & a) // �br�zol�sok cser�je
{
swap(v,a.v);
swap(sz,a.sz);
}
A swap() tagot felhaszn�lhatjuk az �ltal�nos swap() specializ�lt definici�j�ban:
template<class T> void swap(Vector<T>& a, Vector<T>& b)
{
a.swap(b);
}
A less() �s a swap() ezen v�ltozatait haszn�lja a standard k�nyvt�r (�16.3.9,
�20.3.16) is. R�-
ad�sul ezek a p�ld�k sz�les k�rben haszn�lt m�dszereket mutatnak be. A
specializ�ci� akkor
hasznos, ha a sablonparam�terek egy adott halmaz�ra egy �ltal�nos algoritmusn�l
l�tezik
hat�konyabb megval�s�t�s (itt a swap()). Ezenk�v�l akkor is hasznos, ha a
param�tert�-
pus valamilyen szab�lytalans�ga miatt a szabv�nyos algoritmus valamilyen nem
k�v�nt m�-
don muk�dne (mint a less() eset�ben). Ezek a .szab�lytalan. t�pusok t�bbnyire a
be�p�tett
mutat�- �s t�mbt�pusok.
454 Absztrakci�s m�dszerek
13.6. �r�klod�s �s sablonok
Az �r�klod�s �s a sablonok olyan eszk�z�k, amelyekkel meglevok alapj�n �j t�pusok
�p�thet
ok, �s amelyekkel �ltal�noss�gban a k�z�s von�sok k�l�nf�le kihaszn�l�s�val
hasznos
k�d �rhat�. Mint a �3.7.1, �3.8.5 �s �13.5 pontokban l�ttuk, ezen eszk�z�k
p�ros�t�sa sok
hasznos m�dszer alapja.
Egy sablon oszt�lynak (template class) egy nem sablon oszt�lyb�l val�
sz�rmaztat�sa m�-
dot ny�jt arra, hogy sablonok egy halmaza k�z�s megval�s�t�son osztozz�k. A �13.5
pontbeli
vektor j� p�lda erre:
template<class T> class List<T*> : private List<void*> { /* ... */ };
M�sk�nt n�zve a p�lda azt mutatja, hogy a sablon eleg�ns �s t�pusbiztos fel�letet
ad egy
m�sk�nt nem biztons�gosan �s nem eleg�nsan haszn�lhat� eszk�zh�z.
Term�szetesen a sablon oszt�lyok k�z�tti �r�klod�s is hasznos. A b�zisoszt�ly
egyik haszna
az, hogy tov�bbi oszt�lyok sz�m�ra �p�toko�l szolg�l. Ha a b�zisoszt�ly adatai
vagy mu-
veletei valamely sz�rmaztatott oszt�ly sablonparam�ter�tol f�ggenek, akkor mag�nak

a b�zisoszt�lynak is param�tereket kell adni (l�sd p�ld�ul a �3.7.2 pontbeli Vec


oszt�lyt):
template<class T> class vector { /* ... */ };
template<class T> class Vec : public vector<T> { /* ... */ };
A sablon f�ggv�nyek t�lterhel�s-felold�si szab�lyai biztos�tj�k a f�ggv�nyek
helyes muk�-
d�s�t az ilyen sz�rmaztatott t�pusokra (�13.3.2).
Az az eset a leggyakoribb, amikor ugyanaz a sablonparam�ter szerepel a b�zis- �s a
sz�rmaztatott
oszt�lyban is, de ez nem sz�ks�gszeru. �rdekes, b�r ritk�bban alkalmazott
m�dszerek
alapulnak azon, hogy mag�t a sz�rmaztatott oszt�lyt adjuk �t a b�zisoszt�lynak:
template <class C> class Basic_ops { // t�rol�k alapmuveletei
public:
bool operator==(const C&) const; // minden elem �sszehasonl�t�sa
bool operator!=(const C&) const;
// ...
// hozz�f�r�s biztos�t�sa C muveleteihez
const C& derived() const { return static_cast<const C&>(*this); }
};
13. Sablonok 455
template<class T> class Math_container : public Basic_ops< Math_container<T> > {
public:
size_t size() const;
T& operator[ ](size_t);
const T& operator[ ](size_t) const;
// ...
};
Ez�ltal lehetov� v�lik a t�rol�k alapveto muveleteinek az egyes t�rol�kt�l
elk�l�n�tett, egyszeri
meghat�roz�sa. �m mivel az olyan muveletek defin�ci�j�hoz, mint az == �s a != mind

a t�rol�nak, mind annak elemeinek t�pus�ra sz�ks�g van, a b�zisoszt�lyt �t kell


adni
a t�rol�sablonnak.
Ha feltessz�k, hogy a Math_container egy hagyom�nyos vektorra hasonl�t, akkor
a Basic_ops egy tagja valahogy �gy n�zhet ki:
template <class C> bool Basic_ops<C>::operator==(const C& a) const
{
if (derived().size() != a.size()) return false;
for (int i = 0; i<derived().size(); ++i)
if (derived()[i] != a[i]) return false;
return true;
}
A t�rol�k �s a muveletek elv�laszt�s�ra szolg�l� m�sik m�dszer �r�klod�s helyett
sablonparam
�terekkel kapcsolja �ssze azokat:
template<class T, class C> class Mcontainer {
C elements;
public:
T& operator[ ](size_t i) { return elements[i]; }
.. // ...
friend bool operator==(const Mcontainer&, const Mcontainer&); // elemek
// �sszehasonl�t�sa
friend bool operator!=(const Mcontainer&, const Mcontainer&);
// ...
};
template<class T> class My_array { /* ... */ };
Mcontainer< double,My_array<double> > mc;
456 Absztrakci�s m�dszerek
Egy sablonb�l l�trehozott oszt�ly teljesen k�z�ns�ges oszt�ly, ez�rt lehetnek
bar�t (friend)
f�ggv�nyei (�C.13.2) is. Ebben a p�ld�ban az�rt haszn�ltam bar�tokat, hogy a == �s
a != sz�-
m�ra a k�t param�ter szok�sos felcser�lhetos�g�t biztos�tsam (�11.3.2). Ilyen
esetekben
meg lehetne fontolni azt is, hogy a C param�terk�nt t�rol� helyett sablont
haszn�ljunk.
13.6.1. Param�terez�s �s �r�klod�s
A sablonok egy t�pust vagy f�ggv�nyt egy m�sik t�pussal param�tereznek. A sablon
k�dja
minden param�tert�pus eset�ben azonos, csak�gy, mint a sablont haszn�l� legt�bb
k�dr
�sz. Az absztrakt oszt�lyok fel�leteket �rnak le, k�l�nf�le megval�s�t�saik
k�dr�szeit az
oszt�lyhierarchi�k k�z�sen haszn�lhatj�k, �s az absztrakt oszt�lyt haszn�l� k�d
legnagyobb
r�sze nem is f�gg a megval�s�t�st�l. A tervez�s szempontj�b�l a k�t megk�zel�t�s
annyira
k�zeli, hogy k�z�s nevet �rdemel. Minthogy mindketto azt teszi lehetov�, hogy egy
algoritmust
egyszer �rjunk le �s azt�n k�l�nf�le t�pusokra alkalmazzuk, n�ha mindkettot
t�bbalak
�s�gnak (polimorfizmus, polymorphism) h�vj�k. Hogy megk�l�nb�ztess�k oket, a virtu
�lis f�ggv�nyek �ltal biztos�tottat fut�si ideju (run-time) t�bbalak�s�gnak, a
sablonok �ltal
ny�jtottat pedig ford�t�si ideju (compile-time) t�bbalak�s�gnak vagy param�teres
(parametric) t�bbalak�s�gnak h�vj�k.
V�g�l is mikor v�lasszunk absztrakt oszt�lyt �s mikor alkalmazzunk sablont?
Mindk�t esetben
olyan objektumokat kezel�nk, amelyeknek azonos muveleteik vannak. Ha nem sz�ks
�ges egym�ssal al�- �s f�l�rendelts�gi viszonyban �llniuk, akkor legyenek
sablonparam�-
terek. Ha az objektumok aktu�lis t�pusa a ford�t�si idoben nem ismert, akkor
legjobban egy
k�z�s absztrakt oszt�lyb�l �r�klodo oszt�lyk�nt �br�zolhatjuk azokat. Ha a fut�si
ido nagyon
fontos, azaz a muveletek helyben kifejtve t�rt�no ford�that�s�ga alapveto
szempont,
haszn�ljunk sablont. Errol r�szletesebben a �24.4.1 pont �r.
13.6.2. Tag sablonok
Egy oszt�lynak vagy oszt�lysablonnak lehetnek olyan tagjai is, amelyek maguk is
sablonok:
template<class Scalar> class complex {
Scalar re, im;
public:
template<class T>
complex(const complex<T>& c) : re(c.real()), im(c.imag()) { }
// ...
};
13. Sablonok 457
complex<float> cf(0,0);
complex<double> cd = cf; // rendben: float-r�l double-ra alak�t�s haszn�lata
class Quad {
// nincs �talak�t�s int-re
};
complex<Quad> cq;
complex<int> ci = cq; // hiba: nincs �talak�t�s Quad-r�l int-re
Vagyis kiz�r�lag akkor tudunk complex<T2>-bol complex<T1>-et �p�teni, ha T1-nek
kezd
o�rt�k�l adhatjuk T2-t, ami �sszeru megszor�t�snak tunik.
Sajnos azonban a C++ nyelv elfogad a be�p�tett t�pusok k�z�tti bizonyos
�sszerutlen
konverzi�kat is, p�ld�ul double-r�l int-re. A v�grehajt�si idoben a csonk�t�sb�l
eredo hib�kat
el lehetne kapni, implicit_cast (�13.3.1) vagy checked (�C.6.2.6.2) st�lus�
ellenorz�tt
konverzi�val:
template<class Scalar> class complex {
Scalar re, im;
public:
complex() : re(0), im(0) { }
complex(const complex<Scalar>& c) : re(c.real()), im(c.imag()) { }
template<class T2> complex(const complex<T2>& c)
: re(checked_cast<Scalar>(c.real())), im(checked_cast<Scalar>(c.imag())) { }
// ...
};
A teljess�g kedv��rt alap�rtelmezett �s m�sol� konstruktort is megadtam. El�g
k�l�n�s
m�don egy sablon konstruktorb�l a ford�t� soha nem hoz l�tre m�sol� konstruktort,
�gy
k�zvetlen�l deklar�lt m�sol� konstruktor h�j�n a ford�t� alap�rtelmezett
konstruktort hozott
volna l�tre, ami ebben az esetben azonos lett volna az �ltalam megadottal.
Egy sablon tag nem lehet virtu�lis:
class Shape {
// ...
template<class T> virtual bool intersect(const T&) const =0; // hiba: virtu�lis
sablon
};
Ez szab�lytalan. Ha megengedett lenne, akkor a virtu�lis f�ggv�nyek
megval�s�t�s�nak hagyom
�nyos virtu�lisf�ggv�ny-t�bl�s m�dja (�2.5.5) nem lenne alkalmazhat�. A
szerkeszto-
nek az intersect() f�ggv�ny minden �j param�tert�pussal t�rt�no megh�v�sa eset�n
egy
�jabb elemmel kellene bov�tenie a Shape oszt�ly virtu�lisf�ggv�ny-t�bl�j�t.
458 Absztrakci�s m�dszerek
13.6.3. �r�klod�si viszonyok
�ltal�ban �gy gondolnunk egy sablonra, mint �j t�pusok l�trehoz�s�t seg�to
�ltal�nos�t�sra.
M�s sz�val a sablon egy olyan eszk�z, amely sz�ks�g eset�n a felhaszn�l� elo�r�sai
szerinti
t�pusokat hoz l�tre. Ez�rt az oszt�lysablonokat n�ha t�pusk�sz�toknek vagy
t�pusgener�toroknak
h�vj�k.
A C++ nyelv szab�lyai szerint k�t, azonos oszt�lysablonb�l l�trehozott oszt�ly nem
�ll rokons
�gban egym�ssal:
class Shape { /* ... */ };
class Circle : public Shape { /* ... */ };
Ilyenkor egyesek megpr�b�lj�k a set<Circle*>-ot set<Shape*>-k�nt kezelni, ami
hib�s �rvel
�sen nyugv� s�lyos logikai hiba: az .egy Circle egyben Shape is, �gy a Circle-�k
halmaza
egyben Shape-ek halmaza is; teh�t a Circle-�k halmaz�t Shape-ek halmazak�nt is
kezelhetem
. �rvel�s .teh�t. pontja hib�s. Oka, hogy a Circle-�k halmaza kiz�r�lag Circle
t�pus� objektumokat
tartalmaz, m�g a Shape-ek halmaza eset�ben ez egy�ltal�n nem biztos:
class Triangle : public Shape { /* ... */ };
void f(set<Shape*>& s)
{
// ...
s.insert(new Triangle());
// ...
}
void g(set<Circle*>& s)
{
f(s); // t�pushiba: s t�pusa set<Circle*>, nem set<Shape*>
}
A fenti p�ld�t a ford�t�program nem fogja leford�tani, mert nincs be�p�tett
konverzi�
set<Circle*>&-rol set<Shape*>&-re. Nagyon helyesen. Az a garancia, hogy a
set<Circle*>
elemei Circle-�k, lehetov� teszi, hogy az elemekre biztons�gosan �s hat�konyan
v�gezz
�nk Circle-�kre jellemzo muveleteket, p�ld�ul a sug�r lek�rdez�s�t. Ha
megengedn�nk
a set<Circle*>-�knek set<Shape*>-k�nt val� kezel�s�t, akkor ez m�r nem lenne
biztos�tott.
P�ld�ul az f() f�ggv�ny egy Triangle* elemet tesz set<Shape*> param�ter�be; ha
a set<Shape*> egy set<Circle*> lehetne, akkor nem lenne t�bb� igaz, hogy egy
set<Circle*>
csak Circle*-okat tartalmaz.
13. Sablonok 459
13.6.3.1. Sablonok konverzi�ja
Az elozo p�lda azt mutatta be, mi�rt nem lehet semmilyen alap�rtelmezett kapcsolat
k�t,
azonos oszt�lysablonb�l l�trehozott oszt�ly k�z�tt. Egyes oszt�lyokn�l azonban
m�giscsak
szeretn�nk ilyen kapcsolatot kifejezni. P�ld�ul ha egy mutat� sablont k�sz�t�nk,
szeretn�nk
t�kr�zni a mutatott objektumok k�z�tti �r�klod�si viszonyokat. Tag sablonok
(�13.6.2)
ig�ny eset�n sokf�le hasonl� kapcsolatot kifejezhetnek:
template<class T> class Ptr { // mutat� T-re
T* p;
public:
Ptr(T*);
template<class T2> operator Ptr<T2> (); // Ptr<T> konverzi�ja Ptr<T2>-re
// ...
};
Ezut�n szeretn�nk a konverzi�s oper�torokat �gy defini�lni, hogy Ptr-jeinkre
fenn�lljanak
a be�p�tett mutat�kn�l megszokott �r�klod�si kapcsolatok:
void f(Ptr<Circle> pc)
{
Ptr<Shape> ps = pc; // muk�dnie kell
Ptr<Circle> pc2 = ps; // elvileg hib�t eredm�nyez
}
Azt szeretn�nk, hogy az elso kezdo�rt�k-ad�s csak akkor legyen enged�lyezett, ha a
Shape
val�ban k�zvetett vagy k�zvetlen nyilv�nos b�zisoszt�lya a Circle-nek. �ltal�ban
�gy szeretn
�nk a konverzi�s oper�torokat megadni, hogy a Ptr<T>-rol Ptr<T2>-re t�rt�no
konverzi� csak akkor legyen enged�lyezett, ha egy T2* t�pus� mutat� �rt�k�l kaphat
egy
T* t�pus� mutat�t. Ezt �gy tehetj�k meg:
template<class T>
template<class T2>
Ptr<T>::operator Ptr<T2> () { return Ptr<T2>(p); }
A return utas�t�st a ford�t� csak akkor fogadja el, ha p (ami T* t�pus�) a
Ptr<T2>(T2*)
konstruktor param�tere lehet. Ez�rt ha a T* automatikusan T2*-ra konvert�lhat�, a
Ptr<T>-
rol Ptr<T2>-re t�rt�no konverzi� muk�dni fog:
void f(Ptr<Circle> pc)
{
Ptr<Shape> ps = pc; // rendben: Circle* �talak�that� Shape*-ra
Ptr<Circle> pc2 = ps; // hiba: Shape* nem alak�that� Circle*-g�
}
460 Absztrakci�s m�dszerek
Legy�nk �vatosak �s csak logikailag �rtelmes konverzi�kat defini�ljunk.
Jegyezz�k meg, hogy nem lehets�ges egy sablonnak, illetve annak szint�n sablon
tagj�nak
sablonparam�ter-list�it egyes�teni:
template<class T, class T2> // hiba
Ptr<T>::operator Ptr<T2> () { return Ptr<T2>(p); }
13.7. A forr�sk�d szerkezete
A sablonokat haszn�l� k�d szerkezete alapvetoen k�tf�le lehet:
1. A sablonok defin�ci�j�t be�p�tj�k (#include) egy ford�t�si egys�gbe, mielott
haszn
�ln�nk azokat.
2. A haszn�lat elott a sablonoknak csak a deklar�ci�j�t emelj�k be, definici�jukat

k�l�n ford�tjuk.
Ezenk�v�l lehets�ges, hogy a sablonf�ggv�nyeket egy ford�t�si egys�gen bel�l
elosz�r csak
deklar�ljuk, majd haszn�ljuk �s csak v�g�l defini�ljuk.
Hogy l�ssuk a k�tf�le megk�zel�t�s k�z�tti k�l�nbs�get, vegy�nk egy egyszeru
p�ld�t:
#include<iostream>
template<class T> void out(const T& t) { std::cerr << t; }
H�vjuk ezt a f�jlt out.c-nek �s �p�ts�k be, valah�nyszor sz�ks�g�nk van az out()-
ra:
// user1.c:
#include "out.c"
// out() haszn�lata
// user2.c:
#include "out.c"
// out() haszn�lata
Vagyis az out()-ot �s a hozz� sz�ks�ges valamennyi deklar�ci�t t�bb k�l�nb�zo
ford�t�si
egys�gbe is be�p�tj�k. A ford�t�program dolga, hogy csak akkor hozzon l�tre k�dot,
ha
sz�ks�ges, �s hogy a felesleges inform�ci�k feldolgoz�s�t optimaliz�lja, ami azt
is jelenti,
hogy a sablon f�ggv�nyeket ugyan�gy kezeli, mint a helyben kifejtett (inline)
f�ggv�nyeket.
13. Sablonok 461
Ezzel az a nyilv�nval� gond, hogy minden olyan inform�ci�, amelyre az out()-nak
sz�ks�-
ge van, az out()-ot felhaszn�l� valamennyi ford�t�si egys�gbe beleker�l, �s ilyen
m�don
megno a ford�t�program �ltal feldolgozand� adat mennyis�ge. Egy m�sik gond, hogy a
felhaszn
�l�k esetleg v�letlen�l .r�kapnak. az eredetileg csak az out() definici�j�hoz
sz�ks�-
ges deklar�ci�k haszn�lat�ra. Ezt a vesz�lyt n�vterek haszn�lat�val, a makr�k
haszn�lat�-
nak elker�l�s�vel �s �ltal�ban a be�p�tendo inform�ci� mennyis�g�nek
cs�kkent�s�vel h�-
r�thatjuk el.
E gondolatmenet logikus folyom�nya a k�l�n ford�t�s: ha a sablon nem �p�l be a
felhaszn
�l�i k�dba, azok az elemek, melyektol f�gg, nem is befoly�solhatj�k azt. �gy az
eredeti
out.c �llom�nyt k�t r�szre bontjuk:
// out.h:
template<class T> void out(const T& t);
// out.c:
#include<iostream>
#include "out.h"
export template<class T> void out(const T& t) { std::cerr << t; }
Az out.c f�jl most az out() defini�l�s�hoz sz�ks�ges �sszes inform�ci�t
tartalmazza, az out.h
csak a megh�v�s�hoz sz�ks�geset. A felhaszn�l� csak a deklar�ci�t (vagyis a
fel�letet) �p�-
ti be:
// user1.c:
#include "out.h"
// out() haszn�lata
// user2.c:
#include "out.h"
// out() haszn�lata
Ezen a m�don a sablon f�ggv�nyeket a nem helyben kifejtett f�ggv�nyekhez hasonl�an
kezelj
�k. Az out.c-beli defin�ci�t k�l�n ford�tjuk, �s az adott ford�t� dolga sz�ks�g
eset�n az
out() le�r�s�nak megkeres�se. Ez n�mi terhet r� a ford�t�ra, hiszen a sablon-
meghat�roz�s
f�l�s p�ld�nyainak kiszur�se helyett sz�ks�g eset�n meg kell tal�lnia az egyetlen
defin�ci�t.
Jegyezz�k meg, hogy a sablon defin�ci�ja csak akkor �rheto el m�s ford�t�si
egys�gbol, ha
kifejezetten export-k�nt adjuk meg (�9.2.3). (Ez �gy t�rt�nik, hogy a defin�ci�hoz
vagy egy
megelozo deklar�ci�hoz hozz�adjuk az export sz�t.) Ha nem �gy tesz�nk, a
defin�ci�nak
minden haszn�lat hely�rol el�rhetonek kell lennie.
462 Absztrakci�s m�dszerek
A ford�t�- �s szerkesztoprogramt�l, a fejlesztett program fajt�j�t�l, illetve a
fejleszt�s k�lso
felt�teleitol f�gg, hogy melyik m�dszer vagy azok milyen p�ros�t�sa a legjobb.
�ltal�ban
a helyben kifejtett f�ggv�nyeket �s az egy�b, alapvetoen m�s sablon f�ggv�nyeket
h�v�
f�ggv�nyeket �rdemes minden olyan ford�t�si egys�gben elhelyezni, ahol
felhaszn�lj�k
azokat. Egy, a sablon-p�ld�nyos�t�s ter�n �tlagos t�mogat�st ny�jt�
szerkesztoprogram eset
�ben ez meggyors�tja a ford�t�st �s pontosabb hiba�zenetekhez vezet.
Ha a defin�ci�t be�p�tj�k, sebezhetov� tessz�k azt, mert �gy �rtelm�t a be�p�t�s
hely�n �rv
�nyes makr�k �s deklar�ci�k befoly�solhatj�k. Ez�rt a nagyobb vagy bonyolultabb
f�gg�-
seket ig�nylo sablonokat jobb k�l�n ford�ttatni, de akkor is ez az elj�r�s
k�vetendo, ha
a sablon definici�ja sok deklar�ci�t ig�nyel, mert ezek nem k�v�natos
mell�khat�sokkal j�rhatnak
a sablon felhaszn�l�s�nak hely�n.
�n azt tekintem ide�lis megold�snak, ha a sablondefin�ci�kat k�l�n ford�tjuk, a
felhaszn�-
l�i k�dban pedig csak deklar�ci�jukat szerepeltetj�k. Ezen elvek alkalmaz�s�t
azonban
mindig az adott helyzethez kell igaz�tanunk, a sablonok k�l�n ford�t�sa pedig
egyes nyelvi
v�ltozatok eset�ben k�lts�ges mulats�g lehet.
B�rmelyik megk�zel�t�st v�lasszuk is, a nem helyben kifejtett statikus tagoknak
(�C.13.1)
csak egyetlen definici�ja lehet, valamelyik ford�t�si egys�gben. Ebbol k�vetkezoen
ilyen tagokat
lehetoleg ne haszn�ljunk olyan sablonokn�l, amelyek sok ford�t�si egys�gben
szerepelnek.
Fontos c�l, hogy a k�d ugyan�gy muk�dj�k, ak�r egyetlen egys�gben szerepel, ak�r
k�l�n
ford�tott egys�gekbe elosztva. Ezt ink�bb �gy �rhetj�k el, hogy cs�kkentj�k a
defin�ci� f�gg
�s�t a k�rnyezet�tol, nem pedig �gy, hogy a k�rnyezetbol min�l t�bbet �tvisz�nk a
p�ld
�nyos�t�s folyamat�ba.
13.8. Tan�csok
[1] Olyan algoritmusok le�r�s�ra, amelyek sokf�le param�tert�pusra alkalmazhat�k,
sablont haszn�ljunk. �13.3.
[2] A t�rol�kat sablonk�nt k�sz�ts�k el. �13.2.
[3] A t�rol�kat specializ�ljuk mutat�t�pusokra, hogy cs�kkents�k a k�d m�ret�t.
�13.5.
[4] A specializ�ci� elott mindig adjuk meg a sablon �ltal�nos form�j�t. �13.5.
13. Sablonok 463
[5] A specializ�ci�t deklar�ljuk, mielott haszn�ln�nk. �13.5.
[6] A sablonok f�gg�s�t a p�ld�nyos�t�s m�dj�t�l cs�kkents�k a leheto legkisebbre.

�13.2.5, �C.13.8.
[7] Defini�ljunk minden deklar�lt specializ�ci�t. �13.5.
[8] Gondoljuk meg, hogy a sablonnak nincs-e sz�ks�ge C st�lus� karakterl�ncokra
�s t�mb�kre vonatkoz� specializ�ci�kra. �13.5.2.
[9] Param�terezz�nk elj�r�sm�d objektummal. �13.4.
[10] Specializ�ci� �s t�lterhel�s seg�ts�g�vel adjunk azonos fel�letet ugyanazon
fogalom
k�l�nb�zo t�pusokra vonatkoz� megval�s�t�s�nak. �13.5.
[11] Egyszeru esetekre vonatkoz�an egyszeru fel�letet adjunk; a ritk�bb eseteket
t�lterhel�ssel �s alap�rtelmezett param�ter-�rt�kekkel kezelj�k. �13.5, �13.4.
[12] Mielott sablonn� �ltal�nos�tan�nk valamit, v�gezz�nk hibakeres�st egy konkr�t

p�ld�n. �13.2.1.
[13] Ne felejts�k el kitenni az export kulcssz�t azokn�l a defin�ci�kn�l,
amelyeket
m�s ford�t�si egys�gbol is el kell �rni. �13.7.
[14] A nagy vagy nem mag�t�l �rtetodo k�rnyezeti f�ggos�gu sablonokat k�l�n
ford�t�si egys�gben helyezz�k el. �13.7.
[15] Konverzi�kat sablonokkal fejezz�nk ki, de ezeket nagyon �vatosan defini�ljuk.

�13.6.3.1.
[16] Sz�ks�g eset�n egy constraint() f�ggv�ny seg�ts�g�vel korl�tozzuk, milyen
param
�terei lehetnek a sablonnak. �13.9[16], �C.13.10.
[17] A ford�t�si �s �sszeszerkeszt�si idovel val� takar�koskod�s c�lj�b�l explicit
p�ld
�nyos�t�st haszn�ljunk. �C.13.10.
[18] Ha a fut�si ido d�nto szempont, �r�klod�s helyett haszn�ljunk sablonokat.
�13.6.1.
[19] Ha fontos szempont, hogy �j v�ltozatokat �jraford�t�s n�lk�l vezethess�nk be,

sablonok helyett haszn�ljunk �r�klod�st. �13.6.1.


[20] Ha nem lehet k�z�s b�zisoszt�lyt megadni, �r�klod�s helyett haszn�ljunk
sablonokat.
�13.6.1.
[21] Ha olyan be�p�tett t�pusokat �s adatszerkezeteket kell haszn�lnunk,
amelyeknek
a kor�bbi v�ltozatokkal �sszeegyeztethetonek kell maradniuk, �r�klod�s
helyett haszn�ljunk sablonokat. �13.6.1.
464 Absztrakci�s m�dszerek
13.9. Gyakorlatok
1. (*2) Jav�tsuk ki a hib�kat a List �13.2.5 pontbeli definici�j�ban �s �rjuk meg
a ford�t�program �ltal az f() f�ggv�ny �s a List sz�m�ra l�trehozott k�ddal
egyen�rt�ku k�dot. Futtassunk le egy egyszeru programot a saj�t, illetve a sablonb
�l l�trehozott v�ltozat ellenorz�s�re. Amennyiben m�dunk van r�, hasonl�tsuk
�ssze a k�tf�le k�dot.
2. (*3) �rjunk oszt�lysablont egy egyszeresen l�ncolt lista sz�m�ra, amely egy
Link
t�pusb�l sz�rmaztatott t�pus� elemeket tud t�rolni. A Link t�pus tartalmazza az
elemek �sszekapcsol�s�hoz sz�ks�ges inform�ci�kat. Az ilyen list�t .tolakod�.
(intrusive) list�nak nevezik. Ezen lista felhaszn�l�s�val �rjunk egy b�rmilyen t�-

pus� elemeket tartalmazni k�pes (azaz nem tolakod�) egyszeresen l�ncolt list�t.
Hasonl�tsuk �ssze a k�t lista hat�konys�g�t, elonyeiket �s h�tr�nyaikat.
3. (*2.5) �rjunk tolakod� �s nem tolakod� k�tszeresen l�ncolt list�kat. Milyen mu-

veletek sz�ks�gesek az egyszeresen l�ncolt lista muveletein fel�l?


4. (*2) Fejezz�k be a �13.2 pontbeli String sablont a �11.12 pontbeli String
oszt�ly
alapj�n.
5. (*2) Hat�rozzunk meg egy olyan sort()-ot, amely az �sszehasonl�t�si felt�telt
sablonparam�terk�nt veszi �t. Hat�rozzunk meg egy Record oszt�lyt, melynek
k�t tagja van, a count �s a price. Rendezz�nk egy set<Record> halmazt mindk�t
tag szerint.
6. (*2) K�sz�ts�nk egy qsort() sablont.
7. (*2) �rjunk egy programot, amely (key,value) p�rokat olvas be �s az egyes
kulcsokhoz
(key) tartoz� �rt�kek (value) �sszeg�t �rja ki. Adjuk meg, milyen t�pusok
lehetnek kulcsok, illetve �rt�kek.
8. (*2.5) A �11.8 pontbeli Assoc oszt�ly alapj�n k�sz�ts�nk egy egyszeru Map
oszt�lyt. A Map muk�dj�k helyesen kulcsk�nt haszn�lt C st�lus� karakterl�ncokkal
�s string-ekkel is, valamint akkor is, ha az alkalmazott t�pusnak van
alap�rtelmezett
konstruktora, �s akkor is, ha nincs.
9. (*3) Hasonl�tsuk �ssze a �11.8 pontbeli sz�sz�ml�l� program hat�konys�g�t egy
asszociat�v t�mb�t nem haszn�l� program�val. Azonos st�lus� be- �s kimeneti
muveleteket haszn�ljunk mindk�t esetben.
10. (*3) �rjuk �t a �13.9[8]-beli Map-et valamilyen alkalmasabb adatszerkezet .
p�ld
�ul v�r�s-fekete fa (red-black tree) vagy S-fa (splay tree) . felhaszn�l�s�val.
11. (*2.5) Haszn�ljuk fel a Map-et topologikus rendez�st megval�s�t� f�ggv�ny �r�-

s�ra. (A topologikus rendez�st a [Knuth,1987] elso k�tete �rja le, a 280. oldalt�l

kezdodoen.)
12. (*1.5) A �13.9[7]-beli �sszegzo programot jav�tsuk ki, hogy sz�k�z�ket is
tartalmaz
� nevekre is helyesen muk�dj�n.
13. Sablonok 465
13. (*2) �rjunk readline() sablonokat k�l�nf�le sorfajt�k sz�m�ra (p�ld�ul (cikk,
sz�m, �r)).
14. (*2) Haszn�ljuk a �13.4 pontbeli Literate-ben v�zolt m�dszert karakterl�ncok
ford�tott �b�c�sorrendu rendez�s�re. Gondoskodjunk r�la, hogy a m�dszer
olyan C++-v�ltozatokkal is muk�dj�n, ahol a char elojeles (signed), �s ott is,
ahol unsigned. Adjunk egy, a kis- �s nagybetuk k�z�tti k�l�nbs�get elhanyagol
� rendez�st t�mogat� v�ltozatot is.
15. (*1.5) Szerkessz�nk egy p�ld�t, amely legal�bb h�romf�le elt�r�st mutat be egy

f�ggv�nysablon �s egy makr� k�z�tt (a formai k�vetelm�nyek k�l�nbs�g�n


fel�l).
16. (*2) Tervezz�nk egy m�dszert, amellyel biztos�that�, hogy a ford�t�program
minden olyan sablon minden param�ter�re ellenorizzen bizonyos megszor�t�sokat,
amelyeknek megfelelo t�pus� objektum l�trej�n a programban. Csak .a T
param�ternek egy My_base-bol sz�rmaztatott oszt�lynak kell lennie. t�pus�
megszor�t�sok ellenorz�se nem el�g!
466 Absztrakci�s m�dszerek
Kiv�telkezel�s
.Ne sz�ljon k�zbe,
amikor �ppen k�zbesz�lok..
(Winston S. Churchill)
Hibakezel�s . A kiv�telek csoportos�t�sa . A kiv�telek elkap�sa . Minden kiv�tel
elkap�-
sa . Tov�bbdob�s . Az eroforr�sok kezel�se . auto_ptr . A kiv�telek �s a new
oper�-
tor . Az eroforr�sok kimer�l�se . Kiv�telek konstruktorokban . Kiv�telek
destruktorokban
. Olyan kiv�telek, amelyek nem hib�k . Kiv�telek specifik�ci�ja . V�ratlan kiv�-
telek . El nem kapott kiv�telek . A kiv�telek �s a hat�konys�g . A hibakezel�s
egy�b m�djai
. Szabv�nyos kiv�telek . Tan�csok . Gyakorlatok
14.1. Hibakezel�s
Ahogy a �8.3 pontban r�mutattunk, egy k�nyvt�r szerzoje felfedezheti a fut�si
ideju hib�-
kat, de �ltal�ban fogalma sincs r�la, mit kezdjen vel�k. A k�nyvt�r felhaszn�l�ja
tudhatja,
hogyan kell az ilyen hib�kat kezelni, de nem tudja felder�teni azokat .
m�sk�l�nben a felhaszn
�l�i k�dban kezeln� �s nem a k�nyvt�rnak kellene megtal�lnia oket. A kiv�telek
(exception) az ilyen probl�m�k kezel�s�t seg�tik. Az alap�tlet az, hogy ha egy
f�ggv�ny
olyan hib�t tal�l, amelyet nem tud kezelni, akkor egy kiv�telt v�lt ki (.kiv�telt
dob., throw)
14
abban a rem�nyben, hogy a (k�zvetett vagy k�zvetlen) h�v� k�pes kezelni a
probl�m�t.
Az adott probl�m�t kezelni tud� f�ggv�nyek jelezhetik, hogy el akarj�k kapni
(catch) a kiv
�telt (�2.4.2, �8.3).
A hibakezel�s ezen m�dja felveszi a versenyt a hagyom�nyosabb m�dszerekkel.
Tekints�k
�t a t�bbi lehetos�get: ha a program �szreveszi, hogy olyan probl�ma l�pett fel,
amelyet
nem lehet helyben megoldani, akkor
1. befejezheti a program fut�s�t,
2. egy .hiba. jelent�su �rt�ket adhat vissza,
3. egy norm�lis �rt�ket adhat vissza �s a programot .szab�lytalan. �llapotban
hagyhatja,
4. megh�vhat egy, .hiba. eset�n megh�vand� f�ggv�nyt.
Alap�rtelmez�s szerint az elso eset, azaz a program fut�s�nak befejez�se t�rt�nik,
ha olyan
kiv�tel l�p fel, amelyet nem kap el a program. A legt�bb hiba kezel�s�re enn�l
jobb megold
�s sz�ks�ges �s lehets�ges. Azok a k�nyvt�rak, amelyek nem ismerik a befoglal�
program
c�lj�t vagy annak �ltal�nos muk�d�s�t, nem hajthatnak v�gre egyszeruen egy
abort()-
ot vagy exit()-et. Olyan k�nyvt�rat, amely felt�tel n�lk�l befejezi a program
fut�s�t, nem
haszn�lhatunk olyan programban, amelynek nem szabad .elsz�llnia.. A kiv�telek
szerep�t
teh�t �gy is megfogalmazhatn�nk, hogy lehetos�get adnak arra, hogy a vez�rl�s
visszaker
�lj�n a h�v�hoz, ha a megfelelo muvelet helyben nem v�gezheto el.
A m�sodik eset (.hiba jelent�su �rt�k visszaad�sa.) nem mindig kivitelezheto, mert
nem
mindig l�tezik elfogadhat� .hib�t jelento �rt�k.. Ha egy f�ggv�ny p�ld�ul int
t�pussal t�r
vissza, akkor minden int �rt�k hiheto visszat�r�si �rt�k lehet. De ha alkalmazhat�
is ez
a m�dszer, sokszor akkor is k�nyelmetlen, mert minden h�v�st ellenorizni kell, ami
a program
m�ret�t ak�r k�tszeres�re is n�velheti (�14.8). Ez�rt azt�n ezt a m�dszert ritk�n
alkalmazz
�k annyira k�vetkezetesen, hogy minden hib�t �szleljenek vele.
A harmadik m�dszer (.norm�lis �rt�k visszaad�sa �s a program szab�lytalan
�llapotban val
� hagy�sa.) azzal a gonddal j�r, hogy a h�v� esetleg nem veszi �szre, hogy a
program nem
megengedett �llapotba ker�lt. A C standard k�nyvt�r�nak sz�mos f�ggv�nye p�ld�ul
az
errno glob�lis v�ltoz�t �ll�tja be, hogy hib�t jelezzen (�14.8), a programok
azonban jellemz
oen elmulasztj�k az errno v�ltoz� kelloen k�vetkezetes vizsg�lat�t, ami
megakad�lyozn�
a hib�s h�v�sok halmoz�d�s�t. Ezenk�v�l az egyideju hozz�f�r�sn�l (konkurrencia,
concurrency) a glob�lis v�ltoz�k hibajelz�sre val� haszn�lata nem muk�dik j�l.
468 Absztrakci�s m�dszerek
A kiv�telkezel�s nem az olyan esetek kezel�s�re szolg�l, mint amelyekre a
negyedik, a .hibakezel
o f�ggv�ny megh�v�sa. m�d alkalmas, kiv�telek h�j�n viszont a hibakezelo f�ggv
�nynek csak a t�bbi h�rom lehetos�ge van a hiba kezel�s�re. A hibakezelo
f�ggv�nyek �s
a kiv�telek t�m�j�t a �14.4.5 pont t�rgyalja.
A kiv�telkezel�st akkor c�lszeru haszn�lnunk a hagyom�nyos m�dszerek helyett, ha
azok
nem el�gs�gesek, nem .eleg�nsak. vagy hib�kat okozhatnak. A kiv�telek haszn�lata
lehet
ov� teszi a hibakezelo k�dnak a .k�z�ns�ges. k�dt�l val� elv�laszt�s�t, ez�ltal a
programot
olvashat�bb� �s a k�delemzo eszk�z�k sz�m�ra kezelhetobb� teszi. A kiv�telkezelo
elj�r�s szab�lyosabb hibakezel�st tesz lehetov� �s megk�nny�ti a k�l�n meg�rt
k�dr�szek
k�z�tti egy�ttmuk�d�st.
A C++ kiv�telkezel�s�nek a Pascal- �s C-programoz�k sz�m�ra �j von�sa, hogy a
hib�k
(k�l�n�sen a k�nyvt�rakban fell�pett hib�k) alap�rtelmezett kezel�se a program
le�ll�t�sa.
A hagyom�nyos kezel�s az volt, hogy valahogy �tevick�lt�nk a hib�n, azt�n
rem�nykedt
�nk. A kiv�telkezel�s t�r�kenyebb� teszi a programot abban az �rtelemben, hogy
t�bb
gondot �s figyelmet kell ford�tani arra, hogy a program elfogadhat�an fusson.
Mindazon�ltal
ez elony�sebbnek tunik, mintha k�sobb a fejleszt�s sor�n l�pn�nek fel hib�s
eredm�-
nyek, vagy ak�r a fejleszt�s lez�rulta ut�n, amikor a program m�r a mit sem sejto
felhaszn�-
l�k kez�ben van. Ha a le�ll�s az adott programn�l elfogadhatatlan, akkor el lehet
kapni az
�sszes kiv�telt (�14.3.2) vagy az �sszes adott fajt�j�t (�14.6.2), �gy a kiv�tel
csak akkor �ll�tja
le a programot, ha a programoz� ezt hagyja. Ez pedig jobb, mint ha a hiba
hagyom�nyos
m�don t�rt�nt .nem teljes. kezel�s�t k�vetoen v�gzetes hiba, majd felt�tel n�lk�li
le�ll�s
t�rt�nne.
Egyesek a hib�kon val� .�tevick�l�s. nem vonz� tulajdons�gait hiba�zenetek
ki�rat�s�val,
a felhaszn�l� seg�ts�g�t k�ro ablakokkal stb. pr�b�lt�k enyh�teni. Az ilyesmi
foleg a program
hibakeres�s�n�l (debugging, .a program bel�v�se.) hasznos, amikor a felhaszn�l�
a program szerkezet�t ismero programoz�. Nem fejlesztok sz�m�ra az esetleg jelen
sem lev
o felhaszn�l�/kezelo seg�ts�g�t k�ro k�nyvt�r elfogadhatatlan. Ezenk�v�l sokszor
nincs is
hov� �rtes�t�st k�ldeni a hib�r�l (p�ld�ul ha a program olyan k�rnyezetben fut,
ahol a cerr
nem vezet a felhaszn�l� �ltal el�rheto helyre), �s a hiba�zenetek a v�gfelhaszn�l�
sz�m�ra
�gysem mondan�nak semmit. Az a legkevesebb, hogy a hiba�zenet esetleg nem is a
megfelel
o nyelven jelenne meg, mondjuk finn�l egy angol felhaszn�l� sz�m�ra. Enn�l
rosszabb,
hogy a hiba�zenet jellemzoen a k�nyvt�r fogalmaival lenne megfogalmazva, mondjuk
egy
grafikus felhaszn�l�i fel�letrol �rkezett rossz adat hat�s�ra .bad argument to
atan2.. Egy j�
k�nyvt�r nem .halandzs�zik. �gy. A kiv�telek lehetov� teszik az adott k�dr�szlet
sz�m�ra,
hogy a hib�t, amit nem tud kezelni, a k�d olyan r�sze sz�m�ra tov�bb�tsa, amely
tal�n boldogul
vele. A programnak csak olyan r�sze lehet k�pes �rtelmes hiba�zenet k�ld�s�re,
amelynek van fogalma a program �sszef�gg�seirol, k�rnyezet�rol.
14. Kiv�telkezel�s 469
A kiv�telkezel�sre �gy is tekinthet�nk, mint a ford�t�si ideju t�pusellenorz�s �s
t�bb�rtelm
us�g-kiszur�s fut�si ideju megfeleloj�re. A tervez�si folyamatra nagyobb hangs�lyt
helyez
�s megn�velheti egy kezdeti (m�g hib�s) v�ltozat elo�ll�t�s�hoz sz�ks�ges munka
mennyis
�g�t. �m az eredm�ny egy olyan k�d, amelynek sokkal nagyobb az es�lye arra, hogy
az
elv�rt m�don fusson, hogy egy nagyobb program r�sze lehessen, hogy m�s programoz�k

sz�m�ra is �rtheto legyen, hogy eszk�z�kkel lehessen kezelni. Ennek megfeleloen a


kiv�-
telek nyelvileg t�mogatott kezel�se kifejezetten t�mogatja a .j� st�lus�.
programoz�st, mint
ahogy a C++ nyelv m�s eszk�zei t�mogatj�k azt. M�s nyelveken (C vagy Pascal) a j�
st�lus
csak egyes szab�lyok .megker�l�s�vel. �s nem is t�k�letesen �rheto el.
Meg kell azonban jegyezn�nk, hogy a hibakezel�s ezut�n is neh�z feladat marad �s a
kiv�-
telkezelo elj�r�s . j�llehet rendszerezettebb, mint azok a m�dszerek, amelyeket
helyettes
�t . a vez�rl�st kiz�r�lag helyben szab�lyoz� nyelvi elemekhez k�pest kev�sb�
hat�kony.
A C++ nyelv kiv�telkezel�se a programoz�nak a hib�k azon helyen val� kezel�s�re ad
lehet
os�get, ahol ez a rendszer szerkezet�bol ad�d�an a legterm�szetesebb. A kiv�telek
nyilv
�nval�v� teszik a hibakezel�s bonyolults�g�t, de vigy�zzunk, hogy a rossz h�r�rt
ne annak
hoz�j�t hib�ztassuk. Ezen a ponton c�lszeru �jraolvasni a �8.3 pontot, amely a
kiv�telkezel
�s alapveto von�sait mutatja be.
14.1.1. A kiv�telek m�s megk�zel�t�sei
A .kiv�tel. (exception) azon szavak egyike, amelyek k�l�nb�zo emberek sz�m�ra
k�l�nb
�zo jelent�ssel b�rnak. A C++ nyelv kiv�telkezelo rendszer�t �gy tervezt�k, hogy
hib�k �s
m�s kiv�teles jelens�gek kezel�s�t t�mogassa . innen a neve . �s hogy t�mogassa a
hib�k
kezel�s�t f�ggetlen�l fejlesztett �sszetevokbol �ll� programokban.
A kiv�telkezel�s csak a szinkron kiv�telek, p�ld�ul a t�mbindex-hib�k vagy ki- �s
bemeneti
hib�k kezel�s�re szolg�l. Az aszinkron esem�nyek, mint a billentyuzet felol �rkezo
megszak
�t�sok vagy bizonyos aritmetikai hib�k nem felt�tlen�l kiv�telek �s nem
k�zvetlen�l
ezzel az elj�r�ssal kezelendok. Az aszinkron esem�nyek vil�gos �s hat�kony
kezel�s�hez
a kiv�telkezel�s itt le�rt m�dj�t�l alapvetoen k�l�nb�zo elj�r�sokra van sz�ks�g.
Sok rendszernek
vannak az aszinkronit�s kezel�s�re szolg�l� elj�r�sai (p�ld�ul szign�lok
(jelz�sek,
signal) haszn�lata), de mivel ezek rendszerf�ggoek szoktak lenni, le�r�suk itt nem
szerepel.
A kiv�telkezel�s egy nem lok�lis, a (v�grehajt�si) verem .visszateker�s�n. (stack
unwinding, �14.4) alapul� vez�rl�si szerkezet, amelyet alternat�v visszat�r�si
elj�r�sk�nt is
tekinthet�nk. Ez�rt kiv�teleket olyan esetekben is szab�lyosan alkalmazhatunk,
amelyeknek
semmi k�z�k a hib�khoz (�14.5). A kiv�telkezel�snek azonban a hibakezel�s �s a
hibat
uro viselked�s t�mogat�sa az elsodleges c�lja �s ez a fejezet is ezekre
�sszpontos�t.
470 Absztrakci�s m�dszerek
A szabv�nyos C++ nem ismeri a v�grehajt�si sz�l (thread) �s a folyamat (process,
processz)
fogalm�t, ez�rt az egyideju hozz�f�r�ssel �sszef�ggo kiv�teles helyzeteket itt nem
t�rgyaljuk.
A haszn�lt rendszer dokument�ci�ja le�rja az ezeket kezelo eszk�z�ket; itt csak
azt
jegyzem meg, hogy a C++ nyelv kiv�telkezelo rendszer�t �gy tervezt�k, hogy
konkurens
programban is hat�kony legyen, felt�ve, hogy a programoz� vagy a rendszer betart
bizonyos
alapveto szab�lyokat, p�ld�ul azt, hogy szab�lyosan z�rolja (lock) a megosztott
adatszerkezeteket
a haszn�lat elott.
A C++ kiv�telkezelo elj�r�sainak a hib�k �s kiv�teles esem�nyek jelent�se �s
kezel�se a c�ljuk,
de a programoz�nak kell eld�ntenie, hogy egy adott programban mi sz�m�t
kiv�telesnek.
Ez nem mindig k�nnyu (�14.5). Tekints�nk-e kiv�telesnek egy olyan esem�nyt, amely
a program legt�bb fut�sakor fell�p? Lehet-e egy tervezett �s kezelt esem�ny hiba?
Mindk�t
k�rd�sre igen a v�lasz. A .kiv�teles. nem azt jelenti, hogy .szinte soha nem
t�rt�nhet meg.
vagy hogy .v�gzetes.. Jobb �gy �rtelmezni a kiv�telt, hogy .a rendszer valamely
r�sze nem
tudta megtenni, amire k�rt�k.. Szok�s szerint ilyenkor valami m�ssal pr�b�lkozunk.
Kiv�-
telek kiv�lt�sa (.dob�sa.) a f�ggv�nyh�v�sokhoz k�pest ritk�n forduljon elo,
k�l�nben
a rendszer szerkezete �ttekinthetetlen lesz. A legt�bb nagy program norm�lis �s
sikeres futtat
�sa sor�n azonban n�h�ny kiv�tel kiv�lt�sa �s elkap�sa biztosan elo fog fordulni.
14.2. A kiv�telek csoportos�t�sa
A kiv�tel olyan objektum, melynek oszt�lya valamilyen kiv�tel elofordul�s�t �rja
le. A hib�t
�szlelo k�d (�ltal�ban egy k�nyvt�r) .eldobja. (throw) az objektumot (�8.3). A
hib�t kezelni
k�pes k�dr�szlet beavatkoz�si sz�nd�k�t egy .elkap�. (catch) z�rad�kkal jelzi. A
kiv�tel
.eldob�sa. .visszatekeri. a v�grehajt�si vermet, eg�szen addig, am�g egy megfelelo
(vagyis
a kiv�telt kiv�lt� f�ggv�nyt k�zvetve vagy k�zvetlen�l megh�v�) f�ggv�nyben catch-
et
nem tal�lunk.
A kiv�telek gyakran term�szetes m�don csal�dokra oszthat�k. Ebbol k�vetkezoleg a
kiv�-
telek csoportos�t�s�hoz �s kezel�s�hez az �r�klod�s hasznos seg�ts�get ny�jthat.
Egy matematikai
k�nyvt�r kiv�teleit p�ld�ul �gy csoportos�thatjuk:
class Matherr { };
class Overflow: public Matherr { };
class Underflow: public Matherr { };
class Zerodivide: public Matherr { };
// ...
14. Kiv�telkezel�s 471
Ez a szerkezet lehetov� teszi, hogy a pontos t�pusra val� tekintet n�lk�l
kezelj�nk b�rmilyen
Matherr-t:
void f()
{
try {
// ...
}
catch (Overflow) {
// az Overflow (t�lcsordul�s) vagy m�s onnan sz�rmaz� hiba kezel�se
}
catch (Matherr) {
// nem Overflow matematikai (Matherr) hib�k kezel�se
}
}
Itt az Overflow-t k�l�n kezelt�k. Az �sszes t�bbi Matherr kiv�telt az �ltal�nos
z�rad�k fogja
kezelni. A kiv�teleknek hierarchi�ba val� szervez�se fontos lehet a k�d t�m�rs�ge
c�lj�-
b�l. Gondoljuk meg p�ld�ul, hogyan lehetne a matematikai k�nyvt�r �sszes kiv�tel�t

kezelni, ha nem voln�nak csoportos�tva. Az �sszes kiv�telt fel kellene sorolni:


void g()
{
try {
// ...
}
catch (Overflow) { /* ... */ }
catch (Underflow) { /* ... */ }
catch (Zerodivide) { /* ... */ }
}
Ez nemcsak f�raszt�, de egy kiv�tel k�nnyen ki is maradhat. Gondoljuk meg, mi
lenne, ha
nem csoportos�tan�nk a matematikai kiv�teleket. Ha a matematikai k�nyvt�r egy �j
kiv�tellel
bov�lne, minden, az �sszes kiv�telt kezelni k�v�n� k�dr�szletet m�dos�tani
kellene. �ltal
�ban a k�nyvt�r elso v�ltozat�nak kibocs�t�sa ut�n ilyen teljes k�ru m�dos�t�sokra
nincs
m�d. De ha van is, nem biztos, hogy minden k�d a rendelkez�s�nkre �ll, vagy ha
igen, nem
biztos, hogy t�nyleg hajland�ak vagyunk �tdolgozni. Ezek az �jraford�t�si �s
m�dos�that�-
s�gi szempontok ahhoz az ir�nyelvhez vezetn�nek, hogy az elso v�ltozat kibocs�t�sa
ut�n
a k�nyvt�r nem bov�lhetne tov�bbi kiv�telekkel; ez pedig a legt�bb k�nyvt�r
sz�m�ra elfogadhatatlan.
Ez�rt teh�t a kiv�teleket c�lszeru k�nyvt�rank�nti vagy alrendszerenk�nti
csoportokban megadni (�14.6.2).
472 Absztrakci�s m�dszerek
Jegyezz�k meg, hogy sem a be�p�tett matematikai muveletek, sem a (C-vel k�z�s)
alapvet
o matematikai k�nyvt�r nem kiv�telek form�j�ban jelzik az aritmetikai hib�kat.
Ennek
egyik oka, hogy sz�mos utas�t�scs�vet alkalmaz� (pipelined) rendszer aszinkron
m�don
�szlel bizonyos aritmetikai hib�kat, p�ld�ul a null�val val� oszt�st. A Matherr
hierarchia
ez�rt itt csak illusztr�ci�ul szolg�l. A standard k�nyvt�rbeli kiv�teleket a
�14.10 �rja le.
14.2.1. Sz�rmaztatott kiv�telek
Az oszt�lyhierarchi�k kiv�telkezel�sre val� haszn�lata term�szetesen vezet olyan
kiv�telkezel
okh�z, amelyeket a kiv�telek hordozta inform�ci�nak csak egy r�sze �rdekel. Vagyis
egy
kiv�telt �ltal�ban egy b�zisoszt�ly�nak a kezeloje kap el, nem saj�t oszt�ly�nak
kezeloje.
A kiv�tel elkap�s�nak �s megnevez�s�nek muk�d�se a param�teres f�ggv�nyek�vel
azonos.
Vagyis a form�lis param�ter a param�ter-�rt�kkel kap kezdo�rt�ket (�7.2). Ebbol
k�-
vetkezik, hogy a kiv�telnek csak az elkapott oszt�lynak megfelelo r�sze m�sol�dik
le (felszeletel
od�s, slicing, �12.2.3):
class Matherr {
// ...
virtual void debug_print() const { cerr << "Matematikai hiba"; }
};
class Int_overflow: public Matherr {
const char* op;
int a1, a2;
public:
Int_overflow(const char* p, int a, int b) { op = p; a1 = a; a2 = b; }
virtual void debug_print() const { cerr << op << '(' << a1 << ',' << a2 << ')'; }
// ...
};
void f()
{
try {
g();
}
catch (Matherr m) {
// ...
}
}
A Matherr kezelobe val� bel�p�skor az m egy Matherr objektum, m�g ha g() egy
Int_overflow-t v�ltott is ki. K�vetkez�sk�ppen az Int_overflow-ban levo t�bblet
inform�ci�
el�rhetetlen.
14. Kiv�telkezel�s 473
Mint mindig, mutat�k vagy referenci�k haszn�lat�val megakad�lyozhatjuk az
inform�ci�-
veszt�st:
int add(int x, int y)
{
if ((x>0 && y>0 && x>INT_MAX-y) || (x<0 && y<0 && x<INT_MIN-y))
throw Int_overflow("+",x,y);
return x+y; // x+y nem fog t�lcsordulni
}
void f()
{
try {
int i1 = add(1,2);
int i2 = add(INT_MAX,-2);
int i3 = add(INT_MAX,2); // ez az!
}
catch (Matherr& m) {
// ...
m.debug_print();
}
}
Az utols� add() h�v�s kiv�ltotta kiv�tel hat�s�ra Int_overflow::debug_print() fog
v�grehajt
�dni. Ha a kiv�telt �rt�k �s nem referencia szerint kaptuk volna el, akkor
ehelyett
Matherr::debug_print()-re ker�lt volna sor.
14.2.2. �sszetett kiv�telek
Nem minden kiv�telcsoport fa szerkezetu. Egy kiv�tel gyakran k�t csoportba is
tartozik:
class Netfile_err : public Network_err, public File_system_err { /* ... */ };
Egy ilyen Netfile_err -t el lehet kapni a h�l�zati kiv�telekkel t�rodo
f�ggv�nyekben:
void f()
{
try {
// valami
}
catch(Network_err& e) {
// ...
}
}
474 Absztrakci�s m�dszerek
De ak�r a f�jlrendszer-kiv�telekkel foglalkoz� f�ggv�nyekben is:
void g()
{
try {
// valami m�s
}
catch(File_system_err& e) {
// ...
}
}
A hibakezel�s ilyen nem hierarchikus szervez�se akkor fontos, amikor a
szolg�ltat�sok
(p�ld�ul a h�l�zati szolg�ltat�sok) a felhaszn�l� sz�m�ra l�thatatlanok. Ebben a
p�ld�ban
a g() �r�ja esetleg nem is tudott arr�l, hogy h�l�zat is szerepet j�tszik (l�sd
m�g �14.6).
14.3. A kiv�telek elkap�sa
Vegy�k az al�bbi k�dr�szletet:
void f()
{
try {
throw E();
}
catch(H) {
// mikor jutunk ide?
}
}
A vez�rl�s akkor ker�l a kezeloh�z, ha
1. H ugyanaz a t�pus, mint E,
2. H egy�rtelmu b�zisoszt�lya E-nek,
3. H �s E mutat�t�pusok �s a mutatott t�pusokra teljes�l 1. vagy 2.,
4. H referencia �s t�pus�ra teljes�l 1. vagy 2.
14. Kiv�telkezel�s 475
Ezenk�v�l egy kiv�tel elkap�s�n�l ugyan�gy alkalmazhatjuk a const minos�tot, mint
egy
f�ggv�ny param�ter�n�l. Ettol az elkaphat� kiv�telek t�pusa nem v�ltozik meg, csak
megakad
�lyozza, hogy az elkapott kiv�telt m�dos�thassuk.
Az az elv, hogy a kiv�telrol kiv�lt�sakor m�solat k�sz�l, a kezelo pedig az
eredeti kiv�tel
m�solat�t kapja meg. Lehets�ges, hogy egy kiv�telrol elkap�sa elott t�bb m�solat
is k�sz�l,
ez�rt nem lehet olyan kiv�telt kiv�ltani, ami nem m�solhat�. Az adott nyelvi
v�ltozat nagyon
sokf�le m�dszert alkalmazhat a kiv�telek t�rol�s�ra �s tov�bb�t�s�ra, de az
biztos�tott,
hogy a mem�ria elfogy�sakor szabv�nyos m�don kiv�ltand� kiv�tel, a bad_alloc
(�14.4.5)
sz�m�ra van hely.
14.3.1. A kiv�telek tov�bbdob�sa
Gyakran elofordul, hogy miut�n egy kezelo elkapott egy kiv�telt, �gy d�nt, hogy
nem tudja
teljes eg�sz�ben kezelni azt. Ilyenkor a kezelo �ltal�ban megteszi helyben, amit
lehet, majd
tov�bbdobja a kiv�telt. �gy a hib�t v�g�l is a legalkalmasabb helyen lehet
kezelni. Ez akkor
is igaz, ha a kiv�tel kezel�s�hez sz�ks�ges inform�ci� nem egyetlen helyen �ll
rendelkez�sre
�s a hiba k�vetkezm�nyeit legjobban t�bb kezelo k�z�tt elosztva k�sz�b�lhetj�k ki:

void h()
{
try {
// esetleg matematikai hib�kat kiv�lt� k�d
}
catch (Matherr) {
if (teljesen_le_tudjuk_kezelni) {
// Matherr kezel�se
return;
}
else {
// megtessz�k, amit lehet
throw; // a kiv�tel tov�bbdob�sa
}
}
}
A kiv�tel tov�bbdob�s�t az operandus n�lk�li throw jelzi. Ha akkor pr�b�lunk meg
kiv�telt
tov�bbdobni, ha nincs is kiv�tel, terminate() h�v�s fog bek�vetkezni (�14.7). A
ford�t�program
az ilyen esetek egy r�sz�t . de nem mindet . felder�theti �s figyelmeztethet
r�juk.
476 Absztrakci�s m�dszerek
A tov�bbdob�s az eredeti kiv�telre vonatkozik, nem csak annak elkapott r�sz�re,
ami
Matherr-k�nt rendelkez�sre �ll. M�s sz�val, ha a program Int_overflow-t v�ltott
ki, amelyet
h() egy Matherr-k�nt kapott el �s �gy d�nt�tt, hogy tov�bbdobja, akkor a h()
h�v�ja is
Int_overflow-t kap.
14.3.2. Minden kiv�tel elkap�sa
Az elkap�si �s tov�bbdob�si m�dszer egy v�gletes eset�vel is �rdemes
megismerkedn�nk.
Mint ahogy f�ggv�nyekre a ... tetszoleges param�tert jelent (�7.6), a catch(...)
jelent�se is
a tetszoleges kiv�tel elkap�sa:
void m()
{
try {
// valami
}
catch (...) { // minden kiv�telt elkapunk
// takar�t�s
throw;
}
}
�gy ha m() fo r�sz�nek v�grehajt�sa sor�n b�rmilyen kiv�tel l�p fel, sor ker�l a
kezelo f�ggv
�ny rendrak� tev�kenys�g�re. Amint a helyi rendrak�s megt�rt�nt, az arra okot ad�
kiv�-
tel tov�bbdob�dik a tov�bbi hibakezel�s kiv�lt�sa c�lj�b�l. A �14.6.3.2 pont �r
arr�l, hogyan
lehet inform�ci�hoz jutni a ... kezelo �ltal elkapott kiv�telrol.
A hibakezel�snek �ltal�ban (a kiv�telkezel�snek pedig k�l�n�sen) fontos szempontja

a program �ltal felt�telezett �llapot �rv�nyess�g�nek megorz�se (invari�ns,


�24.3.7.1). P�ld
�ul ha m() bizonyos mutat�kat olyan �llapotban hagy h�tra, ahogy azokat tal�lta,
akkor
a kiv�telkezelobe be�rhatjuk a nekik elfogadhat� �rt�ket ad� k�dot. �gy a .minden
kiv�telt
elkap�. kezelo tetszoleges invari�nsok kezel�s�re alkalmas hely lehet. Sok fontos
esetben
azonban egy ilyen kiv�telkezelo nem a legeleg�nsabb megold�s (l�sd �14.4).
14. Kiv�telkezel�s 477
14.3.2.1. A kezelok sorrendje
Mivel egy sz�rmaztatott oszt�ly� kiv�telt t�bb t�pus� kiv�tel kezeloje is
elkaphat, a try utas�-
t�sban a kezelok sorrendje l�nyeges. A kezelok kipr�b�l�s�ra ebben a sorrendben
ker�l sor:
void f()
{
try {
// ...
}
catch (std::ios_base::failure) {
// i/o adatfolyam hib�k kezel�se (�14.10)
}
catch (std::exception& e) {
// standard k�nyvt�rbeli kiv�telek kezel�se (�14.10)
}
catch (...) {
// egy�b kiv�telek kezel�se (�14.3.2)
}
}
Mivel a ford�t�program ismeri az oszt�lyhierarchi�t, sok logikai hib�t kiszurhet:
void g()
{
try {
// ...
}
catch (...) {
// minden kiv�tel kezel�se (�14.3.2)
}
catch (std::exception& e) {
// standard k�nyvt�rbeli kiv�telek kezel�se (�14.10)
}
catch (std::bad_cast) {
// dynamic_cast hib�k kezel�se (�15.4.2)
}
}
Itt az exception soha nem jut szerephez. M�g ha el is t�vol�tjuk a mindent elkap�
kezelot,
a bad_cast akkor sem ker�l sz�ba, mert az exception lesz�rmazottja.
478 Absztrakci�s m�dszerek
14.4. Eroforr�sok kezel�se
Amikor egy f�ggv�ny lefoglal valamilyen eroforr�st . p�ld�ul megnyit egy f�jlt,
lefoglal valamennyi
mem�ri�t a szabad t�rban, z�rol valamit stb. ., gyakran fontos felt�tel a rendszer

tov�bbi muk�d�se szempontj�b�l, hogy az eroforr�st rendben fel is szabad�tsa a


h�v�hoz
val� visszat�r�s elott:
void use_file(const char* fn)
{
FILE* f = fopen(fn,"r");
// f haszn�lata
fclose(f);
}
Ez muk�dok�pesnek tunik, am�g �szre nem vessz�k, hogy ha valami hiba t�rt�nik az
fopen() megh�v�sa ut�n, de az fclose() megh�v�sa elott, akkor egy kiv�tel miatt a
use_file()
f�ggv�ny az fclose() v�grehajt�sa n�lk�l t�rhet vissza. Ugyanez a probl�ma
kiv�telkezel�st
nem t�mogat� nyelvek eset�ben is fell�phet. P�ld�ul a C standard k�nyvt�r�nak
longjmp()
f�ggv�nye ugyanilyen probl�m�t okozhat. M�g egy k�z�ns�ges return utas�t�s miatt
is
visszat�rhet a use_file() az fclose() v�grehajt�sa n�lk�l.
Egy elso k�s�rlet a use_file() hibaturov� t�tel�re �gy n�zhet ki:
void use_file(const char* fn)
{
FILE* f = fopen(fn,"r");
try {
// f haszn�lata
}
catch (...) {
fclose(f);
throw;
}
fclose(f);
}
A f�jlt haszn�l� k�d egy try blokkban van, amely minden hib�t elkap, bez�rja a
f�jlt, majd
tov�bbdobja a kiv�telt.
14. Kiv�telkezel�s 479
Ezzel a megold�ssal az a gond, hogy feleslegesen hossz�, f�rads�gos �s esetleg
lass� is
lehet. R�ad�sul minden t�l hossz� �s f�rads�gos megold�s nyom�ban ott j�rnak a
hib�k, hiszen
a programoz�k elf�radnak. Szerencs�re van jobb megold�s. A megoldand� helyzet
�ltal�nos form�j�ban �gy n�z ki:
void acquire()
{
// elso eroforr�s lek�t�se
// ...
// n-edik eroforr�s lek�t�se
// eroforr�sok felhaszn�l�sa
// n-edik eroforr�s felszabad�t�sa
// ...
// elso eroforr�s felszabad�t�sa
}
�ltal�ban fontos szempont, hogy az eroforr�sokat megszerz�s�kkel ellent�tes
sorrendben
szabad�tsuk fel. Ez eroteljesen eml�keztet a konstruktorok �ltal fel�p�tett �s
destruktorok �ltal
megsemmis�tett helyi objektumok viselked�s�re. �gy azt�n az ilyen eroforr�s-
lefoglal�si
�s -felszabad�t�si probl�m�kat konstruktorokkal �s destruktorokkal b�r� oszt�lyok
objektumainak
haszn�lat�val kezelhetj�k. P�ld�ul megadhatjuk a File_ptr oszt�lyt, amely egy
FILE*-hoz hasonl�an viselkedik:
class File_ptr {
FILE* p;
public:
File_ptr(const char* n, const char* a) { p = fopen(n,a); }
File_ptr(FILE* pp) { p = pp; }
~File_ptr() { fclose(p); }
operator FILE*() { return p; }
};
Egy File_ptr objektumot vagy egy FILE* mutat�val, vagy az fopen()-hez sz�ks�ges
param�-
terekkel hozhatunk l�tre; b�rmelyik esetben �lettartama v�g�n a File_ptr objektum
megsemmis
�l, destruktora pedig bez�rja a f�jlt. Programunk m�rete �gy minim�lisra cs�kken:
void use_file(const char* fn)
{
File_ptr f(fn,"r");
// f haszn�lata
}
480 Absztrakci�s m�dszerek
A destruktor att�l f�ggetlen�l megh�v�dik, hogy a f�ggv�nybol .norm�lisan. vagy
kiv�tel
kiv�lt�sa folyt�n l�pt�nk-e ki. �gy a kiv�telkezelo elj�r�s lehetov� teszi, hogy a
hibakezel�st
elt�vol�tsuk a fo algoritmusb�l. Az �gy ad�d� k�d egyszerubb �s kevesebb hib�t
okoz, mint
hagyom�nyos megfeleloje.
Azt a muveletet, amikor a kiv�telek kezel�sekor a h�v�si l�ncban megkeress�k a
megfelelo
kezelot, rendszerint a .verem visszateker�s�nek. h�vj�k. Ahogy a vermet
.visszatekerik.,
�gy h�vj�k meg a l�trehozott lok�lis objektumok destruktorait.
14.4.1. Konstruktorok �s destruktorok haszn�lata
Az eroforr�sok lok�lis objektumok haszn�lat�val val� kezel�s�t szok�s szerint �gy
h�vj�k,
hogy .kezdeti �rt�kad�s az eroforr�s megszerz�s�vel. (resource acquisition is
initialization).
Ez az �ltal�nos elj�r�s a konstruktorok �s destruktorok tulajdons�gain, valamint a
kiv�telkezel
o rendszerrel val� egy�ttmuk�d�s�k�n alapul.
Egy objektumot addig nem tekint�nk l�tezonek, am�g konstruktora le nem fut.
Destruktora
csak ebben az esetben fog a verem visszateker�sekor megh�v�dni. Egy
r�szobjektumokb�l
�ll� objektumot olyan m�rt�kben tekint�nk l�trehozottnak, amilyen m�rt�kben
r�szobjektumainak
konstruktorai lefutottak, egy t�mb�t pedig addig az elem�ig, amelynek konstruktora

m�r lefutott. A destruktor a verem visszateker�sekor csak a teljes eg�sz�ben


l�trehozott
elemekre fut le.
A konstruktor azt pr�b�lja el�rni, hogy az objektum teljesen �s szab�lyosan
l�trej�jj�n. Ha
ez nem �rheto el, egy j�l meg�rt konstruktor . amennyire csak lehets�ges . olyan
�llapotban
hagyja a rendszert, mint megh�v�sa elott volt. Ide�lis esetben a .na�v m�don.
meg�rt
konstruktorok teljes�tik ezt �s nem hagyj�k az objektumot valamilyen .f�lig
l�trehozott. �llapotban.
Ezt a .kezdeti �rt�kad�s az eroforr�s megszerz�s�vel. m�dszernek a tagokra val
� alkalmaz�s�val �rhetj�k el.
Vegy�nk egy X oszt�lyt, amelynek konstruktora k�t eroforr�st ig�nyel: egy x
�llom�nyt �s
egy y z�rol�st. Ezek megszerz�se nem biztos, hogy siker�l, �s kiv�telt v�lthat ki.
Az X oszt
�ly konstruktor�nak semmilyen k�r�lm�nyek k�z�tt nem szabad �gy visszat�rnie, hogy
az
�llom�nyt lefoglalta, de a z�rat nem. Ezenk�v�l ezt an�lk�l kell el�rni, hogy a
dolog bonyolults
�g�val a programoz�nak t�rodnie kelljen. A megszerzett eroforr�sok �br�zol�s�ra
k�t
oszt�lyt haszn�lunk, a File_ptr-t �s a Lock_ptr-t. Az adott eroforr�s megszerz�s�t
az azt jel�-
lo lok�lis objektum kezdeti �rt�kad�sa �br�zolja:
14. Kiv�telkezel�s 481
class X {
File_ptr aa;
Lock_ptr bb;
public:
X(const char* x, const char* y)
: aa(x,"rw"), // 'x' lefoglal�sa
bb(y) // 'y' lefoglal�sa
{ }
// ...
};
Csak�gy mint a lok�lis objektumos p�ld�ban, itt is az adott ford�t� dolga a
sz�ks�ges nyilv
�ntart�sok vezet�se. A felhaszn�l�nak nem kell ezzel t�rodnie. P�ld�ul ha az aa
l�trehoz
�sa ut�n, de a bb-� elott kiv�tel v�lt�dik ki, akkor az aa destruktor�nak
megh�v�s�ra sor
ker�l, de a bb-�re nem.
Ebbol k�vetkezoleg ahol az eroforr�sok megszerz�se ezen egyszeru modell szerint
t�rt�-
nik, ott a konstruktor �r�j�nak nem kell kifejezett kiv�telkezelo k�dot �rnia.
Az alkalmi m�don kezelt eroforr�sok k�z�tt a leggyakoribb a mem�ria:
class Y {
int* p;
void init();
public:
Y(int s) { p = new int[s]; init(); }
~Y() { delete[ ] p; }
// ...
};
A fenti m�dszer haszn�lata �ltal�nos gyakorlat . �s a .mem�ria elsziv�rg�s�hoz.
(memory
leak) vezethet. Ha az init()-ben kiv�tel keletkezik, a lefoglalt mem�ria nem fog
felszabadulni,
mivel az objektum nem j�tt l�tre teljesen, �gy destruktora nem fut le. �me egy
biztons�-
gos v�ltozat:
class Z {
vector<int> p;
void init();
public:
Z(int s) : p(s) { init(); }
// ...
};
482 Absztrakci�s m�dszerek
A p �ltal haszn�lt mem�ri�t a vector kezeli. Ha az init() kiv�telt v�lt ki, a
lefoglalt mem�ri-
�t p (automatikusan megh�vott) destruktora fogja felszabad�tani.
14.4.2. Auto_ptr
A standard k�nyvt�r auto_ptr sablon oszt�lya t�mogatja a .kezdeti �rt�kad�s az
eroforr�s
megszerz�s�vel. m�dszert. Egy auto_ptr-nek alapvetoen egy mutat�val adhatunk
kezdo�rt
�ket �s ugyan�gy hivatkozhatunk a mutatott objektumra, mint egy hagyom�nyos
mutat�-
n�l. Ezenk�v�l amikor az auto_ptr megsemmis�l, az �ltala mutatott objektum is
automatikusan
t�rlodik:
void f(Point p1, Point p2, auto_ptr<Circle> pc, Shape* pb) // kil�p�skor ne
felejts�k
// el t�r�lni pb-t
{
auto_ptr<Shape> p(new Rectangle(p1,p2)); // p t�glalapra mutat
auto_ptr<Shape> pbox(pb);
p->rotate(45); // az auto_ptr<Shape> pont �gy haszn�lhat�, mint a Shape*
// ...
if (in_a_mess) throw Mess();
// ...
}
Itt a Rectangle, a pb �ltal mutatott Shape �s a pc �ltal mutatott Circle egyar�nt
t�rlodni fog,
ak�r v�lt�dott ki kiv�tel, ak�r nem.
Ezen tulajdonos szerinti kezel�s (vagy destrukt�v m�sol�s) t�mogat�sa c�lj�b�l az
auto_ptreknek
a k�z�ns�ges mutat�kt�l gy�keresen elt�ro m�sol�si m�dszer�k van: egy auto_ptrnek
egy m�sikba val� m�sol�sa ut�n a forr�s nem mutat semmire. Minthogy az
auto_ptreket
a m�sol�s megv�ltoztatja, konstans (const) auto_ptr-eket nem lehet m�solni.
Az auto_ptr sablont a <memory> fej�llom�ny deklar�lja. �me egy lehets�ges
kifejt�se:
template<class X> class std::auto_ptr {
template <class Y> struct auto_ptr_ref { /* ... */ }; // seg�doszt�ly
X* ptr;
public:
typedef X element_type;
explicit auto_ptr(X* p =0) throw() { ptr=p; } // throw() jelent�se "nem v�lt ki
kiv�telt",
// l�sd �14.6
~auto_ptr() throw() { delete ptr; }
14. Kiv�telkezel�s 483
// figyelj�k meg: m�sol�s �s �rt�kad�s nem konstans param�terekkel
auto_ptr(auto_ptr& a) throw(); // m�sol, majd a.ptr=0
template<class Y> auto_ptr(auto_ptr<Y>& a) throw(); // m�sol, majd a.ptr=0
auto_ptr& operator=(auto_ptr& a) throw(); // m�sol, majd a.ptr=0
template<class Y> auto_ptr& operator=(auto_ptr<Y>& a) throw(); // m�sol, majd
a.ptr=0
X& operator*() const throw() { return *ptr; }
X* operator->() const throw() { return ptr; }
X* get() const throw() { return ptr; } // mutat� kinyer�se
X* release() throw() { X* t = ptr; ptr=0; return t; } // tulajdonosv�lt�s
void reset(X* p =0) throw() { if (p!=ptr) { delete ptr; ptr=p; } }
auto_ptr(auto_ptr_ref<X>) throw(); // m�sol�s auto_ptr_ref-bol
template<class Y> operator auto_ptr_ref<Y>() throw(); // m�sol�s auto_ptr_ref-be
template<class Y> operator auto_ptr<Y>() throw(); // destrukt�v m�sol�s auto_ptr-
bol
};
Az auto_ptr_ref c�lja, hogy megval�s�tsa a k�z�ns�ges auto_ptr sz�m�ra a
destrukt�v m�-
sol�st, ugyanakkor megakad�lyozza egy konstans auto_ptr m�sol�s�t. Ha egy D*-ot
B*-g�
lehet alak�tani, akkor a sablonkonstruktor �s a sablon-�rt�kad�s (meghat�rozott
m�don
vagy automatikusan) egy auto_ptr<D>-t auto_ptr<B>-v� tud alak�tani:
void g(Circle* pc)
{
auto_ptr<Circle> p2 = pc; // most p2 felel a t�rl�s�rt
auto_ptr<Circle> p3 = p2; // most p3 felel a t�rl�s�rt (p2 m�r nem)
p2->m = 7; // programoz�i hiba: p2.get()==0
Shape* ps = p3.get(); // mutat� kinyer�se auto_ptr-bol
auto_ptr<Shape> aps = p3; // tulajdonosv�lt�s �s t�puskonverzi�
auto_ptr<Circle> p4 = pc; // programoz�i hiba: most p4 is felel a
// t�rl�s�rt
}
Az nem meghat�rozott, mi t�rt�nik, ha t�bb auto_ptr is mutat egy objektumra, de az
a legval
�sz�nubb, hogy az objektum k�tszer t�rlodik . ami hiba.
Jegyezz�k meg, hogy az auto_ptr destrukt�v m�sol�si m�dszere miatt nem teljes�ti a
szabv
�nyos t�rol�k elemeire vagy a sort()-hoz hasonl� szabv�nyos elj�r�sokra vonatkoz�
k�vetelm
�nyeket:
vector< auto_ptr<Shape> >& v; // vesz�lyes: auto_ptr haszn�lata t�rol�ban
// ...
sort(v.begin(),v.end()); // Ezt ne tegy�k: a rendez�stol v s�r�lhet
484 Absztrakci�s m�dszerek
Vil�gos, hogy az auto_ptr nem egy �ltal�nos .okos. vagy .intelligens. mutat�
(smart pointer).
De amire tervezt�k . az automatikus mutat�k kiv�telbiztos kezel�s�re . arra
l�nyeges
.k�lts�g. n�lk�l megfelel.
14.4.3. Figyelmeztet�s
Nem minden programnak kell mindenfajta hib�val szemben immunisnak lennie �s nem
minden eroforr�s annyira l�tfontoss�g�, hogy a v�delme meg�rje a .kezdeti
�rt�kad�s az
eroforr�s megszerz�s�vel. m�dszernek, az auto_ptr-nek, illetve a catch(...)
alkalmaz�s�nak
f�rads�g�t. P�ld�ul sok, egyszeruen a bemenetet olvas� �s azzal le is fut�
programn�l a s�-
lyosabb fut�si ideju hib�kat �gy is kezelhetj�k, hogy egy alkalmas hiba�zenet
kiad�sa ut�n
a programot le�ll�tjuk. Ezzel a rendszerre b�zzuk a program �ltal lefoglalt �sszes
eroforr�s
felszabad�t�s�t, �gy a felhaszn�l� �jrafuttathatja a programot egy jobb
bemenettel. Az itt le-
�rt m�dszer olyan alkalmaz�sok sz�m�ra hasznos, amelyekn�l a hib�k ilyesf�le
egyszerus�-
tett kezel�se elfogadhatatlan. Egy k�nyvt�r tervezoje p�ld�ul �ltal�ban nem �lhet
feltev�-
sekkel a k�nyvt�rat haszn�l� program hibatur�si k�vetelm�nyeit illetoen, �gy azt�n
el kell
ker�lnie minden felt�tel n�lk�li fut�si ideju hib�t �s minden eroforr�st fel kell
szabad�tania,
mielott egy k�nyvt�ri f�ggv�ny visszat�r. A .kezdeti �rt�kad�s az eroforr�s
megszerz�s�vel.
m�dszer a kiv�teleknek a hib�k jelz�s�re val� felhaszn�l�s�val egy�tt sok ilyen
k�nyvt�r
sz�m�ra megfelelo.
14.4.4. A kiv�telek �s a new oper�tor
Vegy�k a k�vetkezot:
void f(Arena& a, X* buffer)
{
X* p1 = new X;
X* p2 = new X[10];
X* p3 = new(buffer[10]) X; // X �tmeneti t�rba helyez�se (nem
// sz�ks�ges felszabad�t�s)
X* p4 = new(buffer[11]) X[10];
X* p5 = new(a) X; // t�rfoglal�s az 'a' Arena-t�l (a-t kell
// felszabad�tani)
X* p6 = new(a) X[10];
}
14. Kiv�telkezel�s 485
Mi t�rt�nik, ha X konstruktora kiv�telt v�lt ki? Felszabadul-e a new() oper�tor
�ltal lefoglalt
mem�ria? K�z�ns�ges esetben a v�lasz igen, �gy p1 �s p2 kezdeti �rt�kad�sa nem
okoz mem
�ria-elsziv�rg�st.
Ha az elhelyezo utas�t�st (placement syntax, �10.4.11) haszn�ljuk, a v�lasz nem
ennyire
egyszeru. Az elhelyezo utas�t�s n�mely felhaszn�l�sa lefoglal n�mi mem�ri�t, amit
azt�n fel
kellene szabad�tani, de n�melyik nem. Ezenk�v�l az elhelyezo utas�t�s
alkalmaz�s�nak
�ppen a mem�ria nem szabv�nyos lefoglal�sa a l�nyege, �gy azt�n jellemzoen nem
szabv�-
nyos m�don is kell felszabad�tani azt. K�vetkez�sk�ppen a tov�bbiak a felhaszn�lt
mem�-
riafoglal�t�l (allok�tort�l) f�ggnek. Ha egy Z::operator new() mem�riafoglal�
szerepelt, akkor
a rendszer megh�vja a Z::operator delete()-et, felt�ve, hogy van ilyen; m�s m�don
nem
pr�b�l felszabad�t�st v�gezni. A t�mb�k kezel�se ezzel azonos m�don t�rt�nik
(�15.6.1). Ez
az elj�r�s helyesen kezeli a standard k�nyvt�rbeli elhelyezo new oper�tort
(�10.4.11), csak-
�gy, mint minden olyan esetet, amikor a programoz� �sszeillo lefoglal� �s
felszabad�t�
f�ggv�nyp�rt �rt.
14.4.5. Az eroforr�sok kimer�l�se
Visszat�ro programoz�si dilemma, hogy mi t�rt�nj�k, ha nem siker�l egy eroforr�s
lefoglal
�si k�s�rlete, p�ld�ul mert kor�bban meggondolatlanul nyitogattunk f�jlokat (az
fopen()-
nel) �s foglaltunk le mem�ri�t a szabad t�rban (a new oper�torral), an�lk�l, hogy
t�rodt�nk
volna vele, mi van, ha nincs meg a f�jl vagy hogy kifogytunk-e a szabad t�rb�l.
Ilyen probl
�m�val szembes�lve a programoz�k k�tf�le megold�st szoktak alkalmazni:
1. �jrakezd�s: k�rj�nk seg�ts�get valamelyik h�v� f�ggv�nytol �s folytassuk a
program
fut�s�t.
2. Befejez�s: hagyjuk abba a sz�m�t�st �s t�rj�nk vissza a h�v�hoz.
Az elso esetben a h�v�nak fel kell k�sz�lnie arra, hogy seg�ts�get adjon egy
ismeretlen k�dr
�szletnek annak eroforr�s-lefoglal� probl�m�j�ban. A m�sodik esetben a h�v�nak
arra kell
felk�sz�lnie, hogy kezelje az eroforr�s-lefoglal�s sikertelens�g�bol ad�d�
probl�m�t. A m�-
sodik eset a legt�bbsz�r sokkal egyszerubb �s a rendszer elvonatkoztat�si
szintjeinek jobb
sz�tv�laszt�s�t teszi lehetov�. Jegyezz�k meg, hogy a .befejez�s. v�laszt�sakor
nem a program
fut�sa fejezodik be, hanem csak az adott sz�m�t�s. A .befejez�s. (termination)
azon elj
�r�s hagyom�nyos neve, amely egy .sikertelen. sz�m�t�sb�l a h�v� �ltal adott
hibakezelo-
be t�r vissza (ami azt�n �jra megpr�b�lhatja a sz�m�t�st elv�geztetni), ahelyett,
hogy
megpr�b�ln� maga orvosolni a helyzetet �s a hiba fell�pt�nek hely�rol folytatni a
sz�m�t�st.
486 Absztrakci�s m�dszerek
A C++-ban az �jrakezdo modellt a f�ggv�nyh�v�si elj�r�s, a befejezo modellt a
kiv�telkezel
o elj�r�s t�mogatja. Mindkettot szeml�lteti a standard k�nyvt�rbeli new() oper�tor
egy egyszer
u megval�s�t�sa �s felhaszn�l�sa:
void* operator new(size_t size)
{
for (;;) {
if (void* p = malloc(size)) return p; // megpr�b�lunk mem�ri�t tal�lni
if (_new_handler == 0) throw bad_alloc(); // nincs kezelo: feladjuk
_new_handler(); // seg�ts�get k�r�nk
}
}
Itt a C standard k�nyvt�r�nak malloc() f�ggv�ny�t haszn�ltam a szabad mem�riahely
t�nyleges
megkeres�s�re; az operator new() m�s v�ltozatai m�s m�dokat v�laszthatnak. Ha
siker
�lt mem�ri�t tal�lni, a new() oper�tor visszaadhatja az arra hivatkoz� mutat�t; ha
nem,
a new() megh�vja a _new_handler-t. Ha az tal�l a malloc() sz�m�ra lefoglalhat�
mem�ri�t,
akkor minden rendben. Ha nem, akkor a kezelo nem t�rhet vissza a new() oper�torba
v�gtelen
ciklus okoz�sa n�lk�l. A _new_handler ekkor kiv�telt v�lthat ki, ilyen m�don
valamelyik
h�v�ra hagyva a helyzet tiszt�z�s�t:
void my_new_handler()
{
int no_of_bytes_found = find_some_memory();
if (no_of_bytes_found < min_allocation) throw bad_alloc(); // feladjuk
}
Valahol lennie kell egy try blokknak is, a megfelelo kiv�telkezelovel:
try {
// ...
}
catch (bad_alloc) {
// valahogy reag�lunk a mem�ria kifogy�s�ra
}
A new() oper�tor ezen v�ltozat�ban haszn�lt _new_handler egy, a szabv�nyos
set_new_handler() f�ggv�ny �ltal fenntartott f�ggv�nymutat�. Ha saj�t
my_new_handler()-
�nket szeretn�nk _new_handler-k�nt haszn�lni, ezt �rhatjuk:
set_new_handler(&my_new_handler);
14. Kiv�telkezel�s 487
Ha el akarjuk kapni a bad_alloc kiv�telt is, ezt �rhatjuk:
void f()
{
void(*oldnh)() = set_new_handler(&my_new_handler);
try {
// ...
}
catch (bad_alloc) {
// ...
}
catch (...) {
set_new_handler(oldnh); // kezelo �jb�li be�ll�t�sa
throw; // tov�bbdob�s
}
set_new_handler(oldnh); // kezelo �jb�li be�ll�t�sa
}
M�g jobb, ha a catch(...) kezelot a .kezdeti �rt�kad�s az eroforr�s
megszerz�s�vel. m�dszernek
(�14.4) a _new_handler-re val� alkalmaz�s�val elker�lj�k (�14.12[1]).
A _new_handler alkalmaz�s�val a hiba �szlel�s�nek hely�tol semmif�le tov�bbi
inform�ci�
nem jut el a seg�df�ggv�nyig. K�nnyu t�bb inform�ci�t k�zvet�teni, �m min�l t�bb
jut el
belole egy fut�si ideju hiba �szlel�s�nek hely�tol a kijav�t�st seg�to helyig, a
k�t k�d ann�l
ink�bb f�gg egym�st�l. Ebbol ad�d�an az egyik k�dr�szleten csak a m�sikat �rtve �s
esetleg
azt m�dos�tva lehet v�ltoztatni. A k�l�nb�zo helyen levo programr�szek
elszigetel�s�-
re j� m�dszer, ha az ilyen f�gg�seket a legkisebb m�rt�kre szor�tjuk vissza. A
kiv�telkezel
o elj�r�s jobban t�mogatja az elszigetel�st, mint a h�v� �ltal biztos�tott
seg�df�ggv�nyek
megh�v�sa.
�ltal�ban c�lszeru az eroforr�sok megszerz�s�t r�tegekbe, elvonatkoztat�si
szintekbe szervezni,
�s elker�lni, hogy egy r�teg a h�v� r�teg seg�ts�g�re szoruljon. Nagyobb
rendszerek
eset�ben a tapasztalat azt mutatja, hogy a sikeres rendszerek ezt az utat k�vetik.

A kiv�telek kiv�lt�s�hoz sz�ks�g van egy .eldoband�. objektumra. Az egyes C++-


v�ltozatokt�l elv�rjuk, hogy a mem�ria elfogy�sakor is maradjon annyi tartal�k,
amennyi
egy bad_alloc kiv�lt�s�hoz kell, de lehets�ges, hogy valamilyen m�s kiv�tel dob�sa
a mem
�ria elfogy�s�hoz vezet.
488 Absztrakci�s m�dszerek
14.4.6. Kiv�telek konstruktorokban
A kiv�telek adnak megold�st arra a probl�m�ra, hogyan jelents�nk hib�t egy
konstruktorb�l.
Minthogy a konstruktorok nem adnak vissza k�l�n visszat�r�si �rt�ket, amelyet a
h�v� megvizsg
�lhatna, a hagyom�nyos (azaz kiv�teleket nem alkalmaz�) lehetos�gek a k�vetkezok:
1. Adjunk vissza egy hib�s �llapot� objektumot, megb�zva a h�v�ban, hogy az majd
ellenorzi az �llapotot.
2. �ll�tsunk be egy nem lok�lis v�ltoz�t (p�ld�ul az errno-t), hogy jelezze a
l�trehoz
�s sikertelens�g�t, �s b�zzunk a felhaszn�l�ban, hogy ellenorzi a v�ltoz�t.
3. Ne v�gezz�nk kezdeti �rt�kad�st a konstruktorban �s b�zzunk meg a felhaszn�-
l�ban, hogy az elso haszn�lat elott elv�gzi azt.
4. Jel�lj�k meg az objektumot .kezdo�rt�k n�lk�li.-k�nt, �s v�gezze az elso megh�-

vott tagf�ggv�ny a kezdeti �rt�kad�st. Ez a f�ggv�ny jelenti majd a hib�t, ha


a kezdeti �rt�kad�s nem siker�lt.
A kiv�telkezel�s lehetos�get ad arra, hogy a l�trehoz�s sikertelens�g�re vonatkoz�
inform
�ci�t a konstruktorb�l �tadjuk. Egy egyszeru Vector oszt�ly p�ld�ul �gy v�dekezhet
a t�lzott
ig�nyek ellen:
class Vector {
public:
class Size { };
enum { max = 32000 };
Vector(int sz)
{
if (sz<0 || max<sz) throw Size();
// ...
}
// ...
};
A Vector-okat l�trehoz� k�d most elkaphatja a Vector::Size hib�kat, �s
megpr�b�lhatunk
valami �rtelmeset kezdeni vel�k:
Vector* f(int i)
{
try {
Vector* p = new Vector(i);
// ...
return p;
}
14. Kiv�telkezel�s 489
catch(Vector::Size) {
// m�rethiba kezel�se
}
}
Mint mindig, maga a hibakezelo az alapveto hibakezelo �s -helyre�ll�t� m�dszerek
szok�-
sos k�szlet�t alkalmazhatja. Valah�nyszor a h�v� egy kiv�telt kap, megv�ltozik
annak �rtelmez
�se, hogy mi volt a hiba. Ha a kiv�tellel egy�tt a megfelelo inform�ci� is
tov�bb�t�dik,
a probl�ma kezel�s�hez rendelkez�sre �ll� ismeretek halmaza ak�r bov�lhet is. M�s
sz�-
val, a hibakezelo m�dszerek alapveto c�lja az, hogy a hiba felfedez�s�nek eredeti
hely�rol
olyan helyre jutassunk el inform�ci�t, ahol elegendo ismeret �ll rendelkez�sre a
hiba k�-
vetkezm�nyeinek elh�r�t�s�hoz, �s ezt r�ad�sul megb�zhat�an �s k�nyelmesen tegy�k.

A .kezdeti �rt�kad�s az eroforr�s megszerz�s�vel. elj�r�s az egyn�l t�bb


eroforr�st ig�nybe
vevo konstruktorok kezel�s�nek legbiztosabb �s legeleg�nsabb m�dja (�14.4). Ez
l�nyeg
�ben a sok eroforr�s kezel�s�nek probl�m�j�t az egy eroforr�st kezelo egyszerubb
elj�r�s
ism�telt alkalmaz�s�ra vezeti vissza.
14.4.6.1. Kiv�telek �s a tagok kezdeti �rt�kad�sa
Mi t�rt�nik, ha egy tag kezdeti �rt�kad�sa k�zvetlen�l vagy k�zvetve kiv�telt v�lt
ki? Alap-
�rtelmez�s szerint a kiv�telt az a h�v� f�ggv�ny kapja meg, amelyik a tag
oszt�ly�nak
konstruktor�nak megh�vta, de maga a konstruktor is elkaphatja azt, ha a teljes
f�ggv�nyt�rzset
a tag kezdo�rt�k-list�j�val egy�tt egy try blokkba z�rjuk:
class X {
Vector v;
// ...
public:
X(int);
// ...
};
X::X(int s)
try
:v(s) // v kezdo�rt�ke s
{
// ...
}
catch (Vector::Size) { // a v �ltal kiv�ltott kiv�telt itt kapjuk el
// ...
}
490 Absztrakci�s m�dszerek
14.4.6.2. Kiv�telek �s m�sol�s
M�s konstruktorokhoz hasonl�an a m�sol� konstruktor is jelezheti a hib�s fut�st
kiv�tel kiv
�lt�s�val. Ebben az esetben az objektum nem j�n l�tre. A vector m�sol�
konstruktora p�ld
�ul mem�ri�t foglal le �s �tm�solja az elemi objektumokat (16,3,4,, E.3.2.), ami
kiv�telt
v�lthat ki. A kiv�tel kiv�lt�sa elott a m�sol� konstruktor fel kell szabad�tsa a
lefoglalt ero-
forr�sokat. Az E.2. �s E.3. f�ggel�kekben r�szletesen t�rgyaljuk a kiv�telkezel�s
�s a t�rol
�k eroforr�s-gazd�lkod�s�nak kapcsolatait.
A m�sol� �rt�kad� oper�tor ugyan�gy lefoglalhat eroforr�sokat �s kiv�lthat
kiv�telt. Mielott
ez ut�bbit tenn�, az �rt�kad�snak biztos�tania kell, hogy mindk�t operandus�t
azonos �llapotban
hagyja. M�s esetben megszegj�k a standard k�nyvt�rbeli elo�r�sokat, melynek k�-
vetkezm�nye nem meghat�rozott viselked�s lehet.
14.4.7. Kiv�telek destruktorokban
A kiv�telkezelo elj�r�s szemsz�g�bol n�zve egy destruktort k�tf�lek�ppen lehet
megh�vni:
1. Norm�l (szab�lyos) megh�v�s: a hat�k�rbol val� szab�lyos kil�p�skor ((�10.4.3)
vagy egy delete h�v�s folyt�n (�10.4.5) stb.
2. Kiv�telkezel�s k�zbeni megh�v�s: a verem visszateker�se k�zben (�14.4) a
kiv�telkezel
o elj�r�s elhagy egy blokkot, amely destruktorral b�r� objektumot tartalmaz.
Az ut�bbi esetben a kiv�tel nem l�phet ki a destruktorb�l. Ha megteszi, az a
kiv�telkezelo
elj�r�s hib�j�nak sz�m�t, �s megh�v�dik az std::terminate() (�14.7). V�g�lis a
kiv�telkezelo
elj�r�snak �s a destruktornak �ltal�ban nincs m�dja eld�nteni, hogy elfogadhat�-e
az egyik
kiv�telnek a m�sik kedv��rt val� elhanyagol�sa.
Ha a destruktor olyan f�ggv�nyt h�v meg, amely kiv�telt v�lthat ki, akkor ez ellen
v�dekezhet:
X::~X()
try {
f(); // kiv�telt v�lthat ki
}
catch (...) {
// valamit csin�lunk
}
A standard k�nyvt�rbeli uncaught_exception() f�ggv�ny true-val t�r vissza, ha van
olyan
.eldobott. kiv�tel, amelyet m�g nem kaptak el. Ez lehetov� teszi a destruktor
att�l f�ggo
programoz�s�t, hogy az objektum szab�lyos vagy a verem visszateker�se k�zbeni
megsemmis
�t�s�rol van-e sz�.
14. Kiv�telkezel�s 491
14.5. Kiv�telek, amelyek nem hib�k
Ha egy kiv�telre sz�m�tunk �s elkapjuk �s �gy annak nincs a program muk�d�s�re
n�zve
rossz k�vetkezm�nye, akkor mi�rt lenne hiba? Csak mert a programoz� a kiv�telre
mint hib
�ra �s a kiv�telkezelo elj�r�sokra pedig mint hibakezelo eszk�z�kre gondol? Nos, a
kiv�-
teleket �gy is tekinthetj�k, mintha vez�rloszerkezetek lenn�nek:
void f(Queue<X>& q)
{
try {
for (;;) {
X m = q.get(); // 'Empty' kiv�telt v�lt ki, ha a sor �res
// ...
}
}
catch (Queue<X>::Empty) {
return;
}
}
Ez eg�szen j�nak tunik, �gy ebben az esetben t�nyleg nem teljesen vil�gos, mi
sz�m�t hib�-
nak �s mi nem.
A kiv�telkezel�s kev�sb� rendezett elj�r�s, mint az if.hez vagy a for-hoz hasonl�
helyi vez
�rl�si szerkezetek �s azokn�l gyakran kev�sb� hat�kony is, ha a kiv�telre
t�nylegesen sor
ker�l. Ez�rt kiv�teleket csak ott haszn�ljunk, ahol a hagyom�nyosabb vez�rl�si
szerkezetek
nem eleg�nsak vagy nem haszn�lhat�ak. A standard k�nyvt�r p�ld�ul tartalmaz egy
tetszo-
leges elemekbol �ll� queue-t (sor) is, kiv�telek alkalmaz�sa n�lk�l (�17.3.2).
A keresof�ggv�nyekn�l . k�l�n�sen a rekurz�v h�v�sokat nagym�rt�kben alkalmaz�
f�ggv
�nyekn�l (p�ld�ul egy f�ban kereso f�ggv�nyn�l) . j� �tlet befejez�sk�nt kiv�telt
alkalmazni:
void fnd(Tree* p, const string& s)
{
if (s == p->str) throw p; // megtal�lta s-t
if (p->left) fnd(p->left,s);
if (p->right) fnd(p->right,s);
}
Tree* find(Tree* p, const string& s)
{
492 Absztrakci�s m�dszerek
try {
fnd(p,s);
}
catch (Tree* q) { // q->str==s
return q;
}
return 0;
}
Ugyanakkor a kiv�telek ilyen haszn�lata k�nnyen t�lz�sba viheto �s
�ttekinthetetlen k�dhoz
vezethet. Ha �sszeru, ragaszkodjunk .a kiv�telkezel�s hibakezel�s. elvhez. Ekkor
a k�d vil�gosan k�t r�szre k�l�n�l: k�z�ns�ges �s hibakezelo k�dra. Ez �rthetobb�
teszi
a k�dot. Sajnos a .val�. vil�g nem ilyen tiszta, a program szerkezete pedig ezt
(bizonyos fokig
k�v�natos m�don) t�kr�zni fogja.
A hibakezel�s l�nyeg�n�l fogva neh�z. Becs�lj�nk meg mindent, ami seg�t egy
vil�gos modellt
kialak�tani arr�l, mi sz�m�t hib�nak �s hogyan kezelj�k.
14.6. Kiv�telek specifik�ci�ja
A kiv�tel kiv�lt�sa vagy elkap�sa befoly�solja a f�ggv�nynek m�s f�ggv�nyekhez
val� viszony
�t. Ez�rt �rdemes lehet a f�ggv�ny deklar�ci�j�val egy�tt megadni azon kiv�teleket

is, amelyeket a f�ggv�ny kiv�lthat.


void f(int a) throw (x2, x3);
Ha egy f�ggv�ny megadja, milyen kiv�telek l�phetnek fel v�grehajt�sa k�zben, akkor
ezzel
val�j�ban garanci�t ny�jt a haszn�l�inak. Ha a f�ggv�ny fut�sa k�zben valamit
olyasmit
pr�b�l tenni, ami ezt a garanci�t �rv�nytelenn� tenn�, akkor ez a k�s�rlet az
std::unexpected() h�v�ss� fog �talakulni. Az unexpected() alap�rtelmezett
jelent�se
std::terminate(), ami szokv�nyos esetben megh�vja az abort()-ot. (R�szletesen l�sd

a �9.4.1.1 pontban.) Val�j�ban a


void f() throw (x2, x3)
{
// t�rzs
}
14. Kiv�telkezel�s 493
egyen�rt�ku a k�vetkezovel:
void f()
try
{
// t�rzs
}
catch (x2) { throw; } // tov�bbdob�s
catch (x3) { throw; } // tov�bbdob�s
catch (...) {
std::unexpected(); // az unexpected() nem fog visszat�rni
}
Ennek legfontosabb elonye, hogy a f�ggv�ny deklar�ci�ja a h�v�k �ltal el�rheto
fel�let r�-
sze. A f�ggv�nydefin�ci�k viszont nem �ltal�nosan el�rhetoek. Ha hozz� is f�r�nk
az �sszes
k�nyvt�r forr�s�hoz, hat�rozottan nem szeret�nk surun bel�j�k n�zegetni, r�ad�sul
a megkiv
�tel-specifik�ci�kkal (exception specification) ell�tott f�ggv�nydeklar�ci�k
sokkal r�videbbek
�s vil�gosabbak, mint az egyen�rt�ku k�zzel �rott v�ltozat.
A kiv�tel-specifik�ci�k n�lk�li f�ggv�nyekrol azt kell felt�telezn�nk, hogy
b�rmilyen kiv�-
telt kiv�lthatnak:
int f(); // b�rmilyen kiv�telt kiv�lthat
A kiv�telt ki nem v�lt� f�ggv�nyeket �res list�val adhatjuk meg:
int g() throw (); // nem v�lt ki kiv�telt
Azt gondolhatn�nk, az lenne a j� alap�rtelmez�s, hogy a f�ggv�ny nem v�ltana ki
kiv�telt.
Ekkor azonban alapvetoen minden f�ggv�ny r�sz�re sz�ks�ges lenne kiv�teleket
meghat�-
rozni, emiatt pedig sokszor kellene �jraford�tani �s meg is akad�lyozn� a m�s
nyelveken �rt
programokkal val� egy�ttmuk�d�st. Ez azt�n arra �szt�n�zn� a programoz�kat,
hogy .akn
�zz�k al�. a kiv�telkezelo rendszert �s hogy hib�s k�dot �rjanak a kiv�telek
elfojt�s�ra, ez
pedig az aknamunk�t �szre nem vevoknek hamis biztons�g�rzetet adna.
14.6.1. A kiv�telek ellenorz�se
Egy fel�letnek ford�t�si idoben nem lehet minden megs�rt�si k�s�rlet�t
ellenorizni, de az�rt
ford�t�skor sok ellenorz�s t�rt�nik. A specifik�lt (teh�t .enged�lyezett.)
kiv�teleket a ford�-
t� �gy �rtelmezi, hogy a f�ggv�ny azok mindegyik�t ki fogja v�ltani. A kiv�tel-
specifik�ci�k
ford�t�si ideju ellenorz�s�nek szab�lyai a k�nnyen felder�theto hib�kat tiltj�k.
494 Absztrakci�s m�dszerek
Ha egy f�ggv�ny valamely deklar�ci�ja megad kiv�teleket is, akkor mindegyik
deklar�ci�-
j�nak (�s definici�j�nak is) tartalmaznia kell pontosan ugyanazokat a kiv�teleket:

int f() throw (std::bad_alloc);


int f() // hiba: a kiv�tel-meghat�roz�s hi�nyzik
{
// ...
}
Fontos szempont, hogy a kiv�telek ford�t�si egys�gek hat�rain �tny�l� ellenorz�se
nem k�-
telezo. Term�szetesen az adott nyelvi v�ltozat ellenorizhet �gy, de a nagyobb
rendszerek legt
�bbje sz�m�ra fontos, hogy ez ne t�rt�njen meg, vagy ha m�gis, csak akkor jelezzen
v�gzetes
hib�t, ha a kiv�tel-specifik�ci�k megs�rt�s�t nem lehet majd fut�si idoben
elkapni.
A l�nyeg az, hogy �j kiv�tellel val� bov�t�s ne k�nyszer�tse ki a kapcsol�d�
kiv�telspecifik
�ci�k kijav�t�s�t �s az esetleg �rintett �sszes k�d �jraford�t�s�t. A rendszer �gy
egy
f�lig fel�j�tott �llapotban tov�bb muk�dhet �s a v�ratlan kiv�telek dinamikus
(fut�si idobeli)
�szlel�s�re hagyatkozhat, ami alapveto az olyan nagy rendszerekn�l, ahol a nagyobb

friss�t�sek k�lts�gesek �s nincs is meg az �sszes forr�s.


Egy virtu�lis f�ggv�nyt csak olyan f�ggv�nnyel lehet fel�l�rni, amely legal�bb
annyira szigor
�an hat�rozza meg a kiv�teleket, mint maga az eredeti f�ggv�ny:
class B {
public:
virtual void f(); // b�rmit kiv�lthat
virtual void g() throw(X,Y);
virtual void h() throw(X);
};
class D : public B {
public:
void f() throw(X); // rendben
void g() throw(X); // rendben: D::g() szigor�bb, mint B::g()
void h() throw(X,Y); // hiba: D::h() megengedobb, mint B::h()
};
Ezt a szab�lyt a j�zan �sz dikt�lja. Ha egy sz�rmaztatott oszt�ly olyan kiv�telt
v�ltana ki,
amit az eredeti f�ggv�ny nem adott meg lehets�gesk�nt, annak elkap�s�t nem
v�rhatn�nk
el a h�v�t�l. M�sr�szt egy fel�l�r� f�ggv�ny, amely kevesebb kiv�telt v�lt ki,
betartja a fel�l-
�rt f�ggv�ny kiv�tel-specifik�ci�j�ban fel�ll�tott szab�lyokat.
14. Kiv�telkezel�s 495
Ugyan�gy egy, a kiv�teleket szigor�bban meghat�roz� f�ggv�nyt hozz�rendelhet�nk
egy
megengedobb f�ggv�nymutat�hoz, de ford�tva nem:
void f() throw(X);
void (*pf1)() throw(X,Y) = &f; // rendben
void (*pf2)() throw() = &f; // hiba: f() megengedobb, mint pf2
Kiv�tel-specifik�ci� n�lk�li f�ggv�nyre hivatkoz� mutat�t kiv�teleket meghat�roz�
f�ggv
�nymutat�hoz k�l�n�sk�ppen nem rendelhet�nk:
void g(); // b�rmit kiv�lthat
void (*pf3)() throw(X) = &g; // hiba: g() megengedobb, mint pf3
A kiv�tel-specifik�ci� nem r�sze a f�ggv�ny t�pus�nak, a typedef-ek pedig nem is
tartalmazhatnak
ilyet:
typedef void (*PF)() throw(X); // hiba
14.6.2. V�ratlan kiv�telek
Ha a kiv�telek k�re specifik�lt, az ott nem szereplo kiv�telek az unexpected()
megh�v�s�t
v�lthatj�k ki. Az ilyen h�v�sok a tesztel�sen k�v�l �ltal�ban nem k�v�natosak. A
kiv�telek
gondos csoportos�t�s�val �s a fel�letek megfelelo meghat�roz�s�val viszont
elker�lhetok,
de az unexpected() h�v�sokat is el lehet fogni �s �rtalmatlann� tenni.
Egy megfeleloen kidolgozott Y alrendszer gyakran az Yerr oszt�lyb�l sz�rmaztatja a
kiv�teleit:
class Some_Yerr : public Yerr { /* ... */ };
A fenti eset�ben a
void f() throw (Xerr, Yerr, exception);
minden Yerr-t tov�bb�tani fog a h�v�j�nak. �gy teh�t f() a Some_Yerr oszt�ly�
hib�t is tov�bb
�tani fogja �s f()-ben semmilyen Yerr nem fog unexpected() h�v�st kiv�ltani.
A standard k�nyvt�r �ltal kiv�ltott �sszes kiv�tel az exception oszt�ly (�14.10)
lesz�rmazottja.
496 Absztrakci�s m�dszerek
14.6.3. Kiv�telek lek�pez�se
A programot le�ll�tani kezeletlen kiv�tel fell�p�se eset�n n�ha t�l k�ny�rtelen
elj�r�s.
Ilyenkor az unexpected() viselked�s�t kell elfogadhat�bb� tenni.
Ennek az a legegyszerubb m�dja, hogy a standard k�nyvt�rbeli std::bad_exception-t
felvessz
�k a specifik�lt kiv�telek k�z�. Ekkor az unexpected() egyszeruen egy
bad_exceptiont
fog kiv�ltani egy kezelof�ggv�ny megh�v�sa helyett:
class X { };
class Y { };
void f() throw(X,std::bad_exception)
{
// ...
throw Y(); // bad_exception-t v�lt ki
}
A kiv�telkezelo ekkor elkapja az elfogadhatatlan Y kiv�telt �s bad_exception
t�pus�t v�lt ki
helyette. A bad_exception-nel semmi baj, a terminate()-n�l kev�sb� drasztikus . de
az�rt
�gy is meglehetosen durva beavatkoz�s, r�ad�sul az inform�ci�, hogy milyen kiv�tel
okozta
a probl�m�t, elv�sz.
14.6.3.1. Kiv�telek felhaszn�l�i lek�pez�se
Vegy�nk egy g() f�ggv�nyt, amely nem h�l�zati k�rnyezethez k�sz�lt. T�telezz�k
fel, hogy
g() csak a saj�t .Y alrendszer�vel. kapcsolatos kiv�telek kiv�lt�s�t enged�lyezi.
Tegy�k fel,
hogy g()-t h�l�zati k�rnyezetben kell megh�vnunk.
void g() throw(Yerr);
Term�szetesen g() nem fog tudni semmit a h�l�zati kiv�telekrol �s az unexpected()-
et fogja
megh�vni, ha ilyennel tal�lkozik. A g() h�l�zati k�rnyezetben val� haszn�lat�hoz
olyan
k�dra van sz�ks�g�nk, amely h�l�zati kiv�teleket kezel, vagy �t kell �rnunk g()-t.
Tegy�k
fel, hogy az �jra�r�s nem lehets�ges vagy nem k�v�natos. Ekkor a probl�m�t az
unexpected() jelent�s�nek fel�lb�r�l�s�val oldhatjuk meg.
A mem�ria elfogy�s�t a _new_handler kezeli, amelyet a set_new_handler() �ll�t be.
Ugyan-
�gy a v�ratlan kiv�telre adott v�laszt egy _unexpected_handler hat�rozza meg,
amelyet az
<exception> fej�llom�nyban megadott std::set_unexpected() �ll�t be:
14. Kiv�telkezel�s 497
typedef void(*unexpected_handler)();
unexpected_handler set_unexpected(unexpected_handler);
A v�ratlan kiv�telek megfelelo kezel�s�hez l�tre kell hoznunk egy oszt�lyt, hogy a
.kezdeti
�rt�kad�s az eroforr�s megszerz�s�vel. m�dszert haszn�lhassuk az unexpected()
f�ggv�-
nyekben:
class STC { // t�rol �s vissza�ll�t
unexpected_handler old;
public:
STC(unexpected_handler f) { old = set_unexpected(f); }
~STC() { set_unexpected(old); }
};
Ezut�n defini�lunk egy f�ggv�nyt az unexpected() erre az esetre k�v�nt
jelent�s�vel:
class Yunexpected : public Yerr { };
void throwY() throw(Yunexpected) { throw Yunexpected(); }
A throwY()-t unexpected()-k�nt haszn�lva b�rmilyen kiv�telbol Yunexpected lesz.
V�g�l elk�sz�thetj�k g()-nek egy h�l�zati k�rnyezetben alkalmazhat� v�ltozat�t:
void networked_g() throw(Yerr)
{
STC xx(&throwY); // az unexpected() most Yunexpected-et v�lt ki
g();
}
Mivel az Yunexpected az Yerr-bol sz�rmazik, a kiv�tel-specifik�ci� nem s�r�l. Ha
a throwY() olyan kiv�telt v�ltott volna ki, amit a specifik�ci� nem enged�lyez,
akkor
a terminate() hajt�dott volna v�gre.
Az�ltal, hogy mentett�k �s vissza�ll�tottuk az _unexpected_handler-t, t�bb
alrendszer sz�-
m�ra tett�k lehetov� . egym�sra val� hat�s n�lk�l . a v�ratlan kiv�telek
kezel�s�t. A v�ratlan
kiv�telek enged�lyezett� alak�t�s�nak e m�dszere alapvetoen a rendszer �ltal
a bad_exception-nal ny�jtott szolg�ltat�s rugalmasabb v�ltozata.
498 Absztrakci�s m�dszerek
14.6.3.2. Kiv�telek t�pus�nak vissza�ll�t�sa
A v�ratlan kiv�telek Yunexpected-d� alak�t�sa lehetov� tenn� a networked_g()
felhaszn�l�-
j�nak, hogy megtudja: egy v�ratlan kiv�telt k�pezt�nk le az Yunexpected-re. Azt
azonban
nem fogja tudni, hogy melyik kiv�tel lek�pez�se t�rt�nt meg. Egy egyszeru
elj�r�ssal lehet
ov� tehetj�k ennek megjegyz�s�t �s tov�bb�t�s�t. P�ld�ul �gy tudn�nk inform�ci�t
gyujteni
a Network_exception-�krol:
class Yunexpected : public Yerr {
public:
Network_exception* pe;
Yunexpected(Network_exception* p) :pe(p?p->clone():0) { }
~Yunexpected() { delete p; }
};
void throwY() throw(Yunexpected)
{
try {
throw; // A tov�bbdobott kiv�telt azonnal el kell kapni!
}
catch(Network_exception& p) {
throw Yunexpected(&p); // lek�pezett kiv�tel kiv�lt�sa
}
catch(...) {
throw Yunexpected(0);
}
}
A kiv�telek tov�bbdob�sa �s elkap�sa lehetov� teszi, hogy azon t�pusok �sszes
kiv�tel�t
kezelj�k, amelyeket meg tudunk nevezni. A throwY() f�ggv�nyt az unexpected() h�vja
meg,
azt pedig elvileg egy catch(...) kezelo. �gy teh�t biztosan van tov�bbdobhat�
kiv�tel. Egy
unexpected() f�ggv�ny nem tekinthet el a hib�t�l �s nem t�rhet vissza. Ha
megpr�b�l �gy
tenni, az unexpected() maga fog bad_expection-t kiv�ltani (�14.6.3). A clone()
f�ggv�nyt
arra haszn�ljuk, hogy a kiv�tel egy m�solata sz�m�ra helyet foglaljon a szabad
mem�ri�-
ban. Ez a m�solat t�l�li a verem .visszateker�s�t..
14.7. El nem kapott kiv�telek
Ha egy kiv�telt nem kapnak el, akkor az std::terminate() megh�v�s�ra ker�l sor.
A terminate() fog megh�v�dni akkor is, ha a kiv�telkezelo elj�r�s a vermet
s�r�ltnek tal�lja,
vagy ha egy, a verem visszateker�se sor�n megh�vott destruktor kiv�tel
kiv�lt�s�val pr�-
b�l v�get �rni.
14. Kiv�telkezel�s 499
A v�ratlan kiv�teleket az _unexpected_handler kezeli, amelyet az
std::set_unexpected() �ll
�t be. Ehhez hasonl�an, az el nem kapott kiv�telek kezel�s�t az _uncaught_handler
v�gzi,
amelyet az <exception> fej�llom�nyban megadott std::set_uncaught() �ll�t be:
typedef void(*terminate_handler)();
terminate_handler set_terminate(terminate_handler);
A visszat�r�si �rt�k a set_terminate()-nek elozoleg adott f�ggv�ny.
A terminate() megh�v�s�nak oka, hogy idonk�nt a kiv�telkezel�ssel fel kell hagyni
kev�sb
� kifinomult hibakezel�si m�dszerek jav�ra. A terminate()-et p�ld�ul haszn�lhatjuk
arra,
hogy megszak�tsunk egy folyamatot vagy esetleg �jraind�tsunk egy rendszert (�j
kezdeti �rt
�kad�ssal). A terminate() megh�v�sa drasztikus int�zked�s: akkor kell haszn�lni,
amikor
a kiv�telkezelo elj�r�s �ltal megval�s�tott hibakezelo strat�gia csod�t mondott �s
ideje a hibat
ur�s m�s szintj�re �tt�rni.
A terminate() alap�rtelmez�s szerint az abort()-ot h�vja meg (�9.4.1.1). Ez az
alap�rtelmez
�s a legt�bb felhaszn�l� sz�m�ra megfelelo v�laszt�s, k�l�n�sen a program
hibakeres�se
(debugging) alatt.
Az _uncaught_handler f�ggv�nyekrol a rendszer felt�telezi, hogy nem fognak
visszat�rni
a h�v�jukhoz. Ha az adott f�ggv�ny megpr�b�lja, a terminate() meg fogja h�vni az
abort()-ot.
Jegyezz�k meg, hogy az abort() a programb�l val� nem szab�lyos kil�p�st jelent. Az
exit()
f�ggv�ny visszat�r�si �rt�k�vel jelezhetj�k a rendszernek, hogy a programb�l
szab�lyosan
vagy nem szab�lyosan l�pt�nk-e ki (�9.4.1.1).
Az adott nyelvi v�ltozat hat�rozza meg, hogy a program fut�s�nak el nem kapott
kiv�tel miatti
befejezod�s�n�l a destruktorok megh�v�dnak-e. Bizonyos rendszerekn�l alapveto,
hogy a destruktorok ne h�v�djanak meg, hogy a program futtat�s�t folytatni
lehessen a hibakeres
obol. M�s rendszerek sz�m�ra fel�p�t�s�kbol ad�d�an szinte lehetetlen nem megh
�vni a destruktorokat a kiv�tel kezeloj�nek keres�sekor.
Ha biztos�tani akarjuk a rendrak�st egy el nem kapott kiv�tel eset�ben, a main()
f�ggv�nyben
a t�nylegesen elkapni k�v�nt kiv�telek mell� �rhatunk egy minden kiv�telt elkap�
kezel
ot is (�14.3.2):
int main()
try {
// ...
}
500 Absztrakci�s m�dszerek
catch (std::range_error)
{
cerr << "Tartom�nyhiba: m�r megint!\n";
}
catch (std::bad_alloc)
{
cerr << "A new kifogyott a mem�ri�b�l.\n";
}
catch (...) {
// ...
}
Ez a glob�lis v�ltoz�k konstruktorai �s destruktorai �ltal kiv�ltottak kiv�tel�vel
minden kiv
�telt elkap. A glob�lis v�ltoz�k kezdeti �rt�kad�sa alatt fell�po kiv�teleket nem
lehet elkapni.
Egy nem lok�lis statikus objektum kezdeti �rt�kad�sa k�zbeni throw eset�ben csak
a set_unexpected() (�14.6.2) seg�ts�g�vel kaphatjuk meg a vez�rl�st, ami �jabb ok
arra,
hogy lehetos�g szerint ker�lj�k a glob�lis v�ltoz�kat.
A kiv�telek kiv�lt�s�n�l a kiv�tel fell�p�s�nek pontos helye �ltal�ban nem ismert,
vagyis
kevesebb inform�ci�t kapunk, mint amit egy hibakereso (debugger) tudhat a program
�llapot
�r�l. Ez�rt bizonyos C++ fejlesztok�rnyezetek, programok vagy fejlesztok sz�m�ra
elony�sebb lehet nem elkapni azokat a kiv�teleket, amelyek k�vetkezm�nyeit a
programban
nem k�sz�b�lj�k ki.
14.8. A kiv�telek �s a hat�konys�g
Elvileg lehets�ges a kiv�telkezel�st �gy megtervezni, hogy az ne j�rjon a fut�si
ido n�veked
�s�vel, ha nem ker�l sor kiv�tel kiv�lt�s�ra. R�ad�sul ezt �gy is meg lehet tenni,
hogy egy
kiv�tel kiv�lt�sa ne legyen k�l�n�sebben k�lts�ges egy f�ggv�nyh�v�shoz k�pest. Ha
azonban
a mem�riaig�nyt is cs�kkenteni szeretn�nk, illetve a kiv�telkezel�st a C h�v�si
sorrendj
�vel �s a hibakeresok szabv�nyos elj�r�saival is �ssze szeretn�nk egyeztetni, ha
nem is
lehetetlen, de neh�z feladatra v�llalkozunk . de eml�kezz�nk arra, hogy a
kiv�telek haszn
�lat�nak alternat�v�i sincsenek ingyen. Nem szokatlan olyan hagyom�nyos
rendszerekkel
tal�lkozni, amelyekn�l a k�d fel�t a hibakeres�sre sz�nt�k.
14. Kiv�telkezel�s 501
Vegy�nk egy egyszeru f() f�ggv�nyt, amelynek l�tsz�lag semmi k�ze nincs a
kiv�telkezel�shez:
void g(int);
void f()
{
string s;
// ...
g(1);
g(2);
}
�m g() kiv�telt v�lthat ki, �gy f()-nek tartalmaznia kell a kiv�tel fell�pte
eset�n s-et megsemmis
�to k�dot. Ha g() nem v�ltott volna ki kiv�telt, valamilyen m�s m�don kellett
volna a hib
�t jeleznie. �gy a fentivel �sszehasonl�that� hagyom�nyos k�d, amely kiv�telek
helyett
hib�kat kezel, nem a fenti egyszeru k�d lenne, hanem valami ilyesmi:
bool g(int);
bool f()
{
string s;
// ...
if (g(1))
if (g(2))
return true;
else
return false;
else
return false;
}
A programoz�k szok�s szerint persze nem kezelik ennyire m�dszeresen a hib�kat, �s
az
nem is mindig l�tfontoss�g�. De ha gondos �s m�dszeres hibakezel�s sz�ks�ges,
akkor
jobb azt a sz�m�t�g�pre, vagyis a kiv�telkezelo rendszerre hagyni.
A kiv�telek specifik�ci�ja (�14.6) nagyon hasznos lehet a ford�t� �ltal
l�trehozott k�d jav�-
t�s�ra. Ha az al�bbi m�don kijelentett�k volna, hogy g() nem v�lt ki kiv�telt,
akkor az f()
sz�m�ra l�trehozott k�don jav�thattunk volna:
void g(int) throw();
�rdemes megjegyezni, hogy a hagyom�nyos C f�ggv�nyek nem v�ltanak ki kiv�telt, �gy
a legt
�bb programban az �sszes C f�ggv�ny az �res throw() kiv�tel-meghat�roz�ssal adhat�
meg.
Az adott nyelvi v�ltozat tudhatja, hogy a C-nek csak n�h�ny standard k�nyvt�rbeli
f�ggv�nye
v�lt ki kiv�telt, p�ld�ul az atexit() �s a qsort(), �s ennek ismeret�ben jobb
k�dot k�sz�thet.
502 Absztrakci�s m�dszerek
Mielott egy .C f�ggv�nyt. ell�tn�nk az �res kiv�tel-meghat�roz�ssal (a throw()-
val), gondoljuk
meg, nem v�lthat-e ki kiv�telt. P�ld�ul �t�rhatt�k, hogy a new oper�tort
haszn�lja,
amely viszont bad_alloc-ot v�lthat ki vagy olyan C++-k�nyvt�rat h�vhat meg, amely
ugyanezt
teheti.
14.9. A hibakezel�s egy�b m�djai
A kiv�telkezelo elj�r�s c�lja, hogy lehetov� tegye egy programr�sz sz�m�ra, hogy a
program
m�s r�szeit �rtes�tse egy kiv�teles k�r�lm�ny �szlel�s�rol. A feltev�s az, hogy a
k�t r�sz
f�ggetlen�l k�sz�lt �s a kiv�telt kezelo r�sz tud valami �rtelmeset kezdeni a
hib�val.
A kiv�telkezelok hat�kony haszn�lat�hoz �tfog� strat�gi�ra van sz�ks�g�nk. Vagyis
a program
k�l�nb�zo r�szeinek egyet kell �rteni�k abban, hogyan haszn�lj�k a kiv�teleket �s
hol
kezelik a hib�kat. A kiv�telkezelo elj�r�s l�nyeg�n�l fogva nem lok�lis, �gy
alapveto jelent
os�gu, hogy �tfog� strat�gia �rv�nyes�lj�n. Ebbol k�vetkezik, hogy a hibakezel�s
m�dj�-
ra legjobb a rendszer tervez�s�nek legkor�bbi szakasz�ban gondolni, �s hogy az
alkalmazott
m�dszernek (a teljes program �sszetetts�g�hez k�pest) egyszerunek �s pontosan
meghat
�rozottnak kell lennie. Egy, a l�nyeg�n�l fogva annyira k�nyes ter�leten, mint a
hibakezel
�s, egy bonyolult m�dszerhez nem tudn�nk k�vetkezetesen alkalmazkodni.
Elosz�r is fel kell adni azt a t�vhitet, hogy az �sszes hib�t egyetlen elj�r�ssal
kezelhetj�k; ez
csak bonyol�tan� a helyzetet. A sikeres hibaturo rendszerek t�bbszintuek.
Mindegyik szint
annyi hib�val birk�zik meg, amennyivel csak tud, an�lk�l, hogy t�ls�gosan
megszenvedne
vele, a marad�k kezel�s�t viszont a magasabb szintekre hagyja. A terminate() ezt a
kezel�-
si m�dot azzal t�mogatja, hogy menek�l�si utat hagy arra az esetre, ha maga a
kiv�telkezel
o rendszer s�r�lne vagy nem t�k�letes haszn�lata miatt maradn�nak nem elkapott
kiv�telek.
Az unexpected() c�lja ugyan�gy az, hogy menek�l�si utat hagyjon arra az esetre, ha

a kiv�telek specifik�ci�j�ra �p�lo hibakezelo rendszer m�gsem jelentene a


kiv�telek sz�-
m�ra �thatolhatatlan falat.
Nem minden f�ggv�ny kell, hogy .tuzfalk�nt. viselkedjen. A legt�bb rendszerben nem
lehet
minden f�ggv�nyt �gy meg�rni, hogy vagy teljes sikerrel j�rjon vagy egy pontosan
meghat�rozott m�don legyen sikertelen. Hogy ez mi�rt nem lehets�ges, az programr�l

programra �s programoz�r�l programoz�ra v�ltozik. Nagyobb programok eset�ben a k�-

vetkezo okokat sorolhatjuk fel:


14. Kiv�telkezel�s 503
1. T�l sok munka kellene ennek a .megb�zhat�s�gnak. olyan biztos�t�s�hoz, hogy
k�vetkezetesen mindenhol �rv�nyes�lj�n.
2. A sz�ks�ges t�rter�let �s fut�si ido n�veked�se nagyobb lenne az elfogadhat�n�l

(mert rendszeresen ugyanazon hib�k . p�ld�ul �rv�nytelen param�terek . ism�-


telt ellenorz�s�re ker�l sor).
3. M�s nyelven �rt f�ggv�nyek nem alkalmazkodn�nak a szab�lyokhoz.
4. Ez a puszt�n helyi �rtelemben vett .megb�zhat�s�g. olyan bonyolults�ghoz
vezetne,
amely v�g�l al��sn� a teljes rendszer megb�zhat�s�g�t.
Ugyanakkor egy program olyan k�l�n�ll� r�szrendszerekre bont�sa, amelyek vagy
teljes sikerrel
j�rnak, vagy meghat�rozott m�don lesznek sikertelenek, alapveto, megteheto �s
gazdas
�gos. Egy fobb k�nyvt�rat, r�szrendszert vagy kulcsfontoss�g� f�ggv�nyt �gy kell
megtervezni.
A kiv�teleket ilyen k�nyvt�rak vagy r�szrendszerek fel�letei sz�m�ra c�lszeru
meghat�rozni.
Rendszerint nem adatik meg az a luxus, hogy egy rendszer �sszes k�dj�t .a
null�r�l. k�sz�thess
�k el. Ez�rt egy �ltal�nos, minden programr�szre kiterjedo hibakezel�si strat�gia
megalkot
�sakor figyelembe kell venn�nk az egyes, a mi�nktol elt�ro m�dszert alkalmaz�
programr
�szleteket is. Ehhez pedig tekintetbe kell venn�nk olyan k�rd�seket, mint hogy a
programr
�szlet hogyan kezeli az eroforr�sokat, vagy milyen �llapotba ker�l egy hib�ja ut�n

a rendszer. Az a c�l, hogy a programr�szlet l�tsz�lag akkor is az �ltal�nos


hibakezel�si m�dszer
szerint kezelje a hib�kat, ha val�j�ban elt�ro belso elj�r�st alkalmaz.
Alkalmasint sz�ks�ges lehet az egyik st�lus� hibajelz�srol a m�sikra �tt�rni.
P�ld�ul egy C
k�nyvt�ri f�ggv�ny megh�v�sa ut�n ellenorizhetj�k az errno-t �s kiv�telt
v�lthatunk ki,
vagy ford�tva, elkaphatunk egy kiv�telt �s az errno-t be�ll�thatjuk, mielott a C+
+-k�nyvt
�rb�l visszat�r�nk egy C programba:
void callC() throw(C_blewit)
{
errno = 0;
c_function();
if (errno) {
// takar�t�s (ha lehets�ges �s sz�ks�ges)
throw C_blewit(errno);
}
}
extern "C" void call_from_C() throw()
{
504 Absztrakci�s m�dszerek
try {
c_plus_plus_function();
}
catch (...) {
// takar�t�s (ha lehets�ges �s sz�ks�ges)
errno = E_CPLPLFCTBLEWIT;
}
}
Ilyenkor fontos, hogy k�vetkezetesen j�rjunk el, hogy a hibajelento st�lusok
�talak�t�sa
teljes legyen.
A hibakezel�s . a lehetos�gekhez m�rten . hierarchikus legyen. Ha egy f�ggv�ny
fut�si idej
u hib�t �szlel, ne k�rjen seg�ts�get vagy eroforr�st a h�v�j�t�l. Az ilyen k�r�sek
az egym�st
�l f�ggo elemek k�z�tt k�rbe-k�rbe j�r� v�gtelen ciklusokat okoznak, ami a
programot �ttekinthetetlenn
� teszi, a v�gtelen ciklusok lehetos�g�vel pedig a hib�kat kezelo k�dba egy
nem k�v�natos lehetos�get �p�t.
Alkalmazzunk olyan egyszerus�to m�dszereket, mint a .kezdeti �rt�kad�s az
eroforr�s megszerz
�s�vel., illetve olyan egyszerus�to feltev�seket, mint .a kiv�telek hib�kat
jelentenek..
Ezzel a hibakezelo k�dot szab�lyosabb� tehetj�k. L�sd m�g a �24.3.7.1 pontot, ahol
elmagyar
�zzuk, hogyan lehet �llapotbiztos�t�kat (invari�nsokat) �s feltev�seket haszn�lni,
hogy
a kiv�telek kiv�lt�sa szab�lyosabb legyen.
14.10. Szabv�nyos kiv�telek
A k�vetkezo t�bl�zat a szabv�nyos kiv�teleket �s az azokat kiv�lt� f�ggv�nyeket,
oper�torokat,
�ltal�nos eszk�z�ket mutatja be:
14. Kiv�telkezel�s 505
Szabv�nyos (a nyelvbe be�p�tett) kiv�telek
N�v Kiv�lt� Hivatkoz�s Fej�llom�ny
bad_alloc new �6.2.6.2, �19.4.5 <new>
bad_cast dynamic_cast �15.4.1.1 <typeinfo>
bad_typeid typeid �15.4.4 <typeinfo>
bad_exception kiv�tel_specifik�ci� �14.6.3 <exception>
A k�nyvt�ri kiv�telek a standard k�nyvt�r exception nevu . az <exception>
fej�llom�nyban
megadott . kiv�teloszt�lyb�l kiindul� oszt�lyhierarchia tagjai:
class exception {
public:
exception() throw();
exception(const exception&) throw();
exception& operator=(const exception&) throw();
virtual ~exception() throw();
virtual const char* what() const throw();
private:
// ...
};
A hierarchia �gy n�z ki:
506 Absztrakci�s m�dszerek
Szabv�nyos (a standard k�nyvt�r �ltal kiv�ltott) kiv�telek
N�v Ki dobja Hivatkoz�s Fej�llom�ny
out_of_range at() �16.3.3,�20.3.3 <stdexcept>
bitset<>::operator[ ]() �17.5.3 <stdexcept>
invalid_argument bitset konstruktor �17.5.3.1 <stdexcept>
overflow_error bitset<>::to_ulong() �17.5.3.3 <stdexcept>
ios_base::failure ios_base::clear() �21.3.6 <ios>
exception
logic_error runtime_error
lenght_error
domain_error
out_of_range
invalid_argument
ios_base::failure
range_error
bad_alloc
bad_exception
bad_cast
bad_typeid
overflow_error
underflow_error
Ez meglehetosen k�r�lm�nyesnek tunik ahhoz k�pest, hogy nyolc szabv�nyos kiv�telt
�lel
fel. Oka, hogy a hierarchia megpr�b�l a standard k�nyvt�rban meghat�rozott
kiv�teleken
k�v�li kiv�telek sz�m�ra is haszn�lhat� keretrendszert adni. A logikai hib�k
(logic error)
azok, amelyeket elvileg a program indul�sa elott, f�ggv�ny- vagy
konstruktorparam�terek
ellenorz�s�vel el lehetne kapni. A t�bbi fut�si ideju hiba (run-time error).
N�melyek ezt az
�sszes hiba �s kiv�tel sz�m�ra hasznos keretrendszernek l�tj�k . �n nem.
A standard k�nyvt�rbeli kiv�telek az exception �ltal meghat�rozott f�ggv�nyeket
nem bo-
v�tik �jakkal, csak megfeleloen defini�lj�k a megk�v�nt virtu�lis f�ggv�nyeket.
�gy az al�bbit
�rhatjuk:
void f()
try {
// a standard k�nyvt�r haszn�lata
}
catch (exception& e) {
cout << "standard k�nyvt�ri kiv�tel " << e.what() << '\n'; // tal�n
// ...
}
catch (...) {
cout << "m�sik kiv�tel\n";
// ...
}
A standard k�nyvt�rbeli kiv�telek az exception-bol sz�rmaznak, a t�bbi viszont nem
felt�tlen
�l, �gy hiba lenne az �sszes kiv�telt az exception elkap�s�val megpr�b�lni
lekezelni. Hasonl
�an hiba lenne felt�telezni, hogy az �sszes, az exception-bol sz�rmaz� kiv�tel
standard
k�nyvt�rbeli kiv�tel, a felhaszn�l�k ugyanis hozz�adhatj�k saj�t kiv�teleiket az
exception
hierarchi�hoz.
Jegyezz�k meg, hogy az expection-muveletek maguk nem v�ltanak ki kiv�telt. Ebbol
k�-
vetkezoen egy standard k�nyvt�rbeli kiv�tel kiv�lt�sa nem v�lt ki bad_alloc
kiv�telt. A kiv
�telkezelo rendszer fenntart a saj�t c�ljaira egy kis mem�ri�t (p�ld�ul a
veremben), hogy
ott t�rolhassa a kiv�teleket. Term�szetesen �rhatunk olyan k�dot, amely a rendszer
�sszes
mem�ri�j�t elfogyasztja �s �gy hib�t k�nyszer�t ki.
�me egy f�ggv�ny, amit ha megh�vunk, kipr�b�lja, hogy a f�ggv�nyh�v�sn�l vagy a
kiv�telkezel
�sn�l fogy-e ki elosz�r a mem�ria:
void perverted()
{
try {
throw exception(); // ism�tlodo kiv�tel
}
14. Kiv�telkezel�s 507
catch (exception& e) {
perverted(); // ism�tlodo f�ggv�nyh�v�s
cout << e.what();
}
}
A kimeneti utas�t�s egyed�l azt a c�lt szolg�lja, hogy megakad�lyozza a
ford�t�programot
az e nevu kiv�tel �ltal felhaszn�lt mem�ria �jrahasznos�t�s�ban.
14.11. Tan�csok
[1] Hibakezel�sre haszn�ljunk kiv�teleket. �14.1, �14.5, �14.9.
[2] Ne haszn�ljunk kiv�teleket, ha a helyi vez�rl�si szerkezetek el�gs�gesek.
�14.1.
[3] Az eroforr�sok kezel�s�re a .kezdeti �rt�kad�s az eroforr�s megszerz�s�vel.
m�dszert haszn�ljuk. �14.4.
[4] Nem minden programnak kell .kiv�telbiztosnak. lennie. �14.4.3.
[5] Az invari�nsok �rv�nyess�g�nek megorz�s�re haszn�ljuk a .kezdeti �rt�kad�s
az eroforr�s megszerz�s�vel. m�dszert �s a kiv�telkezeloket. �14.3.2.
[6] Min�l kevesebb try blokkot haszn�ljunk. Meghat�rozott kezelok�d helyett
a .kezdeti �rt�kad�s az eroforr�s megszerz�s�vel. m�dszert haszn�ljuk. �14.4.
[7] Nem minden f�ggv�nynek kell minden lehets�ges hib�t kezelnie. �14.9.
[8] A konstruktorhib�k jelz�s�re v�ltsunk ki kiv�telt. �14.9.
[9] Ha egy �rt�kad�s v�lt ki kiv�telt, elotte gondoskodjon param�tereinek
k�vetkezetes
�llapotba hoz�s�r�l. �14.4.6.2.
[10] A destruktorokban ker�lj�k a kiv�telek kiv�lt�s�t. �14.4.7.
[11] A main() f�ggv�ny kapja el �s jelentse az �sszes hib�t. �14.7.
[12] K�l�n�ts�k el a k�z�ns�ges k�dot a hibakezel�stol. �14.4.5 �s �14.5.
[13] Gondoskodjunk arr�l, hogy egy konstruktorban minden lefoglalt eroforr�st
felszabad
�tsunk, ha a konstruktor kiv�telt v�lt ki. �14.4.
[14] Az eroforr�sok kezel�se hierarchikus legyen. �14.4.
[15] A fobb fel�letekben hat�rozzuk meg az enged�lyezett kiv�teleket. �14.9.
[16] Legy�nk r�sen, nehogy a new �ltal lefoglalt �s a kiv�telek fell�pte eset�n
fel
nem szabad�tott mem�ria elsziv�rogjon. �14.4.1, �14.4.2, �14.4.4.
[17] A f�ggv�nyekrol t�telezz�k fel, hogy minden kiv�telt kiv�lthatnak, amit
megengedtek
nekik. �14.6.
[18] Ne t�telezz�k fel, hogy minden kiv�tel az exception oszt�ly lesz�rmazottja.
�14.10.
[19] Egy k�nyvt�r ne fejezze be egyoldal�an a program fut�s�t. Ehelyett v�ltson ki

kiv�telt �s hadd d�nts�n a h�v�. �14.1.


508 Absztrakci�s m�dszerek
[20] Egy k�nyvt�r ne bocs�sson ki a v�gfelhaszn�l�nak sz�nt diagnosztikai
�zeneteket.
Ehelyett v�ltson ki kiv�telt �s hadd d�nts�n a h�v�. �14.1.
[21] A tervez�s sor�n min�l hamarabb alak�tsuk ki a hibakezel�si strat�gi�t. �14.9

14.12. Gyakorlatok
1. (*2) �ltal�nos�tsuk a �14.6.3.1 pontbeli STC oszt�lyt sablonn�, amely a
.kezdeti
�rt�kad�s az eroforr�s megszerz�s�vel. m�dszert haszn�lja k�l�nf�le t�pus�
f�ggv�nyek t�rol�s�ra �s vissza�ll�t�s�ra.
2. (*3) Eg�sz�ts�k ki a �11.11 pontbeli Ptr_to_T oszt�lyt mint egy olyan sablont,
amely kiv�telekkel jelzi a fut�si ideju hib�kat.
3. (*3) �rjunk f�ggv�nyt, amely egy bin�ris fa cs�csaiban keres egy char* t�pus�
mezo alapj�n. A hello-t tartalmaz� cs�cs megtal�l�sakor a find(.hello.) a cs�csra
hivatkoz� mutat�val t�rjen vissza; a keres�s sikertelens�g�t kiv�tellel jelezz�k.
4. (*3.) Hozzunk l�tre egy Int oszt�lyt, amely pontosan �gy viselkedik, mint az
elemi int t�pus, csak t�l- �s alulcsordul�s eset�n kiv�telt v�lt ki.
5. (*2.5) Vegy�k a felhaszn�lt oper�ci�s rendszer C fel�let�nek �llom�nyok megnyit
�s�ra, lez�r�s�ra, olvas�s�ra, �r�s�ra val� alapveto muveleteit, �s �rjunk hozz
�juk egyen�rt�ku C++ f�ggv�nyeket, amelyek a megfelelo C f�ggv�nyeket h�vj
�k meg, de hiba eset�n kiv�telt v�ltanak ki.
6. (*2.5) �rjunk egy teljes Vector sablont Range �s Size kiv�telekkel.
7. (*1) �rjunk egy ciklust, ami kisz�m�tja a �14.12[6]-beli Vector �sszeg�t a
Vector
m�ret�nek lek�rdez�se n�lk�l. Ez mi�rt nem j� �tlet?
8. (*2.5) Gondoljuk meg, mi lenne, ha egy Exception oszt�lyt haszn�ln�nk az
�sszes kiv�telk�nt haszn�lt oszt�ly osek�nt (b�zisoszt�lyak�nt). Hogyan n�zne
ki? Hogyan lehetne haszn�lni? Mire lenne j�? Milyen h�tr�nyok sz�rmazn�nak
abb�l a megk�t�sbol, hogy ezt az oszt�lyt kell haszn�lni?
9. (*1) Adott a k�vetkezo f�ggv�ny:
int main() { /* ... */ }
V�ltoztassuk meg �gy, hogy minden kiv�telt elkapjon, hiba�zenett� alak�tsa
azokat, majd megh�vja az abort()-ot. Vigy�zat: a �14.9 pontbeli call_from_C()
f�ggv�ny nem teljesen kezel minden esetet.
10. (*2) �rjunk visszah�v�sok (callback) megval�s�t�s�ra alkalmas oszt�lyt vagy
sablont.
11. (*2.5) �rjunk egy Lock oszt�lyt, amely valamely rendszer sz�m�ra a konkurens
hozz�f�r�st t�mogatja.
14. Kiv�telkezel�s 509
Oszt�lyhierarchi�k
.Az absztrakci� szelekt�v tudatlans�g..
(Andrew Koenig)
T�bbsz�r�s �r�klod�s . A t�bb�rtelmus�g felold�sa . �r�klod�s �s using deklar�ci-
�k . Ism�tlodo b�zisoszt�lyok . Virtu�lis b�zisoszt�lyok . A t�bbsz�r�s �r�klod�s
haszn�-
lata . Hozz�f�r�s-szab�lyoz�s . V�dett tagok . B�zisoszt�lyok el�r�se . Fut�si
ideju t�pusinform
�ci� . dynamic_cast . Statikus �s dinamikus konverzi� . typeid . Kiterjesztett
t�pusinform
�ci� . A fut�si ideju t�pusinform�ci� helyes �s helytelen haszn�lata . Tagra
hivatkoz
� mutat�k . Szabad t�r . .Virtu�lis konstruktorok. . Tan�csok . Gyakorlatok
15.1. Bevezet�s �s �ttekint�s
Ez a fejezet a sz�rmaztatott oszt�lyoknak �s a virtu�lis f�ggv�nyeknek a m�s
nyelvi elemekkel,
p�ld�ul a hozz�f�r�s-szab�lyoz�ssal, a n�vfelold�ssal, a szabad t�r kezel�s�vel,
a konstruktorokkal, a mutat�kkal �s a t�puskonverzi�kkal val� k�lcs�nhat�s�t
t�rgyalja. �t
fo r�szbol �ll:
�15.2 T�bbsz�r�s �r�klod�s
�15.3 Hozz�f�r�s-szab�lyoz�s
15
�15.4 Fut�si ideju t�pusazonos�t�s
�15.5 Tagokra hivatkoz� mutat�k
�15.6 A szabad t�r haszn�lata
Az oszt�lyokat �ltal�ban b�zisoszt�lyok .h�l�j�b�l. hozzuk l�tre. Mivel a legt�bb
ilyen h�-
l� hagyom�nyosan fa szerkezetu, az oszt�lyokb�l �ll� h�l�kat vagy oszt�lyh�l�kat
(class
lattice) gyakran nevezik oszt�lyhierarchi�nak (class hierarchy) is. Az oszt�lyokat
c�lszeru
�gy megtervezni, hogy a felhaszn�l�knak ne kelljen indokolatlan m�rt�kben azzal
t�rodni-
�k, hogy egy oszt�ly milyen m�don �p�l fel m�s oszt�lyokb�l. �gy p�ld�ul a
virtu�lis f�ggv
�nyek megh�v�si m�dja biztos�tja, hogy ha egy f() f�ggv�nyt megh�vunk egy
objektumra,
akkor mindig ugyanaz a f�ggv�ny hajt�dik v�gre, f�ggetlen�l att�l, hogy a
hierarchia melyik
oszt�lya deklar�lta a f�ggv�nyt a megh�v�shoz. Ez a fejezet az oszt�lyh�l�k
�ssze�ll�t�-
s�nak �s az oszt�lytagok el�r�s�nek m�djair�l, illetve az oszt�lyh�l�k ford�t�si
�s fut�si idej
u bej�r�s�nak eszk�zeirol sz�l.
15.2. T�bbsz�r�s �r�klod�s
Ahogy a �2.5.4 �s �12.3 pontokban l�ttuk, egy oszt�lynak t�bb k�zvetlen
b�zisoszt�lya is lehet,
azaz t�bb oszt�lyt is megadhatunk a : jel ut�n az oszt�ly deklar�ci�j�ban. Vegy�nk
egy
szimul�ci�s programot, ahol a p�rhuzamos tev�kenys�geket a Task (Feladat)
oszt�llyal, az
adatgyujt�st �s -megjelen�t�st pedig a Displayed (Megjelen�t�s) oszt�llyal
�br�zoljuk. Ekkor
olyan szimul�lt egyedeket hat�rozhatunk meg, mint a Satellite (Muhold):
class Satellite : public Task, public Displayed {
// ...
};
T�bb k�zvetlen b�zisoszt�ly haszn�lat�t szok�s szerint t�bbsz�r�s �r�klod�snek
(multiple
inheritance) nevezik. Az egyszeres �r�klod�sn�l (single inheritance) csak egy
k�zvetlen
b�zisoszt�ly van.
A Satellite-okra saj�t muveleteiken k�v�l a Task-ok �s Displayed-ek muveleteinek
uni�ja is
alkalmazhat�:
void f(Satellite& s)
{
s.draw(); // Displayed::draw()
s.delay(10); // Task::delay()
s.transmit(); // Satellite::transmit()
}
512 Absztrakci�s m�dszerek
Hasonl�an, ha egy f�ggv�ny Task vagy Displayed param�tert v�r, akkor adhatunk neki
egy
Satellite-ot is:
void highlight(Displayed*);
void suspend(Task*);
void g(Satellite* p)
{
highlight(p); // mutat� �tad�sa a Satellite Displayed r�sz�re
suspend(p); // mutat� �tad�sa a Satellite Task r�sz�re
}
A program l�trehoz�sa nyilv�n valamilyen egyszeru elj�r�s alkalmaz�s�t k�veteli
meg a ford
�t�programt�l, hogy a Task-ot v�r� f�ggv�nyek m�s r�sz�t l�ss�k egy Satellite-nak,
mint
a Displayed-et v�r�k. A virtu�lis f�ggv�nyek a megszokott m�don muk�dnek:
class Task {
// ...
virtual void pending() = 0;
};
class Displayed {
// ...
virtual void draw() = 0;
};
class Satellite : public Task, public Displayed {
// ...
void pending(); // fel�l�rja a Task::pending() f�ggv�nyt
void draw(); // fel�l�rja a Displayed::draw() f�ggv�nyt
};
Ez biztos�tja, hogy Satellite::draw(), illetve Satellite::pending() fog
megh�v�dni, ha egy
Satellite-ot Displayed-k�nt, illetve Task-k�nt kezel�nk.
Jegyezz�k meg, hogy ha csak egyszeres �r�klod�st haszn�lhatn�nk, akkor ez a
k�r�lm�ny
korl�tozn� a programoz�t a Satellite, Displayed �s Task oszt�lyok megval�s�t�s�nak
megv�-
laszt�s�ban. Egy Satellite vagy Task, vagy Displayed lehetne, de nem mindketto
(hacsak
a Task nem a Displayed-bol sz�rmazik vagy ford�tva). Ezen lehetos�gek mindegyike
cs�kkenti
a rugalmass�got.
Mi sz�ks�ge lehet b�rkinek egy Satellite oszt�lyra? Nos, b�rmilyen meglepo, a
Satellite p�ld
�t a val�s�gb�l mer�tett�k. Volt . �s tal�n m�g mindig van . egy olyan program,
amely
a t�bbsz�r�s �r�klod�s le�r�s�ra itt haszn�lt minta szerint �p�lt fel. A program
muholdakat,
15. Oszt�lyhierarchi�k 513
f�ldi �llom�sokat stb. mag�ba foglal� h�rk�zl�si rendszerek szerkezet�nek
tanulm�nyoz�-
s�ra szolg�lt. Egy ilyen szimul�ci� birtok�ban meg tudjuk v�laszolni a forgalmi
adatokra vonatkoz
� k�rd�seket, meg tudjuk hat�rozni, mi t�rt�nik, ha egy f�ldi �llom�st vihar
akad�-
lyoz, muholdas �s f�ldi kapcsolatok elonyeit-h�tr�nyait tudjuk elemezni stb. A
k�l�nb�zo
k�r�lm�nyek ut�nz�sa sz�mos megjelen�t�si �s hibakeres�si muveletet ig�nyel, �s
sz�ks�g
van a Satellite-okhoz hasonl� objektumok, illetve r�szegys�geik �llapot�nak
t�rol�s�ra is,
az elemz�s, illetve a hibakeres�s �s -elh�r�t�s c�lj�b�l.
15.2.1. A t�bb�rtelmus�g felold�sa
K�t b�zisoszt�lynak lehetnek azonos nevu tagf�ggv�nyei is:
class Task {
// ...
virtual debug_info* get_debug();
};
class Displayed {
// ...
virtual debug_info* get_debug();
};
Ha egy Satellite-ot haszn�lunk, akkor ezeket a f�ggv�nyeket egy�rtelmuen kell
megnevezn
�nk:
void f(Satellite* sp)
{
debug_info* dip = sp->get_debug(); // hiba: t�bb�rtelmu
dip = sp->Task::get_debug(); // rendben
dip = sp->Displayed::get_debug(); // rendben
}
Az explicit megnevez�s azonban zavar�, ez�rt �ltal�ban legjobb elker�lni az ilyen
probl�m�-
kat. Ennek legegyszerubb m�dja, ha a sz�rmaztatott oszt�lyban k�sz�t�nk egy �j
f�ggv�nyt:
class Satellite : public Task, public Displayed {
// ...
debug_info* get_debug() // fel�l�rja a Task::get_debug() �s
// Displayed::get_debug() f�ggv�nyeket
{
514 Absztrakci�s m�dszerek
debug_info* dip1 = Task::get_debug();
debug_info* dip2 = Displayed::get_debug();
return dip1->merge(dip2);
}
};
Ez�ltal a Satellite b�zisoszt�lyaira vonatkoz� inform�ci�k felhaszn�l�s�t helyhez
k�t�tt�k.
Mivel a Satellite::get_debug() elfedi mindk�t b�zisoszt�ly�nak get_debug()
f�ggv�ny�t,
a Satellite::get_debug() h�v�dik meg, valah�nyszor get_debug()-ot h�vunk meg egy
Satellite
objektumra.
A Telstar::draw minos�tett n�v a Telstar-ban vagy valamelyik b�zisoszt�ly�ban
megadott
draw-ra vonatkozhat:
class Telstar : public Satellite {
// ...
void draw()
{
draw(); // hopp�!: rekurz�v h�v�s
Satellite::draw(); // megtal�lja a Displayed::draw-t
Displayed::draw();
Satellite::Displayed::draw(); // felesleges k�tszeri minos�t�s
}
};
Vagyis ha a Satellite::draw nem a Satellite oszt�lyban bevezetett draw-t jelenti,
akkor a ford
�t�program v�gign�zi a b�zisoszt�lyokat, vagyis Task::draw-t �s Displayed::draw-t
keres.
Ha csak egyet tal�l, akkor azt fogja haszn�lni, ha t�bbet vagy egyet sem, a
Satellite::draw
ismeretlen vagy t�bb�rtelmu lesz.
15.2.2. �r�klod�s �s using deklar�ci�k
A t�lterhel�s felold�s�ra nem ker�l sor k�l�nb�zo oszt�lyok hat�k�r�n kereszt�l
(�7.4),
a k�l�nb�zo b�zisoszt�lyok f�ggv�nyei k�z�tti t�bb�rtelmus�gek felold�sa pedig nem
t�rt
�nik meg a param�tert�pus alapj�n.
Egym�ssal alapvetoen nem rokon oszt�lyok egyes�t�sekor, p�ld�ul a Task �s
Displayed oszt
�lyok Satellite-t� val� .�sszegy�r�s�n�l. az elnevez�sekben megmutatkoz�
hasonl�s�g �ltal
�ban nem jelent k�z�s c�lt. Amikor az ilyen nevek �tk�znek, ez gyakran
meglepet�sk�nt
�ri a felhaszn�l�t:
15. Oszt�lyhierarchi�k 515
class Task {
// ...
void debug(double p); // inform�ci� ki�r�sa csak akkor, ha a priorit�s
// alacsonyabb p-n�l
};
class Displayed {
// ...
void debug(int v); // min�l nagyobb 'v,' ann�l t�bb hibakeres�si inform�ci� �r�dik
ki
};
class Satellite : public Task, public Displayed {
// ...
};
void g(Satellite* p)
{
p->debug(1); // hiba, t�bb�rtelmu: Displayed::debug(int) vagy
// Task::debug(double) ?
p->Task::debug(1); // rendben
p->Displayed::debug(1); // rendben
}
De mi van akkor, ha a k�l�nb�zo b�zisoszt�lyokban tudatos tervez�si d�nt�s
k�vetkezt�-
ben szerepelnek azonos nevek, �s a felhaszn�l� sz�m�ra k�v�natos lenne a
param�tert�pus
alapj�n v�lasztani k�z�l�k? Ebben az esetben a f�ggv�nyeket a using deklar�ci�val
(�8.2.2)
hozhatjuk k�z�s hat�k�rbe:
class A {
public:
int f(int);
char f(char);
// ...
};
class B {
public:
double f(double);
// ...
};
class AB: public A, public B {
public:
using A::f;
using B::f;
char f(char); // elfedi A::f(char)-t
AB f(AB);
};
516 Absztrakci�s m�dszerek
void g(AB& ab)
{
ab.f(1); // A::f(int)
ab.f('a'); // AB::f(char)
ab.f(2.0); // B::f(double)
ab.f(ab); // AB::f(AB)
}
A using deklar�ci�k lehetov� teszik, hogy a b�zis- �s sz�rmaztatott oszt�lyok
f�ggv�nyeib
ol t�lterhelt f�ggv�nyek halmaz�t �ll�tsuk elo. A sz�rmaztatott oszt�lyban
megadott f�ggv
�nyek elfedik (hide) a b�zisoszt�ly f�ggv�nyeit, amelyek egy�bk�nt el�rhetoek
lenn�nek.
A b�zisoszt�ly virtu�lis f�ggv�nyei ugyan�gy fel�l�rhat�k (override), mint
egy�bk�nt
(�15.2.3.1).
Egy oszt�lydeklar�ci� using deklar�ci�j�nak (�8.2.2) egy b�zisoszt�ly tagj�ra kell
vonatkoznia.
Egy oszt�ly tagj�ra vonatkoz� using deklar�ci� nem szerepelhet az oszt�lyon, annak

sz�rmaztatott oszt�ly�n, illetve annak tagf�ggv�nyein k�v�l, a using direkt�v�k


(�8.2.3) pedig
nem szerepelhetnek egy oszt�ly definici�j�ban �s nem vonatkozhatnak oszt�lyra.
A using deklar�ci�k nem szolg�lhatnak kieg�sz�to inform�ci� el�r�s�re sem, csak az
egy�bk
�nt is hozz�f�rheto inform�ci�k k�nyelmesebb haszn�lat�t teszik lehetov�
(�15.3.2.2).
15.2.3. Ism�tlodo b�zisoszt�lyok
Az�ltal, hogy t�bb b�zisoszt�ly lehet, elofordulhat, hogy egy oszt�ly k�tszer
fordul elo a
b�zisoszt�lyok k�z�tt. P�ld�ul ha mind a Task, mind a Displayed a Link (Kapcsolat)
oszt�lyb
�l sz�rmazott volna, a Satellite-oknak k�t Link-je lenne:
struct Link {
Link* next;
};
class Task : public Link {
// a Link-et a Task-ok list�j�hoz (az �temezo list�hoz) haszn�ljuk
// ...
};
class Displayed : public Link {
// a Link-et a Displayed objektumok list�j�hoz (a megjelen�t�si list�hoz)
haszn�ljuk
// ...
};
15. Oszt�lyhierarchi�k 517
Ez nem gond. K�t k�l�n Link objektum szolg�l a list�k �br�zol�s�ra �s a k�t lista
nem zavarja
egym�st. Term�szetesen a Link oszt�ly tagjaira nem hivatkozhatunk a k�t�rtelmus�g
vesz�lye n�lk�l (�15.2.3.1). Egy Satellite objektumot �gy rajzolhatunk le:
Ha a k�z�s b�zisoszt�lyt nem szabad k�t k�l�n objektummal �br�zolni, virtu�lis
b�zisoszt
�lyokat (�15.2.4) alkalmazhatunk.
A Link-hez hasonl�an t�bbsz�r szereplo b�zisoszt�lyok olyan elemek, amelyeket nem
szabad
a k�zvetlen�l �r�klo oszt�lyon k�v�l haszn�lni. Ha egy ilyen oszt�lyra olyan
pontr�l
kell hivatkozni, ahonn�t annak t�bb p�ld�nya is l�that�, a t�bb�rtelmus�g
elker�l�se �rdek
�ben a hivatkoz�st minos�teni kell:
void mess_with_links(Satellite* p)
{
p->next = 0; // hiba: t�bb�rtelmu (melyik Link?)
p->Link::next = 0; // hiba: t�bb�rtelmu (melyik Link?)
p->Task::Link::next = 0; // rendben
p->Displayed::Link::next = 0; // rendben
// ...
}
Ez pontosan ugyanaz az elj�r�s, mint amit a tagokra val� t�bb�rtelmu hivatkoz�sok
felold
�s�ra haszn�lunk (�15.2.1).
15.2.3.1. Fel�l�r�s
A t�bbsz�r szereplo b�zisoszt�lyok valamely virtu�lis f�ggv�ny�t a sz�rmaztatott
oszt�ly
(egyetlen) f�ggv�nye fel�l�rhatja (fel�lb�r�lhatja, override). Egy objektumnak
saj�t mag�t
egy f�jlb�l kiolvasni vagy oda vissza�rni val� k�pess�g�t p�ld�ul �gy
�br�zolhatjuk:
class Storable {
public:
virtual const char* get_file() = 0;
virtual void read() = 0;
518 Absztrakci�s m�dszerek
Link Link
Task Displayed
Satellite
virtual void write() = 0;
virtual ~Storable() { }
};
Term�szetesen t�bb felhaszn�l� �p�thet erre, hogy olyan oszt�lyokat �rjon, amelyek
f�ggetlen
�l vagy egy�tt haszn�lva jobban kidolgozott oszt�lyokat adnak. P�ld�ul
le�ll�thatunk �s
�jraind�thatunk egy szimul�ci�t, ha mentj�k az alkot�elemeket �s k�sobb
vissza�ll�tjuk azokat.
Ezt az �tletet �gy val�s�thatjuk meg:
class Transmitter : public Storable {
public:
void write();
// ...
};
class Receiver : public Storable {
public:
void write();
// ...
};
class Radio : public Transmitter, public Receiver {
public:
const char* get_file();
void read();
void write();
// ...
};
A fel�l�r� f�ggv�ny �ltal�ban megh�vja a b�zisoszt�lybeli v�ltozatokat �s a
sz�rmaztatott
oszt�lyra jellemzo tennival�kat v�gzi el:
void Radio::write()
{
Transmitter::write();
Receiver::write();
// ki�rja a Radio-ra jellemzo adatokat
}
Az ism�tlodo b�zisoszt�lyokr�l sz�rmaztatott oszt�lyokra val� t�puskonverzi�t a
�15.4.2
pont �rja le. Arr�l, hogyan lehet az egyes write() f�ggv�nyeket a sz�rmaztatott
oszt�lyok k�-
l�n f�ggv�nyeivel fel�l�rni, a �25.6 pont sz�l.
15. Oszt�lyhierarchi�k 519
15.2.4. Virtu�lis b�zisoszt�lyok
Az elozo pont Radio p�ld�ja az�rt muk�dik, mert a Storable oszt�lyt biztons�gosan,
k�nyelmesen
�s hat�konyan lehet t�bbsz�r�zni. Ez azonban az olyan oszt�lyok eset�ben
rendszerint
nem igaz, amelyek j� �p�tok�vei m�s oszt�lyoknak. A Storable oszt�lyt p�ld�ul �gy
is
meghat�rozhatn�nk, mint ami tartalmazza az objektum ment�s�re haszn�lt f�jl nev�t:

class Storable {
public:
Storable(const char* s);
virtual void read() = 0;
virtual void write() = 0;
virtual ~Storable();
private:
const char* store;
Storable(const Storable&);
Storable& operator=(const Storable&);
};
A Storable ezen l�tsz�lag csek�ly m�dos�t�sa ut�n meg kell v�ltoztatnunk a Radio
szerkezet
�t is. Az objektum �sszes r�sze a Storable azonos p�ld�ny�n kell, hogy osztozz�k;
k�l�nben
sz�ks�gtelen�l neh�z feladat lenne az objektum t�bbsz�ri t�rol�s�nak
megakad�lyoz�-
sa. A virtu�lis b�zisoszt�lyok (virtual base class) ezt a megoszt�st seg�tik. A
sz�rmaztatott
oszt�ly minden virtu�lis b�zisoszt�ly�t ugyanaz a (megosztott) objektum �br�zolja:

class Transmitter : public virtual Storable {


public:
void write();
// ...
};
class Receiver : public virtual Storable {
public:
void write();
// ...
};
class Radio : public Transmitter, public Receiver {
public:
void write();
// ...
};
520 Absztrakci�s m�dszerek
�br�val:
Hasonl�tsuk �ssze ezt az �br�t a Satellite objektum �15.2.3-beli rajz�val, hogy
l�ssuk a k�-
l�nbs�get a k�z�ns�ges �s a virtu�lis �r�klod�s k�z�tt. Az �r�klod�si gr�fban egy
adott nev
u oszt�ly minden virtu�lisk�nt megadott b�zisoszt�ly�t az oszt�ly egyetlen
objektuma �br
�zolja, a nem virtu�lis b�zisoszt�lyokat viszont saj�t r�szobjektumuk.
15.2.4.1. Virtu�lis b�zisoszt�lyok programoz�sa
Amikor a programoz� f�ggv�nyeket k�sz�t egy olyan oszt�ly sz�m�ra, amelynek
virtu�lis
b�zisoszt�lya van, nem tudhatja, hogy a b�zisoszt�lyt meg kell-e osztani egy�b
sz�rmaztatott
oszt�lyokkal, ami gondot jelenthet, ha egy szolg�ltat�st �gy kell megval�s�tani,
hogy a
b�zisoszt�ly egy adott f�ggv�ny�nek megh�v�s�ra pontosan egyszer ker�lj�n sor,
p�ld�ul
mert a nyelv elo�rja, hogy egy virtu�lis b�zisoszt�ly konstruktora csak egyszer
futhat le.
A virtu�lis b�zisoszt�ly konstruktor�t a teljes objektum, azaz a legt�volabbi
sz�rmaztatott
oszt�ly konstruktora h�vja meg (automatikusan vagy k�zvetlen�l):
class A { // nincs konstruktor
// ...
};
class B {
public:
B(); // alap�rtelmezett konstruktor
// ...
};
class C {
public:
C(int); // nincs alap�rtelmezett konstruktor
};
15. Oszt�lyhierarchi�k 521
Storable
Receiver Transmitter
Radio
class D : virtual public A, virtual public B, virtual public C
{
D() { /* ... */ } // hiba: C-nek nincs alap�rtelmezett konstruktora
D(int i) : C(i) { /* ... */ }; // rendben
// ...
};
A virtu�lis b�zisoszt�ly konstruktora a sz�rmaztatott oszt�lyok konstruktora elott
h�v�dik
meg. Sz�ks�g eset�n a programoz� ezt a muk�d�st ut�nozhatja is, ha a virtu�lis
b�zisoszt
�ly f�ggv�ny�t csak a legt�volabbi sz�rmaztatott oszt�lyb�l h�vja meg. Tegy�k fel,
hogy
van egy alapveto Window oszt�lyunk, amely ki tudja rajzolni tartalm�t:
class Window {
// alapk�d
virtual void draw();
};
Az ablakokat emellett t�bbf�le m�don d�sz�thetj�k �s szolg�ltat�sokkal
eg�sz�thetj�k ki:
class Window_with_border : public virtual Window {
// a szeg�ly k�dja
void own_draw(); // a szeg�ly megjelen�t�se
void draw();
};
class Window_with_menu : public virtual Window {
// a men� k�dja
void own_draw(); // a men� megjelen�t�se
void draw();
};
Az own_draw() f�ggv�nyeknek nem kell virtu�lisaknak lenni�k, mert egy virtu�lis
draw()
f�ggv�nybol akarjuk megh�vni azokat, ami pontosan ismeri az objektum t�pus�t,
amelyre
megh�vt�k.
Ebbol egy muk�dok�pes Clock oszt�lyt �ll�thatunk �ssze:
class Clock : public Window_with_border, public Window_with_menu {
// az �ra k�dja
void own_draw(); // az �ralap �s a mutat�k megjelen�t�se
void draw();
};
522 Absztrakci�s m�dszerek
�br�val:
A draw() f�ggv�nyeket most m�r �gy �rhatjuk meg az own_draw() f�ggv�nyek
felhaszn�l�-
s�val, hogy b�rmelyik draw() megh�v�sa pontosan egyszer h�vja meg a
Window::draw()-t,
f�ggetlen�l att�l, milyen fajta Window-ra h�vt�k meg:
void Window_with_border::draw()
{
Window::draw();
own_draw(); // a szeg�ly megjelen�t�se
}
void Window_with_menu::draw()
{
Window::draw();
own_draw(); // a men� megjelen�t�se
}
void Clock::draw()
{
Window::draw();
Window_with_border::own_draw();
Window_with_menu::own_draw();
own_draw(); // az �ralap �s a mutat�k megjelen�t�se
}
A virtu�lis b�zisoszt�lyokr�l sz�rmaztatott oszt�lyokra val� konverzi�t a �15.4.2
pont �rja le.
15.2.5. A t�bbsz�r�s �r�klod�s haszn�lata
A t�bbsz�r�s �r�klod�s legegyszerubb �s legnyilv�nval�bb felhaszn�l�sa k�t
egy�bk�nt
egym�ssal rokons�gban nem �ll� oszt�ly .�sszeragaszt�sa. egy harmadik oszt�ly
r�szek�nt.
A Task �s Displayed oszt�lyokb�l a �15.2 pontban �sszerakott Satellite oszt�ly is
ilyen.
15. Oszt�lyhierarchi�k 523
Window
Window_with_border Window_with_menu
Clock
A t�bbsz�r�s �r�klod�s ilyen m�don val� haszn�lata egyszeru, hat�kony �s fontos .
de nem
t�l �rdekes, hiszen alapj�ban v�ve csak a tov�bb�t� f�ggv�nyek meg�r�s�t�l k�m�li
meg
a programoz�t. Az elj�r�s nem befoly�solja sz�mottevoen a program �ltal�nos
szerkezet�t �s
alkalmasint �tk�zhet azzal a k�v�nalommal, hogy a megval�s�t�s r�szletei
maradjanak rejtve.
Egy m�dszernek azonban nem kell .okosnak. lennie ahhoz, hogy hasznos legyen.
A t�bbsz�r�s �r�klod�s haszn�lata absztrakt oszt�lyok k�sz�t�s�re m�r nagyobb
jelentos�-
gu, annyiban, hogy befoly�solja a program tervez�s�nek m�dj�t. A �12.4.3-beli
BB_ival_slider oszt�ly egy p�lda erre:
class BB_ival_slider
: public Ival_slider // fel�let
, protected BBslider // megval�s�t�s
{
// az 'Ival_slider' �s a 'BBslider' �ltal ig�nyelt f�ggv�nyek megval�s�t�sa
// a 'BBslider' szolg�ltat�sainak haszn�lata
};
Ebben a p�ld�ban a k�t b�zisoszt�ly logikailag k�l�nb�zo szerepet j�tszik. Az
egyik egy
nyilv�nos absztrakt oszt�ly, amely a fel�letet ny�jtja, a m�sik pedig egy v�dett
(protected)
konkr�t oszt�ly, amely a megval�s�t�sr�l gondoskodik. A k�tf�le szerep az
oszt�lyok st�lus
�ban �s az alkalmazott hozz�f�r�si szab�lyokban t�kr�zodik. A t�bbsz�r�s �r�klod�s
szerepe
itt l�nyegbev�g�, mert a sz�rmaztatott oszt�lynak mind a fel�let, mind a
megval�s�t�s
virtu�lis f�ggv�nyeit fel�l kell �rnia.
A t�bbsz�r�s �r�klod�s lehetov� teszi a testv�roszt�lyok sz�m�ra, hogy egyetlen
k�z�s os
jelentette f�gg�s bevezet�se n�lk�l osztozhassanak adatokon. Ez az eset, amikor az
�gynevezett
k�r� alak� �r�klod�s (diamond-shaped inheritance) l�p fel. (L�sd a Radio (�15.2.4)

�s a Clock (�15.2.4.1) p�ld�kat.) Ha a b�zisoszt�ly nem ism�telheto, akkor


virtu�lis (�s nem
k�z�ns�ges) b�zisoszt�lyra van sz�ks�g.
Az �n v�lem�nyem az, hogy a k�r� alak� �r�kl�si h�l� akkor kezelheto a legjobban,
ha
vagy a virtu�lis b�zisoszt�ly vagy a belole k�zvetlen�l sz�rmaz� oszt�lyok
absztraktak. Vegy
�k p�ld�ul �jra a �12.4 pont Ival_box oszt�lyait. Ott v�g�l az �sszes Ival_box
oszt�lyt
absztraktt� tett�k, hogy kifejezz�k szerep�ket, vagyis hogy kiz�r�lag fel�letek.
Ez lehetov�
tette, hogy a l�nyegi programk�d minden r�sz�t a megfelelo megval�s�t� oszt�lyokba
rejts
�k, �s az egyes r�szeken val� osztoz�s is csak a megval�s�t�s c�lj�ra haszn�lt
ablakoz�
rendszer klasszikus hierarchi�j�ban t�rt�nt.
Persze lenne �rtelme annak, hogy a Popup_ival_slider-t megval�s�t� oszt�ly nagy
r�sze k�-
z�s legyen a sima Ival_slider-t megval�s�t� oszt�ly�val, �gy az adatbek�ro mezok
kezel�s�n
524 Absztrakci�s m�dszerek
k�v�l azonosak lenn�nek. Ekkor az is term�szetes lenne, hogy az elo�ll� cs�szka-
oszt�lyban
elker�lj�k az Ival_slider objektumok ism�tlod�s�t. Ehhez az Ival_slider-t
virtu�liss�
tessz�k:
class BB_ival_slider : public virtual Ival_slider, protected BBslider { /* ...
*/ };
class Popup_ival_slider : public virtual Ival_slider { /* ... */ };
class BB_popup_ival_slider
: public virtual Popup_ival_slider, protected BB_ival_slider { /* ... */ };
�br�val:
K�nnyen elk�pzelhetj�k a Popup_ival_slider-bol sz�rmaz� tov�bbi fel�leteket �s az
azokb
�l �s a BB_popup_ival_slider-bol sz�rmaz� tov�bbi megval�s�t� oszt�lyokat.
Ha az �tletet v�gigvissz�k, akkor a program fel�let�t k�pezo absztrakt
oszt�lyokb�l val� minden
sz�rmaztat�st virtu�liss� tesz�nk. Ez val�ban a leglogikusabb, leg�ltal�nosabb, �s
legrugalmasabb
megold�snak tunik. Hogy mi�rt nem tettem ezt, annak egyr�szt a hagyom�nyok
figyelembe v�tele az oka, m�sr�szt a virtu�lis b�zisoszt�lyok megval�s�t�s�nak
legnyilv�nval
�bb �s leggyakoribb m�dszerei annyira hely- �s idoig�nyesek, hogy kiterjedt
haszn�latuk
egy oszt�lyon bel�l nem vonz�. Mielott ez a t�rig�nyben �s fut�si idoben m�rt
k�lts�g visszariasztana
benn�nket egy m�s szemsz�gbol vonz� szerkezet v�laszt�s�t�l, gondoljuk meg,
hogy az Ival_box-ot �br�zol� objektum �ltal�ban csak egy mutat�t tartalmaz a
virtu�lis
t�bl�ra. Ahogy a �15.2.4 pontban l�ttuk, egy v�ltoz�kat nem tartalmaz� absztrakt
oszt�ly vesz
�ly n�lk�l ism�telheto. �gy a virtu�lis b�zisoszt�ly helyett k�z�ns�geset
alkalmazhatunk:
class BB_ival_slider : public Ival_slider, protected BBslider { /* ... */ };
class Popup_ival_slider : public Ival_slider { /* ... */ };
class BB_popup_ival_slider
: public Popup_ival_slider, protected BB_ival_slider { /* ... */ };
15. Oszt�lyhierarchi�k 525
Ival_slider BBslider
Popup_ival_slider BB_ival_slider
BB_popup_ival_slider
�br�val:
Ez val�sz�nuleg megval�s�that�, optimaliz�lt v�ltozata az elozoekben bemutatott,
bevallottan
vil�gosabb szerkezetnek.
15.2.5.1. A virtu�lis b�zisoszt�lyok f�ggv�nyeinek fel�l�r�sa
A sz�rmaztatott oszt�lyok fel�l�rhatj�k (override) k�zvetlen vagy k�zvetett
virtu�lis b�zisoszt
�lyaik virtu�lis f�ggv�nyeit. K�t k�l�nb�zo oszt�ly ak�r a virtu�lis b�zisoszt�ly
k�l�nb
�zo f�ggv�nyeit is fel�l�rhatja, �gy t�bb sz�rmaztatott oszt�ly j�rulhat hozz� a
virtu�lis
b�zisoszt�ly �ltal adott fel�let megval�s�t�s�hoz. A Window oszt�lynak lehetnek
p�ld�ul
set_color() �s prompt() f�ggv�nyei. Ekkor a Window_with_border fel�lb�r�lhatja
a set_color()-t, mint a sz�nellenorzo s�ma r�sz�t, a Window_with_menu pedig a
prompt()-
ot, mint a felhaszn�l�i fel�let kezel�s�nek r�sz�t:
class Window {
// ...
virtual void set_color(Color) = 0; // h�tt�rsz�n be�ll�t�sa
virtual void prompt() = 0;
};
class Window_with_border : public virtual Window {
// ...
void set_color(Color); // h�tt�rsz�n kezel�se
};
class Window_with_menu : public virtual Window {
// ...
void prompt(); // felhaszn�l�i tev�kenys�gek kezel�se
};
526 Absztrakci�s m�dszerek
Ival_slider Ival_slider BBslider
Popup_ival_slider BB_ival_slider
BB_popup_ival_slider
class My_window : public Window_with_menu, public Window_with_border {
// ...
};
Mi t�rt�nik, ha k�l�nb�zo sz�rmaztatott oszt�lyok ugyanazt a f�ggv�nyt �rj�k
fel�l? Ez csak
akkor megengedett, ha az egyik sz�rmaztatott oszt�ly minden olyan oszt�ly �r�k�se,
amely
fel�l�rja a f�ggv�nyt, vagyis egy f�ggv�nynek az �sszeset fel�l kell �rnia. A
My_window p�ld
�ul fel�l�rhatja a prompt()-t, hogy a Window_with_menu-belin�l jobb v�ltozatot
adjon:
class My_window : public Window_with_menu, public Window_with_border {
// ...
void prompt();// a felhaszn�l�i tev�kenys�gek kezel�s�t nem hagyjuk a
b�zisoszt�lyra
};
�br�val:
Ha k�t oszt�ly fel�l�r egy b�zisoszt�lybeli f�ggv�nyt, de a k�t f�ggv�ny egyike
nem �rja fel�l
a m�sikat, akkor az oszt�lyhierarchia hib�s. Ilyenkor nem lehet virtu�lis
f�ggv�nyt�bl�t �p�-
teni, mert a teljes objektumra vonatkoz� f�ggv�nyh�v�s k�t�rtelmu lenne. P�ld�ul
ha
a �15.2.4. pontbeli Radio nem adta volna meg a write() f�ggv�nyt, akkor a Receiver
�s
Transmitter oszt�lyokbeli write() deklar�ci�k a Radio-ban hib�t okoztak volna.
Mint
a Radio eset�ben is, az ilyen konfliktust a fel�l�r� f�ggv�nynek a legt�volabbi
sz�rmaztatott
oszt�lyb�l val� megh�v�s�val oldhatjuk meg.
Az olyan oszt�lyokat, amelyek egy virtu�lis b�zisoszt�ly n�melyik (de nem
mindegyik)
f�ggv�ny�nek megval�s�t�s�t tartalmazz�k, gyakran .mixin.-nek nevezik.
15. Oszt�lyhierarchi�k 527
Window { set_color(), prompt() }
Window_with_border { set_color() } Window_with_menu { prompt() }
My_window { prompt() }
15.3. Hozz�f�r�s-szab�lyoz�s
Egy oszt�lytag lehet priv�t (private), v�dett (protected) vagy nyilv�nos (public):

� Ha priv�t, a nev�t csak a tagf�ggv�nyekben �s a deklar�l� oszt�ly bar�taiban


(friend-jeiben) lehet felhaszn�lni.
� Ha v�dett, a nev�t csak a deklar�l� oszt�ly �s bar�tai tagf�ggv�nyeiben,
valamint
az oszt�lyb�l sz�rmaztatott oszt�lyok �s bar�taik tagf�ggv�nyeiben lehet
felhaszn�lni.
� Ha nyilv�nos, a nev�t mindenhol fel lehet haszn�lni.
Ez azt a n�zetet t�kr�zi, hogy egy oszt�lyt h�romf�le f�ggv�ny �rhet el: az
oszt�lyt megval
�s�t� f�ggv�nyek (azaz a bar�tok �s a tagok), egy sz�rmaztatott oszt�lyt
megval�s�t� f�ggv
�nyek (azaz a sz�rmaztatott oszt�lyok bar�tai �s a tagok), �s az egy�b f�ggv�nyek.
Ezt �gy
�br�zolhatjuk:
A hozz�f�r�si szab�lyok egy�ntetuen vonatkoznak a nevekre. Hogy a n�v mit jel�l,
az
�rdektelen a hozz�f�r�s szempontj�b�l. Ez azt jelenti, hogy ugyan�gy lehetnek
priv�t tagf
�ggv�nyek, t�pusok, �lland�k stb., mint priv�t adattagok. P�ld�ul egy hat�kony nem
tolakod
� (non-intrusive, �16.2.1) listaoszt�lynak val�sz�nuleg sz�ks�ge van az elemeket
nyilv
�ntart� adatszerkezetekre. Az ilyen inform�ci� legjobb, ha priv�t:
528 Absztrakci�s m�dszerek
�ltal�nos felhaszn�l�k
sz�rmaztatott oszt�ly tagf�ggv�nyei �s bar�tai
saj�t tagf�ggv�nyek �s bar�tok
nyilv�nos:
v�dett:
priv�t:
template<class T> class List {
private:
struct Link { T val; Link* next; };
struct Chunk {
enum { chunk_size = 15 };
Link v[chunk_size];
Chunk* next;
};
Chunk* allocated;
Link* free;
Link* get_free();
Link* head;
public:
class Underflow { }; // kiv�teloszt�ly
void insert(T);
T get();
// ...
};
template<class T> void List<T>::insert(T val)
{
Link* lnk = get_free();
lnk->val = val;
lnk->next = head;
head = lnk;
}
template<class T> List<T>::Link* List<T>::get_free()
{
if (free == 0) {
// �j Chunk lefoglal�sa �s Link-jeinek a szabad list�ra helyez�se
}
Link* p = free;
free = free->next;
return p;
}
template<class T> T List<T>::get()
{
if (head == 0) throw Underflow();
Link* p= head;
head = p->next;
p->next = free;
free = p;
return p->val;
}
15. Oszt�lyhierarchi�k 529
A List<T> hat�k�rbe az�ltal l�p�nk be, hogy a tagf�ggv�nyben List<T>::-t �runk.
Mivel
a get_free() visszat�r�si �rt�k�t elobb eml�tj�k, mint a List<T>::get_free()
nevet, a Link r�vid
�t�s helyett a teljes List<T>::Link nevet kell haszn�lnunk. A nem tag
f�ggv�nyeknek . a bar
�t (friend) f�ggv�nyek kiv�tel�vel . nincs ilyen hozz�f�r�s�k:
void would_be_meddler(List<T>* p)
{
List<T>::Link* q = 0; // hiba: List<T>::Link priv�t
// ...
q = p->free; // hiba: List<T>::free priv�t
// ...
if (List<T>::Chunk::chunk_size > 31) { // hiba: List<T>::Chunk::chunk_size priv�t
// ...
}
}
Az oszt�lyok (class) tagjai alap�rtelmez�s szerint priv�tok (private), a
strukt�r�k (struct) tagjai
nyilv�nosak (public, �10.2.8).
15.3.1. V�dett tagok
A v�dett (protected) tagok haszn�lat�nak bemutat�s�ra vegy�k a �15.2.4.1 pontbeli
Window p�ld�t. Az own_draw() f�ggv�nyek (akarattal) nem teljes k�ru szolg�ltat�st
adnak.
Arra a c�lra tervezt�k oket, hogy csak a sz�rmaztatott oszt�lyok sz�m�ra
szolg�ljanak
�p�tok�vek�l, az �ltal�nos felhaszn�l�s sz�m�ra nem biztons�gosak, nem
k�nyelmesek.
M�sfelol a draw() muveletek az �ltal�nos felhaszn�l�st szolg�lj�k. Ezt a
k�l�nbs�get
a Window oszt�ly fel�let�nek k�t, egy v�dett �s egy nyilv�nos fel�letre val�
sz�tv�laszt�s�-
val lehet kifejezni:
class Window_with_border {
public:
virtual void draw();
// ...
protected:
void own_draw();
// egy�b kirajzol� k�d
private:
// �br�zol�s stb.
};
530 Absztrakci�s m�dszerek
A sz�rmaztatott oszt�ly a b�zisoszt�ly v�dett tagjai k�z�l csak a saj�t oszt�ly�ba
tartoz� objektumokat
tudja el�rni:
class Buffer {
protected:
char a[128];
// ...
};
class Linked_buffer : public Buffer { /* ... */ };
class Cyclic_buffer : public Buffer {
// ...
void f(Linked_buffer* p) {
a[0] = 0; // rendben: Cyclic_buffer saj�t v�dett tagj�t �ri el
p->a[0] = 0; // hiba: m�s t�pus v�dett tagj�t pr�b�ltuk el�rni
}
};
Ez megakad�lyozza az olyan hib�kat, amelyek az�ltal l�phetn�nek fel, hogy az egyik
sz�rmaztatott
oszt�ly �sszezavarja a m�sik sz�rmaztatott oszt�ly adatait.
15.3.1.1. A v�dett tagok haszn�lata
Az adatok elrejt�s�nek egyszeru priv�t/nyilv�nos modellje j�l szolg�lja a konkr�t
t�pusokat
(�10.3). De ha sz�rmaztatott oszt�lyokat haszn�lunk, akkor k�tf�le felhaszn�l�ja
lesz egy
oszt�lynak: a sz�rmaztatott oszt�lyok �s .a nagyk�z�ns�g.. A muveleteket
megval�s�t� tagok
�s bar�tok ezen felhaszn�l�k �rdek�ben kezelik az objektumokat. A priv�t/nyilv�nos

modell lehetov� teszi a megval�s�t�s �s az �ltal�nos felhaszn�l�s pontos


megk�l�nb�ztet�-
s�t, de a sz�rmaztatott oszt�lyok megfelelo kezel�s�t nem.
A protected-k�nt deklar�lt tagokkal sokkal k�nnyebb vissza�lni, mint a priv�tk�nt
bevezetettekkel.
Ez�rt a tagok v�dettk�nt val� megad�sa �ltal�ban tervez�si hiba. Ha jelentos
mennyis�gu adatot �gy helyez�nk el egy k�z�s oszt�lyban, hogy az �sszes
sz�rmaztatott
oszt�ly haszn�lhatja azokat, az adatok s�r�lhetnek. M�g rosszabb, hogy a v�dett
tagokat
. csak�gy, mint a nyilv�nosakat . nem k�nnyu �tszervezni, mert nincs j� m�dszer az

�sszes haszn�lat felder�t�s�re; �gy a v�dett tagok megnehez�tik a program


m�dos�t�s�t.
Szerencs�re nem kell felt�tlen�l v�dett tagokat haszn�lni; az oszt�lyokra a priv�t
az alap�rtelmezett
hozz�f�r�si kateg�ria �s �ltal�ban ez a jobb v�laszt�s. Az �n tapasztalatom az,
hogy az �sszes sz�rmaztatott oszt�ly �ltal k�zvetlen�l haszn�lhat�, jelentos
mennyis�gu
adat k�z�s oszt�lyban val� elhelyez�se helyett mindig ad�dik m�s megold�s.
15. Oszt�lyhierarchi�k 531
Jegyezz�k meg, hogy ezek a kifog�sok nem �rv�nyesek a v�dett tagf�ggv�nyekre;
a protected minos�tovel remek�l adhatunk meg a sz�rmaztatott oszt�lyokban
haszn�lhat�
muveleteket. A �12.4.2 pontbeli Ival_slider is p�lda erre. Ha ebben a p�ld�ban a
megval�-
s�t� oszt�ly priv�t lett volna, a tov�bbi �r�kl�s lehetetlenn� v�lt volna. A tagok
el�rhetos�-
g�re p�ld�kat a �C.11.1 tartalmaz.
15.3.2. B�zisoszt�lyok el�r�se
A tagokhoz hasonl�an egy b�zisoszt�ly is lehet nyilv�nos, v�dett vagy priv�t:
class X : public B { /* ... */ };
class Y : protected B { /* ... */ };
class Z : private B { /* ... */ };
A nyilv�nos �r�kl�s a sz�rmaztatott oszt�lyt a b�zisoszt�ly egy alt�pus�v�
(subtype) teszi; ez
az �r�kl�s leg�ltal�nosabb form�ja. A v�dett �s a priv�t �r�kl�s a megval�s�t�s
m�dj�nak jel
�l�s�re haszn�latos. A v�dett �r�kl�s olyan oszt�lyhierarchi�kban a leghasznosabb,
ahol jellemz
oen tov�bbi �r�kl�s t�rt�nik (a �12.4.2 pontbeli Ival_slider j� p�lda erre). A
priv�t b�zisoszt
�lyok akkor a leghasznosabbak, amikor egy oszt�lyt a fel�let korl�toz�s�val
hat�rozunk
meg, ami �ltal erosebb garanci�k adhat�k. A mutat�kra vonatkoz� Vector p�ld�ul
�rt�k-ellen
orz�ssel bov�ti ki Vector<void*> b�zisoszt�ly�t (�13.5). Ha azt is biztos�tani
szeretn�nk,
hogy a Vec-hez (�3.7.2) val� minden hozz�f�r�s ellenorz�tt legyen, b�zisoszt�ly�t
priv�tk�nt
kell megadnunk, �gy a Vec-ek nem konvert�l�dnak nem ellenorz�tt vector-r�:
template <class T > class Vec : private Vector <T> { /* ... */ };
Az oszt�ly hozz�f�r�si szintj�t nem musz�j explicit megadni. Ilyenkor az
alap�rtelmezett
hozz�f�r�se class eset�n priv�t, struct eset�n nyilv�nos lesz:
class XX : B { /* ... */ }; // B priv�t b�zisoszt�ly
struct YY : B { /* ... */ }; // B nyilv�nos b�zisoszt�ly
Az olvashat�s�g szempontj�b�l azonban legjobb ki�rni a hozz�f�r�si szintet megad�
kulcssz�t.
A b�zisoszt�ly hozz�f�r�si szintje az oszt�ly tagjainak el�rhetos�ge mellett a
sz�rmaztatott
oszt�lyra hivatkoz� mutat�knak vagy referenci�knak a b�zisoszt�ly t�pus�ra val�
konvert�lhat
�s�g�t is jelzi. Vegy�nk egy B b�zisoszt�lyb�l sz�rmaz� D oszt�lyt:
� Ha B priv�t b�zisoszt�ly, akkor nyilv�nos �s v�dett tagjai csak D
tagf�ggv�nyeibol
�s bar�taib�l �rhetok el. Csak D bar�tai �s tagjai konvert�lhatnak egy D* mutat�t
B*-g�.
532 Absztrakci�s m�dszerek
� Ha B v�dett b�zisoszt�ly, akkor nyilv�nos �s v�dett tagjai csak D
tagf�ggv�nyeibol
�s bar�taib�l, valamint a D-bol sz�rmaz� oszt�lyok tagf�ggv�nyeibol �s bar�taib�l
�rhetok el. Csak D tagf�ggv�nyei �s bar�tai, valamint a D-bol sz�rmaz� oszt�lyok
tagf�ggv�nyei �s bar�tai v�gezhetnek konverzi�t D*-r�l B*-ra.
� Ha B nyilv�nos b�zisoszt�ly, nyilv�nos tagjai b�rhol haszn�lhat�k. Ezenk�v�l
v�dett
tagjai D tagf�ggv�nyeibol �s bar�taib�l, valamint a D-bol sz�rmaz� oszt�lyok
tagf�ggv
�nyeibol �s bar�taib�l �rhetok el. B�rmely f�ggv�ny v�gezhet D*-r�l B*-ra val�
konverzi�t.
Ez alapvetoen azonos a tagok el�rhetos�gi szab�lyaival (�15.3). A b�zisoszt�lyok
el�rheto-
s�g�t ugyanazon szempontok szerint adjuk meg, mint a tagok�t. A BBwindow-t p�ld�ul

az�rt adtam meg az Ival_slider v�dett b�zisoszt�lyak�nt (�12.4.2), mert a BBwindow


ink�bb
az Ival_slider megval�s�t�s�nak, mint fel�let�nek r�sze. A BBwindow-t azonban nem
rejthettem
el teljesen �gy, hogy priv�t b�zisoszt�lly� teszem, mert az Ival_slider-bol
tov�bbi
oszt�lyokat akartam sz�rmaztatni �s azoknak el kellett �rni�k a megval�s�t�st.
A b�zisoszt�lyok el�rhetos�g�re a �C.11.2 mutat p�ld�kat.
15.3.2.1. A t�bbsz�r�s �r�klod�s �s az el�rhetos�g
Ha egy nevet vagy b�zisoszt�lyt egy t�bbsz�r�s �r�klod�si h�l� t�bb �tvonal�n is
el�rhet
�nk, akkor abban az esetben lesz el�rheto, ha valamelyik �t ment�n el�rheto:
struct B {
int m;
static int sm;
// ...
};
class D1 : public virtual B { /* ... */ } ;
class D2 : public virtual B { /* ... */ } ;
class DD : public D1, private D2 { /* ... */ };
DD* pd = new DD;
B* pb = pd; // rendben: el�rheto D1-en kereszt�l
int i1 = pd->m; // rendben: el�rheto D1-en kereszt�l
Ha egy bizonyos elemet t�bb �t ment�n is el�rhet�nk, att�l m�g egy�rtelmuen, azaz
t�bb
�rtelmus�gi hiba n�lk�l hivatkozhatunk r�:
class X1 : public B { /* ... */ } ;
class X2 : public B { /* ... */ } ;
class XX : public X1, public X2 { /* ... */ };
15. Oszt�lyhierarchi�k 533
XX* pxx = new XX;
int i1 = pxx->m; // hiba, t�bb�rtelmu: XX::X1::B::m vagy XX::X2::B::m
int i2 = pxx->sm; // rendben: csak egy B::sm van egy XX-ben
15.3.2.2. A using deklar�ci�k �s az el�rhetos�g
A using deklar�ci�k nem szolg�lhatnak t�bb inform�ci� el�r�s�re, csak az egy�bk�nt
is
hozz�f�rheto adatok k�nyelmesebb haszn�lat�t teszik lehetov�. M�sr�szt viszont, ha
egy inform
�ci� el�rheto, akkor a hozz�f�r�si jog m�s felhaszn�l�k fel� tov�bbadhat�:
class B {
private:
int a;
protected:
int b;
public:
int c;
};
class D : public B {
public:
using B::a; // hiba: B::a priv�t
using B::b; // B::b nyilv�nosan el�rheto D-n kereszt�l
};
Ha egy using deklar�ci� priv�t vagy v�dett �r�klod�ssel j�r egy�tt, akkor a
b�zisoszt�ly �ltal
rendesen felk�n�lt szolg�ltat�sok egy r�sz�hez fel�letet adhat:
class BB : private B { // hozz�f�r�st ad a B::b �s B::c nevekhez, de a B::a-hoz
nem
public:
using B::b;
using B::c;
};
L�sd m�g a �15.2.2 pontot.
534 Absztrakci�s m�dszerek
15.4. Fut�si ideju t�pusinform�ci�
A �12.4 pontban le�rt Ival_box-ok val�szeru haszn�lata lenne, ha �tadn�nk azokat
egy k�perny
okezelo rendszernek, majd az visszaadn� oket a programnak, valah�nyszor valamilyen

tev�kenys�g t�rt�nt. Sok felhaszn�l�i fel�let muk�dik �gy. Egy felhaszn�l�i


fel�letet kezelo
rendszer azonban nem felt�tlen�l tud a mi Ival_box-ainkr�l. A rendszer fel�let�t a
rendszer
saj�t oszt�lyai �s objektumai nyelv�n adj�k meg, nem a mi alkalmaz�sunk
oszt�lyainak
nyelv�n. Ez sz�ks�gszeru �s rendj�n is val�, de azzal a kellemetlen
k�vetkezm�nnyel j�r,
hogy inform�ci�t veszt�nk a rendszernek �tadott �s k�sobb nek�nk visszaadott
objektumok
t�pus�r�l.
Az .elveszett. adatok visszanyer�s�hez valahogy meg kell tudnunk k�rdezni az
objektumt
�l a t�pus�t. B�rmilyen muveletet akarunk is v�gezni az objektummal, alkalmas
t�pus�, az
objektumra hivatkoz� mutat�ra vagy referenci�ra van sz�ks�g�nk. K�vetkez�sk�ppen
egy
objektum t�pus�nak fut�si idoben val� lek�rdez�s�hez a legnyilv�nval�bb �s
leghasznosabb
muvelet az, amely �rv�nyes mutat�t ad vissza, ha az objektum a v�rt t�pus�,
illetve
.nullpointert., ha nem. Pontosan ezt teszi a dynamic_cast oper�tor. P�ld�ul tegy�k
fel,
hogy a rendszer a my_event_handler()-t arra a BBwindow-ra hivatkoz� mutat�val
h�vja
meg, amellyel egy tev�kenys�g t�rt�nt. Ekkor az Ival_box oszt�ly do_something()
f�ggv�-
ny�t haszn�lva megh�vhatn�nk programunkat:
void my_event_handler(BBwindow* pw)
{
if (Ival_box* pb = dynamic_cast<Ival_box*>(pw)) // Vajon pw egy Ival_box-ra mutat?

pb->do_something();
else {
// hopp�! nem v�rt esem�ny
}
}
A folyamatot �gy is magyar�zhatjuk, hogy a dynamic_cast ford�t a felhaszn�l�i
fel�letet kezel
o rendszer saj�tos nyelv�rol az alkalmaz�s nyelv�re. Fontos �szrevenni, hogy mi
nem
nyert eml�t�st ebben a p�ld�ban: az objektum t�nyleges t�pusa. Az objektum az
Ival_box
egy bizonyos fajt�ja lesz, mondjuk Ival_slider, amelyet a BBwindow egy bizonyos
t�pusa val
�s�t meg, mondjuk a BBslider. Az objektum t�nyleges t�pus�nak kider�t�se �s
megeml�t�se
se nem sz�ks�ges, se nem k�v�natos a rendszer �s a program k�z�tti ezen
p�rbesz�dben.
L�tezik fel�let a p�rbesz�d l�nyeg�nek le�r�s�ra, egy j�l megtervezett fel�let
pedig elrejti
a l�nyegtelen r�szleteket.
15. Oszt�lyhierarchi�k 535
Rajzban a
pb = dynamic_cast<Ival_box*>(pw)
utas�t�s hat�s�t �gy �br�zolhatjuk:
A pw-bol �s pb-bol kiindul� nyilak az �tadott objektumra hivatkoz� mutat�kat
jel�lik, m�g
a t�bbi ny�l az �tadott objektum k�l�nb�zo r�szei k�z�tti �r�klod�si viszonyokat
�br�zolja.
A t�pusinform�ci�k fut�si idoben val� haszn�lat�t hagyom�nyosan fut�si ideju
t�pusinform
�ci�nak (run-time type information) h�vj�k �s gyakran RTTI-nek r�vid�tik.
A b�zisoszt�lyr�l sz�rmaztatott oszt�lyra t�rt�no konverzi�t gyakran .lefel�
t�rt�no vagy
sz�rmaztatott ir�ny� konverzi�nak. (downcast) h�vj�k, mert az �r�kl�si f�k a
hagyom�nyos
�br�zol�s szerint a gy�k�rtol .lefel� nonek.. Ehhez hasonl�an a sz�rmaztatott
oszt�lyr�l
b�zisoszt�lyra t�rt�no konverzi� neve .felfel� t�rt�no konverzi�., vagy
.b�zisir�ny� konverzi
�. (upcast). A b�zisoszt�lyr�l testv�rre . p�ld�ul BBwindow-r�l Ival_box-ra . val�

konverzi�t .keresztbe t�rt�no konverzi�nak. (crosscast) h�vj�k.


15.4.1. Dynamic_cast
A dynamic_cast (dinamikus t�pusk�nyszer�t�s) oper�tor k�t param�tert v�r, egy <>
k�z� �rt
t�pust �s egy () k�z� �rt mutat�t vagy referenci�t.
Vegy�k elosz�r a mutat� eset�t:
dynamic_cast<T *>(p)
536 Absztrakci�s m�dszerek
pw BBwindow Ival_box pb
BBslider Ival_slider
BB_ival_slider
Ha a p a T * t�pusba, vagy olyan D * t�pusba tartozik, ahol T b�zisoszt�lya D-nek,
akkor az
eredm�ny ugyanaz, mintha a p-t egy T * v�ltoz�nak adtuk volna �rt�k�l:
class BB_ival_slider : public Ival_slider, protected BBslider {
// ...
};
void f(BB_ival_slider* p)
{
Ival_slider* pi1 = p; // rendben
Ival_slider* pi2 = dynamic_cast<Ival_slider*>(p); // rendben
BBslider* pbb1 = p; // hiba: BBslider v�dett b�zisoszt�ly
BBslider* pbb2 = dynamic_cast<BBslider*>(p); // rendben: pbb2 �rt�ke 0 lesz
}
Ez nem t�l �rdekes. Azt azonban j� tudni, hogy a dynamic_cast nem engedi meg a
v�dett
vagy priv�t b�zisoszt�lyok v�delm�nek v�letlen megs�rt�s�t.
A dynamic_cast c�lja azon esetek kezel�se, amelyekn�l a ford�t�program nem tudja a

konverzi� helyess�g�t meg�t�lni:


dynamic_cast<T *>(p)
A fenti k�d megvizsg�lja a p �ltal mutatott objektumot (ha van ilyen). Ha az
objektum T oszt
�ly� vagy van egy egy�rtelmu T t�pus� ose, akkor a dynamic_cast egy, az objektumra
hivatkoz
� T * t�pus� mutat�t ad vissza, m�s esetben 0-�t. Ha p �rt�ke 0, a dynamic_cast<T
*>(p)
eredm�nye 0 lesz. Jegyezz�k meg, hogy a konverzi� csak egy�rtelmuen azonos�tott
objektumokn
�l muk�dik. Lehet olyan p�ld�kat hozni, ahol a konverzi� nem siker�l �s 0-�t ad,
mert
a p �ltal mutatott objektumnak t�bb T t�pus� b�zisoszt�lyt k�pviselo r�szobjektuma
van
(�15.4.2).
A dynamic_cast-nak a lefel� vagy keresztbe t�rt�no konvert�l�shoz t�bbalak�
(polimorf)
mutat�ra vagy hivatkoz�sra van sz�ks�ge:
class My_slider: public Ival_slider { // t�bbalak� b�zisoszt�ly (Ival_slider
rendelkezik
// virtu�lis f�ggv�nyekkel)
// ...
};
class My_date : public Date { // nem t�bbalak� b�zisoszt�ly (Date nem rendelkezik
// virtu�lis f�ggv�nyekkel)
// ...
};
15. Oszt�lyhierarchi�k 537
void g(Ival_box* pb, Date* pd)
{
My_slider* pd1 = dynamic_cast<My_slider*>(pb); // rendben
My_date* pd2 = dynamic_cast<My_date*>(pd); // hiba: Date nem t�bbalak�
}
Az a megk�t�s, hogy a mutat�nak t�bbalak�nak kell lennie, egyszerus�ti a
dynamic_cast
megval�s�t�s�t, mert megk�nny�ti az objektum t�pus�nak t�rol�s�hoz sz�ks�ges
inform�ci�
hely�nek megtal�l�s�t. �ltal�nos megold�s, hogy a t�pust jelzo mutat�t az objektum
virtu�-
lis f�ggv�nyt�bl�j�ba (�2.5.5) helyezik, ez�ltal egy .t�pus-inform�ci� objektumot.
fuznek az
objektumhoz:
A szaggatott ny�l az eltol�st (offset) jel�li, amelynek seg�ts�g�vel a teljes
objektum kezdete
megtal�lhat�, ha csak egy t�bbalak� r�szobjektumra hivatkoz� mutat� adott.
Vil�gos, hogy
a dynamic_cast hat�konyan felhaszn�lhat�; csak n�h�ny, a b�zisoszt�lyt le�r�
type_info objektumot
kell �sszehasonl�tani, nincs sz�ks�g hosszadalmas keres�sre vagy karakterl�ncok
�sszehasonl�t�s�ra.
A dynamic_cast-nak t�bbalak� t�pusokra val� korl�toz�sa logikai szempontb�l n�zve
is �rtelmes.
Ha egy objektumnak nincs virtu�lis f�ggv�nye, akkor pontos t�pus�nak ismerete
n�lk�l nem kezelheto biztons�gosan, ez�rt �gyelni kell, hogy az ilyen objektum ne
ker�lj
�n olyan k�rnyezetbe, ahol nem ismeretes a pontos t�pusa. Ha azonban a t�pusa
ismert,
nincs sz�ks�g dynamic_cast-ra.
A dynamic_cast c�lt�pusa nem kell, hogy t�bbalak� legyen, ez�rt egy konkr�t t�pust
t�bbalak
�ba csomagolhatunk, mondjuk, hogy egy objektumokat kezelo ki- �s bemeneti
rendszeren
kereszt�l tov�bb�tsuk (�25.4.1), majd k�sobb kicsomagoljuk belole a konkr�t
t�pust:
538 Absztrakci�s m�dszerek
My_slider:
...
vptr
... "My_slider"
b�zisoszt�lyok "Ival_slider"
vtbl:
type_info:
type_info:
class Io_obj { // b�zisoszt�ly-objektum az I/O rendszer sz�m�ra
virtual Io_obj* clone() = 0;
};
class Io_date : public Date, public Io_obj { };
void f(Io_obj* pio)
{
Date* pd = dynamic_cast<Date*>(pio);
// ...
}
Egy t�bbalak� objektum kezdoc�m�t egy void*-ra val� dinamikus t�pusk�nyszer�t�ssel
hat
�rozhatjuk meg:
void g(Ival_box* pb, Date* pd)
{
void* pd1 = dynamic_cast<void*>(pb); // rendben
void* pd2 = dynamic_cast<void*>(pd); // hiba: Date nem t�bbalak�
}
Ez azonban csak nagyon alacsony szintu f�ggv�nyekkel val� egy�ttmuk�d�s c�lj�ra
hasznos.
15.4.1.1. Referenci�k dinamikus t�pusk�nyszer�t�se
Egy objektum t�bbalak� (polymorph) viselked�s�hez akkor f�r�nk hozz�, ha mutat�n
vagy referenci�n �t kezelj�k. A dynamic_cast muvelet sikertelens�g�t 0-val jelzi.
Ez
referenci�kra se nem kivitelezheto, se nem k�v�natos.
Ha egy mutat�r�l, mint eredm�nyrol van sz�, akkor fel kell k�sz�ln�nk arra a
lehetos�gre,
hogy az eredm�ny 0 lesz, azaz a mutat� nem mutat semmilyen objektumra. Ez�rt egy
dynamic_cast muvelet eredm�ny�t mindig ellenorizn�nk kell. A p mutat�n v�gzett
dynamic_cast<T*>(p) egy k�rd�sk�nt foghat� fel: .a p �ltal mutatott objektum T
t�pus�?.
M�sr�szt viszont jogosan t�telezhetj�k fel, hogy egy referencia mindig egy
objektumra vonatkozik.
K�vetkez�sk�ppen egy r referencia eset�n a dynamic_cast<T&>(r) nem k�rd�s,
hanem �ll�t�s: .a r �ltal mutatott objektum T t�pus�.. A dynamic_cast muvelet
eredm�ny�t
maga a dynamic_cast-ot megval�s�t� k�d ellenorzi automatikusan, �s ha a
dynamic_cast
operandusa nem a v�rt t�pus� hivatkoz�s, akkor bad_cast kiv�telt v�lt ki:
15. Oszt�lyhierarchi�k 539
void f(Ival_box* p, Ival_box& r)
{
if (Ival_slider* is = dynamic_cast<Ival_slider*>(p)) { // Vajon p egy Ival_slider-
re mutat?
// 'is' haszn�lata
}
else {
// *p nem slider
}
Ival_slider& is = dynamic_cast<Ival_slider&>(r); // az r egy Ival_slider-re
hivatkozik!
// 'is' haszn�lata
}
A sikertelen dinamikus mutat�- illetve referencia-�talak�t�sok eredm�ny�nek
elt�r�s�ben
a mutat�k, illetve a referenci�k k�z�tti alapveto k�l�nbs�g t�kr�zodik. Ha egy
felhaszn�l�
v�dekezni akar a referencia-�talak�t�s sikertelens�ge ellen, akkor egy megfelelo
kiv�telkezel
ore van sz�ks�ge:
void g()
{
try {
f(new BB_ival_slider,*new BB_ival_slider); // a param�terek Ival_box-k�nt
// ad�dnak �t
f(new BBdial,*new BBdial); // a param�terek Ival_box-k�nt ad�dnak �t
}
catch (bad_cast) { // �14.10
// ...
}
}
Az f() f�ggv�ny elso megh�v�sa sikeresen fog visszat�rni, m�g a m�sodik bad_cast
kiv�telt
v�lt ki, amit g() elkap.
A 0 �rt�k ellenorz�se elhagyhat�, �gy alkalmasint v�letlen�l el is fog maradni. Ha
ez aggasztja
az olvas�t, akkor �rhat egy olyan konverzi�s f�ggv�nyt, amely sikertelens�g eset�n

a 0 �rt�k visszaad�sa helyett kiv�telt v�lt ki (�15.8[1]).


15.4.2. Oszt�lyhierarchi�k bej�r�sa
Ha csak egyszeres �r�klod�st haszn�lunk, az oszt�ly �s b�zisoszt�lyai egyetlen
b�zisoszt
�lyban gy�kerezo f�t alkotnak. Ez egyszeru, de gyakran t�l eros megszor�t�st
jelent. T�bbsz
�r�s �r�klod�s haszn�lata eset�n nincs egyetlen gy�k�r. Ez �nmag�ban nem
bonyol�tja
nagyon a helyzetet, de ha egy oszt�ly t�bbsz�r fordul elo a hierarchi�ban, akkor
n�mi �vatoss
�ggal kell az adott oszt�ly� objektumra vagy objektumokra hivatkoznunk.
540 Absztrakci�s m�dszerek
Term�szetesen a hierarchi�kat igyeksz�nk annyira egyszerunek venni . de nem
egyszer
ubbnek ., amennyire programunk megengedi. De ha m�r kialakult egy bonyolultabb
hierarchia,
hamarosan sz�ks�g�nk lesz annak bej�r�s�ra (vagyis v�gign�z�s�re), hogy alkalmas
oszt�lyt tal�ljunk, amelyet fel�letk�nt haszn�lhatunk. Ez az ig�ny k�t esetben
mer�lhet
fel. N�ha kifejezetten meg akarunk nevezni egy b�zisoszt�lyt vagy annak egy tagj�t
(p�ld�-
ul �15.2.3 �s �15.2.4.1). M�skor egy, a b�zisoszt�lyt vagy annak egy sz�rmaztatott
oszt�ly�t
megjelen�to objektumra hivatkoz� mutat�ra van sz�ks�g�nk, ha adott egy mutat� a
teljes
objektumra vagy annak valamely r�szobjektum�ra (�15.4 �s �15.4.1).
Itt azt tekintj�k �t, hogyan lehet t�pusk�nyszer�t�st (cast) haszn�lva a k�v�nt
t�pus� mutat�-
hoz jutni. Hogy szeml�ltess�k az el�rheto m�dszereket �s a r�juk vonatkoz�
szab�lyokat,
vegy�nk egy t�bbsz�r szereplo �s virtu�lis b�zisoszt�lyt egyar�nt tartalmaz�
h�l�t:
class Component : public virtual Storable { /* ... */ };
class Receiver : public Component { /* ... */ };
class Transmitter : public Component { /* ... */ };
class Radio : public Receiver, public Transmitter { /* ... */ };
�br�val:
Itt a Radio objektumnak k�t Component oszt�ly� r�szobjektuma van. Ez�rt a Radio-n
bel�-
li, Storable-rol Component-re val� dinamikus t�pusk�nyszer�t�s t�bb�rtelmu lesz �s
null�t
ad. Ilyenkor egyszeruen nem lehet tudni, melyik Component-re gondolt a programoz�:

void h1(Radio& r)
{
Storable* ps = &r;
// ...
Component* pc = dynamic_cast<Component*>(ps); // pc = 0
}
15. Oszt�lyhierarchi�k 541
Storable
Receiver Transmitter
Component Component
Radio
Ez a t�bb�rtelmus�g ford�t�si idoben �ltal�ban nem der�theto fel:
void h2(Storable* ps) // ps-rol nem tudjuk, hogy Component-re mutat-e
{
Component* pc = dynamic_cast<Component*>(ps);
// ...
}
A t�bb�rtelmus�gnek ez a fajta felder�t�se csak virtu�lis b�zisoszt�lyokn�l
sz�ks�ges. K�-
z�ns�ges b�zisoszt�lyok �s lefel� (azaz a sz�rmaztatott oszt�ly fel� t�rt�no;
�15.4)
konverzi� eset�n a k�v�nt t�pus� r�szobjektum mindig egy�rtelmu (ha l�tezik).
Ezzel
egyen�rt�ku t�bb�rtelmus�g l�p fel felfel� (azaz a b�zisoszt�ly fel� t�rt�no)
konverzi� eset
�n �s ezek a t�bb�rtelmus�gek ford�t�si idoben kider�lnek.
15.4.2.1. Statikus �s dinamikus konverzi�
A dynamic_cast muvelet t�bbalak� b�zisoszt�lyr�l sz�rmaztatott oszt�lyra vagy
testv�roszt
�lyra val� �talak�t�st tud v�gezni (�15.4.1). A static_cast (�6.2.7) nem vizsg�lja
a kiindul�
objektum t�pus�t, �gy nem k�pes ezekre:
void g(Radio& r)
{
Receiver* prec = &r; // a Receiver a Radio k�z�ns�ges b�zisoszt�lya
Radio* pr = static_cast<Radio*>(prec); // rendben, nincs ellenorz�s
pr = dynamic_cast<Radio*>(prec); // rendben, fut�si ideju ellenorz�s
Storable* ps = &r; // a Storable a Radio virtu�lis b�zisoszt�lya
pr = static_cast<Radio*>(ps); // hiba: virtu�lis b�zisoszt�lyr�l nem lehet
�talak�tani
pr = dynamic_cast<Radio*>(ps); // rendben, fut�si ideju ellenorz�s
}
A dynamic_cast-nak t�bbalak� operandusra van sz�ks�ge, mert egy nem t�bbalak�
objektum
nem t�rol olyan inform�ci�t, amelynek alapj�n meg lehetne keresni azon
objektumokat,
amelyeknek ose (b�zisa). Olyan objektum is lehet p�ld�ul virtu�lis b�zisoszt�ly,
amelynek
a mem�ri�ban val� elhelyezked�s�t egy m�sik nyelv, p�ld�ul a Fortran vagy a C
hat�-
rozza meg. Ezekre vonatkoz�an csak statikus adatok �llnak rendelkez�sre, de
a dynamic_cast megval�s�t�s�hoz sz�ks�ges inform�ci�t a fut�si ideju
t�pusinform�ci� tartalmazza.
Mi�rt akarna valaki static_cast-ot haszn�lni egy oszt�lyhierarchia bej�r�s�ra?
A dynamic_cast n�mileg n�veli a fut�si idot (�15.4.1), de enn�l jelentosebb ok,
hogy milli�
sornyi k�d van a dynamic_cast bevezet�se elotti idokbol. Az ilyen k�dok m�s
m�dokon
542 Absztrakci�s m�dszerek
biztos�tj�k az alkalmazott t�pus�talak�t�sok helyess�g�t, �gy a dynamic_cast-tal
v�geztetett
ellenorz�s feleslegesnek tunik. Az ilyen . �ltal�ban C st�lus� t�puskonverzi�val
(�6.2.7) �r�-
dott . k�dban azonban gyakran maradhatnak rejtett hib�k, �gy, hacsak lehet,
haszn�ljuk
a biztons�gosabb dynamic_cast-ot.
A ford�t�program nem t�telezhet fel semmit egy void* mutat� �ltal mutatott
mem�riater�-
letrol. Ebbol k�vetkezik, hogy az objektum t�pusa felol �rdeklodo dynamic_cast nem
k�-
pes void*-r�l konvert�lni. Ehhez static_cast kell:
Radio* f(void* p)
{
Storable* ps = static_cast<Storable*>(p); // B�zzunk a programoz�ban!
return dynamic_cast<Radio*>(ps);
}
Mind a dynamic_cast, mind a static_cast tiszteletben tartja a const minos�t�st �s
a hozz�f�-
r�si korl�toz�sokat:
class Users : private set<Person> { /* ... */ };
void f(Users* pu, const Receiver* pcr)
{
static_cast<set<Person>*>(pu); // hiba: nem f�rhet hozz�
dynamic_cast<set<Person>*>(pu); // hiba: nem f�rhet hozz�
static_cast<Receiver*>(pcr); // hiba: const minos�t�s nem v�sz el
dynamic_cast<Receiver*>(pcr); // hiba: const minos�t�s nem v�sz el
Receiver* pr = const_cast<Receiver*>(pcr); // rendben
// ...
}
Priv�t b�zisoszt�lyra nem lehet konvert�lni, const-ot nem konstanss� konvert�lni
pedig
csak const_cast-tal lehet (�6.2.7), �s m�g akkor is csak �gy kapunk helyes
eredm�nyt, ha az
objektumot eredetileg nem const-k�nt deklar�ltuk (�10.2.7.1).
15.4.3. Oszt�lyobjektumok fel�p�t�se �s megsemmis�t�se
Egy valamilyen oszt�lyba tartoz� objektum t�bb, mint egyszeruen a mem�ria egy
r�sze
(�4.9.6). Az oszt�lyobjektumokat konstruktoraik �p�tik fel a .nyers mem�ri�b�l. �s

destruktoraik lefut�s�val v�lnak �jra .nyers mem�ri�v�.. Az objektum fel�p�t�se


alulr�l felfel
�, megsemmis�t�se fel�lrol lefel� t�rt�nik, �s az oszt�lyobjektum olyan m�rt�kben
l�tezo
15. Oszt�lyhierarchi�k 543
objektum, amennyire fel�p�t�se, illetve megsemmis�t�se megt�rt�nt. Ez t�kr�zodik a
fut�si
ideju t�pusazonos�t�sra (RTTI), a kiv�telkezel�sre (�14.4.7) �s a virtu�lis
f�ggv�nyekre vonatkoz
� szab�lyokban.
Nem b�lcs dolog az objektumfel�p�t�s vagy -megsemmis�t�s sorrendj�re t�maszkodni,
de
a sorrendet megfigyelhetj�k, ha virtu�lis f�ggv�nyeket, dynamic_cast-ot vagy
typeid-t
(�15.4.4) h�vunk akkor, amikor az objektum m�g nincs k�szen. P�ld�ul ha a �15.4.2
pontbeli
hierarchia Component konstruktora egy virtu�lis f�ggv�nyt h�v, akkor a Storable
vagy
Component-beli v�ltozatot fogja megh�vni, nem a Receiver, Transmitter vagy Radio-
belit.
Az objektum l�trehoz�s�nak ezen pontj�n az objektum m�g nem Radio; csak egy
r�szben
fel�p�tett objektum. Ennek f�ny�ben legjobb elker�lni a virtu�lis f�ggv�nyeknek
konstruktorb�l vagy destruktorb�l val� megh�v�s�t.
15.4.4. Typeid �s kiterjesztett t�pusinform�ci�
A dynamic_cast oper�tor az objektumok t�pus�ra vonatkoz�, fut�si idoben jelentkezo
inform
�ci�ig�ny legnagyobb r�sz�t kiel�g�ti. Fontos tulajdons�ga, hogy biztos�tja a
felhaszn�-
l� k�d helyes muk�d�s�t a programoz� �ltal haszn�lt oszt�lyokb�l sz�rmaz�
oszt�lyokkal
is. �gy a dynamic_cast a virtu�lis f�ggv�nyekhez hasonl�an megorzi a rugalmass�got
�s bo-
v�thetos�get.
N�ha azonban alapveto fontoss�g� tudni az objektum pontos t�pus�t. P�ld�ul tudni
szeretn
�nk az objektum oszt�ly�nak nev�t vagy mem�riakioszt�s�t. A typeid oper�tor ezt az

operandusa t�pus�t jelzo objektum visszaad�s�val t�mogatja. Ha a typeid() f�ggv�ny


lenne,
valahogy �gy adhatn�nk meg:
class type_info;
const type_info& typeid(type_name) throw(); // �l-deklar�ci�
const type_info& typeid(expression) throw(bad_typeid); // �l-deklar�ci�
Azaz a typeid() egy standard k�nyvt�rbeli, a <typeinfo> fej�llom�nyban defini�lt
type_info
nevu t�pusra val� referenci�t ad vissza. Ha operandusk�nt egy t�pusnevet kap, a
typeid() az
azt �br�zol� type_info-ra val� referenci�val t�r vissza, ha kifejez�st, a
kifejez�s �ltal jel�lt
objektumot �br�zol� type_info-ra fog hivatkozni. A typeid() legink�bb egy
referenci�val
vagy mutat�val jel�lt objektum t�pus�nak lek�rdez�s�re haszn�latos:
void f(Shape& r, Shape* p)
{
typeid(r); // az r �ltal hivatkozott objektum t�pusa
typeid(*p); // a p �ltal mutatott objektum t�pusa
typeid(p); // a mutat� t�pusa, vagyis Shape* (nem gyakori, legink�bb t�ved�s)
}
544 Absztrakci�s m�dszerek
Ha a mutat� vagy referencia operandus �rt�ke 0, a typeid() bad_typeid kiv�telt
v�lt ki.
A type_info megval�s�t�s-f�ggetlen r�sze �gy n�z ki:
class type_info {
public:
virtual ~type_info(); // t�bbalak�
bool operator==(const type_info&) const; // �sszehasonl�that�
bool operator!=(const type_info&) const;
bool before(const type_info&) const; // rendez�s
const char* name() const; // a t�pus neve
private:
type_info(const type_info&); // m�sol�s megakad�lyoz�sa
type_info& operator=(const type_info&); // m�sol�s megakad�lyoz�sa
// ...
};
A before() f�ggv�ny lehetov� teszi a type_info objektumok rendez�s�t. A
meghat�rozott
rendez�si sorrendnek nincs k�ze az �r�kl�si viszonyokhoz.
Nem biztos, hogy a rendszer minden egyes t�pus�t egyetlen type_info objektum
k�pviseli.
Dinamikus csatol�s� k�nyvt�rak haszn�lata eset�n p�ld�ul val�ban neh�z a t�bb
type_info
objektumot elker�lo megval�s�t�s elk�sz�t�se. Ez�rt a == muvelettel az
egyenlos�get
a type_info objektumok �s nem az azokra hivatkoz� mutat�k eset�ben vizsg�ljuk.
N�ha tudni akarjuk egy objektum pontos t�pus�t, hogy valamilyen szabv�nyos
muveletet
v�gezz�nk az eg�sz objektumon (�s nem csak annak egy os�n). Ide�lis esetben az
ilyen
muveletek virtu�lis f�ggv�nyek form�j�ban �llnak rendelkez�sre, �gy nem sz�ks�ges
a pontos
t�pus ismerete. Egyes esetekben azonban nem t�telezheto minden egyes kezelt
objektumra
vonatkoz� k�z�s fel�let, �gy a megold�s �tja a pontos t�puson kereszt�l vezet
(�15.4.4.1). Egy m�sik, sokkal egyszerubb haszn�lat az oszt�ly nev�nek
diagnosztikai kimenet
c�lj�ra val� lek�rdez�se:
#include<typeinfo>
void g(Component* p)
{
cout << typeid(*p).name();
}
15. Oszt�lyhierarchi�k 545
Az oszt�lyok nev�nek sz�veges �br�zol�sa az adott nyelvi v�ltozatt�l f�gg. C
st�lus� karakterl
�ncokkal t�rt�nik, amelyek a rendszerhez tartoz� mem�riar�szben vannak, ez�rt ne
pr�b�ljuk meg a delete[ ] muveletet alkalmazni r�juk.
15.4.4.1. Kiterjesztett t�pusinform�ci�
Egy objektum pontos t�pus�nak meghat�roz�sa �ltal�ban csak az elso l�p�s a r�
vonatkoz�
r�szletesebb inform�ci�k megszerz�se �s haszn�lata fel�.
Gondoljuk meg, hogy egy program vagy programoz�st seg�to eszk�z hogyan tudna
fut�si
idoben t�pusokr�l sz�l� inform�ci�t adni a felhaszn�l�knak. Tegy�k fel, hogy van
egy eszk
�z�nk, amely minden felhaszn�lt oszt�lyr�l megmondja az objektum
mem�riakioszt�s�t.
Ezeket a le�r�kat egy map-be tehetem, hogy annak alapj�n a felhaszn�l�i k�d
megtal�lhassa
a mem�riakioszt�si inform�ci�t:
map<string, Layout> layout_table;
void f(B* p)
{
Layout& x = layout_table[typeid(*p).name()];
// x haszn�lata
}
Valaki m�s eg�szen elt�ro inform�ci�t adhat:
struct TI_eq {
bool operator()(const type_info* p, const type_info* q) { return *p==*q; }
};
struct TI_hash {
int operator()(const type_info* p); // has�t��rt�k kisz�m�t�sa (�17.6.2.2)
};
hash_map<const type_info*,Icon,hash_fct,TI_hash,TI_eq> icon_table; // �17.6
void g(B* p)
{
Icon& i = icon_table[&typeid(*p)];
// i haszn�lata
}
546 Absztrakci�s m�dszerek
A typeid-ekhez inform�ci� rendel�s�nek ez a m�dja t�bb programoz� vagy eszk�z
sz�m�ra
teszi lehetov�, hogy a t�pusokhoz egym�st�l teljesen f�ggetlen inform�ci�kat
rendeljenek:
Ez nagyon fontos, mert annak val�sz�nus�ge, hogy valaki inform�ci�knak olyan
halmaz�val
tud elo�llni, amely egymag�ban minden felhaszn�l� ig�nyeit kiel�g�ti, a null�val
egyenlo.
15.4.5. Az RTTI helyes �s helytelen haszn�lata
Csak sz�ks�g eset�n haszn�ljunk explicit fut�si ideju t�pusinform�ci�t. A statikus
(ford�t�si
idoben t�rt�no) ellenorz�s biztons�gosabb, .olcs�bb. �s . alkalmasint . jobban
szerkesztett
programokhoz vezet. A fut�si ideju t�pusinform�ci�t p�ld�ul arra haszn�lhatjuk,
hogy
egy rosszul �lc�zott switch utas�t�st �rjunk:
// a fut�si ideju t�pusinform�ci� helytelen haszn�lata
void rotate(const Shape& r)
{
if (typeid(r) == typeid(Circle)) {
// nem csin�lunk semmit
}
else if (typeid(r) == typeid(Triangle)) {
// h�romsz�g forgat�sa
}
else if (typeid(r) == typeid(Square)) {
// n�gyzet forgat�sa
}
// ...
}
A dynamic_cast-nak a typeid helyett val� haszn�lata alig jav�tana ezen a k�don.
15. Oszt�lyhierarchi�k 547
layout_table:
icon_table:
"T"
...
...
&typeid(T)
...
Az objektum
mem�riakioszt�sa
A t�pus ikonos
�br�zol�sa
Sajnos ez nem egy l�gbol kapott p�lda; ilyen k�dot t�nyleg �rnak. A C-hez, a
Pascalhoz,
a Modula-2-h�z, vagy az Ad�hoz hasonl� nyelveken nevelkedett programoz� majdnem
ellen
�llhatatlan k�s�rt�st �rez, hogy a programot switch utas�t�sok halmazak�nt �p�tse
fel. Ennek
a k�s�rt�snek �ltal�ban ellen kell �llni. Fut�si ideju t�pusazonos�t�s helyett
ink�bb virtu
�lis f�ggv�nyeket (�2.5.5, �12.2.6) haszn�ljunk a legt�bb olyan eset kezel�s�re,
amikor
a t�puson alapul� fut�si ideju megk�l�nb�ztet�s sz�ks�ges.
Az RTTI helyes haszn�lata sokszor mer�l fel akkor, amikor a k�dban valamilyen
szolg�ltat
�st egy bizonyos oszt�lyhoz kapcsolunk �s a felhaszn�l� �r�klod�ssel akar tov�bbi
szolg
�ltat�sokat hozz�adni. A �15.4 pontbeli Ival_box haszn�lata ennek egy p�ld�ja. Ha
a felhaszn
�l� hajland� �s k�pes a k�nyvt�ri oszt�lyok . p�ld�ul a BBwindow . m�dos�t�s�ra,
akkor az RTTI haszn�lata elker�lheto; k�l�nben viszont sz�ks�ges. De ha a
felhaszn�l� hajland
� is a k�nyvt�ri oszt�lyok m�dos�t�s�ra, az ilyen m�dos�t�s probl�m�khoz vezethet.

P�ld�ul sz�ks�gess� v�lhat a virtu�lis f�ggv�nyek �l-megval�s�t�sa olyan oszt�lyok


eset�-
ben, amelyekn�l azok nem sz�ks�gesek vagy nem �rtelmesek. Ezt a probl�m�t a
�24.4.3 n�-
mileg r�szletesebben t�rgyalja. Az RTTI-nek egy egyszeru, objektumokat kezelo ki-
�s bemeneti
rendszer elk�sz�t�s�re szolg�l� haszn�lat�t a �25.4.1 �rja le.
Azok sz�m�ra, akik a Smalltalkon vagy a Lispen, esetleg m�s, nagym�rt�kben a
dinamikus
t�pusellenorz�sre �p�to nyelveken nevelkedtek, cs�b�t� dolog az RTTI-t t�ls�gosan
�ltal�-
nos t�pusokkal egy�tt haszn�lni. Vegy�k ezt a p�ld�t:
// a fut�si ideju t�pusinform�ci� helytelen haszn�lata
class Object { /* ... */ }; // t�bbalak�
class Container : public Object {
public:
void put(Object*);
Object* get();
// ...
};
class Ship : public Object { /* ... */ };
Ship* f(Ship* ps, Container* c)
{
c->put(ps);
// ...
Object* p = c->get();
if (Ship* q = dynamic_cast<Ship*>(p)) { // fut�si ideju ellenorz�s
return q;
}
548 Absztrakci�s m�dszerek
else {
// valami m�st csin�lunk (�ltal�ban hibakezel�st v�gz�nk)
}
}
Itt az Object oszt�ly sz�ks�gtelen �s mesterk�lt. T�ls�gosan �ltal�nos, mert az
adott alkalmaz
�sban nem felel meg semmilyen elvonatkoztat�si szintnek �s a programoz�t egy
megval�-
s�t�s-szintu fogalom haszn�lat�ra k�nyszer�ti. Az ilyen jellegu probl�m�kat
gyakran jobban
oldja meg, ha kiz�r�lag egy adott t�pus� mutat�t tartalmaz� t�rol� sablonokat
haszn�lunk:
Ship* f(Ship* ps, list<Ship*>& c)
{
c.push_front(ps);
// ...
return c.pop_front();
}
Virtu�lis f�ggv�nyekkel egy�tt haszn�lva �gy majdnem minden esetet megoldhatunk.
15.5. Tagra hivatkoz� mutat�k
Sok oszt�lynak van egyszeru, nagyon �ltal�nos fel�lete, amelyet sokf�le
haszn�latra sz�ntak.
P�ld�ul sok .objektumorient�lt. felhaszn�l�i fel�let hat�roz meg egy sor k�r�st,
amelyre
minden, a k�pernyon megjelen�tett objektumnak tudnia kell v�laszolni. R�ad�sul az
ilyen
k�r�sek k�zvetett vagy k�zvetlen m�don programokt�l �rkezhetnek. Vegy�k ezen elv
egy
egyszeru v�ltozat�t:
class Std_interface {
public:
virtual void start() = 0;
virtual void suspend() = 0;
virtual void resume() = 0;
virtual void quit() = 0;
virtual void full_size() = 0;
virtual void small() = 0;
virtual ~Std_interface() {}
};
15. Oszt�lyhierarchi�k 549
Minden muvelet pontos jelent�s�t az az objektum defini�lja, amelyre alkalmazz�k.
Gyakran
a k�r�st kiad� szem�ly vagy program �s a fogad� objektum k�z�tt egy szoftverr�teg
van.
Ide�lis esetben az ilyen k�ztes r�tegeknek nem kell semmit tudniuk az egyes
muveletekrol
(resume(), full_size() stb.). Ha tudn�nak, a k�ztes r�tegeket fel kellene �j�tani,
valah�nyszor
a muveletek halmaza megv�ltozik. K�vetkez�sk�ppen az ilyen k�ztes r�tegek csup�n
tov�bb�tanak valamely, az alkalmazand� muveletre vonatkoz� adatot a k�r�s
forr�s�t�l
a fogad�hoz.
Ennek egyszeru m�dja az alkalmazand� muveletet jel�lo karakterl�nc k�ld�se.
P�ld�ul
a suspend() megh�v�sa c�lj�b�l a .suspend. (felf�ggeszt�s) sz�veget k�ldhetn�nk.
Valakinek
azonban l�tre kell hoznia a karakterl�ncot, valakinek pedig meg kell fejtenie,
melyik
muvelethez tartozik, ha egy�ltal�n tartozik valamelyikhez. Ez gyakran t�ls�gosan
k�zvetettnek
�s f�rads�gosnak tunik. Ehelyett k�ldhetn�nk csak egy, a muveletet jel�lo eg�sz
�rt�-
ket. Mondjuk a 2 jelenthetn� a suspend-et. De am�g egy eg�sz sz�mot a sz�m�t�g�pek
k�-
nyelmesen kezelnek, az emberek sz�m�ra ez meglehetosen zavar� lehet, r�ad�sul m�g
mindig meg kell �rnunk a k�dot, amely meghat�rozza, hogy a 2 a suspend()-et
jelenti �s
meg kell h�vnunk a suspend()-et.
A C++ nyelv lehetov� teszi az oszt�lyok tagjainak k�zvetett el�r�s�t. A tagra
hivatkoz� mutat
� olyan �rt�k, amely az oszt�ly egy tagj�t azonos�tja. Gondolhatunk r� �gy, mint
egy, az
adott oszt�lyhoz tartoz� objektumban levo tag hely�re, de a ford�t� term�szetesen
figyelembe
veszi az adattagok, a virtu�lis �s nem virtu�lis f�ggv�nyek stb. k�z�tti
k�l�nbs�get.
Vegy�k az Std_interface-t. Ha meg akarjuk h�vni a suspend()-et valamely objektumra
an�lk
�l, hogy k�zvetlen�l megnevezn�nk, akkor egy olyan mutat�ra lesz sz�ks�g�nk, ami
az
Std_interface::suspend() tagra mutat. Ugyancsak sz�ks�g�nk lesz a suspend() r�v�n
felf�ggesztend
o objektumra hivatkoz� mutat�ra vagy referenci�ra. Vegy�nk egy igen egyszeru
p�ld�t:
typedef void (Std_interface::* Pstd_mem)(); // tagra hivatkoz� mutat�
void f(Std_interface* p)
{
Pstd_mem s = &Std_interface::suspend;
p->suspend(); // k�zvetlen h�v�s
(p->*s)(); // h�v�s tagra hivatkoz� mutat�n kereszt�l
}
550 Absztrakci�s m�dszerek
Egy tagra hivatkoz� mutat�t (pointer to member) �gy kapunk, hogy a c�mk�pzo &
oper�-
tort egy teljes nevu (.teljesen minos�tett., fully qualified) oszt�lytagra
alkalmazzuk (p�ld�ul
&Std_interface::suspend()). Az .X oszt�ly egy tagj�ra hivatkoz� mutat�. t�pus�
v�ltoz�kat
az X::* form�ban deklar�lhatjuk.
A C szintaxis �ttekinthetos�g�nek hi�ny�t �ltal�ban a typedef alkalmaz�s�val
ellens�lyozz�k,
az X::* forma viszont l�that�an nagyon sz�pen megfelel a hagyom�nyos *
deklar�tornak.
Egy m tagra hivatkoz� mutat�t egy objektummal kapcsolatban haszn�lhatunk. A
kapcsolatot
a ->* �s .* oper�torokkal fejezhetj�k ki. P�ld�ul a p->*m az m-et a p �ltal
mutatott objektumhoz
k�ti, az obj.*m pedig az obj objektumhoz. Az eredm�ny az m t�pus�nak megfelel
oen haszn�lhat�, de a ->* vagy .* muvelet eredm�ny�t nem lehet k�sobbi haszn�latra

f�lretenni.
Term�szetesen ha tudn�nk, melyik tagot akarjuk megh�vni, k�zvetlen�l megh�vn�nk
azt,
a tagra hivatkoz� mutat�kkal val� bajl�d�s helyett. A k�z�ns�ges
f�ggv�nymutat�khoz hasonl
�an a tagf�ggv�nyekre hivatkoz� mutat�kat akkor haszn�ljuk, amikor a tag nev�nek
ismerete
n�lk�l akarunk egy f�ggv�nyre hivatkozni. A tagra hivatkoz� mutat� azonban nem
egyszeruen egy mutat� egy mem�riater�letre, mint egy v�ltoz� c�me vagy egy
f�ggv�nymutat
�, ink�bb egy adatszerkezeten bel�li eltol�sra (offszetre) vagy egy t�mbbeli
indexre
hasonl�t. Amikor egy tagra hivatkoz� mutat�t a megfelelo t�pus� objektumra
hivatkoz� mutat
�val p�ros�tjuk, olyasvalami keletkezik, ami egy bizonyos objektum egy bizonyos
tagj�t
azonos�tja. Ezt rajzzal �gy �br�zolhatjuk:
Mivel egy virtu�lis tagra hivatkoz� mutat� (a fenti p�ld�ban s) egyfajta eltol�s,
nem f�gg az
objektum hely�tol a mem�ri�ban, ez�rt biztons�gosan �tadhat� egy m�sik c�mt�rnek
(address space), felt�ve, hogy az objektum elhelyezked�se a kettoben azonos. A
k�z�ns�-
ges f�ggv�nyekre hivatkoz� mutat�khoz hasonl�an a nem virtu�lis tagf�ggv�nyekre
hivatkoz
� mutat�kat sem lehet m�sik c�mt�rnek �tadni.
15. Oszt�lyhierarchi�k 551
X::start
X::suspend
p
s
vtbl:
Jegyezz�k meg, hogy a f�ggv�nymutat�n kereszt�l megh�vott f�ggv�ny lehet virtu�lis
is.
P�ld�ul amikor egy f�ggv�nymutat�n kereszt�l megh�vjuk a suspend()-et, akkor azon
objektum
t�pus�nak megfelelo suspend()-et kapjuk, amelyre a f�ggv�nymutat�t alkalmaztuk.
Ez a f�ggv�nymutat�knak igen l�nyeges tulajdons�ga.
Egy tolm�csol� (tov�bb�t�, interpreter) f�ggv�ny egy tagra hivatkoz� mutat�
seg�ts�g�vel
megh�vhat egy karakterl�nccal (vagyis sz�veggel) megadott f�ggv�nyt:
map<string,Std_interface*> variable;
map<string,Pstd_mem> operation;
void call_member(string var, string oper)
{
(variable[var]->*operation[oper])(); // var.oper()
}
A tagf�ggv�nyekre hivatkoz� mutat�k legfontosabb haszn�lat�t a �3.8.5 �s �18.4
pontbeli
mem_fun() f�ggv�nyben vizsg�lhatjuk meg.
A statikus tagok nem tartoznak egy bizonyos objektumhoz, �gy egy statikus tagra
hivatkoz
� mutat� csup�n egy k�z�ns�ges mutat�:
class Task {
// ...
static void schedule();
};
void (*p)() = &Task::schedule; // rendben
void (Task::* pm)() = &Task::schedule; // hiba: egyszeru mutat�t adtunk �rt�k�l
// tagra hivatkoz� mutat�nak
Az adattagokra hivatkoz� mutat�kat a �C.12 pont �rja le.
15.5.1. B�zis- �s sz�rmaztatott oszt�lyok
Egy sz�rmaztatott oszt�ly legal�bb azokkal a tagokkal rendelkezik, amelyeket a
b�zisoszt
�lyb�l �r�k�l, de gyakran t�bbel. Ez azt jelenti, hogy egy b�zisoszt�ly egy
tagj�ra hivatkoz
� mutat�t biztons�gosan �rt�k�l adhatunk egy sz�rmaztatott oszt�lytagra hivatkoz�
mutat�nak, de ford�tva nem. Ezt a tulajdons�got gyakran kontravarianci�nak
(contravariance) h�vj�k:
552 Absztrakci�s m�dszerek
class text : public Std_interface {
public:
void start();
void suspend();
// ...
virtual void print();
private:
vector s;
};
void (Std_interface::* pmi)() = &text::print; // hiba
void (text::*pmt)() = &Std_interface::start; // rendben
A fel nem cser�lhetos�g ezen szab�lya l�tsz�lag ellenkezik azzal a szab�llyal,
hogy egy sz�rmaztatott
oszt�lyra hivatkoz� mutat�t �rt�k�l adhatunk a b�zisoszt�ly�ra hivatkoz� mutat
�nak. Val�j�ban azonban mindk�t szab�ly az�rt van, hogy biztos�tsa az alapveto
garanci�t
arra, hogy egy mutat� soha nem mutat olyan objektumra, amelynek nincsenek meg a
mutat
� t�pusa �ltal �g�rt tulajdons�gai. Ebben az esetben az Std_interface::* b�rmilyen

Std_interface-re alkalmazhat�, �s a legt�bb ilyen objektum v�lhetoleg nem text


t�pus� lesz.
Ez�rt azt�n nincs meg a text::print tagjuk, amellyel pmi-nek kezdo�rt�ket
pr�b�ltunk adni.
A kezdeti �rt�kad�s megtagad�s�val a ford�t�program egy fut�si ideju hib�t�l ment
meg
benn�nket.
15.6. A szabad t�r
Az operator new() �s az operator delete() defini�l�s�val �t lehet venni a
mem�riakezel�st
egy oszt�lyt�l (�6.2.6.2). Ezen glob�lis f�ggv�nyek kicser�l�se azonban nem a
f�l�nkeknek
val�, hiszen elofordulhat, hogy valaki az alap�rtelmezett viselked�sre sz�m�t vagy
ezen
f�ggv�nyek valamilyen m�s v�ltozat�t m�r meg is �rta.
Gyakran jobb megk�zel�t�s ezeket a muveleteket egy bizonyos oszt�lyra meg�rni. Ez
az
oszt�ly t�bb sz�rmaztatott oszt�ly alapja is lehet. Tegy�k fel, hogy a �12.2.6-
beli Employee
oszt�lyt �s annak minden lesz�rmazottj�t szeretn�nk egyedi mem�riafoglal�val
(allok�torral)
�s -felszabad�t�val (deallok�torral) ell�tni:
class Employee {
// ...
public:
// ...
15. Oszt�lyhierarchi�k 553
void* operator new(size_t);
void operator delete(void*, size_t);
};
Az operator new() �s az operator delete() tagf�ggv�nyek automatikusan statikusak
lesznek,
ez�rt nincs this mutat�juk �s nem v�ltoztatnak meg egy objektumot, csak olyan
t�rter�letet
adnak, amelyet a konstruktorok felt�lthetnek �s a destruktorok kitakar�thatnak.
void* Employee::operator new(size_t s)
{
// lefoglal 's' b�jtnyi mem�ri�t �s r� hivatkoz� mutat�t ad vissza
}
void Employee::operator delete(void* p, size_t s)
{
if (p) { // t�rl�s csak ha p!=0; l�sd �6.2.6, �6.2.6.2
// feltessz�k, hogy 'p' 's' b�jt mem�ri�ra mutat, amit az Employee::operator new()
foglalt le
// felszabad�tjuk a mem�ri�t
}
}
Az eddig rejt�lyes size_t param�ter haszna most vil�goss� v�lik. Ez ugyanis a
t�nylegesen
t�rlendo objektum m�rete. Ha egy .sima. Employee-t t�rl�nk, akkor
param�ter�rt�kk�nt
sizeof(Employee)-t; ha egy Manager-t, akkor sizeof(Manager)-t kapunk.
Term�szetesen az
adott oszt�ly egyedi mem�riafoglal�ja t�rolhatja az ilyen inform�ci�t (mint ahogy
az �ltal�-
nos c�l�nak is meg kell ezt tennie) �s nem t�rodhet az operator delete() f�ggv�ny
size_t param
�ter�vel. Ez azonban nehezebb� teszi egy �ltal�nos c�l� mem�riafoglal�
sebess�g�nek
�s mem�riafogyaszt�s�nak jav�t�s�t.
Honnan tudja a ford�t�program a delete() oper�tort a megfelelo m�retettel ell�tni?
K�nnyen,
am�g a delete muveletnek �tadott t�pus azonos az objektum t�nyleges t�pus�val. Ez
azonban
nincs mindig �gy:
class Manager : public Employee {
int level;
// ...
};
void f()
{
Employee* p = new Manager; // probl�m�s (a pontos t�pus ismerete elv�sz)
delete p;
}
Ekkor a ford�t�program nem fogja tudni a pontos m�retet. A t�mb t�rl�s�hez
hasonl�an itt
is a programoz� seg�ts�g�re van sz�ks�g; az Employee b�zisoszt�lyban meg kell adni
egy
virtu�lis destruktort:
554 Absztrakci�s m�dszerek
class Employee {
public:
void* operator new(size_t);
void operator delete(void*, size_t);
virtual ~Employee();
// ...
};
Ak�r egy �res destruktor is megteszi:
Employee::~Employee() { }
A mem�ria felszabad�t�s�t a (m�retet ismero) destruktor v�gzi. Sot ha az Employee-
ben van
destruktor, akkor ez biztos�tja, hogy minden belole sz�rmaztatott oszt�lynak lesz
destruktora (�s �gy tudja a m�retet), akkor is, ha a sz�rmaztatott oszt�lyban nem
szerepel
felhaszn�l�i destruktor:
void f()
{
Employee* p = new Manager;
delete p; // most m�r j� (az Employee t�bbalak�)
}
A mem�ria lefoglal�sa egy (a ford�t�program �ltal l�trehozott) h�v�ssal t�rt�nik:
Employee::operator new(sizeof(Manager))
A felszabad�t�sr�l szint�n egy (a ford�t�program �ltal l�trehozott) h�v�s
gondoskodik:
Employee::operator delete(p,sizeof(Manager))
Vagyis ha olyan mem�riafoglal�/felszabad�t� p�rt akarunk �rni, amely sz�rmaztatott
oszt�-
lyokkal is j�l muk�dik, akkor vagy virtu�lis destruktort kell �rni a
b�zisoszt�lyban, vagy nem
szabad felhaszn�lni a felszabad�t�ban a size_t param�tert. Term�szetesen meg
lehetett volna
�gy tervezni a nyelvet, hogy ne legyen sz�ks�g ilyen megfontol�sokra, de ez csak a
kev
�sb� biztons�gos rendszerekben lehets�ges optimaliz�l�sok elonyeirol val� lemond�s

�r�n t�rt�nhetett volna.


15. Oszt�lyhierarchi�k 555
15.6.1. Mem�riafoglal�s t�mb�k sz�m�ra
Az operator new() �s az operator delete() f�ggv�nyek lehetov� teszik, hogy a
programoz�
v�gezze az egyes objektumok sz�m�ra a mem�riafoglal�st �s -felszabad�t�st. Az
operator
new[ ]() �s az operator delete[ ]() pontosan ugyanezt a szerepet j�tssza a t�mb�k
eset�ben:
class Employee {
public:
void* operator new[ ](size_t);
void operator delete[ ](void*);
// ...
};
void f(int s)
{
Employee* p = new Employee[s];
// ...
delete[ ] p;
}
Itt a sz�ks�ges mem�ri�t a
Employee::operator new[ ](sizeof(Employee)*s+delta)
h�v�s fogja biztos�tani, ahol a delta az adott ford�t�t�l f�ggo minim�lis t�bblet.
A mem�ri�t
az al�bbi h�v�s szabad�tja fel:
Employee::operator delete[ ](p); // felszabad�t s*sizeof(Employee)+delta b�jtot
Az elemek s sz�m�t (illetve a delta-t) a rendszer .megjegyzi.. Ha a delete[ ]()-et
egy- helyett
k�tparam�teres form�ban adtuk volna meg, a h�v�sban a m�sodik param�ter
s*sizeof(Employee) +delta lett volna.
15.6.2. .Virtu�lis konstruktorok.
Miut�n virtu�lis destruktorokr�l hallottunk, nyilv�nval� a k�rd�s: .lehetnek-e
a konstruktorok is virtu�lisak?.. A r�vid v�lasz az, hogy nem. A kicsit hosszabb:
nem, de
a k�v�nt hat�s k�nnyen el�rheto. Egy objektum l�trehoz�s�hoz a konstruktornak
tudnia kell
a l�trehozand� objektum pontos t�pus�t. Ez�rt a konstruktor nem lehet virtu�lis.
R�ad�sul
a konstruktor nem eg�szen olyan, mint a k�z�ns�ges f�ggv�nyek. P�ld�ul olyan
m�dokon
muk�dik egy�tt a mem�riakezelo elj�r�sokkal, ahogy a k�z�ns�ges f�ggv�nyek nem.
Ez�rt
nincs konstruktorra hivatkoz� mutat�.
556 Absztrakci�s m�dszerek
Mindk�t megszor�t�s megker�lheto egy konstruktort megh�v� �s a l�trehozott
objektumot
visszaad� f�ggv�ny k�sz�t�s�vel. Ez kedvezo, mert gyakran hasznos lehet, ha a
pontos t�-
pus ismerete n�lk�l tudunk �j objektumot l�trehozni. Az Ival_box_maker oszt�ly
(�12.4.4)
pontosan erre a c�lra szolg�lt. Itt az �tlet egy m�sik v�ltozat�t mutatom be, ahol
egy oszt�ly
objektumai a felhaszn�l�iknak k�pesek saj�t maguk m�solat�t �tadni:
class Expr {
public:
Expr(); // alap�rtelmezett konstruktor
Expr(const Expr&); // m�sol� konstruktor
virtual Expr* new_expr() { return new Expr(); }
virtual Expr* clone() { return new Expr(*this); }
// ...
};
Mivel a new_expr()-hez �s a clone()-hoz hasonl� f�ggv�nyek virtu�lisak �s
k�zvetett �ton
objektumokat hoznak l�tre, gyakran h�vj�k oket .virtu�lis konstruktornak., b�r az
elnevez
�s n�mileg f�lrevezeto. Mindegyik egy konstruktort haszn�l, hogy megfelelo
objektumot
hozzon l�tre.
Egy sz�rmaztatott oszt�ly fel�l�rhatja a new_expr() �s/vagy clone() f�ggv�nyt,
hogy egy saj
�t t�pus� objektumot adjon vissza:
class Cond : public Expr {
public:
Cond();
Cond(const Cond&);
Cond* new_expr() { return new Cond(); }
Cond* clone() { return new Cond(*this); }
// ...
};
Ez azt jelenti, hogy egy Expr oszt�ly� objektumhoz a felhaszn�l� .pontosan
ugyanolyan t�-
pus�. objektumot tud l�trehozni:
void user(Expr* p)
{
Expr* p2 = p->new_expr();
// ...
}
A p2-h�z rendelt mutat� megfelelo, b�r ismeretlen t�pus�.
15. Oszt�lyhierarchi�k 557
A Cond::new_expr() �s a Cond::clone() visszat�r�si t�pusa Cond* �s nem Expr* ,
ez�rt egy
Cond inform�ci�veszt�s n�lk�l lem�solhat� (.kl�nozhat�.):
void user2(Cond* pc, Expr* pe)
{
Cond* p2 = pc->clone();
Cond* p3 = pe->clone(); // hiba
// ...
}
A fel�l�r� f�ggv�nyek t�pusa ugyanaz kell, hogy legyen, mint a fel�l�rt virtu�lis
f�ggv�ny�,
de a visszat�r�si �rt�k t�pusa kev�sb� szigor�an k�t�tt. Vagyis ha az eredeti
visszat�r�si �rt
�k B* volt, akkor a fel�l�r� f�ggv�ny visszat�r�si �rt�ke lehet D* is, felt�ve,
hogy B nyilv�-
nos b�zisoszt�lya D-nek. Ugyan�gy egy B& visszat�r�si �rt�k D&-ra m�dos�that�.
Jegyezz�k meg, hogy a param�tert�pusok hasonl� m�dos�t�sa t�pushib�hoz vezetne
(l�sd
�15.8[12]).
15.7. Tan�csok
[1] Ha tulajdons�gok uni�j�t akarjuk kifejezni, haszn�ljunk k�z�ns�ges t�bbsz�r�s
�r�klod�st. �15.2, �15.2.4.
[2] A tulajdons�goknak a megval�s�t� k�dt�l val� elv�laszt�s�ra haszn�ljunk t�bbsz
�r�s �r�klod�st. �15.2.5.
[3] Haszn�ljunk virtu�lis b�zisoszt�lyt, ha egy hierarchia n�mely (de nem
mindegyik)
oszt�ly�ra n�zve k�z�s dolgot akarunk kifejezni. �15.2.5.
[4] Ker�lj�k a t�pusk�nyszer�t�st (cast). �15.4.5.
[5] Ha az adott oszt�lyhierarchia bej�r�sa elker�lhetetlen, haszn�ljuk
a dynamic_cast-ot. �15.4.1.
[6] A typeid helyett r�szes�ts�k elonyben a dynamic_cast-ot. �15.4.4.
[7] A protected-del szemben r�szes�ts�k elonyben a private-et. �15.3.1.1.
[8] Adattagokat ne adjunk meg v�dettk�nt. �15.3.1.1.
[9] Ha egy oszt�ly defini�lja az operator delete()-et, akkor legyen virtu�lis
destruktora. �15.6.
[10] A konstruktor vagy destruktor fut�sa alatt ne h�vjunk virtu�lis f�ggv�nyt.
�15.4.3.
[11] Ritk�n . �s lehetoleg csak fel�l�r� virtu�lis f�ggv�nyekben . haszn�ljuk a
tagnevek
explicit minos�t�s�t felold�s c�lj�ra. �15.2.1.
558 Absztrakci�s m�dszerek
15.8. Gyakorlatok
1. (*1) �rjunk olyan ptr_cast sablont, amely ugyan�gy muk�dik, mint
a dynamic_cast, de a 0-val val� visszat�r�s helyett bad_cast kiv�telt v�lt ki.
2. (*2) �rjunk olyan programot, amely egy objektum l�trehoz�sa k�zben az RTTIhez
viszony�tva mutatja be a konstruktorh�v�sok sorrendj�t. Hasonl�an mutassuk
be az objektum lebont�s�t.
3. (*3.5) �rjuk meg a Reversi/Othello t�rsasj�t�k egy v�ltozat�t. Minden j�t�kos
lehessen
�lo szem�ly vagy sz�m�t�g�p. Elosz�r a program helyes muk�d�s�re
�sszpontos�tsunk, �s csak azut�n arra, hogy a program annyira .okos. legyen,
hogy �rdemes legyen ellene j�tszani.
4. (*3) Jav�tsunk a �15.8[3]-beli j�t�k felhaszn�l�i fel�let�n.
5. (*3) K�sz�ts�nk egy grafikus objektumoszt�lyt egy muvelethalmazzal, amely
alapj�n grafikus objektumok egy k�nyvt�ra sz�m�ra k�z�s b�zisoszt�ly lehet.
N�zz�nk bele egy grafikus k�nyvt�rba, hogy ott milyen muveletek vannak. Hozzunk
l�tre egy adatb�zis-objektum oszt�lyt egy muvelethalmazzal, amely alapj�n
elhiheto, hogy k�z�s b�zisoszt�lya az adatb�zisban mezok sorak�nt t�rolt
objektumoknak.
Vizsg�ljunk meg egy adatb�zis-k�nyvt�rat, hogy ott milyen muveletek
vannak. Hat�rozzunk meg egy grafikus adatb�zis-objektumot t�bbsz�r�s �r�klo-
d�ssel �s an�lk�l, �s hasonl�tsuk �ssze a k�t megold�s elonyeit �s h�tr�nyait.
6. (*2) �rjuk meg a �15.6.2-beli clone() muvelet egy olyan v�ltozat�t, amely a
param
�terben megkapott Arena-ba (�10.4.11) teszi a lem�solt objektumot. K�sz�ts�nk
egy .egyszeru Arena.-t mint az Arena-b�l sz�rmaz� oszt�lyt.
7. (*2) An�lk�l, hogy belen�zn�nk a k�nyvbe, �rjunk le annyi C++-kulcssz�t,
amennyit csak tudunk.
8. (*2) �rjunk szabv�nyos C++-programot, amelyben legal�bb t�z k�l�nb�zo kulcssz
� szerepel egym�s ut�n, �gy, hogy nincs azonos�t�kkal, oper�torokkal vagy
�r�sjelekkel elv�lasztva.
9. (*2.5) Rajzoljuk le a �15.2.4-beli Radio objektum mem�riakioszt�s�nak egy
lehets�-
ges v�ltozat�t. Magyar�zzuk el, hogyan lehetne egy virtu�lis f�ggv�nyt megh�vni.
11. (*3) Gondoljuk meg, hogyan lehet a dynamic_cast-ot megval�s�tani. K�sz�ts�nk
egy dcast sablont, amely �gy viselkedik, mint a dynamic_cast, de csak az �ltalunk
meghat�rozott f�ggv�nyekre �s adatokra t�maszkodik. Gondoskodjunk arr
�l, hogy a rendszert a dcast vagy az elozoleg megadott oszt�lyok megv�ltoztat�-
sa n�lk�l lehessen �j oszt�lyokkal bov�teni.
12. (*2) Tegy�k fel, hogy a f�ggv�nyparam�terek t�pus-ellenorz�si szab�lyai a
visszat
�r�si �rt�kre vonatkoz�akhoz hasonl�an enyh�tettek, teh�t egy Derived* param
�teru f�ggv�ny fel�l�rhat egy Base*-ot. �rjunk egy programot, ami konverzi�
n�lk�l elrontana egy Derived t�pus� objektumot. �rjuk le a param�tert�pusokra
vonatkoz� fel�l�r�si szab�lyok egy biztons�gos enyh�t�s�t.
15. Oszt�lyhierarchi�k 559
Harmadik r�sz
A standard k�nyvt�r
Ebben a r�szben a C++ standard k�nyvt�r�t mutatjuk be. Megvizsg�ljuk a k�nyvt�r
szerkezet
�t �s azokat az alapveto m�dszereket, amelyeket az egyes elemek megval�s�t�s�hoz
haszn�ltak. C�lunk az, hogy meg�rts�k, hogyan kell haszn�lni ezt a k�nyvt�rat,
illetve
szeml�ltess�k azokat az �ltal�nos m�dszereket, amelyeket tervez�skor �s
programoz�skor
haszn�lhatunk. Ezenk�v�l bemutatjuk azt is, hogyan bov�thetj�k a k�nyvt�rat,
pontosabban
a rendszer fejlesztoi hogyan k�pzelt�k el a tov�bbfejleszt�st.
Fejezetek
16.A k�nyvt�r szerkezete �s a t�rol�k
17. Szabv�nyos t�rol�k
18. Algoritmusok �s f�ggv�nyobjektumok
19. Bej�r�k �s mem�riafoglal�k
20. Karakterl�ncok
21. Adatfolyamok
22. Sz�mok
....s te, Marcus, oly sok mindent adt�l nekem, �m �n adok neked most egy
j�tan�csot. Sok
ember l�gy. Hagyd el a r�gi j�t�kot, hogy mindig csak ugyanaz a Marcus Cocoza
vagy.
T�lont�l sokat vesszodt�l m�r Marcus Cocoz�val, m�g v�g�l val�s�ggal a rabszolg�ja
lett�l.
Szinte semmit sem teszel an�lk�l, hogy ne m�rlegeln�d, vajon milyen hat�ssal lesz
Marcus
Cocoza boldogs�g�ra �s tekint�ly�re. Sz�ntelen f�lelemben �lsz, hogy Marcus Cocoza

esetleg valami ostobas�got k�vet el, vagy elunja mag�t. Deh�t mit sz�m�t mindez
val�j�ban?
Az emberek az eg�sz vil�gon ostobas�gokat muvelnek... Szeretn�m ha felszabaduln�l,
ha
sz�ved �jra megtal�ln� b�k�j�t. Mostant�l fogva ne csak egy, hanem t�bb ember
l�gy,
annyi, amennyit csak el tudsz gondolni....
(Karen Blixen: �lmodoz�k; Kert�sz Judit ford�t�sa)
A k�nyvt�r szerkezete �s a t�rol�k
.�jdons�g volt.
Egyedi volt. Egyszeru volt.
Biztos, hogy sikeres lesz!.
(H. Nelson)
Tervez�si szempontok a standard k�nyvt�rhoz . A k�nyvt�r szerkezete . Szabv�nyos
fej�llom
�nyok . Nyelvi t�mogat�s . A t�rol�k szerkezete . Bej�r�k . B�zisoszt�llyal
rendelkezo
t�rol�k . Az STL t�rol�i . vector . Bej�r�k . Elemek el�r�se . Konstruktorok .
M�dos�t�k
. Listamuveletek . M�ret �s kapacit�s . vector<bool> . Tan�csok . Gyakorlatok
16.1. A standard k�nyvt�r
Minek kell szerepelnie a C++ standard k�nyvt�r�ban? A programoz� szempontj�b�l az
tu-
nik ide�lisnak, ha egy k�nyvt�rban megtal�l minden olyan oszt�lyt, f�ggv�nyt, �s
sablont,
ami �rdekes, jelentos �s el�gg� �ltal�nos. A k�rd�s azonban most nem az, hogy egy
k�nyvt
�rban mi legyen benne, hanem az, hogy a standard k�nyvt�r milyen elemeket
tartalmazzon.
Az elobbi k�rd�s eset�ben �sszeru megk�zel�t�s, hogy minden el�rheto legyen, az
ut�bbi esetben azonban ez nem alkalmazhat�. A standard k�nyvt�r olyan eszk�z,
amelyet
minden C++-v�ltozat tartalmaz, �gy minden programoz� sz�m�that r�.
16
A C++ standard k�nyvt�ra a k�vetkezo szolg�ltat�sokat ny�jtja:
1. T�mogatja a nyelv lehetos�geinek haszn�lat�t, p�ld�ul a mem�riakezel�st
(�6.2.6) �s a fut�si ideju t�pusinform�ci� (RTTI, �15.4) kezel�s�t.
2. Inform�ci�kat ad az adott nyelvi v�ltozat egyedi tulajdons�gair�l, p�ld�ul
megadja a legnagyobb float �rt�ket (�22.2).
3. El�rhetov� teszi azokat a f�ggv�nyeket, amelyeket nem lehet a nyelven bel�l
optim�lisan elk�sz�teni minden rendszer sz�m�ra (p�ld�ul sqrt(), �22.3
vagy memmove(), �19.4.6).
4. Olyan magas szintu szolg�ltat�sokat ny�jt, amelyekre a programoz� m�s
rendszerre
�tviheto (hordozhat�) programok k�sz�t�sekor t�maszkodhat, p�ld�ul
list�kat (�17.2.2), asszociat�v t�mb�ket (map) (�17.4.1), rendezo f�ggv�nyeket
(�18.7.1) �s bemeneti/kimeneti adatfolyamokat (21. fejezet).
5. Keretet biztos�t a k�nyvt�r elemeinek tov�bbfejleszt�s�re, p�ld�ul szab�lyokkal

�s eszk�z�kkel seg�ti, hogy a felhaszn�l� ugyanolyan bemeneti/kimeneti fel�letet


biztos�thasson saj�t t�pusaihoz, mint a k�nyvt�r a be�p�tett t�pusokhoz.
6. Tov�bbi k�nyvt�rak k�z�s alapj�ul szolg�l.
N�h�ny tov�bbi eszk�zt . p�ld�ul a v�letlensz�m-elo�ll�t�kat (�22.7) . csak az�rt
helyeztek
a standard k�nyvt�rba, mert �gy haszn�latuk k�nyelmes �s hagyom�nyosan itt a
hely�k.
A k�nyvt�r tervez�sekor legink�bb az utols� h�rom szerepk�rt vett�k figyelembe.
Ezek
a szerepek erosen �sszef�ggnek. A hordozhat�s�g p�ld�ul olyan �ltal�nos fogalom,
amely
fontos tervez�si szempont minden egyedi c�l� k�nyvt�r eset�ben. A k�z�s
t�rol�t�pusok
(p�ld�ul a list�k vagy asszociat�v t�mb�k) pedig igen jelentosek a k�l�n
fejlesztett k�nyvt
�rak k�nyelmes egy�ttmuk�d�s�nek biztos�t�s�ban.
Az utols� pont k�l�n�sen fontos a tervez�s szempontj�b�l, mert ezzel korl�tozhat�
a standard
k�nyvt�r hat�k�re �s g�tat szabhatunk a szolg�ltat�sok �z�n�nek. A karakterl�nc-
�s
listakezelo lehetos�gek p�ld�ul a standard k�nyvt�rban kaptak helyet. Ha ez nem
�gy t�rt
�nt volna, akkor a k�l�n fejlesztett k�nyvt�rak csak a be�p�tett t�pusok
seg�ts�g�vel mu-
k�dhetn�nek egy�tt egym�ssal. Ugyanakkor a mintailleszto �s a grafikai lehetos�gek
nem
szerepelnek itt, mert . b�r tagadhatatlanul sz�les k�rben haszn�latosak . nem
kimondottan
a k�l�n fejlesztett k�nyvt�rak k�z�tti egy�ttmuk�d�st szolg�lj�k.
Ha egy lehetos�g nem felt�tlen�l sz�ks�ges a fenti szerepk�r�k teljes�t�s�hez,
akkor azt
megval�s�thatjuk k�l�n, a standard k�nyvt�ron k�v�l is. Azzal, hogy kihagyunk egy
szolg�ltat
�st a standard k�nyvt�rb�l, azt a lehetos�get is nyitva hagyjuk a tov�bbi
k�nyvt�rak sz�-
m�ra, hogy ugyanazt az �tletet m�s-m�s form�ban val�s�ts�k meg.
564 A standard k�nyvt�r
16.1.1. Tervez�si korl�toz�sok
A standard k�nyvt�rak szerepk�reibol sz�mos korl�toz�s k�vetkezik a k�nyvt�r
szerkezet
�re n�zve. A C++ standard k�nyvt�ra �ltal k�n�lt szolg�ltat�sok tervez�sekor az
al�bbi
szempontokat tartott�k szem elott:
1. Komoly seg�ts�get jelentsen l�nyeg�ben minden tanul� �s profi programoz�
sz�m�ra, k�z�j�k �rtve a tov�bbi k�nyvt�rak fejlesztoit is.
2. K�zvetve vagy k�zvetlen�l minden programoz� felhaszn�lhassa az �sszes olyan
c�lra, ami a k�nyvt�r hat�sk�r�be esik.
3. El�g hat�kony legyen ahhoz, hogy a k�sobbi k�nyvt�rak elo�ll�t�s�ban komoly
vet�lyt�rsa legyen a saj�t kezuleg elo�ll�tott f�ggv�nyeknek, oszt�lyoknak �s
sablonoknak.
4. Mentes legyen az elj�r�sm�d szab�lyoz�s�t�l, vagy lehetos�get adjon r�, hogy
a felhaszn�l� param�terk�nt hat�rozza meg az elj�r�sm�dot.
5. Legyen primit�v, a matematikai �rtelemben. Egy olyan �sszetevo, amely k�t,
gyeng�n �sszef�ggo feladatk�rt t�lt be, kev�sb� hat�kony, mint k�t �n�ll�
komponens, amelyeket kimondottan az adott szerep bet�lt�s�re fejlesztettek ki.
6. Legyen k�nyelmes, hat�kony �s el�g biztons�gos a szok�sos felhaszn�l�si ter�-
leteken.
7. Ny�jtson teljesk�ru szolg�ltat�sokat ahhoz, amit v�llal. A standard k�nyvt�r
fontos
feladatok megval�s�t�s�t is r�hagyhatja m�s k�nyvt�rakra, de ha egy feladat
teljes�t�s�t v�llalja, akkor elegendo eszk�zt kell biztos�tania ahhoz, hogy az
egyes felhaszn�l�knak �s fejlesztoknek ne kelljen azokat m�s m�dszerekkel
helyettes�teni�k.
8. Legyen �sszhangban a be�p�tett t�pusokkal �s muveletekkel �s biztasson azok
haszn�lat�ra.
9. Alap�rtelmez�s szerint legyen t�pusbiztos (mindig helyesen kezelje a k�l�nb�zo
t�pusokat).
10. T�mogassa az �ltal�nosan elfogadott programoz�si st�lusokat.
11. Legyen bov�theto �gy, hogy a felhaszn�l� �ltal l�trehozott t�pusokat hasonl�
form�ban kezelhess�k, mint a be�p�tett �s a standard k�nyvt�rban
meghat�rozottakat.
Rossz megold�s p�ld�ul, ha egy rendezo f�ggv�nybe be�p�tj�k az �sszehasonl�t�si
m�dszert,
hiszen ugyanazok az adatok m�s-m�s szempont szerint is rendezhetok. Ez�rt a C
standard
k�nyvt�r�nak qsort() f�ggv�nye param�terk�nt veszi �t az �sszehasonl�t�st v�gzo
f�ggv�nyt, �s nem valamilyen r�gz�tett muveletre (p�ld�ul a < oper�torra)
hivatkozik (�7.7).
M�sr�szrol ebben a megold�sban minden egyes �sszehasonl�t�s alkalm�val meg kell
h�v-
16. A k�nyvt�r szerkezete �s a t�rol�k 565
nunk egy f�ggv�nyt, ami t�bbletterhet jelent a qsort() elj�r�st felhaszn�l�
tov�bbi elj�r�sokban.
Szinte minden adatt�pus eset�ben k�nnyen elv�gezhetj�k az �sszehasonl�t�st,
an�lk�l,
hogy f�ggv�nyh�v�ssal rontan�nk a rendszer teljes�tm�ny�t.
Jelentos ez a teljes�tm�nyroml�s? A legt�bb esetben val�sz�nuleg nem. Egyes
algoritmusok
eset�ben azonban ezek a f�ggv�nyh�v�sok adj�k a v�grehajt�si ido jelentos r�sz�t,
ez�rt
ilyenkor a felhaszn�l�k m�s megold�sokat fognak keresni. Ez a probl�m�t a �13.4
pontban
oldottuk meg, ahol bemutattuk, hogyan adhatunk meg �sszehasonl�t�si felt�telt egy
sablonparam
�terrel. A p�lda szeml�ltette, hogy a hat�konys�g �s az �ltal�noss�g k�t egym�ssal

szemben �ll� k�vetelm�ny. Egy szabv�ny k�nyvt�rnak azonban nem csak meg kell
val�s�-
tania feladatait, hanem el�g hat�konyan kell azokat elv�geznie ahhoz, hogy a
felhaszn�l�knak
esz�be se jusson saj�t elj�r�sokat �rni az adott c�lra. Ellenkezo esetben a
bonyolultabb
eszk�z�k fejlesztoi k�nytelenek kiker�lni a standard k�nyvt�r szolg�ltat�sait,
hiszen csak
�gy maradhatnak versenyk�pesek. Ez pedig nem csak a k�nyvt�rak fejlesztoinek okoz
sok
t�bbletmunk�t, hanem azon felhaszn�l�k �let�t is megnehez�ti, akik
platformf�ggetlen
programokat szeretn�nek k�sz�teni vagy t�bb, k�l�n fejlesztett k�nyvt�rat
szeretn�nek
haszn�lni.
A .primit�vs�g. �s a .k�nyelmess�g a szok�sos felhaszn�l�si ter�leteken.
k�vetelm�nyek is
szemben �llnak egym�ssal. Egy szabv�ny k�nyvt�rban az elso k�vetelm�ny azonnal
kiz�r
minden optimaliz�l�si lehetos�get arra n�zve, hogy felk�sz�lj�nk a gyakori
esetekre.
Az olyan �sszetevok azonban, amelyek �ltal�nos, de nem primit�v szolg�ltat�sokat
ny�jtanak,
szerepelhetnek a standard k�nyvt�rban a .primit�vek. mellett, de nem helyett�k.
A k�lcs�n�s kiz�r�s nem akad�lyozhat benn�nket abban, hogy mind a profi, mind az
alkalmi
programoz� �let�t egyszerubb� tegy�k. Azt sem engedhetj�k meg, hogy egy �sszetevo
alap�rtelmezett viselked�se hom�lyos vagy vesz�lyes legyen.
16.1.2. A standard k�nyvt�r szerkezete
A standard k�nyvt�r szolg�ltat�sait az std n�vt�rben defini�lt�k �s fej�llom�nyok
seg�ts�g�-
vel �rhetj�k el azokat. Ezek a fej�llom�nyok jelzik a k�nyvt�r legfontosabb
r�szeit, �gy felsorol
�sukb�l �ttekint�st kaphatunk a k�n�lt eszk�z�krol. Ezek szerint n�zz�k v�gig
a k�nyvt�rat a most k�vetkezo fejezetekben is.
Ezen alfejezet tov�bbi r�sz�ben a fej�llom�nyokat soroljuk fel, szerepeik szerint
csoportos
�tva. Mindegyikrol adunk egy r�vid le�r�st is �s megeml�tj�k, hol tal�lhat�
r�szletes elemz
�s�k. A csoportos�t�st �gy v�lasztottuk meg, hogy illeszkedjen a standard k�nyvt�r
szerkezet
�hez. Ha a szabv�nyra vonatkoz� hivatkoz�st adunk meg (p�ld�ul �s.18.1), akkor az
adott lehetos�get itt nem vizsg�ljuk r�szletesen.
566 A standard k�nyvt�r
Ha egy szabv�nyos fej�llom�ny neve c betuvel kezdodik, akkor az egy szabv�nyos C
k�nyvt�rbeli fej�llom�ny megfeleloje. Minden <X.h> fej�llom�nyhoz, amely a C
standard
k�nyvt�r�nak r�szek�nt neveket ad meg a glob�lis n�vt�rben, l�tezik egy <cX>
megfelelo,
amely ugyanazon neveket az std n�vt�rbe helyezi (�9.2.2).
A multimap �s multiset asszociat�v t�rol�kat sorrendben a <map>, illetve a <set>
�llom�nyban
tal�lhatjuk meg. A priority_queue oszt�ly a <queue> f�jlban szerepel.
A <memory> fej�llom�ny tartalmazza az auto_ptr sablont is, amely elsosorban arra
haszn�lhat
�, hogy sim�bb� tegy�k a mutat�k �s kiv�telek egy�ttmuk�d�s�t (�14.4.2).
16. A k�nyvt�r szerkezete �s a t�rol�k 567
T�rol�k
<vector> T t�pus� elemek egydimenzi�s t�mbje �16.3
<list> T t�pus� elemek k�tir�ny� list�ja �17.2.2
<deque> T t�pus� elemek k�tv�gu sora �17.2.3
<queue> T t�pus� elemekbol k�pzett sor �17.3.2
<stack> T t�pus� elemekbol k�pzett verem �17.3.1
<map> T t�pus� elemek asszociat�v t�mbje �17.4.1
<set> T t�pus� elemek halmaza �17.4.3
<bitset> logikai �rt�kek t�mbje �17.5.3
�ltal�nos eszk�z�k
<utility> oper�torok �s p�rok �17.1.4, �17.4.1.2
<functional> f�ggv�nyobjektumok �18.4
<memory> mem�riafoglal�k a t�rol�khoz �19.4.4
<ctime> C st�lus� d�tum- �s idokezel�s �s.20.5
Bej�r�k
<iterator> bej�r�k �s kezel�s�k 19. fejezet
A bej�r�k (iterator) lehetov� teszik, hogy a szabv�nyos algoritmusokat �ltal�nosan
haszn�lhassuk
a szabv�nyos t�rol�kban �s m�s hasonl� t�pusokban (�2.7.2, �19.2.1).
Egy szokv�nyos �ltal�nos algoritmus egyform�n alkalmazhat� b�rmilyen t�pus� elemek

b�rmilyen sorozat�ra (�3.8, �18.3). A C standard k�nyvt�r�ban szereplo bsearch()


�s qsort()
f�ggv�nyek csak a be�p�tett t�mb�kre haszn�lhat�k, melyek elemeihez a felhaszn�l�
nem
hat�rozhat meg sem m�sol� konstruktort, sem destruktort (�7.7).
A kiv�telkezel�sre t�maszkod� hibaellenorz�st a �24.3.7.1 pontban vizsg�ljuk meg.
568 A standard k�nyvt�r
Algoritmusok
<algorithm> �ltal�nos algoritmusok 18.fejezet
<cstdlib> bsearch() qsort() �18.11
Ellenorz�sek, diagnosztika
<exception> kiv�teloszt�ly �14.10
<stdexcept> szabv�nyos kiv�telek �14.10
<cassert> hibaellenorzo makr� �24.3.7.2
(felt�telezett �rt�k biztos�t�sa)
<cerrno> C st�lus� hibakezel�s �20.4.1
Karakterl�ncok
<string> T t�pus� elemekbol �ll� karakterl�nc 20. fejezet
<cctype> karakterek oszt�lyoz�sa �20.4.2
<cwtype> .sz�les. karakterek oszt�lyoz�sa �20.4.2
<cstring> C st�lus� karakterl�ncokat �20.4.1
kezelo f�ggv�nyek
<cwchar> C st�lus� sz�les karakterl�ncok kezel�se �20.4
<cstdlib> C st�lus� karakterl�ncokat �20.4.1
kezelo f�ggv�nyek
A <cstring> fej�llom�nyban szerepelnek az strlen(), strcpy() stb. f�ggv�nyek. A
<cstdlib>
adja meg az atof() �s atoi() f�ggv�nyeket, amelyek a C st�lus� karakterl�ncokat
alak�tj�k
sz�m�rt�kekre.
Az adatfolyam-m�dos�t�k (manipulator) olyan objektumok, melyek seg�ts�g�vel az
adatfolyamok
�llapot�t megv�ltoztathatjuk (�21.4.6). (P�ld�ul m�dos�thatjuk a lebegopontos sz�-

mok kimeneti form�tum�t.)


A locale az olyan kultur�lis elt�r�sek meghat�roz�s�ra szolg�l, mint a d�tumok
�r�sm�dja,
a p�nzegys�gek jel�l�s�re haszn�lt szimb�lumok vagy a karakterl�ncok rendez�s�re
vonatkoz
� szab�lyok, melyek a k�l�nb�zo term�szetes nyelvekben �s kult�r�kban jelentosen
elt�rhetnek.
16. A k�nyvt�r szerkezete �s a t�rol�k 569
Ki- �s bemenet
<iosfwd> elozetes deklar�ci�k �21.1
az I/O szolg�ltat�sokhoz
<iostream> szabv�nyos bemeneti adatfolyamok �21.2.1
objektumai �s muveletei
<ios> bemeneti adatfolyamok b�zisoszt�lyai �21.2.1
<streambuf> �tmeneti t�r adatfolyamokhoz �21.6
<istream> bemeneti adatfolyam sablon �21.3.1
<ostream> kimeneti adatfolyam sablon �21.2.1
<iomanip> adatfolyam-m�dos�t�k (manipul�torok) �21.4.6.2
<sstream> adatfolyamok �21.5.3
karakterl�ncb�l/karakterl�ncba
<cstdlib> karakteroszt�lyoz� f�ggv�nyek �20.4.2
<fstream> adatfolyamok f�jlokb�l/f�jlokba �21.5.1
<cstdio> a printf() f�ggv�nycsal�d �21.8
<cwchar> printf() szolg�ltat�sok �21.8
.sz�les. karakterekre
Nemzetk�zi szolg�ltat�sok
<locale> kultur�lis elt�r�sek �br�zol�sa �21.7
<clocale> kultur�lis elt�r�sek �br�zol�sa C st�lusban �21.7
A <cstddef> fej�llom�ny hat�rozza meg azt a t�pust, amit a sizeof() f�ggv�ny
visszaad
(size_t), a mutat�knak egym�sb�l val� kivon�sakor keletkezo �rt�k t�pus�t
(ptrdiff_t) �s
a h�rhedt NULL makr�t (�5.1.1).
A hagyom�nyt k�vetve az abs(), �s div() f�ggv�ny a <cstdlib> fej�llom�nyban
tal�lhat�, b�r
matematikai f�ggv�nyek l�v�n jobban illen�nek a <cmath> f�jlba. (�22.3)
A felhaszn�l�k �s a k�nyvt�rak fejlesztoi nem bov�thetik vagy szuk�thetik a
szabv�nyos fej-
�llom�nyokban szereplo deklar�ci�k k�r�t. A fej�llom�nyok jelent�s�t �gy sem
m�dos�thatjuk,
hogy megpr�b�lunk makr�kat megadni az �llom�nyok beszerkeszt�se elott vagy
megv�ltoztatjuk a deklar�ci�k jelent�s�t azzal, hogy saj�t deklar�ci�kat k�sz�t�nk
a fej�llo-
570 A standard k�nyvt�r
A programnyelvi elemek t�mogat�sa
<limits> numerikus �rt�khat�rok �22.2
<climits> C st�lus�, numerikus, skal�r �rt�k- �22.2.1
hat�rokat megad� makr�k
<cfloat> C st�lus�, numerikus, lebegopontos �22.2.1
�rt�khat�rokat megad� makr�k
<new> dinamikus mem�riakezel�s �16.1.3
<typeinfo> fut�si ideju t�pusazonos�t�s t�mogat�sa �15.4.1
<exception> kiv�telkezel�s t�mogat�sa �14.10
<cstddef> C k�nyvt�rak nyelvi t�mogat�sa �6.2.1
<cstdarg> v�ltoz� hossz�s�g� param�terlist�val �7.6
rendelkezo f�ggv�nyek kezel�se
<csetjmp> C st�lus� verem-visszateker�s �s.18.7
<cstdlib> programbefejez�s �9.4.1.1
<ctime> rendszer�ra �D.4.4.1
<csignal> C st�lus� szign�lkezel�s �D.4.4.1
Numerikus �rt�kek
<complex> komplex sz�mok �s muveletek �22.5
<valarray> numerikus vektorok �s muveletek �22.4
<numeric> �ltal�nos�tott numerikus muveletek �22.6
<cmath> �ltal�nos matematikai muveletek �22.3
<cstdlib> C st�lus� v�letlensz�mok �22.7
m�ny k�rnyezet�ben (�9.2.3). B�rmely program, amely nem tartja be ezeket a
j�t�kszab�-
lyokat, nem nevezheti mag�t a szabv�nyhoz igazod�nak, �s az ilyen tr�kk�ket
alkalmaz�
programok �ltal�ban nem vihetok �t m�s rendszerre. Lehet, hogy ma muk�dnek, de az
adott k�rnyezet legkisebb v�ltoz�sa haszn�lhatatlann� teheti oket. Tart�zkodjunk
az ilyen
szemf�nyveszt�stol.
Ahhoz, hogy a standard k�nyvt�r valamely lehetos�get haszn�lhassuk, a megfelelo
fej�llom
�nyt be kell �p�ten�nk (#include). Nem jelent a szabv�nynak megfelelo megold�st,
ha
a megfelelo deklar�ci�kat saj�t kezuleg adjuk meg programunkban. Ennek oka az,
hogy bizonyos
nyelvi v�ltozatok a be�p�tett szabv�nyos fej�llom�nyok alapj�n optimaliz�lj�k a
ford
�t�st, m�sok pedig a standard k�nyvt�r szolg�ltat�sait optimaliz�lj�k, att�l
f�ggoen, milyen
fej�llom�nyokat haszn�ltunk. �ltal�ban igaz, hogy a fejlesztok olyan form�ban
haszn�lhatj
�k a szabv�nyos fej�llom�nyokat, amelyre a programoz�k nem k�sz�lhetnek fel �s
programjaik
k�sz�t�sekor nem is kell tudniuk ezek szerkezet�rol.
Ezzel szemben a programoz� specializ�lhatja a szolg�ltat�s-sablonokat, p�ld�ul a
swap()
sablon f�ggv�nyt (�16.3.9), �gy ezek jobban igazodhatnak a nem szabv�nyos
k�nyvt�rakhoz
�s a felhaszn�l�i t�pusokhoz.
16.1.3. Nyelvi elemek t�mogat�sa
A standard k�nyvt�rnak egy kis r�sze a nyelvi elemek t�mogat�s�val foglalkozik,
azaz
olyan szolg�ltat�sokat ny�jt, amelyekre a program futtat�s�hoz az�rt van sz�ks�g,
mert
a nyelv eszk�zei ezektol f�ggoen muk�dnek.
Azon k�nyvt�ri f�ggv�nyeket, amelyek a new �s delete oper�torok kezel�s�t seg�tik,

a �6.2.6, a �10.4.11, a �14.4.4 �s a �15.6 pontban mutattuk be. Ezek a <new>


fej�llom�nyban
szerepelnek.
A fut�si ideju t�pusazonos�t�s elsosorban a type_info oszt�lyt jelenti, amely a
<typeinfo> fej-
�llom�nyban tal�lhat� �s a �15.4.4 pont �rt le.
A szabv�nyos kiv�telek oszt�lyait a �14.10 pontban vizsg�ltuk, hely�k a <new>,
a <typeinfo>, az <ios>, az <exception>, illetve az <stdexcept> fej�llom�nyban van.

A program elind�t�s�r�l �s befejez�s�rol a �3.2, a �9.4 �s a �10.4.9 pontban volt


sz�.
16. A k�nyvt�r szerkezete �s a t�rol�k 571
16.2. A t�rol�k szerkezete
A t�rol� (container) olyan objektum, amely m�s objektumokat tartalmaz. P�ldak�ppen
megeml
�thetj�k a list�kat (list), a vektorokat (vector) �s az asszociat�v t�mb�ket
(map). �ltal�ban
lehetos�g�nk van r�, hogy a t�rol�kban objektumokat helyezz�nk el vagy
elt�vol�tsuk azokat
onnan. Term�szetesen ez az �tlet sz�mtalan form�ban megval�s�that�. A C++ standard

k�nyvt�r�nak t�rol�it k�t felt�tel szem elott tart�s�val fejlesztett�k ki:


biztos�ts�k a leheto legnagyobb
szabads�got a felhaszn�l�nak �j, egy�ni t�rol�k fejleszt�s�ben, ugyanakkor
ny�jtsanak
hasonl� kezeloi fel�letet. Ez a megk�zel�t�s lehetov� teszi, hogy a t�rol�k
hat�konys
�ga a leheto legnagyobb legyen �s a felhaszn�l�k olyan programot �rhassanak,
amelyek
f�ggetlenek az �ppen haszn�lt t�rol� t�pus�t�l.
A t�rol�k tervezoi �ltal�ban vagy csak az egyik, vagy csak a m�sik felt�tellel
foglalkoznak.
A standard k�nyvt�rban szereplo t�rol�k �s algoritmusok bemutatj�k, hogy
lehets�ges egyszerre
�ltal�nos �s hat�kony eszk�z�ket l�trehozni. A k�vetkezokben k�t hagyom�nyos
t�rol�t�pus eross�geit �s gyenges�geit mutatjuk be, �gy megismerkedhet�nk a
szabv�nyos
t�rol�k szerkezet�vel.
16.2.1. Egyedi c�l� t�rol�k �s bej�r�k
A legk�zenfekvobb megk�zel�t�s egy vektor �s egy lista megval�s�t�s�ra az, hogy
mindkett
ot olyan form�ban k�sz�tj�k el, ami legjobban megfelel a tervezett c�loknak:
template<class T> class Vector { // optim�lis
public:
explicit Vector(size_t n); // kezdetben n darab, T() �rt�ku elemet t�rol
T& operator[ ](size_t); // indexel�s
// ...
};
template<class T> class List { // optim�lis
public:
class Link { /* ... */ };
List(); // kezdetben �res
void put(T*); // az aktu�lis elem el� helyez�s
T* get(); // az aktu�lis elem megszerz�se
// ...
};
572 A standard k�nyvt�r
Mindk�t oszt�ly olyan muveleteket k�n�l, amely ide�lis felhaszn�l�sukhoz, �s
mindkettoben
szabadon kiv�laszthatjuk a megfelelo �br�zol�st, an�lk�l, hogy m�s
t�rol�t�pusokkal foglalkozn
�nk. Ez lehetov� teszi, hogy a muveletek megval�s�t�sa k�zel optim�lis legyen.
K�l�-
n�sen fontos, hogy a leggyakrabban haszn�lt muveletek (teh�t a put() a List
eset�ben, illetve
az operator[ ]() a Vector eset�ben) eg�szen r�videk �s k�nnyen optimaliz�lhat�ak
(pl.
helyben (inline) kifejthetok) legyenek.
A t�rol�k egyik leggyakoribb felhaszn�l�si m�dja, hogy egym�s ut�n v�gigl�pked�nk
a t�-
rol�ban t�rolt elemeken. Ezt nevezz�k a t�rol� bej�r�s�nak, a feladat
megval�s�t�s�hoz
pedig �ltal�ban l�trehozunk egy bej�r� (iterator) oszt�lyt, amely megfelel az
adott t�rol�
t�pus�nak. (�11.5 �s �11.14[7])
Bizonyos esetekben, amikor a felhaszn�l� bej�r egy t�rol�t, nem is akarja tudni,
hogy az
adatokat t�nylegesen egy list�ban vagy egy vektorban t�roljuk. Ezekben a
helyzetekben
a bej�r�snak nem szabad att�l f�ggnie, hogy a List vagy a Vector oszt�lyt
haszn�ltuk. Az ide-
�lis az, ha mindk�t esetben pontosan ugyanazt a programr�szletet haszn�lhatjuk.
A megold�st a bej�r� (iterator) oszt�ly jelenti, amely biztos�t egy .k�rem a
k�vetkezot. mu-
veletet, amely minden t�rol� sz�m�ra megval�s�that�. P�ld�ul:
template<class T> class Itor { // k�z�s fel�let (absztrakt oszt�ly �2.5.4, �12.3)
public:
// 0 visszaad�s�val jelezz�k, hogy nincs t�bb elem
virtual T* first() = 0; // mutat� az elso elemre
virtual T* next() = 0; // mutat� a k�vetkezo elemre
};
Ezt az oszt�lyt k�sobb elk�sz�thetj�k k�l�n a Vector �s k�l�n a List oszt�lyhoz:
template<class T> class Vector_itor : public Itor<T> { // vektor-megval�s�t�s
Vector<T>& v;
size_t index; // az aktu�lis elem index�rt�ke
public:
Vector_itor(Vector<T>& vv) : v(vv), index(0) { }
T* first() { return (v.size()) ? &v[index=0] : 0; }
T* next() { return (++index<v.size()) ? &v[index] : 0; }
};
template<class T> class List_itor : public Itor<T> { // lista-megval�s�t�s
List<T>& lst;
List<T>::Link p; // az aktu�lis elemre mutat
16. A k�nyvt�r szerkezete �s a t�rol�k 573
public:
List_itor(List<T>&);
T* first();
T* next();
};
Grafikus form�ban (szaggatott vonallal jelezve a .megval�s�t�s a .
felhaszn�l�s�val.
kapcsolatot):
A k�t bej�r� (iterator) belso szerkezete jelentosen elt�r, de ez a felhaszn�l�
sz�m�ra l�thatatlan
marad. Ezek ut�n b�rmit bej�rhatunk, amire az Itor oszt�lyt meg tudjuk val�s�tani.

P�ld�ul:
int count(Itor<char>& ii, char term)
{
int c = 0;
for (char* p = ii.first(); p; p=ii.next()) if (*p==term) c++;
return c;
}
Van azonban egy kis probl�ma. A bej�r�n elv�gzendo muvelet lehet rendk�v�l
egyszeru,
m�gis mindig v�gre kell hajtanunk egy (virtu�lis) f�ggv�nyh�v�st. A legt�bb
esetben ez
a teljes�tm�nyroml�s nem jelent nagy vesztes�get az egy�b tev�kenys�gek mellett. A
nagyteljes
�tm�nyu rendszerekben azonban gyakran �ppen egy egyszeru t�rol� gyors bej�r�sa
jelenti
a l�tfontoss�g� feladatot, �s a f�ggv�nyek megh�v�sa sokkal .k�lts�gesebb. lehet,
mint egy eg�sz sz�mokkal v�gzett �sszead�s vagy egy mutat��rt�k-sz�m�t�s (ami a
Vector
�s a List eset�ben megval�s�tja a next() f�ggv�nyt). Ez�rt a fenti modell nem
haszn�lhat�,
vagy legal�bbis nem t�k�letes egy szabv�nyos k�nyvt�r szolg�ltat�sak�nt.
574 A standard k�nyvt�r
Vector List
Itor
Vector_itor List_itor
Ennek ellen�re a t�rol�-bej�r� szeml�let nagyon j�l haszn�lhat� sok rendszer
eset�ben.
�vekig ez volt programjaim kedvenc megold�sa. Az elony�ket �s a h�tr�nyokat az
al�bbiakkal
foglalhatjuk �ssze:
+ Az �n�ll� t�rol�k (container) egyszeruek �s hat�konyak.
+ A t�rol�knak nem kell hasonl�taniuk egym�sra. A bej�r� (iterator) �s a beburkol
� (wrapper) oszt�lyok (�25.7.1) seg�ts�g�vel a k�l�n fejlesztett t�rol�kat is egys
�ges form�ban �rhetj�k el.
+ A k�z�s felhaszn�l�i fel�letet a bej�r�k biztos�tj�k (nem egy �ltal�nos
t�rol�t�pus, �16.2.2).
+ Ugyanahhoz a t�rol�hoz t�bb bej�r�t is defini�lhatunk a k�l�nb�zo ig�nyeknek
megfeleloen.
+ A t�rol�k alap�rtelmez�s szerint t�pusbiztosak �s homog�nek (azaz a t�rol�
minden eleme ugyanolyan t�pus�). Heterog�n t�rol�kat �gy hozhatunk l�tre,
hogy olyan mutat�kb�l hozunk l�tre egy homog�n t�rol�t, amelyek azonos
ossel rendelkezo objektumokra mutatnak.
+ A t�rol�k nem tolakod�k (non-intrusive), (azaz nem ig�nylik, hogy a t�rol�
tagjai
egy k�z�s ostol sz�rmazzanak, vagy valamilyen hivatkoz� mezovel rendelkezzenek).
A nem tolakod� t�rol�k j�l haszn�lhat�ak a be�p�tett t�pusok, vagy
a mi hat�sk�r�nk�n k�v�l l�trehozott adatszerkezetek eset�ben.
- Minden bej�r�n kereszt�li hozz�f�r�s egy virtu�lis f�ggv�nyh�v�ssal rontja
a rendszer hat�konys�g�t. Az egyszeru hozz�f�r�si elj�r�sokhoz k�pest ez
a m�dszer komoly idovesztes�get is jelenthet.
- A bej�r�-oszt�lyok hierarchi�ja k�nnyen �ttekinthetetlenn� v�lhat.
- Semmilyen k�z�s alapot nem tal�lhatunk a k�l�nb�zo t�rol�k k�z�tt, m�g kev
�sb� a t�rol�kban t�rolt objektumok k�z�tt. Ez megnehez�ti az olyan �ltal�nos
feladatokra val� felk�sz�l�st, mint a perzisztencia (persistence) biztos�t�sa vagy

az objektum be- �s kivitel.


A + jellel az elony�ket, - jellel a h�tr�nyokat soroltuk fel.
A bej�r�k �ltal biztos�tott rugalmass�gra k�l�n felh�vn�nk a figyelmet. Egy olyan
k�z�s felhaszn
�l�i fel�let, mint az Itor, akkor is megval�s�that�, amikor a t�rol� (eset�nkben
a Vector �s a List) megtervez�se �s elk�sz�t�se m�r r�g megt�rt�nt. Amikor a
t�rol�t tervezz
�k, �ltal�ban konkr�t form�ban gondolkodunk, p�ld�ul egy t�mb�t vagy egy list�t
k�sz�-
t�nk. Csak k�sobb l�tjuk meg az elvont �br�zol�s azon lehetos�geit, amelyek egy
adott
k�rnyezetben egyar�nt alkalmazhat�ak a t�mb�kre �s a list�kra is.
Ezt a .k�sei elvonatkoztat�st. tulajdonk�ppen t�bbsz�r is elv�gezhetj�k. P�ld�ul
k�pzelj�k
el, hogy egy halmazt szeretn�nk l�trehozni. A halmaz teljesen m�s jellegu elvont
�br�zol�s,
16. A k�nyvt�r szerkezete �s a t�rol�k 575
mint az Itor, de ugyanazzal a m�dszerrel, amelyet az Itor eset�ben alkalmaztunk,
k�sz�thet
�nk egy halmaz jellegu fel�letet is a Vector �s a List oszt�lyhoz:
Ez�rt a k�sei elvonatkoztat�s az absztrakt oszt�lyok seg�ts�g�vel lehetov� teszi,
hogy
ugyanazokat a fogalmakat t�bb, k�l�nb�zo form�ban is �br�zolhassuk, �s ez akkor is
igaz,
ha az egyes megval�s�t�sokban semmilyen hasonl�s�g sincs. A list�k �s a vektorok
eset�-
ben m�g tal�lhatunk n�h�ny nyilv�nval� hasonl�s�got, de az Itor fel�letet ak�r egy
istream
sz�m�ra is k�nnyen elk�sz�thetn�nk.
Elm�letileg a list�ban szereplo utols� k�t pont jelenti a szeml�let igazi
h�tr�ny�t. Ez azt jelenti,
hogy ez a megk�zel�t�s m�g akkor sem lehet ide�lis megold�s egy szabv�nyos k�nyvt
�rban, ha a bej�r�k f�ggv�nyh�v�saib�l illetve a hasonl� t�rol�-fel�letekbol eredo
teljes�tm
�nyroml�st siker�lt is kik�sz�b�ln�nk (amire bizonyos helyzetekben lehetos�g van).

A nem tolakod� (non-intrusive) t�rol�k n�h�ny esetben egy kicsit lassabbak �s


kicsit t�bb
helyet ig�nyelnek, mint a tolakod� t�rol�k. �n magam ezt nem tartom gondnak; ha
m�gis
az lenne, az Itor-hoz hasonl� bej�r�kat tolakod� t�rol�khoz is elk�sz�thetj�k
(�16.5[11]).
16.2.2. T�rol�k k�z�s ossel
Egy tolakod� t�rol� elk�sz�theto an�lk�l is, hogy sablonokat (template)
haszn�ln�nk vagy
b�rmely m�s m�don param�tereket adn�nk meg a t�pushoz:
struct Link {
Link* pre;
Link* suc;
// ...
};
576 A standard k�nyvt�r
Vektor List
Set Itor
Vector_set Vector_itor List_set List_itor
class List {
Link* head;
Link* curr; // az aktu�lis elem
public:
Link* get(); // az aktu�lis elem elt�vol�t�sa �s visszaad�sa
void put(Link*); // besz�r�s az aktu�lis elem el�
// ...
};
A List itt nem m�s, mint Link t�pus� objektumok list�ja, azaz olyan objektumok
t�rol�s�ra
k�pes, amelyek a Link adatszerkezetbol sz�rmaznak:
class Ship : public Link { /* ... */ };
void f(List* lst)
{
while (Link* po = lst->get()) {
if (Ship* ps = dynamic_cast<Ship*>(po)) { // a Ship-nek t�bbalak�nak kell lennie
// (�15.4.1)
// a ship haszn�lata
}
else {
// hopp�, valami m�st csin�lunk
}
}
}
A Simula ebben a st�lusban hat�rozta meg szabv�nyos t�rol�it, teh�t ezt a
megold�st tekinthetj
�k az objektumorient�lt programoz�st t�mogat� nyelvek eredeti szeml�let�nek.
Napjainkban
minden objektum k�z�s b�zisoszt�ly�nak neve Object vagy valami hasonl�.
Az Object oszt�ly �ltal�ban sz�mos m�s szolg�ltat�st is ny�jt azon k�v�l, hogy
�sszekapcsolja
a t�rol�kat.
Ez a szeml�let gyakran (b�r nem sz�ks�gszeruen) kieg�sz�l egy �ltal�nos
t�rol�t�pussal is:
class Container : public Object {
public:
virtual Object* get(); // az aktu�lis elem elt�vol�t�sa �s visszaad�sa
virtual void put(Object*); // besz�r�s az aktu�lis elem el�
virtual Object*& operator[ ](size_t); // indexel�s
// ...
};
16. A k�nyvt�r szerkezete �s a t�rol�k 577
Figyelj�k meg, hogy a Container oszt�lyban szereplo muveletek virtu�lisak, �gy a
k�l�nb�-
zo t�rol�k saj�t ig�nyeiknek megfeleloen fel�l�rhatj�k azokat:
class List : public Container {
public:
Object* get();
void put(Object*);
// ...
};
class Vector : public Container {
public:
Object*& operator[ ](size_t);
// ...
};
Sajnos azonnal jelentkezik egy probl�ma. Milyen muveleteket kell biztos�tania a
Container
oszt�lynak? Csak azok a f�ggv�nyek szerepelhetnek, amelyeket minden t�rol� meg tud
val
�s�tani, de az �sszes t�rol� muvelethalmaz�nak metszete nevets�gesen szuk fel�let.
Sot, az
az igazs�g, hogy az igaz�n �rdekes esetekben ez a metszet teljesen �res. Teh�t
gyakorlatilag
a t�mogatni k�v�nt t�rol�t�pusokban szereplo, l�nyeges muveletek uni�j�t kell
szerepeltetn
�nk. A szolg�ltat�sokhoz biztos�tott fel�letek ilyen uni�j�t k�v�r vagy bos�ges
fel�letnek
nevezz�k. (fat interface, �24.4.3)
Vagy e fel�let le�r�s�ban k�sz�t�nk valamilyen alap�rtelmezett v�ltozatot a
f�ggv�nyekhez,
vagy azokat tiszt�n virtu�lisakk� (pure virtual) t�ve arra k�telezz�k a
sz�rmaztatott oszt�-
lyokat, hogy ok fejts�k ki a f�ggv�nyeket. Mindk�t esetben sok-sok olyan f�ggv�nyt

kapunk, amelyek egyszeruen fut�si ideju hib�t v�ltanak ki:


class Container : public Object {
public:
struct Bad_op { // kiv�teloszt�ly
const char* p;
Bad_op(const char* pp) :p(pp) { }
};
virtual void put(Object*) { throw Bad_op("put-hiba"); }
virtual Object* get() { throw Bad_op("get-hiba"); }
virtual Object*& operator[ ](int) { throw Bad_op("[ ]"); }
// ...
};
578 A standard k�nyvt�r
Ha v�dekezni szeretn�nk azon lehetos�ggel szemben, hogy egy t�rol� nem t�mogatja
a get() f�ggv�ny haszn�lat�t, el kell kapnunk valahol a Container::Bad_op
kiv�telt. Ezek
ut�n a kor�bbi Ship p�ld�t a k�vetkezo form�ban val�s�thatjuk meg:
class Ship : public Object { /* ... */ };
void f1(Container* pc)
{
try {
while (Object* po = pc->get()) {
if (Ship* ps = dynamic_cast<Ship*>(po)) {
// a ship haszn�lata
}
else {
// hopp�, valami m�st csin�lunk
}
}
}
catch (Container::Bad_op& bad) {
// hopp�, valami m�st csin�lunk
}
}
Ez �gy t�ls�gosan bonyolult, ez�rt a Bad_op kiv�tel ellenorz�s�t �rdemes m�shova
helyezn
�nk. Ha sz�m�thatunk r�, hogy a kiv�teleket m�shol kezelik, akkor a p�ld�t az
al�bbi form
�ra r�vid�thetj�k:
void f2(Container* pc)
{
while (Object* po = pc->get()) {
Ship& s = dynamic_cast<Ship&>(*po);
// a Ship haszn�lata
}
}
Ennek ellen�re az az �rz�s�nk, hogy a fut�si ideju t�pusellenorz�s st�lustalan �s
nem is t�l
hat�kony. Ez�rt ink�bb a statikus t�pusellenorz�s mellett maradunk:
void f3(Itor<Ship>* i)
{
while (Ship* ps = i->next()) {
// a Ship haszn�lata
}
}
16. A k�nyvt�r szerkezete �s a t�rol�k 579
A t�rol�tervez�s .objektumok k�z�s b�zisoszt�llyal. megk�zel�t�s�nek elonyeit �s
h�tr�-
nyait az al�bbiakkal foglalhatjuk �ssze (n�zz�k meg a �16.5[10] feladatot is):
- A k�l�nb�zo t�rol�kon v�gzett muveletek virtu�lis f�ggv�nyh�v�st eredm�nyeznek.
- Minden t�rol�t a Container oszt�lyb�l kell sz�rmaztatnunk. Ennek k�vetkezt�-
ben k�v�r fel�letet kell k�sz�ten�nk, �s nagy m�rt�ku elorel�t�sra, illetve fut�si

ideju t�pusellenorz�sre van sz�ks�g. Egy k�l�n fejlesztett t�rol�t egy �ltal�nos
keretbe szor�tani a legjobb esetben is k�r�lm�nyes (�16.5[12]).
+ A k�z�s Container b�zisoszt�ly egyszeru megold�st k�n�l olyan t�rol�k fejleszt
�s�hez, amelyek hasonl� muveleteket biztos�tanak.
- A t�rol�k heterog�nek �s alap�rtelmez�s szerint nem t�pusbiztosak. (Mind�ssze
arra sz�m�thatunk, hogy az elemek t�pusa Object *.) Ha sz�ks�g van r�, sablonok
(template) seg�ts�g�vel hozhatunk l�tre t�pusbiztos �s homog�n t�rol�kat.
- A t�rol�k tolakod�ak (ami eset�nkben azt jelenti, hogy minden elemnek az
Object oszt�lyb�l kell sz�rmaznia). Be�p�tett t�pusokba tartoz� objektumokat,
illetve a mi hat�sk�r�nk�n k�v�l meghat�rozott adatszerkezeteket k�zvetlen�l
nem helyezhet�nk el benn�k.
- A t�rol�b�l kiemelt elemekre megfelelo t�puskonverzi�t kell alkalmaznunk,
mielott haszn�lhatn�nk azokat.
+ A Container �s az Object oszt�ly olyan szolg�ltat�sok kialak�t�s�hoz haszn�lhat
�, amelyek minden t�rol�ra vagy minden objektumra alkalmazhat�k. Ez nagym
�rt�kben leegyszerus�ti az olyan �ltal�nos szolg�ltat�sok megval�s�t�s�t, mint
a perzisztencia biztos�t�sa vagy az objektumok ki- �s bevitele.
Ugyan�gy, mint kor�bban (�16.2.1), a + az elony�ket, a - a h�tr�nyokat jel�li.
Az egym�st�l f�ggetlen t�rol�khoz �s bej�r�khoz viszony�tva a k�z�s
b�zisoszt�llyal rendelkez
o objektumok �tlete feleslegesen sok munk�t h�r�t a felhaszn�l�ra, jelentos fut�si

ideju terhel�st jelent �s korl�tozza a t�rol�ban elhelyezheto objektumok k�r�t.


R�ad�sul
sok oszt�ly eset�ben az Object oszt�lyb�l val� sz�rmaztat�s a megval�s�t�s
r�szleteinek felfed
�s�t jelenti, ez�rt ez a megk�zel�t�s nagyon t�vol �ll az ide�lis megold�st�l egy
szabv�-
nyos k�nyvt�r eset�ben.
Ennek ellen�re az ezen megold�s �ltal k�n�lt �ltal�noss�got �s rugalmass�got nem
szabad
al�becs�ln�nk. Sz�mtalan v�ltozat�t, sz�mtalan programban sikeresen felhaszn�lt�k
m�r.
Ennek a megk�zel�t�snek azokon a ter�leteken van jelentos�ge, ahol a hat�konys�g
kev�sb
� fontos, mint az egyszerus�g, amelyet az egyszeru Container fel�let �s az
objektum ki-
�s bevitelhez hasonl� szolg�ltat�sok biztos�tanak.
580 A standard k�nyvt�r
16.2.3. A standard k�nyvt�r t�rol�i
A standard k�nyvt�r t�rol�i (container) �s bej�r�i (iterator) . amelyet gyakran
nevez�nk
STL (Standard Template Library) keretrendszernek, (�3.10) . olyan megk�zel�t�sk�nt
foghat
�k fel, amely a kor�bban bemutatott k�t hagyom�nyos modell elonyeit a leheto
legjobban
kiakn�zza. Az STL azonban egyik m�dszert sem alkalmazza k�zvetlen�l; c�lja az,
hogy egyszerre
hat�kony �s �ltal�nos algoritmusokat k�n�ljon, mindenf�le megalkuv�s n�lk�l. A hat
�konys�g �rdek�ben az alkot�k a gyakran haszn�lt adatel�ro f�ggv�nyek eset�ben
elvetett
�k a nehezen optimaliz�lhat� virtu�lis f�ggv�nyeket, �gy nem adhattak szabv�nyos
fel�letet a t�rol�k �s a bej�r�k sz�m�ra absztrakt oszt�ly form�j�ban. Ehelyett
mindegyik t�-
rol�t�pus t�mogatja az alapveto muveleteknek egy szabv�nyos halmaz�t. A k�v�r
fel�letek
probl�m�j�nak (�16.2.2, �24.4.3) elker�l�se �rdek�ben az olyan muveletek, amelyek
nem
minden t�rol�ban val�s�that�k meg hat�konyan, nem szerepelnek ebben a k�z�s
halmazban.
Az indexel�s p�ld�ul alkalmazhat� a vector eset�ben, de nem haszn�lhat� a list
t�rol
�kra. Ezenk�v�l minden t�rol�t�pus saj�t bej�r�kat biztos�t, amelyek a szok�sos
bej�r�mu-
veleteket teszik el�rhetov�.
A szabv�nyos t�rol�k nem k�z�s b�zisoszt�lyb�l sz�rmaznak, hanem minden t�rol�
�n�ll
�an tartalmazza a szabv�nyos t�rol�fel�letet. Ugyan�gy nincs k�z�s bej�r�-os sem.
A szabv
�nyos t�rol�k �s bej�r�k haszn�latakor nem t�rt�nik fut�si ideju t�pusellenorz�s,
sem
k�zvetlen (explicit), sem automatikus (implicit) form�ban.
A minden t�rol�ra kiterjedo k�z�s szolg�ltat�sok biztos�t�sa igen fontos �s
bonyolult feladat.
Az STL ezt a mem�riafoglal�k (allok�tor, allocator) seg�ts�g�vel val�s�tja meg,
amelyeket
sablonparam�terk�nt adunk meg (�19.4.3), ez�rt nincs sz�ks�g k�z�s b�zisoszt�lyra.

Mielott a r�szleteket megvizsg�ln�nk �s konkr�t p�ld�kat mutatn�nk be, foglaljuk


�ssze az
STL szeml�lete �ltal biztos�tott elony�ket �s h�tr�nyokat:
+ Az �n�ll� t�rol�k egyszeruek �s hat�konyak (nem eg�szen olyan egyszeruek,
mint a t�nyleg teljesen f�ggetlen t�rol�k, de ugyanolyan hat�konyak).
+ Mindegyik t�rol� biztos�tja a szabv�nyos muveleteket szabv�nyos n�ven �s jelent
�ssel. Ha sz�ks�g van r�, az adott t�rol�t�pusnak megfelelo tov�bbi muveletek
is megtal�lhat�k. Ezenk�v�l, a becsomagol� vagy beburkol� (wrapper) oszt
�lyok (�25.7.1) seg�ts�g�vel a k�l�n fejlesztett t�rol�k is beilleszthetok a k�z�s

keretrendszerbe. (�16.5[14])
+ A tov�bbi k�z�s haszn�lati form�kat a szabv�nyos bej�r�k biztos�tj�k. Minden
t�rol� biztos�t bej�r�kat, amelyek lehetov� teszik bizonyos muveletek v�grehajt
�s�t szabv�nyos n�ven �s jelent�ssel. Minden bej�r�-t�pus k�l�n l�tezik minden
t�rol�t�pushoz, �gy ezek a bej�r�k a leheto legegyszerubbek �s a leheto
leghat�konyabbak.
16. A k�nyvt�r szerkezete �s a t�rol�k 581
+ A k�l�nb�zo sz�ks�gletek kiel�g�t�s�re minden t�rol�hoz l�trehozhatunk saj�t
bej�r�kat vagy �ltal�nos fel�leteket, a szabv�nyos bej�r�k mellett.
+ A t�rol�k alap�rtelmez�s szerint t�pusbiztosak �s homog�nek (azaz az adott
t�rol� minden eleme ugyanolyan t�pus�). Heterog�n t�rol�kat �gy k�sz�thet
�nk, hogy egy olyan homog�n t�rol�t hozunk l�tre, amely k�z�s b�zisoszt�lyra
hivatkoz� mutat�kat tartalmaz.
+ A t�rol�k nem tolakod�ak (azaz a t�rol� tagjainak nem kell egy adott b�zisoszt
�lyb�l sz�rmazniuk, vagy hivatkoz� mezoket tartalmazniuk). A nem tolakod�
t�rol�k a be�p�tett t�pusok eset�ben haszn�lhat�k j�l, illetve az olyan
adatszerkezetekhez,
melyeket a mi hat�sk�r�nk�n k�v�l hat�roztak meg.
+ Az �ltal�nos keretrendszer lehetov� teszi tolakod� t�rol�k haszn�lat�t is.
Term�-
szetesen ez az elemek t�pus�ra n�zve komoly megk�t�seket jelenthet.
+ Minden t�rol� haszn�l egy param�tert, az �gynevezett mem�riafoglal�t
(allocator), amely olyan szolg�ltat�sok kezel�s�hez ny�jt seg�ts�get, amelyek
minden t�rol�ban megjelennek. Ez nagym�rt�kben megk�nny�ti az olyan �ltal�-
nos feladatok megval�s�t�s�t, mint a perzisztencia biztos�t�sa vagy az objektum
ki- �s bevitel.(�19.4.3)
- A t�rol�k �s bej�r�k nem rendelkeznek olyan szabv�nyos, fut�si ideju �br�zol
�ssal, amelyet p�ld�ul f�ggv�nyparam�terk�nt �tadhatn�nk (b�r a szabv�nyos
t�rol�k �s bej�r�k eset�ben k�nnyen l�trehozhatn�nk ilyet, ha erre az adott
programban sz�ks�g�nk van, �19.3).
Ugyan�gy, mint eddig (�16.2.1) a + az elony�ket, a - a h�tr�nyokat jel�li.
A t�rol�knak (container) �s a bej�r�knak (iterator) teh�t nincs r�gz�tett,
�ltal�nos �br�zol�-
sa. Ehelyett minden t�rol� ugyanazt a szabv�nyos fel�letet biztos�tja szabv�nyos
muveletek
form�j�ban. Ennek k�vetkezt�ben a t�rol�kat egyform�n kezelhetj�k �s fel is
cser�lhetj�k.
A bej�r�kat is hasonl�an haszn�lhatjuk. Ez az ido- �s t�rhaszn�lati hat�konys�got
csak kev
�ss� rontja, a felhaszn�l� viszont kihaszn�lhatja az egys�gess�get, mind a t�rol�k
szintj�n
(a k�z�s b�zisoszt�lyb�l sz�rmaz� t�rol�k eset�ben), mind a bej�r�k szintj�n (a
specializ�lt
t�rol�k eset�ben).
Az STL megk�zel�t�se erosen �p�t a sablonok (template) haszn�lat�ra. Ahhoz, hogy
elker
�lj�k a felesleges k�dism�tl�seket, gyakran van sz�ks�g arra, hogy mutat�kat
tartalmaz�
t�rol�kban r�szlegesen specializ�lt v�ltozatok k�sz�t�s�vel k�z�sen haszn�lhat�
�sszetevo-
ket hozunk l�tre (�13.5).
582 A standard k�nyvt�r
16.3. A vektor
Itt a vector-t �gy �rjuk le, mint a teljes szabv�nyos t�rol�k egyik p�ld�j�t. Ha
m�st nem mondunk,
a vector-ra vonatkoz� �ll�t�sok v�ltoztat�s n�lk�l alkalmazhat�k az �sszes t�bbi
szabv
�nyos t�rol�ra is. A 17. fejezet foglalkozik azokkal a lehetos�gekkel, amelyek
kiz�r�lag
a list, a set, a map vagy valamelyik m�sik t�rol�ra vonatkoznak. Azokat a
lehetos�geket,
amelyeket kifejezetten a vector . vagy egy hasonl� t�rol� . val�s�t meg, csak
bizonyos m�rt
�kig r�szletezz�k. C�lunk az, hogy megismerj�k a vector lehets�ges felhaszn�l�si
ter�leteit
�s meg�rts�k a standard k�nyvt�r glob�lis szerkezet�ben elfoglalt szerep�t.
A �17.1 pontban �ttekintj�k a standard t�rol�k tulajdons�gait �s az �ltaluk k�n�lt
lehetos�-
geket. Az al�bbiakban a vector t�rol�t k�l�nb�zo szempontok szerint mutatjuk be: a
tagt�-
pusok, a bej�r�k, az elemek el�r�se, a konstruktorok, a veremmuveletek, a
listamuveletek,
a m�ret �s kapacit�s, a seg�df�ggv�nyek, illetve a vector<bool> szempontj�b�l.
16.3.1. T�pusok
A szabv�nyos vector egy sablon (template), amely az std n�vt�rhez tartozik �s a
<vector>
fej�llom�nyban tal�lhat�. Elosz�r is n�h�ny szabv�nyos t�pusnevet defini�l:
template <class T, class A = allocator<T> > class std::vector {
public:
// t�pusok
typedef T value_type; // elemt�pus
typedef A allocator_type; // mem�riakezelo-t�pus
typedef typename A::size_type size_type;
typedef typename A::difference_type difference_type;
typedef megval�s�t�s_f�ggo1 iterator; // T*
typedef megval�s�t�s_f�ggo2 const_iterator; // const T*
typedef std::reverse_iterator<iterator> reverse_iterator;
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
typedef typename A::pointer pointer; // elemmutat�
typedef typename A::const_pointer const_pointer;
typedef typename A::reference reference; // hivatkoz�s elemre
typedef typename A::const_reference const_reference;
// ...
};
16. A k�nyvt�r szerkezete �s a t�rol�k 583
Minden szabv�nyos t�rol� defini�lja ezeket a t�pusokat, mint saj�t tagjait, de a
saj�t megval
�s�t�s�nak legmegfelelobb form�ban.
A t�rol� elemeinek t�pus�t az elso sablonparam�ter hat�rozza meg, amit gyakran
nevez�nk
�rt�kt�pusnak (value_type) is. A mem�riafoglal� t�pusa (allocator_type) . amelyet
(nem k�-
telezoen) a sablon m�sodik param�ter�ben adhatunk meg . azt hat�rozza meg, hogy
a value_type hogyan tart kapcsolatot a k�l�nb�zo mem�riakezelo elj�r�sokkal. Ezen
bel�l,
a mem�riafoglal� adja meg azokat a f�ggv�nyeket, amelyeket a t�rol� az elemek
t�rol�s�-
ra szolg�l� mem�ria lefoglal�s�ra �s felszabad�t�s�ra haszn�l. A
mem�riafoglal�kr�l a �19.4
pontban lesz sz� r�szletesen. �ltal�ban a size_type hat�rozza meg azt a t�pust,
amelyet a t�-
rol� indexel�s�hez haszn�lunk, m�g a difference_type annak az �rt�knek a t�pus�t
jel�li,
amelyet k�t bej�r� k�l�nbs�g�nek k�pz�sekor kapunk. A legt�bb t�rol� eset�ben ezek

a size_t, illetve a ptrdiff_t t�pust jelentik (�6.2.1)


A bej�r�kat a �2.7.2 pontban mutattuk be �s a 19. fejezetben foglalkozunk vel�k
r�szletesen.
�gy k�pzelhetj�k el oket, mint egy t�rol� valamelyik elem�re hivatkoz� mutat�t.
Minden t�rol� le�r egy iterator nevu t�pust, amellyel az elemekre mutathatunk.
Rendelkez�-
s�nkre �ll egy const_iterator t�pus is, amelyet akkor haszn�lunk, ha nincs sz�ks�g
az elemek
m�dos�t�s�ra. Ugyan�gy, mint a mutat�k eset�ben, itt is mindig haszn�ljuk a
biztons
�gosabb const v�ltozatot, hacsak nem felt�tlen�l a m�sik lehetos�gre van
sz�ks�g�nk.
A vector bej�r�inak konkr�t t�pusa a megval�s�t�st�l f�gg, a legnyilv�nval�bb
megold�s egy
hagyom�nyosan defini�lt vector eset�ben a T*, illetve a const T*.
A visszafel� halad� bej�r�k t�pus�t a vector sz�m�ra a szabv�nyos reverse_iterator
sablon
seg�ts�g�vel hat�rozt�k meg. (�19.2.5) Ez az elemek sorozat�t ford�tott sorrendben
szolg�ltatja.
A �3.8.1 pontban bemutattuk, hogy ezen t�pusok seg�ts�g�vel a felhaszn�l� �gy
�rhat t�rol
�kat haszn�l� programr�szleteket, hogy a t�nylegesen haszn�lt t�pusokr�l semmit
sem tud,
sot, olyan k�dot is �rhat, amely minden szabv�nyos t�rol� eset�ben haszn�lhat�:
template<class C> typename C::value_type sum(const C& c)
{
typename C::value_type s = 0;
typename C::const_iterator p = c.begin(); // kezd�s az elej�n
while (p!=c.end()) { // folytat�s a v�g�ig
s += *p; // elem �rt�k�nek megszerz�se
++p; // p a k�vetkezo elemre fog mutatni
}
return s;
}
584 A standard k�nyvt�r
A typename haszn�lata egy sablonparam�ter tagj�nak neve elott el�g furcs�n n�z ki,
de
a ford�t�program nem akad fenn rajta, ugyanis nincs �ltal�nos m�dszer arra, hogy
egy sablonparam
�ter valamelyik tagj�r�l eld�nts�k, hogy az t�pusn�v-e. (�C.13.5)
Ugyan�gy, mint a mutat�k eset�ben, az elotagk�nt haszn�lt * a bej�r� indirekci�j�t
jelenti
(�2.7.2, �19.2.1), m�g a ++ a bej�r� n�vel�s�t v�gzi.
16.3.2. Bej�r�k
Ahogy az elozo alfejezetben m�r bemutattuk, a programoz�k a bej�r�kat arra
haszn�lhatj
�k, hogy bej�rj�k a t�rol�t az elemek t�pus�nak pontos ismerete n�lk�l. N�h�ny
tagf�ggv
�ny teszi lehetov�, hogy el�rj�k az elemek sorozat�nak valamelyik v�g�t:
template <class T, class A = allocator<T> > class vector {
public:
// ...
// iterators:
iterator begin(); // az elso elemre mutat
const_iterator begin() const;
iterator end(); // az "utols� ut�ni" elemre mutat
const_iterator end() const;
reverse_iterator rbegin(); // h�tulr�l az elso elemre mutat
const_reverse_iterator rbegin() const;
reverse_iterator rend(); // h�tulr�l az "utols� ut�ni" elemre mutat
const_reverse_iterator rend() const;
// ...
};
A begin()/end() p�r a t�rol� elemeit a szok�sos sorrendben adja meg, azaz elsok�nt
a .nulladik
. elemet (vagyis az elsot) kapjuk, majd sorban a k�vetkezoket; az rbegin()/rend()
p�rn
�l viszont ford�tott sorrendben, azaz az n-1. elem ut�n k�vetkezik az n-2., majd
az n-3.,
�s �gy tov�bb. P�ld�ul ha egy iterator haszn�lat�val ilyen sorozatot kapunk:
16. A k�nyvt�r szerkezete �s a t�rol�k 585
A B C
begin() end()
akkor a reverse_iterator a k�vetkezo elemsorozatot adja (�19.2.5):
�gy lehetos�g�nk van olyan algoritmusok k�sz�t�s�re, amelyeknek ford�tott
sorrendben van
sz�ks�ge az elemek sorozat�ra. P�ld�ul:
template<class C> typename C::iterator find_last(C& c, typename C::value_type v)
{
typename C::reverse_iterator ri = find(c.rbegin(),c.rend(),v);
if (ri == c.rend()) return c.end(); // a c.end() jelzi, hogy "nem tal�lhat�"
typename C::iterator i = ri.base();
return --i;
}
Egy reverse_iterator eset�ben az ri.base() f�ggv�ny egy olyan bej�r�t ad vissza,
amely az ri
�ltal kijel�lt hely ut�n k�vetkezo elemre mutat. (�19.2.5) A visszafel� halad�
bej�r�k n�lk�l
egy ciklust kellett volna k�sz�ten�nk:
template<class C> typename C::iterator find_last(C& c, typename C::value_type v)
{
typename C::iterator p = c.end(); // keres�s a v�g�tol visszafel�
while (p!=c.begin())
if (*--p==v) return p;
return c.end(); // a c.end() jelzi, hogy "nem tal�lhat�"
}
A visszafel� halad� bej�r� is k�z�ns�ges bej�r�, teh�t �rhattuk volna ezt is:
template<class C> typename C::iterator find_last(C& c, typename C::value_type v)
{
typename C::reverse_iterator p = c.rbegin(); // a sorozat �tn�z�se visszafel�
while (p!=c.rend()) {
if (*p==v) {
typename C::iterator i = p.base();
return --i;
}
++p; // vigy�zzunk: n�vel�s, nem cs�kkent�s (--)
}
return c.end(); // a c.end() jelzi, hogy "nem tal�lhat�"
}
586 A standard k�nyvt�r
C B A
rbegin() rend()
Figyelj�nk r�, hogy a C::reverse_iterator t�pus nem ugyanaz, mint a C::iterator.
16.3.3. Az elemek el�r�se
A vector igen fontos tulajdons�ga a t�bbi t�rol�val �sszehasonl�tva, hogy az egyes
elemeket
b�rmilyen sorrendben k�nnyen �s hat�konyan el�rhetj�k:
template <class T, class A = allocator<T> > class vector {
public:
// ...
// hozz�f�r�s az elemekhez
reference operator[ ](size_type n); // nem ellenorz�tt hozz�f�r�s
const_reference operator[ ](size_type n) const;
reference at(size_type n); // ellenorz�tt hozz�f�r�s
const_reference at(size_type n) const;
reference front(); // elso elem
const_reference front() const;
reference back(); // utols� elem
const_reference back() const;
// ...
};
Az indexel�shez az operator[ ]() vagy az at() f�ggv�nyt haszn�ljuk. A [ ] oper�tor
ellenorizetlen
hozz�f�r�st biztos�t, m�g az at() indexhat�r-ellenorz�st is v�gez �s out_of_range
kiv
�telt v�lt ki, ha a megadott index nem a megfelelo tartom�nyba esik:
void f(vector<int>& v, int i1, int i2)
try {
for(int i = 0; i < v.size(); i++) {
// a tartom�ny m�r ellenorz�tt, itt a nem ellenorz�tt v[i]-t kell haszn�lnunk
}
v.at(i1) = v.at(i2); // hozz�f�r�skor a tartom�ny ellenorz�se
// ...
}
catch(out_of_range) {
// hopp�, kics�sztunk a tartom�nyon k�v�lre
}
16. A k�nyvt�r szerkezete �s a t�rol�k 587
Ez a p�lda bemutat egy hasznos �tletet is: ha az indexhat�rokat m�r valamilyen
m�don ellen
orizt�k, akkor az ellenorizetlen indexelo oper�tort teljes biztons�ggal
haszn�lhatjuk. Ellenkez
o esetben viszont �rdemes az at() f�ggv�nyt alkalmaznunk. Ez a k�l�nbs�g fontos
lehet olyan programokn�l, ahol a hat�konys�gra is figyeln�nk kell. Ha a
hat�konys�g nem
jelentos szempont vagy nem tudjuk egy�rtelmuen eld�nteni, hogy a tartom�ny
ellenorz�tte,
akkor biztons�gosabb ellenorz�tt [ ] oper�torral rendelkezo vektort haszn�ljunk
(p�ld�-
ul a Vec-et, �3.7.2), vagy legal�bbis ellenorz�tt bej�r�t (�19.3).
A t�mb�k alap�rtelmezett hozz�f�r�si m�dja ellenorizetlen. Biztons�gos
(ellenorz�tt) szolg
�ltat�sokat megval�s�thatunk egy gyors alaprendszer felett, de gyors szolg�ltat�st
lass�
alaprendszer felett nem.
A hozz�f�r�si muveletek reference vagy const_reference t�pus� �rt�ket adnak
vissza, att�l
f�ggoen, hogy konstans objektumra alkalmaztuk-e azokat. Az elemek el�r�s�re a
referencia
megfelelo t�pus. A vector<X> legegyszerubb �s legk�zenfekvobb megval�s�t�s�ban
a reference egyszeruen X&, m�g a const_reference megfeleloje a const X&. Ha egy
indexhat
�ron k�v�li elemre pr�b�lunk hivatkozni, az eredm�ny meghat�rozhatatlan lesz:
void f(vector<double>& v)
{
double d = v[v.size()]; // nem meghat�rozhat�: rossz index�rt�k
list<char> lst;
char c = lst.front(); // nem meghat�rozhat�: a lista �res
}
A szabv�nyos sorozatok k�z�l csak a vector �s a deque (�17.2.3) t�mogatja az
indexel�st.
Ennek oka az, hogy a rendszer tervezoi nem akart�k a felhaszn�l�kat alapvetoen
rossz hat
�sfok� muveletek bevezet�s�vel megzavarni. Az indexel�s p�ld�ul nem alkalmazhat� a
list
t�pusra (�17.2.2), mert vesz�lyesen rossz hat�sfok� elj�r�s lenne (konkr�tabban:
O(n)).
A front() �s back() tagf�ggv�nyek sorrendben az elso, illetve az utols� elemre
hivatkoz�
referenci�kat adnak vissza. Akkor igaz�n hasznosak, ha biztosan tudjuk, hogy
l�teznek
ezek az elemek �s programunkban valami�rt k�l�n�sen fontosak. Ennek gyakori esete,

amikor egy vektort veremk�nt (stack, �16.3.5) akarunk haszn�lni. Jegyezz�k meg,
hogy
a front() arra az elemre ad hivatkoz�st, amelyre a begin() egy bej�r�t. A front()
�gy is elk
�pzelheto, mint maga az elso elem, m�g a begin() ink�bb az elso elemre hivatkoz�
mutat
�. A back() �s az end() k�z�tti kapcsolat egy kicsit bonyolultabb: a back() az
utols� elem,
m�g az end() egy mutat� az .utols� ut�ni. poz�ci�ra.
588 A standard k�nyvt�r
16.3.4. Konstruktorok
Term�szetesen a vector a konstruktoroknak, destruktoroknak �s m�sol� muveleteknek
is
teljes t�rh�z�t k�n�lja:
template <class T, class A = allocator<T> > class vector {
public:
// ...
// konstruktorok, stb.
explicit vector(const A& = A());
explicit vector(size_type n, const T& val = T(), const A& = A()); // n darab val
template <class In> // az In-nek bemeneti bej�r�nak kell lennie (�19.2.1)
vector(In first, In last, const A& = A()); // m�sol�s [first:last[-b�l
vector(const vector& x);
~vector();
vector& operator=(const vector& x);
template <class In> // az In-nek bemeneti bej�r�nak kell lennie (�19.2.1)
void assign(In first, In last); // m�sol�s [first:last[-b�l
void assign(size_type n, const T& val); // n darab val
// ...
};
A vector gyors hozz�f�r�st tesz lehetov� tetszoleges elem�hez, de m�ret�nek
m�dos�t�sa viszonylag
bonyolult. Ez�rt �ltal�ban a vector l�trehoz�sakor megadjuk annak m�ret�t is:
vector<Record> vr(10000);
void f(int s1, int s2)
{
vector<int> vi(s1);
vector<double>* p = new vector<double>(s2);
}
Az ilyen m�don l�trehozott vektorelemeknek az elemek t�pus�nak megfelelo
alap�rtelmezett
konstruktorok adnak kezdo�rt�ket, teh�t a vr vektornak mind a 10 000 elem�re lefut

a Record() f�ggv�ny, a vi si darab elem�nek pedig egy-egy int() h�v�s ad


kezdo�rt�ket.
Gondoljunk r�, hogy a be�p�tett t�pusok alap�rtelmezett konstruktora az adott
t�pusnak
megfelelo 0 �rt�ket adja kezdo�rt�k�l. (�4.9.5, �10.4.2)
16. A k�nyvt�r szerkezete �s a t�rol�k 589
Ha egy t�pus nem rendelkezik alap�rtelmezett konstruktorral, akkor belole nem
hozhatunk
l�tre vektort, hacsak nem adjuk meg az �sszes elem kezdo�rt�k�t. P�ld�ul:
class Num { // v�gtelen pontoss�g
public:
Num(long);
// nincs alap�rtelmezett konstruktor
// ...
};
vector<Num> v1(1000); // hiba: nincs alap�rtelmezett Num
vector<Num> v2(1000,Num(0)); // rendben
Mivel egy vector nem t�rolhat negat�v sz�m� elemet, �gy m�ret�nek nemnegat�v
sz�mnak
kell lennie. Ez azon k�vetelm�nyben jut kifejez�sre, hogy a vektor size_type
t�pus�nak
unsigned-nak kell lennie. Ez bizonyos rendszerekben nagyobb vektorm�ret
haszn�lat�t teszi
lehetov�, egyes esetekben viszont meglepet�sekhez is vezethet:
void f(int i)
{
vector<char> vc0(-1); // a ford�t� erre k�nnyen figyelmeztethet
vector<char> vc1(i);
}
void g()
{
f(-1); // becsapjuk f()-et, hogy elfogadjon egy igen nagy pozit�v sz�mot
}
Az f(-1) h�v�sban a -1 �rt�ket egy igen nagy pozit�v sz�mra alak�tja a rendszer
(�C.6.3). Ha
szerencs�nk van, ford�t�nk figyelmeztet erre.
A vector m�ret�t k�zvetve is megadhatjuk, �gy, hogy felsoroljuk a kezdeti
elemhalmazt. Ezt
�gy val�s�thatjuk meg, hogy a konstruktornak azon �rt�kek sorozat�t adjuk �t,
amelyekbol
a vektort fel kell �p�teni:
void f(const list<X>& lst)
{
vector<X> v1(lst.begin(),lst.end()); // elemek m�sol�sa list�b�l
char p[ ] = "despair";
vector<char> v2(p,&p[sizeof(p)-1]); // karakterek m�sol�sa C st�lus�
karakterl�ncb�l
}
590 A standard k�nyvt�r
Minden esetben a vector konstruktora sz�m�tja ki a vektor m�ret�t, mik�zben a
bemeneti
sorozatb�l �tm�solja az elemeket.
A vector azon konstruktorait, melyek egyetlen param�tert ig�nyelnek, az explicit
kulcssz�-
val deklar�ljuk, �gy v�letlen konverzi�k nem fordulhatnak elo (�11.7.1):
vector<int> v1(10); // rendben: 10 eg�szbol �ll� vektor
vector<int> v2 = vector<int>(10); // rendben: 10 eg�szbol �ll� vektor
vector<int> v3 = v2; // rendben: v3 v2 m�solata
vector<int> v4 = 10; // hiba: automatikus konvert�l�s k�s�rlete 10-rol
vector<int>-re
A m�sol� konstruktor �s a m�sol� �rt�kad�s a vector elemeit m�solj�k le. Egy sok
elembol
�ll� vektor eset�ben ez hosszadalmas muvelet lehet, ez�rt a vektorokat �ltal�ban
referenciak
�nt adjuk �t:
void f1(vector<int>&); // szok�sos st�lus
void f2(const vector<int>&); // szok�sos st�lus
void f3(vector<int>); // szokatlan st�lus
void h()
{
vector<int> v(10000);
// ...
f1(v); // hivatkoz�s �tad�sa
f2(v); // hivatkoz�s �tad�sa
f3(v); // a 10 000 elem �j vektorba m�sol�sa az f3() sz�m�ra
}
Az assign f�ggv�nyek a t�bbparam�teres konstruktorok p�rjainak tekinthetok. Az�rt
van
r�juk sz�ks�g, mert az = egyetlen, jobb oldali operandust v�r, �gy ha
alap�rtelmezett param
�ter�rt�ket akarunk haszn�lni vagy �rt�kek teljes sorozat�t akarjuk �tadni, az
assign f�ggv
�nyre van sz�ks�g�nk:
class Book {
// ...
};
void f(vector<Num>& vn, vector<char>& vc, vector<Book>& vb, list<Book>& lb)
{
vn.assign(10,Num(0)); // Num(0) t�z p�ld�ny�t t�rol� vektor �rt�k�l ad�sa vn-nek
16. A k�nyvt�r szerkezete �s a t�rol�k 591
char s[ ] = "liter�l";
vc.assign(s,&s[sizeof(s)-1]); // a "liter�l" �rt�k�l ad�sa vc-nek
vb.assign(lb.begin(),lb.end()); // listaelemek �rt�k�l ad�sa
// ...
}
Ezek ut�n egy vector objektumot felt�lthet�nk tetszoleges elemsorozattal, ami
t�pus szerint
megfelelo, �s k�sobb is hozz�rendelhet�nk az objektumhoz ilyen sorozatokat.
Fontos,
hogy ezt an�lk�l �rt�k el, hogy nagysz�m� konstruktort illetve konverzi�s
oper�tort kellett
volna defini�lnunk. Figyelj�k meg, hogy az �rt�kad�s teljes eg�sz�ben lecser�li a
vektor
elemeit. Elm�letileg az �sszes r�gi elemet t�r�lj�k, majd az �j elemeket
beillesztj�k. Az �rt
�kad�s ut�n a vector m�rete az �rt�k�l adott elemek sz�m�val egyezik meg:
void f()
{
vector<char> v(10,'x'); // v.size()==10, minden elem �rt�ke 'x'
v.assign(5,'a'); // v.size()==5, minden elem �rt�ke 'a'
// ...
}
Term�szetesen, amit az assign() csin�l, az megval�s�that� k�zvetetten �gy is, hogy
elosz�r
l�trehozzuk a k�v�nt vektort, majd ezt adjuk �rt�k�l:
void f2(vector<Book>& vh, list<Book>& lb)
{
vector<Book> vt(lb.begin(),lb.end());
vh = vt;
// ...
}
Ez a megold�s azonban nem csak cs�nya, de rossz hat�sfok� is lehet.
Ha egy vektor konstruktor�ban k�t ugyanolyan t�pus� param�tert haszn�lunk, akkor
azt
k�tf�lek�ppen is �rtelmezhetn�nk:
vector<int> v(10,50); // vector(m�ret,�rt�k) vagy vector(bej�r�1,bej�r�2)?
// vector(m�ret,�rt�k)!
Az int nem bej�r�, �gy a megval�s�t�soknak biztos�taniuk kell, hogy a megfelelo
konstruktor
fusson le:
vector(vector<int>::size_type, const int&, const vector<int>::allocator_type&);
592 A standard k�nyvt�r
A m�sik lehets�ges konstruktor a k�vetkezo:
vector(vector<int>::iterator, vector<int>::iterator, const
vector<int>::allocator_type&);
A k�nyvt�r ezt a probl�m�t �gy oldja meg, hogy megfelelo m�don t�lterheli a
konstruktorokat,
de hasonl�an kezeli az assign() �s az insert() (�16.3.6) eset�ben elofordul� t�bb-

�rtelmus�get is.
16.3.5. Veremmuveletek
A vektort �ltal�ban �gy k�pzelj�k el, mint egy egys�ges adatszerkezetet, melyben
az elemeket
indexel�ssel �rhetj�k el. Ezt a szeml�letet azonban el is felejthetj�k �s a
vektort a legelvontabb
(leg�ltal�nosabb) sorozat megtestes�toj�nek tekinthetj�k. Ha erre gondolunk �s
megfigyelj�k, hogy a t�mb�knek, vektoroknak milyen �ltal�nos felhaszn�l�si
ter�letei vannak,
nyilv�nval�v� v�lik, hogy a vector oszt�lyban a veremmuveletekre is sz�ks�g lehet:

template <class T, class A = allocator<T> > class vector {


public:
// ...
// veremmuveletek
void push_back(const T& x); // hozz�ad�s a v�g�hez
void pop_back(); // az utols� elem elt�vol�t�sa
// ...
};
Ezek a f�ggv�nyek a vektort veremnek tekintik �s annak v�g�n v�geznek muveleteket:

void f(vector<char>& s)
{
s.push_back('a');
s.push_back('b');
s.push_back('c');
s.pop_back();
if (s[s.size()-1] != 'b') error("Lehetetlen!");
s.pop_back();
if (s.back() != 'a') error("Ennek soha nem szabad megt�rt�nnie!");
}
16. A k�nyvt�r szerkezete �s a t�rol�k 593
Amikor megh�vjuk a push_back() f�ggv�nyt, az s vektor m�rete mindig no egy elemmel
�s
a param�terk�nt megadott elem a vektor v�g�re ker�l. �gy az s[s.size()-1] elem
(ami ugyanaz,
mint az s.back() �ltal visszaadott �rt�k, �16.3.3) a verembe legutolj�ra helyezett
elem lesz.
Att�l eltekintve, hogy a vector sz�t haszn�ljuk a stack helyett, semmi szokatlant
nem muvelt
�nk. A _back ut�tag azt hangs�lyozza ki, hogy az elemet a vektor v�g�re helyezz�k,
nem
pedig az elej�re. Egy �j elem elhelyez�se a vektor v�g�n nagyon k�lts�ges muvelet
is lehet,
hiszen annak t�rol�s�hoz tov�bbi mem�ri�t kell lefoglalnunk. Az adott nyelvi
v�ltozatnak
azonban biztos�tania kell, hogy az ism�tlodo veremmuveletek csak ritk�n okozzanak
m�-
retn�veked�sbol eredo teljes�tm�nycs�kken�st.
Figyelj�k meg, hogy a pop_back() f�ggv�ny sem ad vissza �rt�ket. Egyszeruen t�rli
a legutols
� elemet �s ha azt szeretn�nk megtudni, hogy a kiemel�s (pop) elott milyen �rt�k
szerepelt
a verem tetej�n, akkor azt k�l�n meg kell n�zn�nk. Ezt a t�pus� vermet sokan nem
kedvelik
(�2.5.3, �2.5.4), de ez a megold�s hat�konyabb lehet �s ez tekintheto a
szabv�nynak is.
Mi�rt lehet sz�ks�g veremszeru muveletekre egy vektor eset�ben? Egy nyilv�nval�
indok,
hogy a verem megval�s�t�s�ra ez az egyik lehetos�g (�17.3.1), de enn�l gyakoribb,
hogy
a t�mb�t folyamatosan n�vekedve akarjuk l�trehozni. Elk�pzelheto p�ld�ul, hogy
pontokat
akarunk beolvasni egy t�mbbe, de nem tudjuk, �sszesen h�ny pontot kapunk. Ez
esetben
arra nincs lehetos�g�nk, hogy m�r kezdetben a megfelelo m�retu t�mb�t hozzuk l�tre

�s ut�na csak egyszeruen bele�rjuk a pontokat. Ehelyett a k�vetkezo elj�r�st kell


v�grehajtanunk:
vector<Point> cities;
void add_points(Point sentinel)
{
Point buf;
while (cin >> buf) {
if (buf == sentinel) return;
// �j pont ellenorz�se
cities.push_back(buf);
}
}
Ez a megold�s biztos�tja, hogy a vector ig�ny szerint n�vekedhessen. Ha mind�ssze
annyi
a teendonk, hogy a pontokat elhelyezz�k a vektorban, akkor a cities
adatszerkezetet felt�lthetj
�k k�zvetlen�l egy konstruktor seg�ts�g�vel is (�16.3.4), �ltal�ban azonban
valamilyen
m�don m�g fel kell dolgoznunk a be�rkezo adatokat �s csak fokozatosan t�lthetj�k
fel
a vektort a program elorehaladt�val. Ilyenkor haszn�lhatjuk a push_back()
f�ggv�nyt.
594 A standard k�nyvt�r
A C programokban ez a leggyakoribb felhaszn�l�si ter�lete a realloc() f�ggv�nynek,
amely
a C standard k�nyvt�r�ban szerepel. Ez�rt a vektor . �s �ltal�ban minden
szabv�nyos t�rol
� . biztos�t egy �ltal�nosabb, eleg�nsabb, de nem kev�sb� hat�kony v�ltozatot a
realloc()
helyett.
A vektor m�ret�t (size()) a push_back() automatikusan n�veli, �gy nem fordulhat
elo, hogy
a vektor t�lcsordul (mindaddig, am�g mem�ria ig�nyelheto a rendszertol, �19.4.1).
Alulcsordul
�s ellenben elofordulhat:
void f()
{
vector<int> v;
v.pop_back(); // nem meghat�rozhat� hat�s: v �llapota nem
// meghat�rozhat� lesz
v.push_back(7); // nem meghat�rozhat� hat�s (v �llapota nem
// meghat�rozhat�), val�sz�nuleg rossz
}
Az alulcsordul�s k�vetkezm�nye nem meghat�rozhat� �s a legt�bb C++-v�ltozat
eset�ben
olyan mem�riater�let fel�l�r�s�t eredm�nyezi, amely nem tartozik a vektorhoz. Az
alulcsordul
�st ugyan�gy el kell ker�ln�nk, mint a t�lcsordul�st.
16.3.6. Listamuveletek
A push_back(), a pop_back() �s a back() muvelet (�16.3.5) lehetov� teszi, hogy a
vector oszt
�lyt veremk�nt haszn�ljuk. Bizonyos helyzetekben azonban arra is sz�ks�g�nk lehet,
hogy
a verem k�zep�re illessz�nk be, vagy onnan t�vol�tsunk el egy elemet:
template <class T, class A = allocator<T> > class vector {
public:
// ...
// listamuveletek
iterator insert(iterator pos, const T& x); // x felv�tele pos el�
void insert(iterator pos, size_type n, const T& x); // n darab x felv�tele pos el�

template <class In> // az In-nek bemeneti bej�r�nak kell lennie (�19.2.1)


void insert(iterator pos, In first, In last); // elemek beilleszt�se sorozatb�l
iterator erase(iterator pos); // a pos poz�ci�ban levo elem elt�vol�t�sa
iterator erase(iterator first, iterator last); // a sorozat t�rl�se
void clear(); // minden elem t�rl�se
// ...
};
16. A k�nyvt�r szerkezete �s a t�rol�k 595
Ezen muveletek muk�d�s�nek bemutat�s�hoz egy gy�m�lcs�k (fruit) neveit tartalmaz�
vektort hozunk l�tre. Elosz�r is meghat�rozzuk a vektort, majd felt�ltj�k n�h�ny
n�vvel:
vector<string> fruit;
fruit.push_back("oszibarack");
fruit.push_back("alma");
fruit.push_back("kivi");
fruit.push_back("k�rte");
fruit.push_back("csillaggy�m�lcs");
fruit.push_back("szolo");
Ha hirtelen eleg�nk lesz azokb�l a gy�m�lcs�kbol, melyek neve k betuvel kezdodik,
akkor
ezeket a k�vetkezo elj�r�ssal t�r�lhetj�k ki:
sort(fruit.begin(),fruit.end());
vector<string>::iterator p1 = find_if(fruit.begin(),fruit.end(),initial('k'));
vector<string>::iterator p2 = find_if(p1,fruit.end(),initial_not('k'));
fruit.erase(p1,p2);
Teh�t rendezz�k a vektort, megkeress�k az elso �s az utols� gy�m�lcs�t, melynek
neve k
betuvel kezdodik, v�g�l ezeket t�r�lj�k a fruit objektumb�l. Hogyan k�sz�thet�nk
olyan
f�ggv�nyeket, mint az initial(x) . amely eld�nti, hogy a kezdo karakter x betu-e .
vagy az
initial_not(x), amely akkor ad igaz �rt�ket, ha a kezdobetu nem x? Ezzel a
k�rd�ssel k�-
sobb, a �18.4.2 pontban foglalkozunk r�szletesen.
Az erase(p1,p2) muvelet p1-tol p2-ig t�rli az elemeket (a p2 elem marad). Ezt a
k�vetkezo-
k�ppen szeml�ltethetj�k:
fruit[ ]:
p1 p2
alma csillaggy�m�lcs kivi k�rte oszibarack szolo
Az erase(p1,p2) t�rli a kivi �s a k�rte elemet, teh�t a v�geredm�ny a k�vetkezo
lesz:
fruit[ ]:
alma csillaggy�m�lcs oszibarack szolo
596 A standard k�nyvt�r
Szok�s szerint, a programoz� �ltal megadott sorozat az elso feldolgozand� elemtol
az utols
� feldolgozott elem ut�ni poz�ci�ig tart.
Esetleg esz�nkbe jut az al�bbi megold�ssal pr�b�lkozni:
vector<string>::iterator p1 = find_if(fruit.begin(),fruit.end(),initial('k'));
vector<string>::reverse_iterator p2 =
find_if(fruit.rbegin(),fruit.rend(),initial('k'));
fruit.erase(p1,p2+1); // hopp�! t�pushiba
Azonban a vector<fruit>::iterator �s a vector<fruit>::reverse_iterator nem
felt�tlen�l azonos
t�pus�, �gy nem haszn�lhatjuk oket egy�tt az erase() f�ggv�ny h�v�sakor. Ha egy
reverse_iterator �rt�ket egy iterator �rt�kkel egy�tt akarunk haszn�lni, akkor az
elobbit �t
kell alak�tanunk:
fruit.erase(p1,p2.base()); // iterator kinyer�se reverse_iterator-b�l (�19.2.5)
Ha egy vektorb�l elemeket t�rl�nk, akkor megv�ltozik annak m�rete �s a t�r�lt elem
ut�n
szereplo �rt�keket a felszabadult ter�letre kell m�solnunk. P�ld�nkban a
fruit.size() �rt�ke
4-re v�ltozik, �s az oszibarack, amire eddig fruit[5] n�ven hivatkozhattunk, most
m�r
fruit[3]-k�nt lesz el�rheto.
Term�szetesen arra is lehetos�g�nk van, hogy egyetlen elemet t�r�lj�nk. Ebben az
esetben
csak az erre az elemre mutat� bej�r�ra van sz�ks�g (�s nem egy bej�r�-p�rra):
fruit.erase(find(fruit.begin(),fruit.end(),"oszibarack"));
fruit.erase(fruit.begin()+1);
Ez a k�t sor t�rli az oszibarack-ot �s a csillaggy�m�lcs-�t, �gy a fruit vektorban
m�r csak k�t
elem marad:
fruit[ ]:
alma szolo
Arra is lehetos�g�nk van, hogy egy vektorba elemeket illessz�nk be. P�ld�ul:
fruit.insert(fruit.begin()+1,"cseresznye");
fruit.insert(fruit.end(),"ribizli");
16. A k�nyvt�r szerkezete �s a t�rol�k 597
Az �j elem a megadott elem el� ker�l, az ut�na k�vetkezo elemek pedig elmozdulnak,
hogy
az �j elemet besz�rhassuk. Az eredm�ny:
fruit[ ]:
alma cseresznye szolo ribizli
Figyelj�k meg, hogy az f.insert(f.end(),x) egyen�rt�ku az f.push_back(x)
muvelettel.
Teljes sorozatokat is beilleszthet�nk egy vektorba:
fruit.insert(fruit.begin()+2,citrus.begin(),citrus.end());
Ha a citrus egy m�sik t�rol�, amely �gy n�z ki:
citrus[ ]:
citrom grapefruit narancs lime
akkor a k�vetkezo eredm�nyt kapjuk:
fruit[ ]:
alma cseresznye citrom grapefruit narancs lime szolo ribizli
Az insert() f�ggv�ny a citrus elemeit �tm�solja a fruit vektorba. A citrus t�rol�
v�ltozatlan
marad.
K�ts�gtelen, hogy az insert() �s az erase() �ltal�nosabbak, mint azok a muveletek,
melyek
csak a vektor v�g�nek m�dos�t�s�t teszik lehetov� (�16.3.5). �ppen emiatt azonban
sokkal
t�bb gonddal is j�rhatnak. P�ld�ul ahhoz, hogy az insert() egy �j elemet
beillesszen, esetleg
az �sszes kor�bbi elemet �t kell helyeznie a mem�ri�ban. Ha sokszor haszn�lunk
teljesen
�ltal�nos besz�r� �s t�rlo muveleteket egy t�rol�n, akkor ennek a t�rol�nak
esetleg
nem is vector-nak, hanem ink�bb list-nek k�ne lennie. A list t�rol� hat�konyan
k�pes
egy�ttmuk�dni az insert() �s az erase() muveletekkel, de az indexel�s ez esetben
neh�zkes
(�16.3.3).
A besz�r�s �s a t�rl�s a vector eset�ben esetleg sok-sok elem �thelyez�s�vel j�r,
(m�g a list
vagy az asszociat�v t�rol�k . p�ld�ul a map . eset�ben ez elker�lheto). Ennek
k�vetkezt�-
ben elofordulhat, hogy a vector egyik elem�re mutat� iterator egy insert() vagy
egy erase()
muvelet v�grehajt�sa ut�n egy m�sik, vagy ak�r egy egy�ltal�n nem l�tezo elemre
mutat.
Soha ne pr�b�ljunk meg el�rni elemeket �rv�nytelen bej�r�n kereszt�l, mert az
eredm�ny
598 A standard k�nyvt�r
meghat�rozhatatlan lesz �s �ltal�ban v�gzetes k�vetkezm�nyekkel j�r. K�l�n�sen
vesz�-
lyes egy olyan bej�r� haszn�lata, amely a besz�r�s hely�t jel�lte ki, mert az
insert() az elso
param�ter�t �rv�nytelenn� teszi:
void duplicate_elements(vector<string>& f)
{
for(vector<string>::iterator p = f.begin(); p!=f.end(); ++p) f.insert(p,*p); //
Nem!
}
Erre kell gondolnunk majd a �16.5[15] feladatn�l is. A vector adott v�ltozata az
�j p elem besz
�r�s�hoz esetleg az �sszes elemet �thelyezn�, de a p ut�niakat biztosan.
A clear() muvelet a t�rol� �sszes elem�t t�rli. Ez�rt a c.clear() a
c.erase(c.begin(),c.end())
r�vid�t�s�nek tekintheto. A c.clear() v�grehajt�sa ut�n a c.size() �rt�ke 0 lesz.
16.3.7. Az elemek kiv�laszt�sa
A legt�bb esetben az erase() �s az insert() c�lpontja egy j�l meghat�rozott hely,
p�ld�ul
a begin() vagy az end() eredm�nye, valamilyen keres�si elj�r�s (p�ld�ul a find())
�ltal
visszaadott �rt�k vagy egy bej�r�ssal megtal�lt elempoz�ci�. Ezekben az esetekben
rendelkez
�s�nkre �ll egy bej�r�, amely a k�v�nt elemet jel�li ki. A vector (�s a
vektorszeru t�rol
�k) elemeit azonban meghat�rozhatjuk indexel�ssel is. Hogyan �ll�thatunk elo egy
olyan
bej�r�t, amely az insert() vagy az erase() utas�t�sban megfelelo param�ter a 7-es
sorsz�m�
elem kijel�l�s�hez? Mivel ez a hetedik elem a vektor elej�tol sz�m�tva, �gy a
c.begin()+7 kifejez
�s jelenti a megold�st. A tov�bbi lehetos�gek, amelyek a t�mb�kh�z val� hasonl�s�g

miatt felmer�lhetnek benn�nk, gyakran nem muk�dnek. P�ld�ul gondoljuk v�gig a


k�vetkez
o eseteket:
template<class C> void f(C& c)
{
c.erase(c.begin()+7); // rendben (ha c bej�r�i t�mogatj�k a + muveletet
// (�19.2.1))
c.erase(&c[7]); // nem �ltal�nos
c.erase(c+7); // hiba: 7 hozz�ad�sa egy t�rol�hoz nem �rtelmezheto
c.erase(c.back()); // hiba: c.back() referencia, nem bej�r�
c.erase(c.end()-2); // rendben (utols� elotti elotti elem)
c.erase(c.rbegin()+2); // hiba: vector::reverse_iterator �s vector::iterator
// k�l�nb�zo t�pusok
c.erase((c.rbegin()+2).base()); // zavaros, de j� (�19.2.5)
}
16. A k�nyvt�r szerkezete �s a t�rol�k 599
A legcsalogat�bb lehetos�g a &c[7], amely a vector legnyilv�nval�bb
megval�s�t�s�ban
haszn�lhat� is, hiszen a c[7] egy l�tezo elem, �s ennek c�me haszn�lhat�
bej�r�k�nt. A c viszont
lehet egy olyan t�rol� is, ahol a bej�r� nem egy egyszeru mutat� valamelyik
elemre.
A map index-oper�tora (�17.4.1.3) p�ld�ul egy mapped_type& t�pus� referenci�t, �s
nem
egy elemre hivatkoz� referenci�t (value_type&) ad vissza.
A bej�r�ra nem minden t�rol� eset�ben haszn�lhat� a + muvelet. A list p�ld�ul m�g
a c.begin()+7 forma haszn�lat�t sem t�mogatja. Ha felt�tlen�l hetet kell adnunk
egy
list::iterator objektumhoz, akkor a ++ oper�tort kell ism�telgetn�nk.
A c+7 �s a c.back() forma egyszeruen t�pushib�t eredm�nyez. A t�rol� nem numerikus
v�ltoz
�, amelyhez hetet hozz�adhatn�nk, a c.back() pedig egy konkr�t elem . p�ld�ul a
.k�rte
. �rt�kkel, amely nem hat�rozza meg a k�rte hely�t a c t�rol�ban.
16.3.8. M�ret �s kapacit�s
A vector oszt�lyt eddig �gy pr�b�ltuk meg bemutatni, hogy a leheto legkevesebbet
sz�ljunk
a mem�riakezel�srol. A vector sz�ks�g szerint n�vekszik. �ltal�ban ennyit �ppen
el�g tudnunk.
Ennek ellen�re lehetos�g�nk van r�, hogy k�zvetlen�l a vector mem�riahaszn�lat�-
r�l k�rdezz�nk, �s bizonyos helyzetekben �rdemes is �ln�nk ezzel a lehetos�ggel.
Az ilyen
c�l� muveletek a k�vetkezok:
template <class T, class A = allocator<T> > class vector {
public:
// ...
// kapacit�s
size_type size() const; // elemek sz�ma
bool empty() const { return size()==0; }
size_type max_size() const; // a lehets�ges legnagyobb vektor m�rete
void resize(size_type sz, T val = T()); // a hozz�adott elemeknek val ad
kezdo�rt�ket
size_type capacity() const; // az elemek sz�m�nak megfelelo lefoglalt mem�ria
m�rete
void reserve(size_type n); // hely biztos�t�sa �sszesen n elem sz�m�ra; nem adunk
// kezdo�rt�ket
// length_error kiv�lt�sa, ha n>max_size()
// ...
};
600 A standard k�nyvt�r
A vector minden pillanatban valah�ny elemet t�rol. Az �ppen t�rolt elemek sz�m�t a
size()
f�ggv�nnyel k�rdezhetj�k le �s a resize() seg�ts�g�vel m�dos�thatjuk. Teh�t a
programoz�
meg tudja �llap�tani a vektor m�ret�t �s meg tudja azt v�ltoztatni, ha a vektor
szuknek vagy
t�l nagynak bizonyul:
class Histogram {
vector<int> count;
public:
Histogram(int h) : count(max(h,8)) {}
void record(int i);
// ...
};
void Histogram::record(int i)
{
if (i<0) i = 0;
if (count.size()<=i) count.resize(i+i); // sok hely kell
count[i]++;
}
A resize() haszn�lata egy vector eset�ben nagyon hasonl�t arra, amikor a C
standard k�nyvt
�r�nak realloc() f�ggv�ny�t haszn�ljuk egy dinamikusan lefoglalt C t�mb eset�ben.
Amikor egy vektort �tm�retez�nk, hogy t�bb (vagy kevesebb) elemet t�roljunk benne,
elk
�pzelheto, hogy az �sszes elem �j helyre ker�l a mem�ri�ban. Ez�rt �tm�retezheto
vektorok
elemeire hivatkoz� mutat�kat nem t�rolhatunk ak�rmeddig, egy resize() utas�t�s
ut�n
ugyanis ezek m�r felszabad�tott mem�riater�letre mutatnak. Ehelyett
nyilv�ntarthatunk index
�rt�keket. Soha ne felejts�k el, hogy a push_back(), az insert() �s az erase() is
�tm�retezi
a vektort.
Ha a programoz� tudja, hogy a vektor m�rete a k�sobbiekben mennyire nohet, esetleg
�rdemes
a reserve() f�ggv�ny seg�ts�g�vel elore lefoglalnia a megfelelo m�retu ter�letet a
k�-
sobbi felhaszn�l�shoz:
struct Link {
Link* next;
Link(Link* n =0) : next(n) {}
// ...
};
vector<Link> v;
void chain(size_t n) // v felt�lt�se n sz�m� Link-kel, melyek az elozo Link-re
mutatnak
{
16. A k�nyvt�r szerkezete �s a t�rol�k 601
v.reserve(n);
v.push_back(Link(0));
for (int i = 1; i<n; i++) v.push_back(Link(&v[i-1]));
// ...
}
A v.reserve(n) f�ggv�nyh�v�s biztos�tja, hogy a v m�ret�nek n�vel�sekor mindaddig
nem
lesz sz�ks�g mem�riafoglal�sra, am�g v.size() meg nem haladja n �rt�k�t.
A sz�ks�ges mem�riater�let elozetes lefoglal�s�nak k�t elonye van. Az egyik, hogy
m�g
a legegyszerubb nyelvi v�ltozat is egyetlen muvelettel lefoglalhat elegendo
mem�riater�letet,
�s nem kell minden l�p�sben lass� mem�riaig�nyl�st v�grehajtania. Ezenk�v�l a legt
�bb esetben sz�molhatunk egy logikai elonnyel is, amely tal�n m�g fontosabb, mint
a hat
�konys�gi szempont. Amikor egy vector m�rete megno, akkor elm�letileg minden elem
helye megv�ltozhat a mem�ri�ban. Ennek k�vetkezt�ben minden olyan jellegu
l�ncol�s,
amilyet az elobbi p�ld�ban l�trehoztunk az elemek k�z�tt, csak akkor haszn�lhat�,
ha
a reserve() garant�lja, hogy az elemek mem�riabeli helye nem v�ltozik meg a vektor
fel�p�-
t�se k�zben. Teh�t bizonyos esetekben a reserve() biztos�tja programunk
helyess�g�t,
amellett, hogy hat�konys�gi elony�ket is jelent.
Ugyanezt a biztons�got ny�jtja az is, ha csak kisz�m�that� idok�z�nk�nt fordulhat
elo, hogy
a vector sz�m�ra lefoglalt ter�let elfogy �s egy bonyolult muvelettel �t kell
helyezn�nk az
addig t�rolt elemeket. Ez nagyon fontos lehet olyan programok eset�ben, melyeknek
szigor
� fut�si ideju korl�toz�soknak kell megfelelni�k.
Fontos megjegyezn�nk, hogy a reserve() nem v�ltoztatja meg a vektor (logikai)
m�ret�t,
ez�rt az �j elemeknek sem kell kezdo�rt�ket adnia. Teh�t mindk�t szempontb�l
ellent�tesen
viselkedik, mint a resize().
Ugyan�gy, ahogy a size() az �ppen t�rolt elemek sz�m�t adja meg, a capacity()
f�ggv�ny
a lefoglalt mem�ria-egys�gek sz�m�r�l t�j�koztat. �gy a c.capacity()-c.size()
kifejez�s azt
adja meg, hogy m�g h�ny elemet hozhatunk l�tre �jb�li mem�riafoglal�s n�lk�l.
A vektor m�ret�nek cs�kkent�s�vel nem cs�kkentj�k annak kapacit�s�t. Az �gy
felszabadult
ter�letek teh�t megmaradnak a vector-ban a k�sobbi n�veked�st seg�tendo.
Ha a felszabadult ter�letet vissza szeretn�nk adni a rendszernek, egy kis tr�kkh�z
kell
folyamodnunk:
vector <Link> tmp = v; // v m�solata alap�rtelmezett kapacit�ssal
v.swap(tmp); // most v rendelkezik az alap�rtelmezett kapacit�ssal (�16.3.9)
602 A standard k�nyvt�r
A vector az elemek t�rol�s�hoz sz�ks�ges mem�riater�letet �gy foglalja le, hogy
megh�vja
(a sablonparam�terk�nt megadott) mem�riafoglal� tagf�ggv�nyeit. Az alap�rtelmezett
mem
�riafoglal�, melynek neve allocator (�19.4.1), a new oper�tort haszn�lja a
mem�riafoglal
�shoz, �gy egy bad_alloc kiv�telt v�lt ki, ha m�r nincs el�g szabad mem�ria. M�s
mem�riafoglal
�k m�s m�dszert is k�vethetnek (�19.4.2).
A reserve() �s capacity() f�ggv�nyek csak az olyan egys�ges, .t�m�r. t�rol�k
eset�ben
haszn�lhat�k, mint a vector. A list-hez p�ld�ul ilyen szolg�ltat�s nem �ll
rendelkez�s�nkre.
16.3.9. Tov�bbi tagf�ggv�nyek
Nagyon sok algoritmus . k�zt�k a fontos rendezo elj�r�sok . elemek felcser�l�s�vel
dolgozik.
A csere (�13.5.2) legegyszerubb megval�s�t�sa, hogy egyszeruen �tm�solgatjuk az
elemeket.
A vector oszt�lyt azonban �ltal�ban olyan szerkezet �br�zolja, amely az elemek le-

�r�j�t (handle) t�rolja (�13.5, �17.1.3). �gy k�t vector sokkal hat�konyabban is
felcser�lheto,
ha a le�r�kat cser�lj�k fel. A vector::swap() f�ggv�ny ezt val�s�tja meg. Az
alap�rtelmezett
swap() nagys�grendekkel lassabb, mint a fenti elj�r�s:
template <class T, class A = allocator<T> > class vector {
public:
// ...
void swap(vector&);
allocator_type get_allocator() const;
};
A get_allocator() f�ggv�ny lehetos�get ad a programoz�nak arra, hogy el�rje a
vector mem
�riafoglal�j�t (�16.3.1, �16.3.4). Erre a szolg�ltat�sra �ltal�ban akkor van
sz�ks�g�nk, amikor
egy, a vektorhoz kapcsol�d� adatnak a programban ugyan�gy akarunk mem�ri�t
foglalni,
mint a vector-nak mag�nak (�19.4.1)
16.3.10. Seg�df�ggv�nyek
K�t vector objektumot az == �s a < oper�tor seg�ts�g�vel hasonl�thatunk �ssze:
template <class T, class A>
bool std::operator==(const vector<T,A>& x, const vector<T,A>& y);
16. A k�nyvt�r szerkezete �s a t�rol�k 603
template <class T, class A>
bool std::operator<(const vector<T,A>& x, const vector<T,A>& y);
A v1 �s a v2 vector akkor egyenlo, ha v1.size()==v2.size() �s v1[n]==v2[n] minden
�rtelmes
n index eset�n. Hasonl�an, a < a nyelvi elemek szerinti rendez�st jelenti, teh�t a
< muveletet
a vector eset�ben a k�vetkezok�ppen hat�rozhatjuk meg:
template <class T, class A>
inline bool std::operator<(const vector<T,A>& x, const vector<T,A>& y)
{
return lexicographical_compare (x.begin(),x.end(),y.begin(),y.end()); // l�sd
�18.9
}
Ez azt jelenti, hogy x akkor kisebb, mint y, ha az elso olyan x[i] elem, amely nem
egyezik
meg a megfelelo y[i] elemmel, kisebb, mint y[i], vagy x.size()<y.size() �s minden
x[i] megegyezik
a megfelelo y[i] �rt�kkel.
A standard k�nyvt�r az == �s a < defin�ci�j�nak megfeleloen meghat�rozza a !=, a
<=, a >,
�s a >= oper�tort is.
Mivel a swap() egy tagf�ggv�ny, v1.swap(v2) form�ban h�vhatjuk meg. Nem minden
t�pusban
szerepel azonban a swap() tagf�ggv�ny, �gy az �ltal�nos algoritmusok a swap(a,b)
form
�t haszn�lj�k. Ahhoz, hogy ez a forma a vector-ok eset�ben is muk�dj�n, a standard

k�nyvt�r a k�vetkezo specializ�ci�t adja meg:


template <class T, class A> void std::swap(vector<T,A>& x, vector<T,A>& y)
{
x.swap(y);
}
16.3.11. Vector<bool>
A vector<bool> specializ�lt oszt�ly (�13.5) logikai �rt�keknek egy t�m�r�tett
vektor�t val�-
s�tja meg. Egy bool t�pus� v�ltoz�t is meg kell tudnunk c�mezni, �gy az legal�bb
egy b�jtot
foglal. A vector<bool> oszt�lyt azonban k�nnyen elk�sz�thetj�k �gy is, hogy minden
elem
csak egy bitet foglaljon.
A szok�sos vector muveletek ugyanolyan jelent�ssel haszn�lhat�k a vector<bool>
eset�ben is.
K�l�n�sen fontos, hogy az indexel�s �s a bej�r�s is elv�r�sainknak megfeleloen
muk�dnek:
604 A standard k�nyvt�r
void f(vector<bool>& v)
{
for (int i = 0; i<v.size(); ++i) cin >> v[i]; // ciklus index haszn�lat�val
typedef vector<bool>::const_iterator VI;
for (VI p = v.begin(); p!=v.end(); ++p) cout<<*p; // ciklus bej�r�k
// haszn�lat�val
}
Ennek el�r�s�hez ut�nozni kell a bitenk�nti c�mz�st. Mivel egy mutat� az egy
b�jtn�l kisebb
mem�riaegys�geket nem k�pes azonos�tani, a vector<bool>::iterator nem lehet
mutat�.
A bool* p�ld�ul biztosan nem haszn�lhat� bej�r�k�nt a vector<bool> oszt�lyban:
void f(vector<bool>& v)
{
bool* p = v.begin(); // hiba: nem megfelelo t�pus
// ...
}
A k�l�n�ll� bitek megc�mz�s�nek m�dj�t a �17.5.3 pontban mutatjuk be.
A k�nyvt�rban szerepel a bitset t�pus is, amely logikai �rt�kek halmaz�t t�rolja,
a logikai halmazok
szok�sos muveleteivel (�17.5.3).
16.4. Tan�csok
[1] Hordozhat� programok k�sz�t�s�hez haszn�ljuk a standard k�nyvt�r szolg�ltat
�sait. �16.1.
[2] Ne pr�b�ljuk �jraalkotni a standard k�nyvt�r szolg�ltat�sait. �16.1.2.
[3] Ne higgy�k, hogy minden esetben a standard k�nyvt�r jelenti a legjobb
megold�st.
[4] Amikor �j szolg�ltat�sokat hozunk l�tre, gondoljuk v�gig, hogy nem val�s�that
�k-e meg a standard k�nyvt�r ny�jtotta kereteken bel�l. �16.3.
[5] Ne felejts�k, hogy a standard k�nyvt�r szolg�ltat�sai az std n�vt�rhez
tartoznak.
�16.1.2.
[6] A standard k�nyvt�r szolg�ltat�sait a megfelelo fej�llom�ny seg�ts�g�vel
�p�ts�k
be, ne haszn�ljunk k�zvetlen deklar�ci�t. �16.1.2.
16. A k�nyvt�r szerkezete �s a t�rol�k 605
[7] Haszn�ljuk ki a k�sei elvonatkoztat�s elonyeit. �16.2.1.
[8] Ker�lj�k a k�v�r fel�letek haszn�lat�t. �16.2.2.
[9] Ha az elemeken visszafel� akarunk haladni, haszn�ljunk reverse_iterator-okat
iterator helyett. �16.3.2.
[10] Ha iterator-t szeretn�nk csin�lni egy reverse_iterator-b�l, haszn�ljuk a
base()
f�ggv�nyt. �16.3.2.
[11] T�rol�kat referencia szerint adjunk �t. �16.3.4.
[12] Ha egy t�rol� elemeire akarunk hivatkozni, mutat�k helyett haszn�ljunk
bej�r�-
t�pusokat (p�ld�ul list<char>::iterator). �16.3.1.
[13] Haszn�ljunk const bej�r�kat, ha a t�rol� elemeit nem akarjuk megv�ltoztatni.
�16.3.1.
[14] Ha tartom�nyellenorz�st akarunk v�gezni . ak�r k�zvetlen�l, ak�r k�zvetve .,
haszn�ljuk az at() f�ggv�nyt. �16.3.3.
[15] Haszn�ljuk ink�bb a push_back() vagy a resize() f�ggv�nyt egy t�rol�ban, mint

a realloc() f�ggv�nyt egy t�mbben. �16.3.5.


[16] Ne haszn�ljuk egy �tm�retezett vector bej�r�it. �16.3.8.
[17] A bej�r�k �rv�nytelenn� v�l�s�t elker�lhetj�k a reserve() f�ggv�ny
haszn�lat�-
val. �16.3.8.
[18] Ha sz�ks�ges, a reserve() f�ggv�nyt felhaszn�lhatjuk a teljes�tm�ny
kisz�m�that
�v� t�tel�re is. �16.3.8.
16.5. Feladatok
A fejezet legt�bb feladat�nak megold�s�t k�nnyen megtal�lhatjuk, ha megn�zz�k a
standard
k�nyvt�r adott v�ltozat�t. Mielott azonban megn�zn�nk, hogy a k�nyvt�r k�sz�toi
hogyan
k�zel�tett�k meg az adott probl�m�t, �rdemes saj�t megold�st k�sz�ten�nk.
1. (*1.5.) K�sz�ts�nk egy vector<char> t�pus� objektumot, amely az �b�c� betuit
tartalmazza, sorrendben. �rassuk ki ennek a t�mbnek a tartalm�t elore, majd
visszafel�.
2. (*1.5.) K�sz�ts�nk egy vector<string> objektumot, majd olvassuk be gy�m�lcs
�k neveit a cin eszk�zrol. Rendezz�k a list�t, majd �rassuk ki elemeit.
3. (*1.5.) A 16.5[2] feladat vektor�nak felhaszn�l�s�val �rjunk olyan ciklust,
amely
az �sszes 'a' betuvel kezdodo nevu gy�m�lcs�t jelen�ti meg.
4. (*1.) A 16.5[2] feladat vektor�nak felhaszn�l�s�val �rjunk olyan ciklust,
amellyel
t�r�lhetj�k az �sszes 'a' betuvel kezdodo nevu gy�m�lcs�t.
5. (*1.) A 16.5[2] feladat vektor�nak felhaszn�l�s�val �rjunk olyan ciklust,
amellyel
az �sszes citrusf�l�t t�r�lhetj�k.
606 A standard k�nyvt�r
6. (*1.5.) A 16.5[2] feladat vektor�nak felhaszn�l�s�val �rjunk olyan ciklust,
amely
azokat a gy�m�lcs�ket t�rli, amelyeket nem szeret�nk.
7. (*2.) Fejezz�k be a �16.2.1 pontban elkezdett Vector, List �s Itor oszt�lyt.
8. (*2.5.) Az Itor oszt�lyb�l kiindulva gondoljuk v�gig, hogyan k�sz�thet�nk
bej�r�kat elore halad� bej�r�sokhoz, visszafel� halad� bej�r�sokhoz, olyan
t�rol�hoz, amely a bej�r�s alatt megv�ltozhat, illetve megv�ltoztathatatlan t�rol
�hoz. Szervezz�k �gy ezeket a t�rol�kat , hogy a programoz� mindig azt
a bej�r�t haszn�lhassa, amelyik a leghat�konyabb megold�st k�n�lja az adott
algoritmus
megval�s�t�s�ra. A t�rol�kban ker�lj�nk minden k�dism�tl�st. Milyen
m�s bej�r�-fajt�ra lehet sz�ks�ge egy programoz�nak? Gyujts�k �ssze az �ltalunk
haszn�lt megk�zel�t�s elonyeit �s h�tr�nyait.
9. (*2.) Fejezz�k be a �16.2.2 pontban elkezdett Container, Vector �s List oszt�ly

megval�s�t�s�t.
10. (*2.5.) �ll�tsunk elo 10 000 darab egyenletes eloszl�s� v�letlensz�mot a 0-
1023
tartom�nyban �s t�roljuk azokat a.) a standard k�nyvt�r vector oszt�ly�val, b.)
a �16.5[7] feladat Vector oszt�ly�val, c.) a �16.5[9] feladat Vector oszt�ly�val.
Mindegyik esetben sz�moljuk ki a vektor elemeinek sz�mtani k�zep�t (mintha
m�g nem tudn�nk). M�rj�k a ciklusok lefut�s�nak idej�t. Becs�lj�k meg vagy
sz�moljuk ki a h�romf�le vektor mem�ria-felhaszn�l�s�t, �s hasonl�tsuk �ssze
az �rt�keket.
11. (*1.5.) �rjunk egy bej�r�t, amely lehetov� teszi, hogy a �16.2.2 pontban
bemutatott
Vector oszt�lyt a �16.2.1 pontban haszn�lt t�rol� st�lus�ban kezelj�k.
12. (*1.5.) Sz�rmaztassunk egy oszt�lyt a Container-bol, amely lehetov� teszi,
hogy
a �16.2.1 vektor�t a 16.2.2 pontban bemutatott t�rol�st�lusban haszn�ljuk.
13. (*2.) K�sz�ts�nk olyan oszt�lyokat, amelyek lehetov� teszik, hogy a �16.2.1 �s

a �16.2.2 Vector oszt�lyait szabv�nyos t�rol�kk�nt haszn�ljuk.


14. (*2) �rjunk egy l�tezo (nem szabv�nyos, nem tank�nyvi p�lda) t�rol�t�pushoz
egy olyan sablont, amely ugyanazokkal a tagf�ggv�nyekkel �s t�pus tagokkal
rendelkezik, mint a szabv�nyos vector. Az eredeti t�rol�t�pust ne v�ltoztassuk
meg. Hogyan tudjuk felhaszn�lni azokat a szolg�ltat�sokat, amelyeket a nem
szabv�nyos vektor megval�s�t, de a vector nem?
15. (*1.5) Gondoljuk v�gig, hogyan viselkedik a �16.3.6 pontban bemutatott
duplicate_elements() f�ggv�ny egy olyan vector<string> eset�ben, melynek
h�rom eleme: ne tedd ezt.
16. A k�nyvt�r szerkezete �s a t�rol�k 607
Szabv�nyos t�rol�k
.Itt az ideje, hogy munk�nkat
v�gre szil�rd elm�leti
alapokra helyezz�k..
(Sam Morgan)
Szabv�nyos t�rol�k . T�rol�k �s muveletek - �ttekint�s . Hat�konys�g . �br�zol�s .
Megk
�t�sek az elemekre . Sorozatok . vector . list . deque . �talak�t�k . stack
. queue . priority_queue . Asszociat�v t�rol�k . map . �sszehasonl�t�sok .
multimap .
set . multiset . .Majdnem-t�rol�k. . bitset . T�mb�k . Has�t� t�bl�k . A hash_map
egy
megval�s�t�sa . Tan�csok . Gyakorlatok
17.1. A szabv�nyos t�rol�k
A standard k�nyvt�r k�tf�le t�rol�t tartalmaz: sorozatokat (sequences) �s
asszociat�v t�rol�-
kat (associative container). A sorozatok mindegyike nagyon hasonl�t a vector
t�rol�ra
(�16.3). Ha k�l�n nem eml�tj�k, ugyanazok a tagt�pusok �s f�ggv�nyek haszn�lhat�k
ezekre
is, mint a vektorokra, �s eredm�ny�k is ugyanaz lesz. Az asszociat�v t�rol�k ezen
k�v�l
lehetos�get adnak az elemek kulcsokkal t�rt�no el�r�s�re is (�3.7.4).
17
A be�p�tett t�mb�k (�5.2), a karakterl�ncok (20. fejezet), a valarray oszt�ly
(�22.4) �s
a bitset (bithalmaz) t�pusok szint�n elemek t�rol�s�ra szolg�lnak, �gy ezeket is
t�rol�knak
tekinthetj�k. E t�pusok azonban m�gsem t�k�letesen kidolgozott, szabv�nyos
t�rol�k. Ha
a standard k�nyvt�r elv�r�sainak megfeleloen pr�b�ln�nk meg elk�sz�teni oket,
akkor els
odleges c�ljukat nem tudn�k marad�ktalanul el�rni. A be�p�tett t�mb�ktol p�ld�ul
nem
v�rhatjuk el, hogy egyszerre tarts�k nyilv�n saj�t m�ret�ket �s ugyanakkor
teljesen �sszeegyeztethet
oek maradjanak a C t�mb�kkel.
A szabv�nyos t�rol�k alap�tlete, hogy logikailag felcser�lhetoek legyenek minden
�rtelmes
helyzetben. �gy a felhaszn�l� mindig szabadon v�laszthat k�z�l�k, az �ppen
haszn�lni k�-
v�nt muveletek, illetve a hat�konys�gi szempontok figyelembe v�tel�vel. Ha p�ld�ul
gyakran
kell el�rn�nk elemeket valamilyen kulcs�rt�k seg�ts�g�vel, akkor a map (�17.4.1)
t�rol
�t haszn�ljuk. Ha legt�bbsz�r a szok�sos listamuveletekre van sz�ks�g�nk, akkor a
list
(�17.2.2) a megfelelo oszt�ly. Ha sokszor kell hozz�fuzn�nk elemeket a t�rol�
v�g�hez,
vagy �ppen el kell onnan t�vol�tanunk elemeket, akkor a deque (k�tv�gu sor,
�17.2.3),
a stack (�17.3.1) vagy a queue (�17.3.2) ny�jtja a legt�bb seg�ts�get. Ezeken
k�v�l maga
a programoz� is kifejleszthet olyan t�rol�kat, melyek pontosan illeszkednek a
szabv�nyos
t�rol�k �ltal k�n�lt keretrendszerbe (�17.6). Leggyakrabban a vector oszt�lyt
fogjuk haszn�lni,
mert ennek elonyeit rengeteg felhaszn�l�si ter�leten kiakn�zhatjuk.
Az �tlet, hogy a k�l�nb�zo jellegu t�rol�kat . vagy m�g �ltal�nosabban, az �sszes
inform�-
ci�forr�st . egys�ges form�ban kezelj�k, elvezet minket az �ltal�nos�tott
(generikus) programoz
�s fogalm�hoz (�2.7.2, �3.8). Ezt a szeml�letm�dot k�vetve a standard k�nyvt�r
nagyon
sok �ltal�nos algoritmust biztos�t (18. fejezet), melyek megk�m�lik a programoz�t
att�l, hogy k�zvetlen�l az egyes t�rol�k r�szleteivel foglalkozzon.
17.1.1. Muveletek . �ttekint�s
Ebben a pontban felsoroljuk azokat az oszt�lytagokat, amelyek minden, vagy majdnem

minden t�rol�ban megtal�lhat�k. Ha r�szleteket szeretn�nk megtudni, n�zz�k meg a


megfelel
o fej�llom�nyt (<vector>, <list>, <map> stb, �16.1.2).
610 A standard k�nyvt�r
A t�rol�t tekinthetj�k elemek sorozat�nak, ak�r abban a sorrendben, amelyet a
t�rol� bej�r�-
ja meghat�roz, ak�r ellenkezo ir�nyban. Egy asszociat�v t�rol� eset�ben a
sorrendet a t�rol�
�sszehasonl�t�si szempontja hat�rozza meg (ami alap�rtelmez�s szerint a <
muvelet).
17. Szabv�nyos t�rol�k 611
T�pusok (�16.3.1)
value_type Az elemek t�pusa.
allocator_type A mem�riakezelo t�pusa.
size_type T�pus az indexel�shez, elemsz�ml�l�shoz stb.
difference_type A bej�r�k k�z�tti k�l�nbs�g t�pusa.
iterator �gy viselkedik, mint a value_type* t�pus.
const_iterator A const value_type* megfeleloje.
reverse_iterator A t�rol� elemeit ford�tott sorrendben l�tjuk,
egy�bk�nt a value_type* megfeleloje.
const_reverse_iterator A t�rol� elemeit ford�tott sorrendben l�tjuk;
a const value_type* t�pushoz hasonl�t.
reference Olyan, mint a value_type&.
const_reference Olyan, mint a const value_type&.
key_type A kulcs t�pusa (csak asszociat�v t�rol�khoz).
mapped_type A mapped_value t�pusa (csak asszociat�v
t�rol�khoz).
key_compare Az �sszehasonl�t�si szempont t�pusa (csak asszociat
�v t�rol�khoz).
Bej�r�k (�16.3.2)
begin() Az elso elemre mutat.
end() Az utols� ut�ni elemre mutat.
rbegin() Visszafel� halad� felsorol�s eset�n az elso elemre
mutat.
rend() Visszafel� halad� felsorol�s eset�n az utols� ut�ni
elemre mutat.
N�h�ny elemet k�zvetlen�l is el�rhet�nk:
A vektorok (vector) �s a k�tv�gu sorok (deque) olyan hat�kony muveleteket is
biztos�tanak,
amelyek az elemek sorozat�nak v�g�n (back) v�geznek m�dos�t�sokat. A list�k (list)
�s
a k�tv�gu sorok (deque) az ezekkel egyen�rt�ku muveleteket az elemsorozatok elej�n

(front) is k�pesek elv�gezni:


A t�rol�k lehetov� teszik a listamuveletek haszn�lat�t is:
612 A standard k�nyvt�r
Hozz�f�r�s elemekhez (�16.3.3)
front() Az elso elem.
back() Az utols� elem.
[ ] Indexel�s, ellenorz�s n�lk�li hozz�f�r�s. (List�kn
�l nem haszn�lhat�.)
at() Indexel�s, ellenorz�tt v�ltozat. (List�kn�l nem
haszn�lhat�.)
Verem- �s sormuveletek (�16.3.5, �17.2.2.2)
push_back() Elem besz�r�sa a t�rol� v�g�re.
pop_back() Elem elt�vol�t�sa a t�rol� v�g�rol.
push_front() �j elso elem beilleszt�se (csak list�khoz �s k�tv�-
gu sorokhoz).
pop_front() Az elso elem elt�vol�t�sa (csak list�khoz �s k�tv�-
gu sorokhoz).
Listamuveletek (�16.3.6)
insert(p,x) x beilleszt�se p el�.
insert(p,n,x) x elem n darab m�solat�nak beilleszt�se p el�.
insert(p,first,last) Elemek besz�r�sa a [first:last[ tartom�nyb�l a p el�.
erase(p) A p helyen l�vo elem elt�vol�t�sa.
erase(first,last) A [first:last[ tartom�ny t�rl�se.
clear() Az �sszes elem t�rl�se.
Minden t�rol�ban tal�lhatunk az elemek sz�m�val kapcsolatos muveleteket, illetve
n�h�ny
egy�b f�ggv�nyt is:
A t�rol�k sz�mos konstruktort, illetve �rt�kad� oper�tor biztos�tanak:
17. Szabv�nyos t�rol�k 613
Tov�bbi muveletek (�16.3.8, �16.3.9, �16.3.10)
size() Az elemek sz�ma.
empty() �res a t�rol�?
max_size() A legnagyobb lehets�ges t�rol� m�rete.
capacity() A vector sz�m�ra lefoglalt ter�let m�rete (csak
vektorokhoz).
reserve() Mem�riafoglal�s a k�sobbi n�vel�sek gyors�t�s�-
hoz (csak vektorokhoz).
resize() A t�rol� m�ret�nek m�dos�t�sa (csak vektorokhoz,
list�khoz �s k�tv�gu sorokhoz).
swap() K�t t�rol� elemeinek felcser�l�se.
get_allocator() A t�rol� mem�riafoglal�j�nak lem�sol�sa.
== Megegyezik a k�t t�rol� tartalma?
!= K�l�nb�zik a k�t t�rol� tartalma?
< Az egyik t�rol� �b�c�sorrendben megelozi
a m�sikat?
Konstruktorok stb. (�16.3.4)
container() �res t�rol�.
container(n) n darab elem, alap�rtelmezett �rt�kkel (asszociat�v
t�rol�khoz nem haszn�lhat�).
container(n,x) x elem n p�ld�ny�b�l k�sz�tett t�rol� (asszociat�v
t�rol�khoz nem haszn�lhat�).
container(first,last) A kezdoelemek a [first:last[ tartom�nyb�l
sz�rmaznak.
container(x) M�sol� konstruktor. A kezdeti elemeket az x t�rol
� elemei adj�k.
~container() A t�rol� �s �sszes elem�nek megsemmis�t�se.
Az asszociat�v t�rol�k lehetov� teszik az elemek kulcs alapj�n t�rt�no el�r�s�t:
Ezen �ltal�nos muveleteken k�v�l a legt�bb t�rol� n�h�ny egyedi muveletet is
biztos�t.
614 A standard k�nyvt�r
�rt�kad�sok (�16.3.4)
operator=(x) M�sol� �rt�kad�s. Az elemek az x t�rol�b�l
sz�rmaznak.
assign(n,x) x elem n p�ld�ny�nak beilleszt�se a t�rol�ba
(asszociat�v t�rol�kn�l nem haszn�lhat�).
assign(first,last) �rt�kad�s a [first:last[ tartom�nyb�l.
Asszociat�v muveletek (�17.4.1)
operator[ ](k) A k kulcs� elem el�r�se (egyedi kulccsal rendelkez
o t�rol�khoz).
find(k) k kulccsal rendelkezo elem keres�se.
lower_bound(k) Az elso k kulcs� elem megkeres�se.
upper_bound(k) Az elso olyan elem megkeres�se, melynek kulcsa
nagyobb, mint k.
equal_range(k) A k kulcs� elemek als� �s felso hat�r�nak
megkeres�se.
key_comp() A kulcs-�sszehasonl�t� objektum m�solata.
value_comp() A mapped_value �rt�keket �sszehasonl�t� objektum
m�solata.
17.1.2. T�rol�k . �ttekint�s
A szabv�nyos t�rol�kat (container) az al�bbi t�bl�zat foglalja �ssze:
Az El�r�s oszlopban a K�zvetlen azt jelenti, hogy az elemek tetszoleges sorrendben
el�rhet
ok (k�zvetlen el�r�s, random access), a K�tir�ny� eset�ben pedig k�tir�ny�
(bidirectional)
soros hozz�f�r�su bej�r�kat haszn�lhatunk. A k�tir�ny� bej�r�k muveletei
r�szhalmaz�t
k�pezik a k�zvetlen el�r�suek muveleteinek (�19.2.1).
A t�bl�zat tov�bbi elemeibol az adott muvelet hat�konys�g�ra k�vetkeztethet�nk. A
konstans
�rt�k azt fejezi ki, hogy az adott muvelet v�grehajt�si ideje nem f�gg a t�rol�ban
t�rolt
elemek sz�m�t�l. A konstans idoig�ny egy m�sik szok�sos jel�l�se O(1). Az O(n)
�rt�k azt
fejezi ki, hogy a sz�m�t�si ido ar�nyos a feldolgozott elemek sz�m�val. A +
jel�l�st azokban
17. Szabv�nyos t�rol�k 615
A szabv�nyos t�rol�k muveletei
[ ] Lista- Muveletek Muveletek Bej�r�k
muveletek a t�rol� a t�rol� v�-
elej�n g�n (verem
muveletek)
�16.3.3 �16.3.6 �17.2.2.2 �16.3.5 �19.2.1
�17.4.1.3 �20.3.9 �20.3.9 �20.3.12
vector konstans O(n)+ konstans+ K�zvetlen
list konstans konstans konstans K�tir�ny�
deque konstans O(n) konstans konstans K�zvetlen
stack konstans
queue konstans konstans
priority_queue O(log(n)) O(log(n))
map O(log(n)) O(log(n))+ K�tir�ny�
multimap O(log(n))+ K�tir�ny�
set O(log(n))+ K�tir�ny�
multiset O(log(n))+ K�tir�ny�
string konstans O(n)+ O(n)+ konstans+ K�zvetlen
array konstans K�zvetlen
valarray konstans K�zvetlen
bitset konstans
az esetekben haszn�ltuk, ahol idonk�nt jelentos mennyis�gu t�bbletterhel�s is
elofordulhat.
Egy elem besz�r�sa egy list�ba p�ld�ul mindig ugyanannyi ideig tart, �gy a
megfelelo
helyen a konstans �rt�ket olvashatjuk. Ugyanez a muvelet a vector eset�ben a
besz�r�si
pont ut�n �ll� �sszes elem �thelyez�s�vel j�r, �gy ott az O(n) �rt�k szerepel.
Sot, idonk�nt
az �sszes elemet (teh�t a besz�r�si pont elottieket is) �t kell helyezni, ez�rt a
+ jelet is megadtuk.
A .nagy O. (ordo) egy hagyom�nyos jel�l�sm�d, a + jelet csak az�rt haszn�ltam,
hogy kieg�sz�to inform�ci�t adjak azoknak a programoz�knak, akik az �tlagos
teljes�tm�ny
mellett a muvelet idej�nek megj�solhat�s�g�ra is hangs�lyt helyeznek. Az O(n)+
jel�l�s hagyom
�nyos jelent�se .amortiz�lt line�ris ido. (amortized linear time, vagyis kb.
.t�bbletterhet
jelento, egyenes ar�nyoss�gban n�vekvo ido.).
Term�szetesen, ha a .konstans. egy nagyon hossz� idotartamot jelent, akkor ez
nagyobb
lehet, mint az elemek sz�m�val egyenesen ar�nyos idoig�ny. Nagy adatszerkezetek
eset�-
ben azonban a konstans jelent�se m�gis .olcs�., az O(n) jelent�se pedig .dr�ga.,
m�g az
O(log(n)) idot tekinthetj�k .el�g olcs�nak.. M�g viszonylag nagy n �rt�kek eset�n
is, az
O(log(n)) k�zelebb �ll a konstanshoz, mint az O(n)-hez. Azoknak a programoz�knak,
akiknek programjaik .k�lts�geivel. komolyan foglalkozniuk kell, enn�l alaposabb
ismeretekre
is sz�ks�g�k van. Tiszt�ban kell lenni�k azzal, mely elemek figyelembe v�tel�vel
alakul
ki n �rt�ke. Olyan alapmuvelet szerencs�re nincs, melyet .nagyon dr�g�nak.
nevezhetn
�nk, ami O(n*n) vagy m�g jelentosebb idoig�nyt jelentene.
A string kiv�tel�vel az itt k�z�lt k�lts�g�rt�kek megfelelnek a C++ szabv�ny
elv�r�sainak.
A string t�pusn�l szereplo becsl�sek saj�t felt�telez�seim.
A bonyolults�gnak, illetve az idoig�nynek ezen m�rosz�mai a felso hat�rt jelentik.
Szerep
�k abban �ll, hogy a programoz� megtudhatja belol�k, mit v�rhat el az adott
szolg�ltat�st
�l. Term�szetesen a konkr�t megval�s�t�sok k�sz�toi igyekeznek a l�nyeges helyeken

ezekn�l jobb megold�st biztos�tani.


17.1.3. �br�zol�s
A szabv�ny nem �r elo semmilyen egyedi �br�zol�si m�dot egyik t�rol� eset�ben sem.

A szabv�ny csak a t�rol� fel�let�t �rja le, illetve n�h�ny .bonyolults�gi.


k�vetelm�nyt hat�-
roz meg. Az egyes nyelvi v�ltozatok k�sz�toi maguk v�laszthatj�k meg a
legmegfelelobb �s
gyakran nagyon j�l optimaliz�lt megval�s�t�si m�dot, amely kiel�g�ti az �ltal�nos
k�vetelm
�nyeket. A t�rol�kat �ltal�ban olyan adatszerkezet seg�ts�g�vel hozz�k l�tre,
amely az
elemek el�r�s�t biztos�t� azonos�t� mellett a m�retre �s kapacit�sra vonatkoz�
inform�ci�-
kat is nyilv�ntartja. A vector eset�ben az elemek adatszerkezete leggyakrabban egy
t�mb:
616 A standard k�nyvt�r
A list megval�s�t�s�nak legegyszerubb eszk�ze a l�ncol�s, ahol az elemek egym�sra
mutatnak:
A map leggyakoribb megval�s�t�sa a (kiegyens�lyozott) bin�ris fa, ahol a cs�csok
vagy m�s
n�ven csom�pontok (kulcs, �rt�k) p�rokat jel�lnek ki:
A string megval�s�t�s�ra a �11.12 pontban adtunk egy �tletet, de elk�pzelhetj�k
t�mb�k sorozatak
�nt is, ahol minden t�mb n�h�ny karaktert t�rol:
17. Szabv�nyos t�rol�k 617
m�ret
�br�zol�s
elemek tartal�k hely
vektor:
list:
map:
(kulcs, �rt�k) p�rok:
r�szl�ncok:
string:
�br�zol�s
�br�zol�s
cs�cs
r�szl�nc-le�r�k
cs�cs
�br�zol�s
...
elemek:
17.1.4. Megk�t�sek az elemekre
A t�rol�ban t�rolt elemek a beillesztett objektumok m�solatai, �gy ahhoz, hogy egy
objektum
beker�lhessen a t�rol�ba, olyan t�pus�nak kell lennie, amely lehetov� teszi, hogy
a t�-
rol� m�solatot k�sz�tsen r�la. A t�rol� az elemeket egy m�sol� konstruktor vagy
egy �rt�kad
�s seg�ts�g�vel m�solhatja le. A m�sol�s eredm�ny�nek mindk�t esetben
egyen�rt�kunek
kell lennie az eredeti objektummal. Ez nagyj�b�l azt jelenti, hogy minden
elk�pzelheto
egyenlos�gvizsg�lat azonosnak kell, hogy minos�tse az eredeti �s a m�solt
objektumot.
Az elemek m�sol�s�nak teh�t �gy kell muk�dnie, mint a be�p�tett t�pusok (k�zt�k a
mutat
�k) szok�sos m�sol�s�nak. Az al�bbi �rt�kad�s p�ld�ul nagy l�p�st jelent afel�,
hogy az X
t�pus egy szabv�nyos t�rol� elemeinek t�pusa legyen:
X& X::operator=(const X& a) // helyes �rt�kad� oper�tor
{
// 'a' minden tagj�nak m�sol�sa *this-be
return *this;
}
Az al�bbi k�dr�szlet Y t�pusa viszont helytelen, mert a visszat�r�si �rt�k nem a
szok�sos �s
a jelent�s sem megfelelo.
void Y::operator=(const Y& a) // helytelen �rt�kad� oper�tor
{
// 'a' minden tagj�nak t�rl�se
}
A szabv�nyos t�rol�k szab�lyait�l val� elt�r�sek egy r�sz�t m�r a ford�t� k�pes
jelezni, de
sok esetben ezt a seg�ts�get sem kapjuk meg, csak teljesen v�ratlan esem�nyekkel
ker�l�nk
szembe. Egy olyan m�sol�si muvelet p�ld�ul, amely kiv�telt v�lthat ki, r�szlegesen
�tm�solt
elemet is eredm�nyezhet. Ennek k�vetkezm�nyek�ppen a t�rol� olyan �llapotba ker�l,

amely csak j�val k�sobb okoz probl�m�kat. Az ilyen m�sol�si muveletek teh�t m�r
�nmagukban
is rossz tervez�s k�vetkezm�nyei (�14.4.6.1).
Ha az elemek m�sol�sa nem lehets�ges, megold�st az jelenthet, ha a t�rol�ban
konkr�t objektumok
helyett azokra hivatkoz� mutat�kat helyez�nk el. Ennek legnyilv�nval�bb p�ld
�ja a t�bbalak� (polimorf) t�pusok esete (�2.5.4, �12.2.6). Ha a t�bbalak�s�g
lehetos�g�t
meg akarjuk orizni, akkor a vector<Shape> helyett p�ld�ul a vector<Shape*>
oszt�lyra lesz
sz�ks�g�nk.
618 A standard k�nyvt�r
17.1.4.1. �sszehasonl�t�sok
Az asszociat�v t�rol�k megk�vetelik, hogy elemeiket �ssze lehessen hasonl�tani.
Ugyanez
elmondhat� m�s t�rol�k n�h�ny muvelet�rol is (p�ld�ul a rendezo elj�r�sokr�l, mint

a sort()). Alap�rtelmez�s szerint a sorrend meghat�roz�s�ra a < oper�tort


haszn�ljuk. Ha ez
az adott esetben nem haszn�lhat�, akkor a programoz�nak valamilyen m�s megold�st
kell
tal�lnia (�17.4.1.5, �18.4.2). A rendez�si szempontnak szigor�an megengedonek kell
lennie
(strict weak ordering), ami l�nyeg�ben azt jelenti, hogy a .kisebb mint. �s
.egyenlo. muveletnek
is tranzit�vnak kell lennie. Vegy�k p�ld�ul a k�vetkezo cmp rendez�st:
1. cmp(x,x) mindig hamis.
2. Ha cmp(x,y) �s cmp(y,z), akkor cmp(x,z).
3. Hat�rozzuk meg az egyenlos�g equiv(x,y) muvelet�t a k�vetkezo kifejez�ssel:
!(cmp(x,y)||cmp(y,x)). �gy, ha equiv(x,y) �s equiv(y,z), akkor equiv(x,z).
Ennek megfeleloen a k�vetkezoket �rhatjuk:
template<class Ran> void sort(Ran first, Ran last); // a < haszn�lata az
// �sszehasonl�t�sra
template<class Ran, class Cmp> void sort(Ran first, Ran last, Cmp cmp);
// a cmp haszn�lata
Az elso v�ltozat a < oper�tort haszn�lja, m�g a m�sodik a programoz� �ltal
megadott cmp
rendez�st. Az elozo fejezet gy�m�lcs�ket tartalmaz� t�rol�j�nak eset�ben p�ld�ul
sz�ks�-
g�nk lehet egy olyan rendezo elj�r�sra, amely nem k�l�nb�zteti meg a kis- �s
nagybetuket.
Ezt �gy �rhetj�k el, hogy l�trehozunk egy f�ggv�nyobjektumot (function object)
(�11.9,
�18.4), amely egy string-p�rra elv�gzi az �sszehasonl�t�st:
class Nocase { // kis- �s nagybetuket nem megk�l�nb�zteto karakterl�nc-
// �sszehasonl�t�s
public:
bool operator()(const string&, const string&) const;
};
bool Nocase::operator()(const string& x, const string& y) const
// igazat ad vissza, ha x �b�c�sorrendben megelozi y-t; a kis- �s nagybetuk
k�z�tti
// k�l�nbs�g nem sz�m�t
{
string::const_iterator p = x.begin();
string::const_iterator q = y.begin();
17. Szabv�nyos t�rol�k 619
while (p!=x.end() && q!=y.end() && toupper(*p)==toupper(*q)) {
++p;
++q;
}
if (p == x.end()) return q != y.end();
if (q == y.end()) return false;
return toupper(*p) < toupper(*q);
}
A sort f�ggv�nyt ezut�n megh�vhatjuk ezzel a rendez�si szemponttal. P�ld�ul az
al�bbi sorozatb
�l kiindulva:
fruit:
alma k�rte Alma K�rte citrom
A sort(fruit.begin(), fruit.end, Nocase()) rendez�s eredm�nye a k�vetkezo lesz:
fruit:
Alma alma citrom K�rte k�rte
Ugyanakkor az egyszeru sort(fruit.begin(), fruit.end()) a k�vetkezo eredm�nyt adn�
(felt�-
telezve, hogy olyan karakterk�szletet haszn�lunk, ahol a nagybetuk megelozik a
kisbetuket):
fruit:
Alma K�rte alma citrom k�rte
Vigy�zzunk r�, hogy a < oper�tor a C st�lus� karakterl�ncokn�l (teh�t a char*
t�pusn�l) nem
�b�c�sorrend szerinti rendez�st jelent (�13.5.2). Ennek p�ld�ul az a
k�vetkezm�nye, hogy
az olyan asszociat�v t�rol�k, melyeknek kulcsa C st�lus� karakterl�nc, nem �gy
muk�dnek,
mint ahogy azt elso r�n�z�sre gondoln�nk. Ezen kellemetlens�g kijav�t�s�hoz egy
olyan <
oper�tort kell haszn�lnunk, amely t�nyleg �b�c�sorrend szerinti �sszehasonl�t�st
v�gez:
struct Cstring_less {
bool operator()(const char* p, const char* q) const { return strcmp(p,q)<0; }
};
map<char*,int,Cstring_less> m; // const char* kulcsok �sszehasonl�t�s�ra a
strcmp()
// f�ggv�nyt haszn�l� asszociat�v t�mb
620 A standard k�nyvt�r
17.1.4.2. Tov�bbi rel�ci�s muveletek
A t�rol�k �s az algoritmusok alap�rtelmez�s szerint a < muveletet haszn�lj�k,
amikor az
elemek k�z�tt sorrendet kell meg�llap�taniuk. Ha ez az alap�rtelmez�s nem felel
meg
a programoz�nak, akkor �j �sszehasonl�t�si szempontot is megadhat. Az
egyenlos�gvizsg�-
lat muvelet�t viszont nem adhatjuk meg k�zvetlen�l. Ha van egy sorrend-meghat�roz�
f�ggv
�ny�nk (p�ld�ul a cmp), akkor az egyenlos�get k�t sorrendvizsg�lattal
�llap�thatjuk meg:
if (x == y) // megadott felhaszn�l�i �sszehasonl�t�s eset�n nem haszn�latos
if (!cmp(x,y) && !cmp(y,x)) // a felhaszn�l�i cmp �sszehasonl�t�s eset�n
haszn�latos
Ez a lehetos�g megk�m�l minket att�l, hogy minden asszociat�v t�rol� �s sz�mos
algoritmus
eset�ben k�l�n param�terk�nt adjuk �t az egyenlos�gvizsg�l� elj�r�st. Elso
r�n�z�sre azt
mondhatn�nk, hogy ez a megold�s nem t�l hat�kony, de a t�rol�k rendk�v�l ritk�n
vizsg�lj
�k elemeik egyenlos�g�t, �s ilyenkor is �ltal�ban elegendo egyetlen cmp() h�v�s.
A .kisebb mint. (alap�rtelmez�s szerint < ) muvelettel v�gzett egyen�rt�kus�g-
vizsg�lat
gyakorlati okokb�l is hasznosabb lehet, mint az .egyenlo. (==) haszn�lata. Az
asszociat�v
t�rol�k (�17.4) p�ld�ul a ! (cmp(x,y)||cmp(y,x)) egyen�rt�kus�g-vizsg�lattal
hasonl�tj�k
�ssze a kulcsaikat. Az egyen�rt�ku kulcsok nem felt�tlen�l egyenlok. Egy olyan
multimap
(�17.4.2) p�ld�ul, amelynek sorrend-meghat�roz� f�ggv�nye nem k�l�nb�zteti meg a
kis-
�s nagybetuket, a Last, last, lAst, �s lasT karakterl�ncokat egyen�rt�kunek fogja
minos�teni,
annak ellen�re, hogy az == oper�tor k�l�nb�zonek tartja azokat. �gy teh�t
lehetos�g�nk
ny�lik arra, hogy a sz�munkra l�nyegtelen k�l�nbs�gektol a rendez�sben
eltekints�nk.
A < �s az == oper�tor seg�ts�g�vel a t�bbi szok�sos �sszehasonl�t� muveletet
k�nnyen
defini�lhatjuk. A standard k�nyvt�r az std::rel_ops n�vt�rben adja meg ezeket �s a
<utility>
fej�llom�ny seg�ts�g�vel haszn�lhat�k:
template<class T> bool rel_ops::operator!=(const T& x, const T& y) { return !
(x==y); }
template<class T> bool rel_ops::operator>(const T& x, const T& y) { return y<x; }
template<class T> bool rel_ops::operator<=(const T& x, const T& y) { return !
(y<x); }
template<class T> bool rel_ops::operator>=(const T& x, const T& y) { return !
(x<y); }
A rel_ops n�vt�r alkalmaz�sa biztos�tja, hogy az oper�torokat k�nnyen el�rhetj�k,
amikor
sz�ks�g van r�juk, viszont meghat�roz�suk nem t�rt�nik meg .titokban., ha explicit
nem
k�rj�k a n�vt�r haszn�lat�t.
void f()
{
using namespace std;
// a !=, > stb. alap�rtelmez�s szerint nem j�n l�tre
}
17. Szabv�nyos t�rol�k 621
void g()
{
using namespace std;
using namespace std::rel_ops;
// a !=, > stb. alap�rtelmez�s szerint l�trej�n
}
A !=, stb. oper�torokat nem az std n�vt�r �rja le, mert nem mindig van r�juk
sz�ks�g, �s bizonyos
esetekben meghat�roz�suk meg is v�ltoztatn� a felhaszn�l� programj�nak muk�d�s�t.
P�ld�ul, ha egy �ltal�nos matematikai k�nyvt�rat akarunk k�sz�teni, akkor
val�sz�nuleg a saj
�t rel�ci�s muveleteinkre lesz sz�ks�g�nk �s nem a be�p�tett f�ggv�nyekre.
17.2. Sorozatok
A sorozatok k�r�lbel�l �gy n�znek ki, mint a kor�bban (�16.3) bemutatott vector. A
standard
k�nyvt�r �ltal biztos�tott alapveto sorozatok a k�vetkezok:
vector list deque
Ezekbol sz�rmaznak . a megfelelo fel�let kialak�t�s�val . az al�bbi t�rol�k:
stack queue priority_queue
Ezeket a sorozatokat t�rol�-�talak�t�knak (container adapter), sorozat-
�talak�t�knak
(sequence adapter) vagy egyszeruen �talak�t�knak (adapter, �17.3) nevezz�k.
17.2.1. A vector
A szabv�nyos vector oszt�llyal a �16.3 pontban m�r r�szletesen foglalkoztunk. Az
elozetes
mem�riafoglal�s (reserve) lehetos�ge kiz�r�lag a vektorokra jellemzo. Az indexel�s
a [ ]
oper�torral ellenorizetlen adatel�r�st jelent. Ha ellenorz�tt hozz�f�r�st
szeretn�nk, haszn�ljuk
az at() f�ggv�nyt (�16.3.3), egy ellenorz�tt vektort (�3.7.2) vagy egy ellenorz�tt
bej�r�t
(�19.3). A vector oszt�lyokban k�zvetlen el�r�su (random-access) bej�r�kat
(�19.2.1) haszn
�lhatunk.
622 A standard k�nyvt�r
17.2.2. A list
A lista egy olyan sorozat, amely elemek besz�r�s�ra �s t�rl�s�re a legalkalmasabb.
A vector
(�s a deque, �17.2.3) oszt�llyal �sszehasonl�tva az indexel�s f�jdalmasan lass�
lenne, �gy
meg sem val�s�tott�k a list t�rol�ban. Ennek k�vetkezm�nye, hogy a list csak
k�tir�ny�
(bidirectional) bej�r�kat (�19.2.1) biztos�t, k�zvetlen el�r�sueket nem
haszn�lhatunk. A list
oszt�lyt ezek alapj�n valamilyen k�tir�ny� l�ncolt list�val szok�s megval�s�tani
(�17.8[16]).
A lista mindazon tagt�pusok �s tagf�ggv�nyek haszn�lat�t lehetov� teszi, melyet a
vektor
(�16.3) eset�ben megtal�lunk, kiv�ve az indexel�st, a capacity() �s a reserve()
f�ggv�nyeket:
template <class T, class A = allocator<T> > class std::list {
public:
// a vector-�hoz hasonl� t�pusok �s muveletek, kiv�ve: [ ], at(), capacity(), �s
reserve()
// ...
};
17.2.2.1. �thelyez�s, rendez�s, �sszef�s�l�s
Az �ltal�nos sorozat-muveletek mellett a list sz�mos, kifejezetten a list�khoz
k�sz�tett mu-
veleteket k�n�l:
template <class T, class A = allocator<T> > class list {
public:
// ...
// kifejezetten list�khoz k�sz�tett muveletek
void splice(iterator pos, list& x); // x minden elem�nek �thelyez�se
// a list�ban levo pos el�, m�sol�s n�lk�l
void splice(iterator pos, list& x, iterator p); // *p �thelyez�se x-bol
// a list�ban levo pos el�, m�sol�s n�lk�l
void splice(iterator pos, list& x, iterator first, iterator last);
void merge(list&); // rendezett list�k �sszef�s�l�se
template <class Cmp> void merge(list&, Cmp);
void sort();
template <class Cmp> void sort(Cmp);
// ...
};
17. Szabv�nyos t�rol�k 623
Ezek a listamuveletek stabilak (stable), ami azt jelenti, hogy az egyen�rt�ku
�rt�kkel rendelkez
o elemek egym�shoz viszony�tott (relat�v) sorrendje nem v�ltozik meg.
A �16.3.6 pontban p�ldak�ppen a fruit t�rol�n v�gezt�nk muveleteket. Azok a
feladatok
v�ltoztat�s n�lk�l elv�gezhetok akkor is, ha a fruit t�rt�netesen egy lista.
Ezenk�v�l az
egyik lista elemeit egyetlen splice muvelettel �t is helyezhetj�k egy m�sik
list�ba. Induljunk
ki az al�bbi list�kb�l:
fruit:
alma k�rte
citrus:
narancs grapefruit citrom
A k�vetkezo muvelettel tudjuk a narancs elemet �thelyezni a citrus list�b�l a
fruit list�ba:
list<string>::iterator p = find_if(fruit.begin(),fruit.end(),initial('k'));
fruit.splice(p,citrus,citrus.begin());
A muvelet kiveszi a citrus elso elem�t, majd beilleszti ezt az elemet a fruit
t�rol� elso k bet
uvel kezdodo eleme el�. Az eredm�ny teh�t a k�vetkezo:
fruit:
alma narancs k�rte
citrus:
grapefruit citrom
Jegyezz�k meg, hogy a splice() nem k�sz�t m�solatokat az elemekrol �gy, mint az
insert()
(�16.3.6), csak a list�k adatszerkezet�t rendezi �t a feladatnak megfeleloen.
A splice() seg�ts�g�vel nem csak egyetlen elemet, hanem tartom�nyokat, vagy ak�r
teljes list
�kat is �thelyezhet�nk:
fruit.splice(fruit.begin(),citrus);
Eredm�nye:
fruit:
grapefruit citrom alma narancs k�rte
citrus:
<�res>
624 A standard k�nyvt�r
A splice f�ggv�ny minden v�ltozat�nak a m�sodik param�terben meg kell adnunk azt a
list
objektumot, amelybol az elemeket �t kell helyezni. Ez teszi lehetov�, hogy az
eredeti list�-
b�l t�r�lj�k az elemet. Egy bej�r� erre �nmag�ban nem lenne alkalmas, hiszen egy
konkr
�t elemre mutat� bej�r�b�l semmilyen �ltal�nos m�dszerrel nem lehet megtudni, hogy
az
adott elem �ppen melyik t�rol�ban tal�lhat� (�18.6).
Term�szetesen, a bej�r�-param�ternek olyan �rv�nyes bej�r�t kell tartalmaznia,
amely
a megfelelo list�hoz kapcsol�dik. Teh�t vagy a list egyik elem�re kell mutatnia,
vagy a lista
end() f�ggv�ny�nek �rt�k�t kell tartalmaznia. Ha ez nem �gy van, akkor az eredm�ny

nem meghat�rozhat� �s �ltal�ban v�gzetes probl�m�kat okoz:


list<string>::iterator p = find_if(fruit.begin(),fruit.end(),initial('k'));
fruit.splice(p,citrus,citrus.begin()); // rendben
fruit.splice(p,citrus,fruit.begin()); // hiba: fruit.begin() nem mutat citrus-ban
levo elemre
citrus.splice(p,fruit,fruit.begin()); // hiba: p nem mutat citrus-ban levo elemre
Az elso splice() helyes m�g akkor is, ha a citrus t�rol� �res.
A merge() k�t rendezett list�t egyes�t (f�s�l �ssze). Az egyik list�b�l t�rli az
elemeket, mik
�zben a m�sikba besz�rja azokat, a rendez�s megorz�s�vel.
f1:
alma birsalma k�rte
f2:
citrom grapefruit narancs lime
Ez a k�t lista az al�bbi programr�szlettel rendezheto �s fuzheto �ssze:
f1.sort();
f2.sort();
f1.merge(f2);
Az eredm�ny a k�vetkezo lesz:
f1:
alma birsalma citrom grapefruit k�rte lime narancs
f2:
<�res>
Ha az �sszef�s�lt list�k valamelyike nem volt rendezett, a merge() akkor is olyan
list�t eredm
�nyez, amelyben a k�t lista elemeinek uni�ja szerepel, de az elemek helyes
sorrendje
nem biztos�tott.
17. Szabv�nyos t�rol�k 625
A splice() f�ggv�nyhez hasonl�an a merge() sem m�solja az elemeket, hanem a
forr�slist�-
b�l kiveszi, majd a c�llist�ba beilleszti azokat. Az x.merge(y) f�ggv�ny megh�v�sa
ut�n az
y lista �res lesz.
17.2.2.2. Muveletek a lista elej�n
A lista elso elem�re vonatkoz� muveletek azoknak a minden sorozatban megtal�lhat�
elj�-
r�soknak a p�rjai, melyek az utols� elemre hivatkoznak (�16.3.6):
template <class T, class A = allocator<T> > class list {
public:
// ...
// hozz�f�r�s elemekhez
reference front(); // hivatkoz�s az elso elemre
const_reference front() const;
void push_front(const T&); // �j elso elem hozz�ad�sa
void pop_front(); // elso elem elt�vol�t�sa
// ...
};
A t�rol� elso elem�nek neve front. A list eset�ben a front fejelem muveletei
ugyanolyan hat
�konyak �s k�nyelmesek, mint a sorozat v�g�t kezelo f�ggv�nyek (�16.3.5). Ha mi
d�nthet
�nk, akkor �rdemesebb az utols� elemet haszn�lni, mert az �gy meg�rt
programr�szletek
a vector �s a list sz�m�ra is megfeleloek. �gy ha csak egy kicsi es�ly is van
arra, hogy az �ltalunk
list�ra haszn�lt algoritmust valamikor . �ltal�nos elj�r�sk�nt . m�s
t�rol�t�pusokra is
alkalmazzuk, akkor mindenk�ppen az utols� elem muveleteit haszn�ljuk, hiszen ezek
j�val
sz�lesebb k�rben muk�dok�pesek. Itt is ahhoz a szab�lyhoz kell igazodnunk,
miszerint
a leheto legnagyobb rugalmass�g el�r�se �rdek�ben �rdemes a leheto legkisebb
muvelethalmazt
haszn�lnunk egy feladat elv�gz�s�hez (�17.1.4.1).
17.2.2.3. Tov�bbi muveletek
Az elemek besz�r�sa �s t�rl�se rendk�v�l hat�kony muvelet a list t�rol�ban. Ez
term�szetesen
arra �szt�nzi a programoz�kat, hogy list�t haszn�ljanak, ha programjaikban az
ilyen
muveletek gyakoriak. Ez�rt fontos, hogy az elemek k�zvetlen t�rl�s�re �ltal�nos,
szabv�-
nyos m�dszereket adjunk:
626 A standard k�nyvt�r
template <class T, class A = allocator<T> > class list {
public:
// ...
void remove(const T& val);
template <class Pred> void remove_if(Pred p);
void unique(); // k�tszer szereplo elemek elt�vol�t�sa == haszn�lat�val
template <class BinPred> void unique(BinPred b); // k�tszer szereplo elemek
// elt�vol�t�sa b haszn�lat�val
void reverse(); // az elemek sorrendj�nek megford�t�sa
};
P�ld�ul tegy�k fel, hogy adott az al�bbi lista:
fruit:
alma narancs grapefruit citrom narancs g�r�gdinnye k�rte birsalma
Ekkor a .narancs. �rt�kkel rendelkezo elemeket a k�vetkezo paranccsal
t�vol�thatjuk el:
fruit.remove("narancs");
Az eredm�ny teh�t:
fruit:
alma grapefruit citrom g�r�gdinnye k�rte birsalma
Gyakran bizonyos felt�telt kiel�g�to elemeket szeretn�nk t�r�lni, nem csak egy
adott �rt�kkel
rendelkezoket. A remove_if f�ggv�ny pontosan ezt a feladatot hajtja v�gre. A
k�vetkez
o utas�t�s p�ld�ul az �sszes .g. betuvel kezdodo gy�m�lcsnevet t�rli a fruit
list�b�l:
fruit.remove_if(initial('g'));
A f�ggv�ny lefut�sa ut�n a fruit a k�vetkezok�ppen n�z ki:
fruit:
alma citrom k�rte birsalma
A t�rl�seknek gyakran az az oka, hogy meg szeretn�nk sz�ntetni az ism�tlod�seket.
A unique() f�ggv�ny ezzel a c�llal szerepel a list oszt�lyban:
fruit.sort();
fruit.unique();
17. Szabv�nyos t�rol�k 627
A rendez�sre az�rt van sz�ks�g, mert a unique() csak azokat az ism�tlod�seket
szuri ki,
amelyekn�l k�zvetlen�l egym�s ut�n szerepel k�t (vagy t�bb) azonos �rt�k. P�ld�ul
ha
a fruit lista tartalma a k�vetkezo:
alma k�rte alma alma k�rte
akkor a fruit.unique() h�v�s �nmag�ban az al�bbi eredm�nyt adn�:
alma k�rte alma k�rte
Ha elosz�r rendez�nk, akkor a v�geredm�ny:
alma k�rte
Ha csak bizonyos ism�tlod�seket akarunk megsz�ntetni, akkor megadhatunk egy
predik�-
tumot (felt�telt), amely meghat�rozza, mely ism�tlod�sek nem kellenek. P�ld�ul
meghat�-
rozhatjuk a k�toperandus� (bin�ris) initial2(x) predik�tumot (�18.4.2), amely
karakterl�ncokat
vizsg�l, �s csak akkor ad igaz �rt�ket, ha a karakterl�nc x betuvel kezdodik.
Teh�t ha
a k�vetkezo list�b�l indulunk ki:
k�rte k�rte alma alma
akkor a k�vetkezo utas�t�ssal el tudjuk t�ntetni az �sszes .k. betuvel kezdodo,
egym�s ut�n
k�vetkezo nevet:
fruit.unique(initial2('k'));
Az eredm�ny a k�vetkezo lesz:
k�rte alma alma
A �16.3.2 pontban m�r volt r�la sz�, hogy a t�rol� elemeit n�ha ford�tott
sorrendben akarjuk
el�rni. A list eset�ben lehetos�g van arra, hogy az elemek sorrendj�t teljesen
megford�tsuk,
azaz az utols� elem v�ljon elsov�, az elso pedig utols�v�. A reverse() f�ggv�ny
ezt
a muveletet az elemek m�sol�sa n�lk�l val�s�tja meg. Vegy�k a k�vetkezo list�t:
fruit:
ban�n cseresznye eper k�rte
628 A standard k�nyvt�r
Ekkor a fruit.reverse() h�v�s eredm�nye a k�vetkezo lesz:
fruit:
k�rte eper cseresznye ban�n
A list�b�l elt�vol�tott elemek teljesen t�rlodnek. Egy mutat� t�rl�se azonban nem
jelenti azt,
hogy maga a mutatott objektum is t�rlodik. Ha olyan mutat�kb�l �ll� t�rol�t
akarunk haszn
�lni, amely automatikusan t�rli a belole kivett mutat�k �ltal mutatott
objektumokat, akkor
azt nek�nk kell meg�rnunk (�17.8[13]).
17.2.3. A deque
A deque egy k�tv�gu sort (double-ended queue) val�s�t meg. Ez azt jelenti, hogy a
deque
egy olyan sorozat, amit arra optimaliz�ltak, hogy egyr�szt mindk�t v�g�n
ugyanolyan hat�-
kony muveleteket haszn�lhassunk, mint egy list-n�l, m�sr�szt az indexel�s
ugyanolyan hat
�kony legyen, mint a vector eset�ben:
template <class T, class A = allocator<T> > class std::deque {
// a vector-�hoz hasonl� t�pusok �s muveletek (�16.3.3, �16.3.5, �16.3.6), kiv�ve:

// capacity() �s reserve()
// a list-�hez hasonl� fejelem-muveletek (�17.2.2.2)
};
Az adatszerkezet belsej�ben az elemek t�rl�se �s besz�r�sa ugyanolyan (rossz)
hat�konys
�g�, mint a vector-n�l. Ennek k�vetkezt�ben a deque t�rol�t akkor haszn�ljuk, ha
besz�-
r�sok �s t�rl�sek �ltal�ban csak a v�geken fordulnak elo, p�ld�ul egy vas�tszakasz
modellez
�s�hez vagy egy k�rtyapakli �br�zol�s�hoz:
deque<car> siding_no_3;
deque<Card> bonus;
17.3. Sorozat-�talak�t�k
A vector, a list �s a deque sorozatok nem �p�thetok fel egym�sb�l komoly
hat�konys�groml
�s n�lk�l. Ugyanakkor a verem (stack) �s a sor (queue) eleg�nsan �s hat�konyan
megval
�s�that� e h�rom alap-sorozatt�pus seg�ts�g�vel. �gy ezt a k�t oszt�lyt nem
teljesen �n�ll�
t�rol�k�nt hat�rozt�k meg, hanem az alapt�rol�k �talak�t�ik�nt.
17. Szabv�nyos t�rol�k 629
Egy t�rol� �talak�t�ja (adapter) egy leszuk�tett (korl�tozott) fel�letet ad az
adott t�rol�hoz.
A legszembetunobb, hogy az �talak�t�k nem biztos�tanak bej�r�kat, mert a c�ljuknak
megfelel
o felhaszn�l�skor a leszuk�tett fel�let elegendo szolg�ltat�st ny�jt. Azokat a
m�dszereket,
melyekkel egy t�rol�b�l l�trehozhatunk egy �talak�t�t, �ltal�nosan haszn�lhatjuk
olyan
esetekben, amikor egy oszt�ly szolg�ltat�sait a felhaszn�l�k ig�nyeihez szeretn�nk
igaz�tani,
az eredeti oszt�ly megv�ltoztat�sa n�lk�l.
17.3.1. A stack
A stack (verem) t�rol�t a <stack> fej�llom�ny �rja le. Annyira egyszeru szerkezet,
hogy le-
�r�s�nak legegyszerubb m�dja, ha bemutatunk egy lehets�ges megval�s�t�st:
template <class T, class C = deque<T> > class std::stack {
protected:
C c;
public:
typedef typename C::value_type value_type;
typedef typename C::size_type size_type;
typedef C container_type;
explicit stack(const C& a = C()) : c(a) { }
bool empty() const { return c.empty(); }
size_type size() const { return c.size(); }
value_type& top() { return c.back(); }
const value_type& top() const { return c.back(); }
void push(const value_type& x) { c.push_back(x); }
void pop() { c.pop_back(); }
};
Vagyis a stack egyszeruen egy fel�let egy olyan t�rol�hoz, melynek t�pus�t
sablonparam�-
terk�nt adjuk meg. A stack mind�ssze annyit tesz, hogy elrejti t�rol�j�nak nem
verem st�lus
� muveleteit, valamint a back(), push_back(), pop_back() f�ggv�nyeket hagyom�nyos
nev�k�n (top(), push(), pop()) teszi el�rhetov�.
Alap�rtelmez�s szerint a stack egy deque t�rol�t haszn�l elemeinek t�rol�s�ra, de
b�rmilyen
sorozatot haszn�lhatunk, melyben el�rheto a back(), a push_back() �s a pop_back()
f�ggv�ny:
stack<char> s1; // char t�pus� elemek t�rol�sa deque<char> seg�ts�g�vel
stack< int,vector<int> > s2; // int t�pus� elemek t�rol�sa vector<int>
seg�ts�g�vel
630 A standard k�nyvt�r
Egy verem kezdeti felt�lt�s�hez felhaszn�lhatunk egy m�r l�tezo t�rol�t is:
void print_backwards(vector<int>& v)
{
stack< int,vector<int> > state(v); // kezdo�llapot be�ll�t�sa v seg�ts�g�vel
while (state.size()) {
cout << state.top();
state.pop();
}
}
De gondoljunk r�, hogy ez a muvelet a param�terk�nt megadott t�rol� elemeinek
m�sol�-
s�val j�r, �gy rendk�v�l hosszadalmas lehet.
A veremhez az elemek t�rol�s�hoz haszn�lt t�rol� push_back() muvelet�vel adunk
elemeket.
�gy a stack nem telhet meg mindaddig, am�g a t�rol� k�pes mem�ri�t lefoglalni (mem
�riafoglal�j�nak seg�ts�g�vel, �19.4).
Ugyanakkor a verem alulcsordulhat:
void f()
{
stack<int> s;
s.push(2);
if (s.empty()) { // az alulcsordul�s megakad�lyozhat�
// nincs kiemel�s
}
else { // de nem elk�pzelhetetlen
s.pop(); // j�: s.size() �rt�ke 0 lesz
s.pop(); // nem meghat�rozott hat�s, val�sz�nuleg rossz
}
}
Jegyezz�k meg, hogy a felso elem haszn�lat�hoz nincs sz�ks�g�nk a pop()
f�ggv�nyre.
Erre a top() utas�t�s szolg�l, a pop() muveletre pedig akkor van sz�ks�g, ha el
akarjuk t�vol
�tani a legfelso elemet. Ez a megold�s nem t�ls�gosan k�nyelmetlen, �s sokkal
hat�konyabb,
amikor a pop() muveletre nincs sz�ks�g:
void f(stack<char>& s)
{
if (s.top()=='c') s.pop(); // nem k�telezo kezdo 'c' elt�vol�t�sa
// ...
}
17. Szabv�nyos t�rol�k 631
Az �n�ll�an, teljesen kifejlesztett t�rol�kkal ellent�tben a veremnek (�s a t�bbi
t�rol�-�talak
�t�nak) nem lehet mem�riafoglal�t megadni sablonparam�terk�nt, azt a stack
megval�s�-
t�s�hoz haszn�lt t�rol� saj�t mem�riafoglal�ja helyettes�ti.
17.3.2. A queue
A <queue> fej�llom�nyban le�rt queue (sor) olyan fel�let egy t�rol�hoz, amely
lehetov� teszi
az elemek besz�r�s�t az adatszerkezet v�g�re, illetve kiv�tel�t a t�rol� elej�rol:

template <class T, class C = deque<T> > class std::queue {


protected:
C c;
public:
typedef typename C::value_type value_type;
typedef typename C::size_type size_type;
typedef C container_type;
explicit queue(const C& a = C()) : c(a) { }
bool empty() const { return c.empty(); }
size_type size() const { return c.size(); }
value_type& front() { return c.front(); }
const value_type& front() const { return c.front(); }
value_type& back() { return c.back(); }
const value_type& back() const { return c.back(); }
void push(const value_type& x) { c.push_back(x); }
void pop() { c.pop_front(); }
};
Alap�rtelmez�s szerint a queue a deque t�rol�t haszn�lja elemeinek t�rol�s�hoz, de
b�rmely
sorozat bet�ltheti ezt a szerepet, amely rendelkezik a front(), back(),
push_back() �s
pop_front() f�ggv�nyekkel. Mivel a vector nem teszi lehetov� a pop_front()
haszn�lat�t,
a vektor nem lehet a sor belso t�rol�ja.
632 A standard k�nyvt�r
A sor szerkezet szinte minden rendszerben elofordul valamilyen form�ban. Egy
egyszeru
�zenetalap� kiszolg�l�t p�ld�ul a k�vetkezok�ppen hat�rozhatunk meg:
struct Message {
// ...
};
void server(queue<Message>& q)
{
while(!q.empty()) {
Message& m = q.front(); // �zenet elfog�sa
m.service(); // a k�r�st kiszolg�l� f�ggv�ny megh�v�sa
q.pop(); // �zenet t�rl�se
}
}
Az �zeneteket a push() utas�t�s seg�ts�g�vel helyezhetj�k a sorba.
Ha az �gyf�l (kliens) �s a kiszolg�l� (szerver) k�l�n-k�l�n folyamatk�nt vagy
sz�lk�nt fut,
akkor a sor-hozz�f�r�seket valamilyen m�don �ssze kell hangolnunk
(szinkroniz�l�s):
void server2(queue<Message>& q, Lock& lck)
{
while(!q.empty()) {
Message m;
{ LockPtr h(lck); // z�rol�s az �zenet kinyer�se k�zben (�14.4.1)
if (q.empty()) return; // valaki m�s m�r megszerezte az �zenetet
m = q.front();
q.pop();
}
m.service(); // a k�r�st kiszolg�l� f�ggv�ny megh�v�sa
}
}
Az egyideju hozz�f�r�snek (konkurrencia, p�rhuzamoss�g), illetve a z�rol�snak
(lock) m�g
nincs szabv�nyos defin�ci�ja sem a C++ nyelvben, sem a sz�m�t�stechnika vil�g�ban.
Ha
ezeket a lehetos�geket szeretn�nk haszn�lni, akkor j�rjunk ut�na, hogy saj�t
rendszer�nk
milyen lehetos�geket biztos�t, �s azokat hogyan �rhetj�k el a C++ nyelvbol
(�17.8[8]).
17.3.3. A priority_queue
A priority_queue (priorit�sos sor) egy olyan sor, melyben az elemek fontoss�gi
�rt�ket kapnak,
�s ez az �rt�k szab�lyozza, hogy az elemek milyen sorrendben vehetok ki:
17. Szabv�nyos t�rol�k 633
template <class T, class C = vector<T>, class Cmp = less<typename C::value_type> >

class std::priority_queue {
protected:
C c;
Cmp cmp;
public:
typedef typename C::value_type value_type;
typedef typename C::size_type size_type;
typedef C container_type;
explicit priority_queue(const Cmp& a1 = Cmp(), const C& a2 = C())
: c(a2), cmp(a1) { make_heap(c.begin(),c.end(),cmp); } // l�sd �18.8
template <class In>
priority_queue(In first, In last, const Cmp& = Cmp(), const C& = C());
bool empty() const { return c.empty(); }
size_type size() const { return c.size(); }
const value_type& top() const { return c.front(); }
void push(const value_type&);
void pop();
};
A priority_queue-t a <queue> fej�llom�ny deklar�lja.
Alap�rtelmez�s szerint a priority_queue az elemeket egyszeruen a < oper�tor
seg�ts�g�vel
hasonl�tja �ssze, �s a top() mindig a legnagyobb elemet adja vissza:
struct Message {
int priority;
bool operator<(const Message& x) const { return priority < x.priority; }
// ...
};
void server(priority_queue<Message>& q, Lock& lck)
{
while(!q.empty()) {
Message m;
{ LockPtr h(lck); // z�rol�s az �zenet kinyer�se k�zben (�14.4.1)
if (q.empty()) return; // valaki m�s m�r megszerezte az �zenetet
m = q.top();
q.pop();
}
m.service(); // a k�r�st kiszolg�l� f�ggv�ny megh�v�sa
}
}
634 A standard k�nyvt�r
Ez a programr�szlet abban k�l�nb�zik a sorn�l (queue, �17.3.2) bemutatott
p�ld�t�l, hogy
itt az �zenetek k�z�l a legfontosabb (.legnagyobb priorit�s�.) ker�l elosz�r
feldolgoz�sra.
Az nem meghat�rozott, hogy az azonos fontoss�gi �rt�kkel rendelkezo elemek k�z�l
melyik
jelenik meg elosz�r a sor elej�n. K�t elem fontoss�ga (priorit�sa) akkor egyezik
meg,
ha egyik sem .fontosabb. a m�sikn�l (�17.4.1.5).
Ha a < oper�tor nem felel meg c�ljainknak, akkor egy sablonparam�ter seg�ts�g�vel
megadhatjuk
az �sszehasonl�t� muveletet. P�ld�ul karakterl�ncokat rendezhet�nk a kis- �s
nagybetuk megk�l�nb�ztet�se n�lk�l, ha az al�bbi sorban helyezz�k el azokat:
priority_queue<string, vector<string>, Nocase> pq; // Nocase haszn�lata az
// �sszehasonl�t�sokhoz (�17.1.4.1)
A karakterl�ncokat a pq.push() utas�t�ssal tessz�k be a sorba �s a pq.top(),
pq.pop() muveletekkel
dolgozhatjuk fel.
Az olyan sablonokb�l l�trehozott objektumok, melyekn�l k�l�nb�zo
sablonparam�tereket
haszn�ltunk, k�l�nb�zo t�pus�ak (�13.6.3.1):
priority_queue<string>& pq1 = pq; // hiba: nem megfelelo t�pus
�sszehasonl�t�si szempontot megadhatunk �gy is, hogy k�zben nem v�ltoztatjuk meg
a priorit�sos sor t�pus�t. Ehhez egy megfelelo t�pus� �sszehasonl�t� objektumot
kell l�trehoznunk,
melynek konstruktor-param�ter�ben megadjuk az �rv�nyes �sszehasonl�t�si
szempontot:
struct String_cmp { // fut�si ideju �sszehasonl�t�si felt�telt kifejezo t�pus
String_cmp(int n = 0); // az n �sszehasonl�t�si felt�tel haszn�lata
// ...
};
typedef priority_queue<string, vector<string>, String_cmp> Pqueue;
void g(Pqueue& pq) // a pq a String_cmp()-et haszn�lja az �sszehasonl�t�sokhoz
{
Pqueue pq2(String_cmp(nocase));
pq = pq2; // rendben: pq �s pq2 azonos t�pus�, �gy pq most
// a String_cmp(nocase)-t shaszn�lja
}
Az elemek rendez�se n�mi teljes�tm�nyroml�ssal j�r, de ez egy�ltal�n nem jelentos.

A priority_queue egyik hat�kony megval�s�t�si m�dja a faszerkezet, mellyel az


elemek egy-
17. Szabv�nyos t�rol�k 635
m�shoz viszony�tott hely�t k�nnyed�n be�ll�thatjuk. Ezzel a megold�ssal a push()
�s
a pop() muvelet k�lts�ge is O(log(n)).
Alap�rtelmez�s szerint a priority_queue egy vector t�rol�t haszn�l elemeinek
nyilv�ntart�s-
�ra, de b�rmely sorozatt�pus megfelel e c�lra, amely rendelkezik a front(),
push_back() �s
pop_back() f�ggv�nyekkel, valamint lehetov� teszi k�zvetlen el�r�su bej�r�k
haszn�lat�t.
A priorit�sos sorok leggyakrabban haszn�lt megval�s�t�si eszk�ze a heap (kupac
vagy halom,
�18.8)
17.4. Asszociat�v t�rol�k
Az asszociat�v t�mb az egyik leghasznosabb felhaszn�l�i t�pus. Ennek k�vetkezt�ben
az els
osorban sz�veg- vagy szimb�lum-feldolgoz�sra kifejlesztett nyelvekben gyakran
be�p�tett
t�pusk�nt szerepel. Az asszociat�v t�mb, melynek gyakori elnevez�se a map
(hozz�rendel
�s, lek�pez�s) �s a dictionary (sz�t�r) is, �rt�kp�rokat t�rol. Az egyik �rt�k a
kulcs (key),
melyet a m�sik �rt�k (a hozz�rendelt �rt�k, mapped value) el�r�s�hez haszn�lunk.
Az asszociat�v t�mb�t �gy k�pzelhetj�k el, mint egy t�mb�t, melynek indexe nem
felt�tlen
�l egy eg�sz sz�m:
template<class K, class V> class Assoc {
public:
V& operator[ ](const K&); // hivatkoz�s visszaad�sa a K-nak megfelelo V-re
// ...
};
Itt a K t�pus� kulcs seg�ts�g�vel a V t�pus� hozz�rendelt �rt�ket v�lasztjuk ki.
Az asszociat�v t�rol� az asszociat�v t�mb fogalm�nak �ltal�nos�t�sa. A map sablon
a hagyom
�nyos asszociat�v t�mbnek felel meg, ahol minden kulcs�rt�khez egyetlen �rt�ket
rendel
�nk. A multimap egy olyan asszociat�v t�mb, amely megengedi, hogy ugyanolyan
kulcs-
�rt�kkel t�bb elem is szerepeljen, m�g a set �s a multiset olyan egyedi
asszociat�v t�mb�k,
melyekben nincs hozz�rendelt �rt�k.
636 A standard k�nyvt�r
17.4.1. A map
A map (kulcs,�rt�k) p�rok sorozata, melyben a bejegyz�seket a kulcs (key) alapj�n
gyorsan
el�rhetj�k. A map t�rol�ban a kulcsok egyediek, azaz minden kulcshoz legfeljebb
egy �rt
�ket rendel�nk hozz�. A map szerkezetben k�tir�ny� bej�r�kat haszn�lhatunk
(�19.2.1).
A map megk�veteli, hogy a kulcsk�nt haszn�lt t�pusokban a .kisebb mint. muvelet
haszn
�lhat� legyen (�17.1.4.1), �s ez alapj�n az elemeket rendezve t�rolja. Ennek
k�vetkezt�-
ben a map bej�r�sakor az elemeket rendezve kapjuk meg. Ha olyan elemeink vannak,
melyek
k�z�tt nem lehet egy�rtelmu sorrendet meg�llap�tani, vagy nincs sz�ks�g arra, hogy

az elemeket rendezve t�roljuk, akkor haszn�ljuk ink�bb a hash_map szerkezetet


(�17.6).
17.4.1.1. T�pusok
A map a t�rol�k szok�sos t�pus tagjain (�16.3.1) k�v�l n�h�ny, az oszt�ly egyedi
c�lj�nak
megfelelo t�pust is meghat�roz:
template <class Key, class T, class Cmp = less<Key>,
class A = allocator< pair<const Key,T> > >
class std::map {
public:
// t�pusok
typedef Key key_type;
typedef T mapped_type;
typedef pair<const Key, T> value_type;
typedef Cmp key_compare;
typedef A allocator_type;
typedef typename A::reference reference;
typedef typename A::const_reference const_reference;
typedef megval�s�t�s_f�ggo1 iterator;
typedef megval�s�t�s_f�ggo2 const_iterator;
typedef typename A::size_type size_type;
typedef typename A::difference_type difference_type;
typedef std::reverse_iterator<iterator> reverse_iterator;
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
// ...
};
17. Szabv�nyos t�rol�k 637
Jegyezz�k meg, hogy a value_type a map eset�ben a (kulcs, �rt�k) p�rt (pair)
jelenti. A hozz
�rendelt �rt�kek t�pus�t a mapped_type adja meg. Teh�t a map nem m�s, mint
pair<const
Key, mapped_type> t�pus� elemek sorozata. Szok�s szerint a konkr�t bej�r�-t�pusok
az adott
megval�s�t�st�l f�ggoek. Mivel a map t�rol�t leggyakrabban valamilyen faszerkezet
seg�ts�-
g�vel val�s�tj�k meg, a bej�r�k �ltal�ban biztos�tanak valamilyen fabej�r�st.
A visszafel� halad� bej�r�kat a szabv�nyos reverse_iterator sablonok (�19.2.5)
seg�ts�g�vel
hat�rozhatjuk meg.
17.4.1.2. Bej�r�k �s p�rok
A map a szok�sos f�ggv�nyeket biztos�tja a bej�r�k el�r�s�hez (�16.3.2):
template <class Key, class T, class Cmp = less<Key>,
class A = allocator< pair<const Key,T> > > class map {
public:
// ...
// bej�r�k
iterator begin();
const_iterator begin() const;
iterator end();
const_iterator end() const;
reverse_iterator rbegin();
const_reverse_iterator rbegin() const;
reverse_iterator rend();
const_reverse_iterator rend() const;
// ...
};
A map bej�r�sakor pair<const Key, mapped_type> t�pus� elemek sorozat�n haladunk
v�-
gig. P�ld�ul egy telefonk�nyv bejegyz�seit az al�bbi elj�r�ssal �rathatjuk ki:
void f(map<string,number>& phone_book)
{
typedef map<string,number>::const_iterator CI;
for (CI p = phone_book.begin(); p!=phone_book.end(); ++p)
cout << p->first << '\t' << p->second << '\n';
}
638 A standard k�nyvt�r
A map bej�r�i az elemeket kulcs szerint n�vekvo sorrendben adj�k vissza
(�17.1.4.5), �gy
a phone_book bejegyz�sei �b�c�sorrendben jelennek meg. Egy pair elso elem�re a
first, m�-
sodik elem�re a second n�vvel hivatkozhatunk, f�ggetlen�l att�l, hogy �ppen milyen
t�pus
�ak ezek az elemek:
template <class T1, class T2> struct std::pair {
typedef T1 first_type;
typedef T2 second_type;
T1 first;
T2 second;
pair() :first(T1()), second(T2()) { }
pair(const T1& x, const T2& y) :first(x), second(y) { }
template<class U, class V>
pair(const pair<U, V>& p) :first(p.first), second(p.second) { }
};
Az utols� konstruktorra az�rt van sz�ks�g, hogy a p�rokon t�puskonverzi�t is
v�gezhess�nk
(�13.6.2):
pair<int,double> f(char c, int i)
{
pair<char,int> x(c,i);
// ...
return x; // pair<char,int>-rol pair<int,double>-ra val� konverzi� sz�ks�ges
.. return pair<int,double>(c,i); // konverzi� sz�ks�ges
}
A map eset�ben a p�r elso tagja a kulcs, a m�sodik tagja a hozz�rendelt �rt�k.
A pair adatszerkezet nem csak a map megval�s�t�s�ban haszn�lhat�, �gy ez is egy
�n�ll�
oszt�ly a standard k�nyvt�rban. A pair le�r�s�t a <utility> fej�llom�nyban
tal�lhatjuk meg.
A pair t�pus� v�ltoz�k l�trehoz�s�t k�nny�ti meg a k�vetkezo f�ggv�ny:
template <class T1, class T2> pair<T1,T2> std::make_pair(T1 t1, T2 t2)
{
return pair<T1,T2>(t1,t2);
}
A pair alap�rtelmezett kezdo�rt�keit k�t elemt�pus�nak alap�rtelmezett �rt�ke
adja. Fontos,
hogy ha az elemek t�pusa be�p�tett, akkor a kezdo�rt�k 0 (�5.1.1), karakterl�ncok
eset�ben
pedig egy .�res. karakterl�nc (�20.3.4). Olyan t�pus, melynek nincs
alap�rtelmezett
konstruktora, csak akkor lehet egy pair eleme, ha a pair kezdo�rt�k�t kifejezetten
megadjuk.
17. Szabv�nyos t�rol�k 639
17.4.1.3. Indexel�s
A legjellemzobb map-muvelet a hozz�rendel�ses (asszoci�ci�s) keres�s, amit az
indexelo
oper�tor val�s�t meg:
template <class Key, class T, class Cmp = less<Key>,
class A = allocator< pair<const Key,T> > >
class map {
public:
// ...
mapped_type& operator[ ](const key_type& k); // a k kulcs� elem el�r�se
// ...
};
Az indexelo oper�tor a megadott kulcsot indexnek tekintve egy keres�st hajt v�gre
�s
visszaadja a kulcshoz rendelt �rt�ket. Ha a kulcs nem tal�lhat� meg a t�rol�ban,
akkor ezzel
a kulccsal �s a mapped_type alap�rtelmezett �rt�k�vel egy �j elem ker�l az
asszociat�v
t�mbbe:
void f()
{
map<string,int> m; // a map kezdetben �res
int x = m["Henry"]; // �j bejegyz�s k�sz�t�se ("Henry"); a kezdo�rt�k 0, a
// visszaadott �rt�k 0
m["Harry"] = 7; // �j bejegyz�s k�sz�t�se ("Harry"), a kezdo�rt�k 0, kapott �rt�k
7
int y = m["Henry"]; // a "Henry" bejegyz�s �rt�k�nek visszaad�sa
m["Harry"] = 9; // "Harry" �rt�k�nek m�dos�t�sa 9-re
}
Egy kicsit val�s�gszerubb p�lda: k�pzelj�nk el egy programot, amely kisz�m�tja a
bemenet
�n megadott t�rgyak darabsz�m�t. A list�ban (n�v, mennyis�g) bejegyz�sek
szerepelnek.
Az �sszes�t�st el szeretn�nk v�gezni t�rgyank�nt �s az eg�sz list�ra is. A lista
lehet p�ld�ul
a k�vetkezo:
sz�g 100 kalap�cs 2 fur�sz 3 fur�sz 4 kalap�cs 7 sz�g 1000 sz�g 250
A feladat nagy r�sz�t elv�gezhetj�k, mik�zben a (n�v, mennyis�g) p�rokat
beolvassuk egy
map t�rol�ba:
void readitems(map<string,int>& m)
{
string word;
int val = 0;
while (cin >> word >> val) m[word] += val;
}
640 A standard k�nyvt�r
Az m[word] indexel�s azonos�tja a megfelelo (string, int) p�rt, �s visszaadja az
int �rt�ket.
A fenti programr�szletben kihaszn�ljuk azt is, hogy az �j elemek int �rt�ke
alap�rtelmez�s
szerint 0.
A readitems() f�ggv�nnyel fel�p�tett map egy szok�sos ciklus seg�ts�g�vel
jelen�theto meg:
int main()
{
map<string,int> tbl;
readitems(tbl);
int total = 0;
typedef map<string,int>::const_iterator CI;
for (CI p = tbl.begin(); p!=tbl.end(); ++p) {
total += p->second;
cout << p->first << '\t' << p->second << '\n';
}
cout << "----------------\n�sszesen\t" << total << '\n';
return !cin;
}
A fenti bemenettel a f�ggv�ny eredm�nye a k�vetkezo:
fur�sz 7
kalap�cs 9
sz�g 1350
------------------------
�sszesen 1366
Figyelj�k meg, hogy a nevek �b�c�sorrendben jelennek meg (�17.4.1, �17.4.1.5).
Az indexelo oper�tornak meg kell tal�lnia a megadott kulcs�rt�ket a t�rol�ban. Ez
term�szetesen
nem olyan egyszeru muvelet, mint a t�mb�k eset�ben az eg�sz �rt�kkel val� indexel
�s. A pontos k�lts�g: O(log(a_map_m�rete)). Ez sok alkalmaz�s eset�ben m�g
elfogadhat�,
ha azonban a mi c�ljainknak t�l dr�ga, �rdemesebb has�t� t�rol�t (�17.6)
haszn�lnunk. Ha
a map t�rol�ban nem tal�lhat� meg egy kulcs, akkor az erre vonatkoz� indexel�ssel
l�trehozunk
egy alap�rtelmezett elemet. Ennek k�vetkezt�ben a const map oszt�lyok eset�ben
nem haszn�lhatjuk az operator[ ]() muveletet. R�ad�sul az indexel�s csak akkor
haszn�lhat
�, ha a mapped_type t�pusnak van alap�rtelmezett �rt�ke. Ha csak arra vagyunk
k�v�ncsiak,
hogy egy adott kulcs megtal�lhat�-e a t�rol�ban, akkor haszn�ljuk a find()
muveletet
(�17.4.1.6), ami a map megv�ltoztat�sa n�lk�l keresi meg a kulcsot.
17. Szabv�nyos t�rol�k 641
17.4.1.4. Konstruktorok
A map a szok�sos konstruktorokat �s egy�b f�ggv�nyeket biztos�tja (�16.3.4):
template <class Key, class T, class Cmp =less<Key>,
class A =allocator<pair<const Key,T> > >
class map {
public:
// ...
// l�trehoz�s/m�sol�s/megsemmis�t�s:
explicit map(const Cmp& = Cmp(), const A& = A());
template <class In> map(In first, In last, const Cmp& = Cmp(), const A& = A());
map(const map&);
~map();
map& operator=(const map&);
// ...
};
A t�rol� lem�sol�sa azt jelenti, hogy helyet foglalunk az elemeknek, majd
mindegyikrol m�-
solatot k�sz�t�nk (�16.3.4). Ez nagyon k�lts�ges muvelet is lehet, ez�rt csak
akkor haszn�ljuk,
ha elker�lhetetlen. Ebbol k�vetkezik, hogy az olyan t�rol�kat, mint a map, csak
referencia szerint �rdemes �tadni.
A sablon konstruktor pair<const Key, T> elemek sorozat�t kapja param�terk�nt,
amelyet
egy bemeneti bej�r�-p�rral adunk meg. A f�ggv�ny a sorozat elemeit az insert()
muvelet
seg�ts�g�vel sz�rja be az asszociat�v t�mbbe.
17.4.1.5. �sszehasonl�t�sok
Ahhoz, hogy egy adott kulcs� elemet megtal�ljunk egy map-ben, a map muveleteinek
�ssze kell tudnia hasonl�tani a kulcsokat. A bej�r�k is a kulcsok n�vekvo �rt�kei
szerint haladnak
v�gig a t�rol�n, �gy a besz�r�sok is kulcs-�sszehasonl�t�sokat v�geznek (ahhoz,
hogy az elemeket elhelyezz�k a map t�rol�t �br�zol� faszerkezetben).
Alap�rtelmez�s szerint a kulcsok �sszehasonl�t�s�hoz haszn�lt muvelet a < (kisebb
mint)
oper�tor, de egy sablon- vagy konstruktor-param�terben m�s f�ggv�nyt is
megadhatunk
(�17.3.3). Az itt megadott rendez�si szempont a kulcsokat hasonl�tja �ssze, m�g a
map ese-
642 A standard k�nyvt�r
t�ben a value_type (kulcs, �rt�k) p�rokat jelent. Ez�rt van sz�ks�g a value_comp()
f�ggv
�nyre, amely a kulcsokat �sszehasonl�t� elj�r�s alapj�n a p�rokat hasonl�tja
�ssze:
template <class Key, class T, class Cmp = less<Key>,
class A = allocator< pair<const Key,T> > >
class map {
public:
// ...
typedef Cmp key_compare;
class value_compare : public binary_function<value_type,value_type,bool> {
friend class map;
protected:
Cmp cmp;
value_compare(Cmp c) : cmp(c) {}
public:
bool operator()(const value_type& x, const value_type& y) const
{ return cmp(x.first, y.first); }
};
key_compare key_comp() const;
value_compare value_comp() const;
// ...
};
P�ld�ul:
map<string,int> m1;
map<string,int,Nocase> m2; // �sszehasonl�t�s t�pus�nak megad�sa (�17.1.4.1)
map<string,int,String_cmp> m3; // �sszehasonl�t�s t�pus�nak megad�sa (�17.1.4.1)
map<string,int,String_cmp> m4(String_cmp(literary)); // �sszehasonl�tand� objektum

// �tad�sa
A key_comp() �s a value_comp() tagf�ggv�ny lehetov� teszi, hogy az asszociat�v
t�mbben
az eg�sz elemekre a csak kulcsokra, illetve a csak �rt�kekre vonatkoz�
�sszehasonl�t� mu-
veleteket haszn�ljuk. Erre legt�bbsz�r akkor van sz�ks�g, ha ugyanazt az
�sszehasonl�t�st
szeretn�nk haszn�lni egy m�sik t�rol�ban vagy algoritmusban is:
void f(map<string,int>& m)
{
map<string,int> mm; // �sszehasonl�t�s alap�rtelmez�s szerint < oper�torral
map<string,int> mmm(m.key_comp()); // m szerinti �sszehasonl�t�s
// ...
}
17. Szabv�nyos t�rol�k 643
A �17.1.4.1 pontban p�ld�t l�thatunk arra, hogyan adhatunk meg egyedi
�sszehasonl�t�sokat,
a �18.4 pontban pedig a f�ggv�nyobjektumok �ltal�nos bemutat�s�val foglalkozunk.
17.4.1.6. Muveletek asszociat�v t�mb�kkel
A map �s term�szetesen az �sszes asszociat�v t�rol� legfontosabb tulajdons�ga,
hogy egy
kulcs alapj�n f�rhet�nk hozz� az inform�ci�khoz. Ezen c�l megval�s�t�s�hoz sz�mos
egyedi
f�ggv�ny �ll rendelkez�s�nkre:
template <class Key, class T, class Cmp = less<Key>,
class A = allocator< pair<const Key,T> > >
class map {
public:
// ...
// map-muveletek
iterator find(const key_type& k); // a k kulcs� elem megkeres�se
const_iterator find(const key_type& k) const;
size_type count(const key_type& k) const; // a k kulcs� elemek sz�m�nak
// meghat�roz�sa
iterator lower_bound(const key_type& k); // az elso k kulcs� elem megkeres�se
const_iterator lower_bound(const key_type& k) const;
iterator upper_bound(const key_type& k); // az elso k-n�l nagyobb kulcs� elem
// megkeres�se
const_iterator upper_bound(const key_type& k) const;
pair<iterator,iterator> equal_range(const key_type& k);
pair<const_iterator,const_iterator> equal_range(const key_type& k) const;
// ...
};
Az m.find(k) muvelet egyszeruen visszaad egy k kulcs� elemre hivatkoz� bej�r�t. Ha
ilyen
elem nincs, akkor a visszaadott bej�r� az m.end(). Egy egyedi kulcsokkal
rendelkezo t�rol
� eset�ben (mint a map �s a set) az eredm�ny az egyetlen k kulcs� elemre mutat�
bej�r�
lesz. Ha a t�rol� nem teszi k�telezov� egyedi kulcsok haszn�lat�t (mint a multimap
�s
a multiset), akkor a visszaadott bej�r� az elso megfelelo kulcs� elem lesz:
void f(map<string,int>& m)
{
map<string,int>::iterator p = m.find("Arany");
644 A standard k�nyvt�r
if (p!=m.end()) { // ha "Arany"-at tal�ltunk
// ...
}
else if (m.find("Ez�st")!=m.end()) { // "Ez�st" keres�se
// ...
}
// ...
}
Egy multimap (�17.4.2) eset�ben az elso k kulcs� elem megkeres�se helyett
�ltal�ban az
�sszes ilyen elemre sz�ks�g�nk van. Az m.lower_bound(k) �s az m.upper_bound(k)
f�ggv
�nyekkel az m k kulcs� elemeibol �ll� r�szsorozat elej�t, illetve v�g�t
k�rdezhetj�k le.
Szok�s szerint, a sorozat v�g�t jelzo bej�r� az utols� ut�ni elemre mutat:
void f(multimap<string,int>& m)
{
multimap<string,int>::iterator lb = m.lower_bound("Arany");
multimap<string,int>::iterator ub = m.upper_bound("Arany");
for (multimap<string,int>::iterator p = lb; p!=ub; ++p) {
// ...
}
}
Az als� �s a felso hat�r meghat�roz�sa k�t k�l�n muvelettel nem t�l eleg�ns �s nem
is hat
�kony. Ez�rt �ll rendelkez�s�nkre az equal_range() f�ggv�ny, amely mindk�t �rt�ket

visszaadja:
void f(multimap<string,int>& m)
{
typedef multimap<string,int>::iterator MI;
pair<MI,MI> g = m.equal_range("Arany");
for (MI p = g.first; p!=g.second; ++p) {
// ...
}
}
Ha a lower_bound(k) nem tal�lja meg a k kulcsot, akkor az elso olyan elemre
hivatkoz�
bej�r�t adja vissza, melynek kulcsa nagyobb, mint k, illetve az end() bej�r�t, ha
nem l�tezik
k-n�l nagyobb kulcs. Ugyanezt a hibajelz�si m�dot haszn�lja az upper_bound() �s az

equal_range() is.
17. Szabv�nyos t�rol�k 645
17.4.1.7. Listamuveletek
Ha egy asszociat�v t�mbbe �j �rt�ket szeretn�nk bevinni, akkor a hagyom�nyos
megold�s
az, hogy egyszeru indexel�ssel �rt�ket adunk az adott kulcs� elemnek:
phone_book["Rendel�si oszt�ly"] = 8226339;
Ez a sor biztos�tja, hogy a phone_book t�rol�ban meglesz a Rendel�si oszt�ly
bejegyz�s
a megfelelo �rt�kkel, f�ggetlen�l att�l, hogy kor�bban l�tezett-e m�r ilyen kulcs.
Elemeket
beilleszthet�nk k�zvetlen�l az insert() f�ggv�ny seg�ts�g�vel is, �s az erase()
szolg�l az elemek
t�rl�s�re:
template <class Key, class T, class Cmp = less<Key>,
class A = allocator< pair<const Key,T> > >
class map {
public:
// ...
// listamuveletek
pair<iterator, bool> insert(const value_type& val); // (kulcs,�rt�k) p�r besz�r�sa

iterator insert(iterator pos, const value_type& val); // a pos csak javaslat


template <class In> void insert(In first, In last); // elemek besz�r�sa sorozatb�l

void erase(iterator pos); // a mutatott elem t�rl�se


size_type erase(const key_type& k); // a k kulcs� elem t�rl�se (ha van ilyen)
void erase(iterator first, iterator last); // tartom�ny t�rl�se
void clear(); // minden elem t�rl�se
// ...
};
Az m.insert(val) f�ggv�ny besz�rja a val �rt�ket, amely egy (Key, T) p�rt ad meg.
Mivel
a map egyedi kulcsokkal foglalkozik, a besz�r�sra csak akkor ker�l sor, ha az m
t�rol�ban
m�g nincs ilyen kulccsal rendelkezo elem. Az m.insert(val) visszat�r�si �rt�ke egy

pair<iterator,bool>. A p�r m�sodik, logikai tagja akkor igaz, ha a val �rt�k


t�nylegesen beker
�lt a t�rol�ba. A bej�r� az m azon elem�t jel�li ki, melynek kulcsa megegyezik a
val kulcs
�val (val.first):
void f(map<string,int>& m)
{
pair<string,int> p99("Pali",99);
pair<map<string,int>::iterator,bool> p = m.insert(p99);
if (p.second) {
646 A standard k�nyvt�r
// "Pali"-t besz�rtuk
}
else {
// "Pali" m�r szerepelt
}
map<string,int>::iterator i = p.first; // points to m["Pali"]
// ...
}
�ltal�ban nem �rdekel minket, hogy a kulcs kor�bban m�r szerepelt-e a map-ben vagy
�j
elemk�nt ker�lt be. Ha m�gis erre vagyunk k�v�ncsiak, annak oka �ltal�ban az, hogy
a k�-
v�nt kulcs egy m�sik map t�rol�ba is ker�lhet az �ltalunk vizsg�lt helyett, �s ezt
�szre kell
venn�nk. Az insert() m�sik k�t v�ltozata nem jelzi, hogy az �j �rt�k t�nyleg
beker�lt-e
a t�rol�ba.
Ha az insert(pos,val) forma szerint egy poz�ci�t is megadunk, akkor csak egy
aj�nl�st
adunk, hogy a rendszer a val kulcs�nak keres�s�t a pos poz�ci�t�l kezdje. Ha az
aj�nl�s helyes,
jelentos teljes�tm�nyn�veked�st �rhet�nk el. Ha nem tudunk j� aj�nl�st adni,
haszn�ljuk
ink�bb az elozo v�ltozatot, mind az olvashat�s�g, mind a hat�konys�g �rdek�ben:
void f(map<string,int>& m)
{
m["Dilbert"] = 3; // eleg�ns, de val�sz�nuleg kev�sb� hat�kony
m.insert(m.begin(),make_pair(const string("Dogbert"),99)); // cs�nya
}
Val�j�ban a [ ] egy kicsit t�bb, mint egyszeruen az insert() k�nyelmesebb alakja.
Az m[k]
eredm�nye a k�vetkezo kifejez�ssel egyen�rt�ku:
(*(m.insert(make_pair(k,V())).first)).second
ahol a V() a hozz�rendelt �rt�k alap�rtelmezett �rt�k�t jel�li. Ha ezt az
egyen�rt�kus�get
meg�rtett�k, akkor val�sz�nuleg m�r �rtj�k az asszociat�v t�rol�kat is. Mivel a
[ ] mindenk�ppen
haszn�lja a V() �rt�ket, nem haszn�lhatjuk az indexel�st olyan map eset�ben,
melynek
�rt�kt�pusa nem rendelkezik alap�rtelmezett �rt�kkel. Ez egy sajn�latos
hi�nyoss�ga az
asszociat�v t�rol�knak, annak ellen�re, hogy az alap�rtelmezett �rt�k megl�te nem
alapveto
k�vetelm�ny�k (ld. �17.6.2). Az elemek t�rl�s�t is kulcs szerint v�gezhetj�k el:
void f(map<string,int>& m)
{
int count = m.erase("Ratbert");
// ...
}
17. Szabv�nyos t�rol�k 647
A visszaadott eg�sz �rt�k a t�r�lt elemek sz�m�t adja meg. Teh�t a count tartalma
0, ha
nincs .Ratbert. kulcs� elem a t�rol�ban. A multimap �s a multiset eset�ben a
visszaadott
�rt�k egyn�l nagyobb is lehet. Egy elemet egy r� mutat� bej�r� seg�ts�g�vel
t�r�lhet�nk,
elemek sorozat�t pedig a megfelelo tartom�ny kijel�l�s�vel:
void g(map<string,int>& m)
{
m.erase(m.find("Catbert"));
m.erase(m.find("Alice"),m.find("Wally"));
}
Term�szetesen gyorsabban lehet t�r�lni egy olyan elemet, melynek m�r megtal�ltuk
a bej�r�j�t, mint egy olyat, melyet elosz�r a kulcs alapj�n meg kell keresn�nk. Az
erase()
ut�n a bej�r�t tov�bb m�r nem haszn�lhatjuk, mivel az �ltala mutatott elem
megsemmis�lt.
Az m.erase(b,e) h�v�sa, ahol e �rt�ke m.end() vesz�lytelen (b vagy m valamelyik
elem�re
hivatkozik, vagy m.end()). Ugyanakkor az m.erase(p) megh�v�sa, amennyiben p �rt�ke

m.end(), s�lyos hiba �s t�nkreteheti a t�rol�t.


17.4.1.8. Tov�bbi muveletek
A map biztos�tja azokat a szok�sos f�ggv�nyeket, melyek az elemek sz�m�val
foglalkoznak,
illetve egy specializ�lt swap() f�ggv�nyt:
template <class Key, class T, class Cmp = less<Key>,
class A = allocator< pair<const Key,T> > >
class map {
public:
// ...
// kapacit�s:
size_type size() const; // elemek sz�ma
size_type max_size() const; // a lehets�ges legnagyobb map m�rete
bool empty() const { return size()==0; }
void swap(map&);
};
Szok�s szerint a size() �s a max_size() �ltal visszaadott �rt�k valamilyen
elemsz�m.
Ezenk�v�l a map haszn�latakor rendelkez�s�nkre �llnak az �sszehasonl�t� oper�torok
(==,
!=, <, >, <=, >=), valamint a swap() elj�r�s is, ezek azonban nem tagf�ggv�nyei a
map
oszt�lynak:
648 A standard k�nyvt�r
template <class Key, class T, class Cmp, class A>
bool operator==(const map<Key,T,Cmp,A>&, const map<Key,T,Cmp,A>&);
// ugyan�gy !=, <, >, <=, and >=
template <class Key, class T, class Cmp, class A>
void swap(map<Key,T,Cmp,A>&, map<Key,T,Cmp,A>&);
Mi�rt lehet sz�ks�g arra, hogy k�t asszociat�v t�mb�t �sszehasonl�tsunk? Ha k�t
map objektumot
hasonl�tunk �ssze, �ltal�ban nem csak azt akarjuk megtudni, hogy egyenloek-e,
hanem
azt is, hogy miben k�l�nb�znek, ha k�l�nb�znek. Ilyenkor teh�t az == �s a != nem
haszn�lhat�. Az ==, a < �s a swap() megval�s�t�s�val azonban lehetov� v�lik, hogy
olyan
algoritmusokat k�sz�ts�nk, melyek minden t�rol�ra alkalmazhat�k. Ezekre a
f�ggv�nyekre
p�ld�ul akkor lehet sz�ks�g�nk, ha asszociat�v t�mb�kbol �ll� vektort szeretn�nk
rendezni
vagy map t�rol�k halmaz�ra van sz�ks�g�nk.
17.4.2. A multimap
A multimap nagyon hasonl�t a map t�rol�ra, azzal a kiv�tellel, hogy ugyanaz a
kulcs t�bbsz
�r is szerepelhet:
template <class Key, class T, class Cmp = less<Key>,
class A = allocator< pair<const Key,T> > >
class std::multimap {
public:
// mint a map, kiv�ve a k�vetkezot:
iterator insert(const value_type&); // bej�r�t ad vissza, nem p�rt
// nincs indexelo oper�tor ([ ])
};
P�ld�ul (felhaszn�lva a �17.1.4.1 pontban C st�lus� karakterl�ncok
�sszehasonl�t�s�hoz bemutatott
CString_less oszt�lyt):
void f(map<char*,int,Cstring_less>& m, multimap<char*,int,Cstring_less>& mm)
{
m.insert(make_pair("x",4));
m.insert(make_pair("x",5));// nincs hat�sa: "x" m�r szerepel (�17.4.1.7)
// most m["x"] == 4
17. Szabv�nyos t�rol�k 649
mm.insert(make_pair("x",4));
mm.insert(make_pair("x",5));
// mm most ("x",4)-et �s ("x",5)-�t is tartalmazza
}
Teh�t a multimap t�rol�ban nem lehet olyan indexel�st megval�s�tani, mint a map
eset�-
ben. Itt az equal_range(), a lower_bound() �s az upper_bound() muvelet (�17.4.1.6)
jelenti
az azonos kulcs� elemek el�r�s�re szolg�l� legfobb eszk�zt.
Term�szetesen ha ugyanahhoz a kulcshoz t�bb �rt�ket is hozz�rendelhet�nk, akkor a
map
helyett felt�tlen�l a multimap szerkezetet haszn�ljuk. Ez pedig sokkal gyakrabban
elofordul,
mint gondoln�nk. Bizonyos tekintetben a multimap sokkal tiszt�bb �s eleg�nsabb
megold�st ad, mint a map.
Mivel egy embernek t�bb telefonsz�ma is lehet, a telefonk�nyvet is �rdemesebb
multimap
form�ban elk�sz�teni. Saj�t telefonsz�maimat p�ld�ul a k�vetkezo programr�szlettel
jelen�thetem
meg:
void print_numbers(const multimap<string,int>& phone_book)
{
typedef multimap<string,int>::const_iterator I;
pair<I,I> b = phone_book.equal_range("Stroustrup");
for (I i = b.first; i != b.second; ++i) cout << i->second << '\n';
}
A multimap eset�ben az insert() mindig beilleszti a param�terek�nt megadott
elemet, �gy
nincs sz�ks�g a pair<iterator, bool> t�pus� visszat�r�si �rt�kre; a
multimap::insert() egyetlen
bej�r�t ad vissza. Az egys�gess�g �rdek�ben a k�nyvt�r tartalmazhatn� az insert()
�ltal
�nos form�j�t, mind a map-hez, mind a multimap-hez, annak ellen�re, hogy a bool
r�sz felesleges
a multimap oszt�lyban. Egy m�sik tervez�si szeml�let szerint elk�sz�thett�k volna
az egyszeru insert() f�ggv�nyt mindk�t t�rol�hoz, amely nem ad vissza logikai
�rt�ket. Ez
esetben viszont a map felhaszn�l�inak valamilyen m�s lehetos�get kellett volna
biztos�tani
annak meg�llap�t�s�hoz, hogy �j kulcs ker�lt-e a t�rol�ba. Ebben a k�rd�sben a
k�l�nb�-
zo fel�lettervez�si elm�letek �tk�ztek, �s nem sz�letett megegyez�s.
17.4.3. A set
A set (halmaz) olyan egyedi map (�17.4.1) t�rol�nak tekintheto, ahol a
hozz�rendelt �rt�-
kek �rdektelenek, �gy csak a kulcsokat tartjuk meg. Ez a fel�letnek csup�n apr�
m�dos�t�-
s�t jelenti:
650 A standard k�nyvt�r
template <class Key, class Cmp = less<Key>, class A = allocator<Key> >
class std::set {
public:
// mint a map, kiv�ve a k�vetkezot
typedef Key value_type; // a kulcs maga az �rt�k
typedef Cmp value_compare;
// nincs indexelo oper�tor ([ ])
};
A value_type t�pust teh�t itt a key_type t�pussal azonosk�nt hat�rozzuk meg. Ez a
tr�kk lehet
ov� teszi, hogy nagyon sok esetben ugyanazzal a programmal kezelj�nk egy map �s
egy
set t�rol�t.
Figyelj�k meg, hogy a set egy sorrendvizsg�l� oper�tort haszn�l (alap�rtelmez�s
szerint <),
�s nem egyenlos�get (==) ellenoriz. Ennek k�vetkezt�ben az elemek egyen�rt�kus�g�t

a nem-egyenlos�g hat�rozza meg (�17.1.4.1) �s a halmaz bej�r�sakor az elemeket


meghat
�rozott sorrendben kapjuk meg.
Ugyan�gy, mint a map eset�ben, itt is rendelkez�s�nkre �llnak a halmazokat
�sszehasonl
�t� oper�torok (==, !=,< , >, <=, >=) �s a swap() f�ggv�ny is.
17.4.4. A multiset
A multiset egy olyan halmaz, amely megengedi, hogy ugyanazok a kulcsok t�bbsz�r is
elo-
forduljanak:
template <class Key, class Cmp = less<Key>, class A = allocator<Key> >
class std::multiset {
public:
// mint a set, kiv�ve a k�vetkezot:
iterator insert(const value_type&); // bej�r�t ad vissza, nem p�rt
};
A t�bbsz�r elofordul� kulcsok el�r�s�hez elsosorban az equal_range(), a
lower_bound()
�s az upper_bound() f�ggv�nyeket haszn�lhatjuk.
17. Szabv�nyos t�rol�k 651
17.5. Majdnem-t�rol�k
A be�p�tett t�mb�k (�5.2), a karakterl�ncok (20. fejezet), valamint a valarray
(�22.4) �s
a bitset (�17.5.3) oszt�lyok is elemeket t�rolnak, �gy sok szempontb�l t�rol�nak
tekinthetj
�k oket. Mindegyik hordoz azonban n�h�ny olyan von�st, amely ellentmond a
szabv�nyos
t�rol�k elveinek, ez�rt ezek a .majdnem-t�rol�k. nem mindig cser�lhetok fel a
teljesen kifejlesztett
t�rol�kkal, p�ld�ul a vector vagy a list oszt�lyokkal.
17.5.1. Karakterl�ncok
A basic_string oszt�ly lehetos�get ad indexel�sre, haszn�lhatunk k�zvetlen el�r�su
bej�r�-
kat �s a t�rol�kn�l megszokott k�nyelmi lehetos�gek t�bbs�ge is rendelkez�s�nkre
�ll (20.
fejezet). A basic_string azonban nem teszi lehetov�, hogy annyif�le t�pust
haszn�ljunk
elemk�nt, mint a t�rol�kban. Legink�bb karakterl�ncokhoz felel meg �s �ltal�ban a
t�rol�kt
�l jelentosen elt�ro form�ban haszn�ljuk.
17.5.2. A valarray
A valarray kifejezetten a sz�mokkal v�gzett muveletekhez k�sz�lt vektor, �gy nem
is akar
�ltal�nos t�rol� lenni. Ehelyett sz�mos hasznos matematikai muveletet biztos�t,
m�g a szabv
�nyos t�rol�k muveletei (�17.1.1) k�z�l csak a size() �s az indexel�s �ll a
rendelkez�s�nkre
(�22.4.2). A valarray elemeit k�zvetlen el�r�su bej�r�val �rhetj�k el (�19.2.1).
17.5.3. Bithalmazok
Egy rendszer szempontj�b�l gyakran van sz�ks�g arra, hogy p�ld�ul egy bemeneti
adatfolyamot
(�21.3.3) egy sor k�t�rt�ku (p�ld�ul j�/rossz, igaz/hamis, kikapcsolt/bekapcsolt)
�llapotjelz
ovel �rjunk le. A C++ eg�sz �rt�kekre megval�s�tott bitszintu muveletek seg�ts�g�-

vel t�mogatja az ilyen �llapotjelzok hat�kony kezel�s�t (amennyiben csak n�h�ny


van
belol�k). Ilyen muvelet az & (�s), a | (vagy), a ^ (kiz�r� vagy), a << (l�ptet�s
balra) �s a >>
(l�ptet�s jobbra). A bitset<N> oszt�ly ezt a fogalmat �ltal�nos�tja. Seg�ts�g�vel
egyszeruen
v�gezhet�nk muveleteket N darab biten, melyeket 0-t�l N.1-ig indexel�nk. Az N
�rt�k�t
ford�t�si idoben r�gz�tj�k. Egy olyan bitsorozat eset�ben, amely nem f�r el egy
long int v�ltoz
�ban, a bitset haszn�lata sokkal k�nyelmesebb, mint az int �rt�kek k�zvetlen
kezel�se.
Kevesebb jelzobit eset�ben hat�konys�gi szempontok alapj�n kell d�nten�nk. Ha a
biteket
sorsz�moz�s helyett el szeretn�nk nevezni, halmazt (set, �17.4.3), felsorol�si
t�pust (�4.8),
vagy bitmezot (bitfield, �C.8.1) haszn�lhatunk.
652 A standard k�nyvt�r
A bitset<N> N darab bit t�mbj�nek tekintheto. A bitset a vector<bool> oszt�lyt�l
abban k�-
l�nb�zik, hogy r�gz�tett m�retu, a set t�rol�t�l abban, hogy eg�szekkel �s nem
asszociat�v
�rt�kkel indexelheto, illetve mindkettotol elt�r abban, hogy k�zvetlen
bitmuveleteket k�n�l.
Egy be�p�tett mutat� (�5.1) seg�ts�g�vel nem tudunk biteket kijel�lni, ez�rt a
bitset oszt�lynak
meg kell hat�roznia egy .hivatkoz�s bitre. t�pust. Ez a m�dszer �ltal�nosan
haszn�lhat
� olyan objektumok eset�ben, melyekhez a be�p�tett mutat�k valamilyen okb�l nem
haszn�lhat�k:
template<size_t N> class std::bitset {
public:
class reference { // hivatkoz�s egyetlen bitre
friend class bitset;
reference();
public: // b[i] az (i+1)-edik bitre hivatkozik
~reference();
reference& operator=(bool x); // b[i] = x;
reference& operator=(const reference&); // b[i] = b[j];
bool operator~() const; // return ~b[i]
operator bool() const; // x = b[i];
reference& flip(); // b[i].flip();
};
// ...
};
A bitset sablon az std n�vt�rhez tartozik �s a <bitset> fej�llom�ny seg�ts�g�vel
�rhetj�k el.
A C++ t�rt�net�re visszany�l� okokb�l a bitset n�h�ny szempontb�l elt�r a standard
k�nyvt
�r oszt�lyainak st�lus�t�l. P�ld�ul, ha egy index (amit gyakran bitpoz�ci�nak
nevez�nk) k�-
v�l esik a megengedett tartom�nyon, akkor egy out_of_range kiv�tel keletkezik. Nem
�llnak
rendelkez�s�nkre bej�r�k. A bitpoz�ci�kat jobbr�l balra sz�mozzuk, ugyan�gy, ahogy

a biteket egy g�pi sz�ban. �gy a b[i] bit �rt�ke pow(2,i). A bitset teh�t egy N
bites bin�ris
sz�mnak tekintheto:
17. Szabv�nyos t�rol�k 653
1 1 1 1 0 1 1 1 0 1
pozici�: 9 8 7 6 5 4 3 2 1 0
bitset<10>(989)
17.5.3.1. Konstruktorok
Egy bitset objektumot l�trehozhatunk alap�rtelmezett �rt�kkel, valamint egy
unsigned long
int vagy egy string bitjeibol is:
template<size_t N> class bitset {
public:
// ...
// konstruktorok
bitset(); // N nulla bit
bitset(unsigned long val); // bitek a val-b�l
template<class Ch, class Tr, class A> // Tr karakter-jellemzo (�20.2)
explicit bitset(const basic_string<Ch,Tr,A>& str, // bitek az str karakterl�ncb�l
basic_string<Ch,Tr,A>::size_type pos = 0,
basic_string<Ch,Tr,A>::size_type n = basic_string<Ch,Tr,A>::npos);
// ...
};
A bitek alap�rtelmezett �rt�ke 0. Ha unsigned long int param�tert adunk meg, akkor

a sz�m minden egyes bitje a neki megfelelo bit kezdo�rt�k�t hat�rozza meg. A
basic_string
(20. fejezet) ugyan�gy muk�dik; a .0. karakter jelenti a 0 bit�rt�ket, az .1.
karakter az 1 bit-
�rt�ket. Minden m�s karakter invalid_argument kiv�telt v�lt ki. Alap�rtelmez�s
szerint
a rendszer a bitek be�ll�t�s�hoz teljes karakterl�ncot haszn�l, de a basic_string
konstruktor�nak (�20.3.4) megfelelo st�lusban megadhatjuk, hogy a karaktereknek
csak egy
r�sztartom�ny�t haszn�ljuk, a pos poz�ci�t�l kezdve a l�nc v�g�ig vagy a pos+n
poz�ci�ig:
void f()
{
bitset<10> b1; // all 0
bitset<16> b2 = 0xaaaa; // 1010101010101010
bitset<32> b3 = 0xaaaa; // 00000000000000001010101010101010
bitset<10> b4("1010101010"); // 1010101010
bitset<10> b5("10110111011110",4); // 0111011110
bitset<10> b6("10110111011110",2,8); // 0011011101
bitset<10> b7("n0g00d"); // invalid_argument v�lt�dott ki
bitset<10> b8 = "n0g00d"; // hiba: nincs char*-r�l bitset-re val� �talak�t�s
}
A bitset oszt�ly alapveto c�lja az, hogy egyetlen g�pi sz� helyig�nyu
bitsorozathoz hat�-
kony megold�st adhassunk. A fel�letet ennek a szeml�letnek megfeleloen alak�tott�k
ki.
654 A standard k�nyvt�r
17.5.3.2. Bitkezelo muveletek
A bitset sz�mos olyan muveletet biztos�t, melyekkel egyes biteket �rhet�nk el vagy
az
�sszes bitet egyszerre kezelhetj�k:
template<size_t N> class std::bitset {
public:
// ...
// bithalmaz-muveletek
reference operator[ ](size_t pos); // b[i]
bitset& operator&=(const bitset& s); // �s
bitset& operator|=(const bitset& s); // vagy
bitset& operator^=(const bitset& s); // kiz�r� vagy
bitset& operator<<=(size_t n); // logikai eltol�s balra (felt�lt�s null�kkal)
bitset& operator>>=(size_t n); // logikai eltol�s jobbra (felt�lt�s null�kkal)
bitset& set(); // minden bit 1-re �ll�t�sa
bitset& set(size_t pos, int val = 1); // b[pos]=val
bitset& reset(); // minden bit 0-ra �ll�t�sa
bitset& reset(size_t pos); // b[pos]=0
bitset& flip(); // minden bit �rt�k�nek m�dos�t�sa
bitset& flip(size_t pos); // b[pos] �rt�k�nek m�dos�t�sa
bitset operator~() const { return bitset<N>(*this).flip(); } // komplemens halmaz
// l�trehoz�sa
bitset operator<<(size_t n) const { return bitset<N>(*this)<<=n; } // eltolt
halmaz
// l�trehoz�sa
bitset operator>>(size_t n) const { return bitset<N>(*this)>>=n; } // eltolt
halmaz
// l�trehoz�sa
// ...
};
Az indexelo oper�tor out_of_range kiv�telt v�lt ki, ha a megadott index k�v�l esik
a megengedett
tartom�nyon. Nem ellenorz�tt indexel�sre nincs lehetos�g.
A muveletek �ltal visszaadott bitset& �rt�k a *this. Azok a muveletek, melyek a
bitset& helyett
bitset �rt�ket adnak vissza, egy m�solatot k�sz�tenek a *this objektumr�l, ezen a
m�-
solaton v�gzik el a k�v�nt muveletet, �s ennek eredm�ny�t adj�k vissza. Fontos,
hogy a <<
�s a >> muveletek itt t�nyleg eltol�st jelentenek �s nem be- vagy kimeneti
muveleteket.
17. Szabv�nyos t�rol�k 655
A bitset kimeneti oper�tora egy olyan << f�ggv�ny, melynek k�t param�tere egy
ostream
�s egy bitset (�17.5.3.3).
Amikor a biteket eltoljuk, logikai eltol�s t�rt�nik (teh�t nem ciklikus). Ez azt
jelenti, hogy
n�h�ny bit .kiesik., m�sok pedig az alap�rtelmezett 0 �rt�ket kapj�k meg. Mivel a
size_t t�-
pus elojel n�lk�li, arra nincs lehetos�g�nk, hogy negat�v sz�mmal toljuk el a
bitsorozatot.
Ennek k�vetkezt�ben a b<<-1 utas�t�s egy igen nagy pozit�v sz�mmal tolja el a
biteket, �gy
a b bitset minden bitj�nek �rt�ke 0 lesz. A ford�t�k �ltal�ban figyelmeztetnek
erre a hib�ra.
17.5.3.3. Tov�bbi muveletek
A bitset is t�mogatja az olyan szok�sos muveleteket, mint a size(), az ==, a ki-
�s bemenet stb.:
template<size_t N> class bitset {
public:
// ...
unsigned long to_ulong() const;
template <class Ch, class Tr, class A> basic_string<Ch,Tr,A> to_string() const;
size_t count() const; // 1 �rt�ku bitek sz�ma
size_t size() const { return N; } // bitek sz�ma
bool operator==(const bitset& s) const;
bool operator!=(const bitset& s) const;
bool test(size_t pos) const; // igaz, ha b[pos] �rt�ke 1
bool any() const; // igaz, ha b�rmelyik bit �rt�ke 1
bool none() const; // igaz, ha egyik bit �rt�ke sem 1
};
A to_ulong() �s a to_string() f�ggv�ny a megfelelo konstruktor ford�tott (inverz)
muvelete.
A f�lre�rtheto �talak�t�sok elker�l�se �rdek�ben a szok�sos konverzi�s oper�torok
helyett
a fenti muveletek �llnak rendelkez�s�nkre. Ha a bitset objektumnak olyan bitjei is
�rt�ket
tartalmaznak, melyek nem �br�zolhat�k unsigned long int form�ban, a to_ulong()
f�ggv
�ny overflow_error kiv�telt v�lt ki.
A to_string() muvelet a megfelelo t�pus� karakterl�ncot �ll�tja elo, amely '0' �s
'1' karakterekb
ol �p�l fel. A basic_string a karakterl�ncok �br�zol�s�hoz haszn�lt sablon (20.
fejezet).
656 A standard k�nyvt�r
A to_string() f�ggv�nyt haszn�lhatjuk egy int bin�ris alakj�nak ki�rat�s�hoz is:
void binary(int i)
{
bitset<8*sizeof(int)> b = i; // 8 bites b�jtot t�telez�nk fel (l�sd m�g �22.2)
cout << b.template to_string< char,char_traits<char>,allocator<char> >() << '\n';
}
Sajnos egy minos�tett sablon tag megh�v�sa igen bonyolult �s ritk�n haszn�lt
utas�t�sform�t
k�vetel (�C.13.6). A tagf�ggv�nyeken k�v�l a bitset lehetov� teszi a logikai &
(�s), a | (vagy),
a ^ (kiz�r� vagy), valamint a szok�sos ki- �s bemeneti oper�torok haszn�lat�t is:
template<size_t N> bitset<N> std::operator&(const bitset<N>&, const bitset<N>&);
template<size_t N> bitset<N> std::operator|(const bitset<N>&, const bitset<N>&);
template<size_t N> bitset<N> std::operator^(const bitset<N>&, const bitset<N>&);
template <class charT, class Tr, size_t N>
basic_istream<charT,Tr>& std::operator>>(basic_istream<charT,Tr>&, bitset<N>&);
template <class charT, class Tr, size_t N>
basic_ostream<charT,Tr>& std::operator<<(basic_ostream<charT,Tr>&, const
bitset<N>&);
Teh�t egy bitset objektumot ki�rathatunk an�lk�l is, hogy elobb karakterl�ncc�
alak�tan�nk:
void binary(int i)
{
bitset<8*sizeof(int)> b = i; // 8 bites b�jtot t�telez�nk fel (l�sd m�g �22.2)
cout << b << '\n';
}
Ez a programr�szlet null�k �s egyesek form�j�ban �rja ki a biteket �s a legnagyobb

helyi�rt�ku bit lesz a bal oldalon.


17.5.4. Be�p�tett t�mb�k
A be�p�tett t�mb�k t�mogatj�k az indexel�st �s . a szok�sos mutat�k form�j�ban .
a k�zvetlen el�r�su bej�r�k haszn�lat�t is (�2.7.2). A t�mb azonban nem tudja a
saj�t m�ret
�t, �gy a programoz�nak kell azt nyilv�ntartania. A t�mb�k �ltal�ban nem
biztos�tj�k
a szabv�nyos tagmuveleteket �s -t�pusokat.
N�ha nagyon hasznos az a lehetos�g, hogy egy be�p�tett t�mb�t elrejthet�nk a
szabv�nyos
t�rol�k k�nyelmes jel�l�srendszere m�g�, �gy, hogy k�zben megtartjuk
alacsonyszintu term
�szet�nek elonyeit:
17. Szabv�nyos t�rol�k 657
template<class T, int max> struct c_array {
typedef T value_type;
typedef T* iterator;
typedef const T* const_iterator;
typedef T& reference;
typedef const T& const_reference;
T v[max];
operator T*() { return v; }
reference operator[ ](size_t i) { return v[i]; }
const_reference operator[ ](ptrdiff_t i) const { return v[i]; }
iterator begin() { return v; }
const_iterator begin() const { return v; }
iterator end() { return v+max; }
const_iterator end() const { return v+max; }
ptrdiff_t size() const { return max; }
};
A t�mb�kkel val� kompatibilit�s miatt az elojeles ptrdiff_t t�pust (16.2.2)
haszn�lom indexk
�nt az elojel n�lk�li size_t helyett.
A c_array sablon nem r�sze a standard k�nyvt�rnak. Mind�ssze egyszeru p�ldak�nt
szerepel
itt arra, hogy egy .idegen. t�rol�t hogyan igaz�thatunk a szabv�nyos t�rol�k
keretrendszer
�hez. Ez az oszt�ly olyan szabv�nyos algoritmusokhoz (18. fejezet) haszn�lhat�,
melyeknek
a begin(), end() stb. muveletekre van sz�ks�g�k. A verembe an�lk�l helyezheto,
hogy k�zvetve dinamikus mem�ri�t haszn�ln�nk, �s ezenk�v�l �tadhat� olyan C
st�lus�
f�ggv�nyeknek is, melyek mutat�t v�rnak param�terk�nt:
void f(int* p, int sz); // C st�lus
void g()
{
c_array<int,10> a;
f(a,a.size()); // C st�lus� haszn�lat
c_array<int,10>::iterator p = find(a.begin(),a.end(),777); // C++/STL st�lus�
// haszn�lat
// ...
}
658 A standard k�nyvt�r
17.6. �j t�rol�k l�trehoz�sa
A szabv�nyos t�rol�k olyan keretrendszert biztos�tanak, melyet a programoz�
szabadon
bov�thet. Az al�bbiakban azt mutatom be, hogyan k�sz�thet�nk olyan t�rol�kat,
melyek felcser
�lhetok a szabv�nyos t�rol�kkal, ha indokolt. A bemutatott p�lda a gyakorlatban is
mu-
k�dik, de nem optim�lis. A fel�letet �gy v�lasztottam meg, hogy az nagyon k�zel
�lljon
a hash_map l�tezo, sz�les k�rben el�rheto, magas szintu megval�s�t�saihoz. Az itt
bemutatott
hash_map arra haszn�lhat�, hogy megtanuljuk az �ltal�nos alapelveket. Komoly munk
�hoz haszn�ljunk ink�bb a t�mogatott hash_map t�pust.
17.6.1. A hash_map
A map olyan asszociat�v t�rol�, melynek szinte b�rmilyen t�pus� eleme lehet,
hiszen az
egyetlen k�vetelm�ny egy .kisebb mint. muvelet az elemek �sszehasonl�t�s�hoz
(�17.4.1.5). Ha azonban t�bbet tudunk a kulcs t�pus�r�l, �ltal�ban ler�vid�thetj�k
az elemek
megtal�l�s�hoz sz�ks�ges idot, azzal, hogy has�t� f�ggv�nyt (hash function)
k�sz�t�nk �s
a t�rol�t has�t� t�blak�nt (hash table) val�s�tjuk meg.
A has�t� f�ggv�ny egy olyan elj�r�s, amely egy �rt�khez gyorsan hozz� tud rendelni
egy indexet,
m�gpedig �gy, hogy k�t k�l�nb�zo �rt�k ritk�n kapja ugyanazt. A has�t� t�bla ezut
�n l�nyeg�ben �gy muk�dik, hogy az �rt�ket a kisz�m�tott indexre helyezi, ha az
m�g
�res, ellenkezo esetben az index .k�zel�be.. Ha egy elem a hozz� rendelt indexen
tal�lhat
�, akkor annak megtal�l�sa nagyon gyors lehet, de az index .k�zel�ben. elhelyezett
elem
keres�se sem t�l lass�, ha az elemek egyenlos�g�nek vizsg�lata megfeleloen gyors.
Ez�rt
azt�n nem ritka, hogy olyan nagyobb t�rol�k eset�ben, ahol a keres�s a
legjelentosebb mu-
velet, a hash_map ak�r 5.10-szer gyorsabban v�gzi el ezt a feladatot, mint a map.
Ugyanakkor
az is igaz, hogy a hash_map egy rosszul megv�lasztott has�t� f�ggv�nnyel m�g
a map-n�l is sokkal lassabb lehet.
Has�t� t�bl�t sokf�lek�ppen k�sz�thet�nk. A hash_table fel�let�nek csak ott kell
k�l�nb�znie
a szabv�nyos t�rol�k fel�let�tol, ahol a has�t�s hat�konys�ga ezt megk�veteli. A
legalapvet
obb k�l�nbs�g a map �s a hash_map k�z�tt, hogy a map a < muvelettel hasonl�tja
�ssze az elemeit, m�g a hash_map az == muveletet haszn�lja �s sz�ks�ge van egy
has�t�
f�ggv�nyre is. Teh�t ha a hash_map objektumot nem alap�rtelmezett be�ll�t�sokkal
akarjuk
l�trehozni, akkor a param�terek jelentosen elt�rnek a map t�rol�n�l haszn�ltakt�l:

map<string,int> m1; // karakterl�ncok �sszehasonl�t�sa < haszn�lat�val


map<string,int,Nocase> m2; // karakterl�ncok �sszehasonl�t�sa Nocase()
// haszn�lat�val (�17.1.4.1)
17. Szabv�nyos t�rol�k 659
hash_map<string,int> hm1; // has�t�s Hash<string>() haszn�lat�val (�17.6.2.3),
// �sszehasonl�t�s == haszn�lat�val
hash_map<string,int,hfct> hm2; // has�t�s hfct() haszn�lat�val, �sszehasonl�t�s ==

// haszn�lat�val
hash_map<string,int,hfct,eql> hm3; // has�t�s hfct() haszn�lat�val,
�sszehasonl�t�s eql
// haszn�lat�val
A has�t�sos keres�st haszn�l� t�rol�t egy vagy t�bb t�bl�zat seg�ts�g�vel
hozhatjuk l�tre.
Az elemek t�rol�s�n k�v�l a t�rol�nak nyilv�n kell tartania azt is, milyen �rt�ket
milyen has
�tott �rt�khez (az elozoekben .index.) rendelt hozz�. Erre szolg�l a .has�t�
t�bla.. A has�-
t� t�bl�k teljes�tm�nye �ltal�ban jelentosen romlik, ha t�ls�gosan tel�tett�
v�lnak, teh�t
mondjuk 75 sz�zal�kig megteltek. Ez�rt az al�bbiakban le�rt hash_map automatikusan
n�-
veli m�ret�t, ha t�l tel�tett� v�lik. Az �tm�retez�s azonban rendk�v�l k�lts�ges
muvelet lehet,
�gy mindenk�ppen lehetov� kell tenn�nk egy kezdeti m�ret megad�s�t.
Ezek alapj�n a hash_map elso v�ltozata a k�vetkezo lehet:
template<class Key, class T, class H = Hash<Key>,
class EQ = equal_to<Key>, class A = allocator< pair<const Key,T> > >
class hash_map {
// mint a map, kiv�ve a k�vetkezoket:
typedef H Hasher;
typedef EQ key_equal;
hash_map(const T& dv =T(), size_type n =101, const H& hf =H(), const EQ& =EQ());
template<class In> hash_map(In first, In last,
const T& dv =T(), size_type n =101, const H& hf =H(), const EQ& =EQ());
};
Ez l�nyeg�ben megegyezik a map fel�let�vel (�17.4.1.4), csak a < muveletet az ==
oper�-
torral helyettes�tett�k �s megadtunk egy has�t� f�ggv�nyt is.
A k�nyvben eddig haszn�lt map objektumok (�3.7.4, �6.1, �17.4.1) k�nnyed�n
helyettes�thetok
a hash_map szerkezettel. Nem kell m�st tenn�nk, csak a map nevet �t kell �rnunk
hash_mapre.
A map cser�j�t hash_map-re �ltal�ban leegyszerus�thetj�k egy typedef utas�t�ssal:
typedef hash_map<string,record> Map;
Map dictionary;
A typedef arra is haszn�lhat�, hogy a sz�t�r (dictionary) t�nyleges t�pus�t
elrejts�k a felhaszn
�l�k elol.
660 A standard k�nyvt�r
B�r a meghat�roz�s nem eg�szen pontos, a map �s a hash_map k�z�tti ellent�tet
tekinthetj
�k egyszeruen t�r-ido ellent�tnek. Ha a hat�konys�g nem fontos, nem �rdemes idot
vesztegetni
a k�z�tt�k val� v�laszt�sra: mindketto j�l haszn�lhat�. Nagy �s neh�zkesen
haszn�lhat
� t�bl�k eset�ben a hash_map jelentos elonye a sebess�g, �s ezt �rdemes
haszn�lnunk,
hacsak nem fontos a kis t�rig�ny. M�g ha takar�koskodnunk is kell a mem�ri�val,
akkor is
�rdemes megvizsg�lnunk n�h�ny egy�b lehetos�get a t�rig�ny cs�kkent�s�re, mielott
az
.egyszeru. map szerkezetet v�lasztjuk. Az aktu�lis m�ret kisz�m�t�sa nagyon fontos
ahhoz,
hogy ne egy alapjaiban rossz k�dot pr�b�ljunk optimaliz�lni.
A hat�kony has�t�s megval�s�t�s�nak legfontosabb r�sze a megfelelo has�t� f�ggv�ny
megv
�laszt�sa. Ha nem tal�lunk j� has�t� f�ggv�nyt, akkor a map k�nnyen
t�lsz�rnyalhatja
a hash_map hat�konys�g�t. A C st�lus� karakterl�ncokra vagy eg�sz sz�mokra �p�lo
has�-
t�s �ltal�ban el�g hat�kony tud lenni, de mindig �rdemes arra gondolnunk, hogy egy
has�-
t� f�ggv�ny hat�konys�ga nagym�rt�kben f�gg az aktu�lis �rt�kektol, melyeket
has�tanunk
kell (�17.8[35]). A hash_map t�rol�t kell haszn�lnunk akkor, ha a kulcshoz nem
adhatunk
meg < muveletet vagy az nem felel meg elv�r�sainknak. Megford�tva: a has�t�
f�ggv�ny
nem hat�roz meg az elemek k�z�tt olyan sorrendet, mint amilyet a < oper�tor, �gy a
map
oszt�lyra van sz�ks�g�nk, ha az elemek sorrendje fontos. A map oszt�lyhoz
hasonl�an
a hash_map is biztos�t egy find() f�ggv�nyt, amely meg�llap�tja, hogy egy kulcs
szerepel-e
m�r a t�rol�ban.
17.6.2. �br�zol�s �s l�trehoz�s
A hash_map sokf�lek�ppen megval�s�that�. Itt egy olyan form�t mutatok be, amely
viszonylag
gyors, de legfontosabb muveletei el�g egyszeruek. Ezek a muveletek
a konstruktorok, a keres�s (a [ ] oper�tor), az �tm�retez�s �s az egy elem
t�rl�s�t v�gzo
f�ggv�ny (erase()).
A has�t� t�bla itt bemutatott egyszeru megval�s�t�sa egy olyan vektort haszn�l,
amely a bejegyz
�sekre hivatkoz� mutat�kat t�rolja. Minden bejegyz�sben (Entry) szerepel egy kulcs

(key), egy �rt�k (value) , egy mutat� a k�vetkezo ugyanilyen has�t�k�ddal


rendelkezo
Entry bejegyz�sre (ha van ilyen), illetve egy t�r�lts�get jelzo (erased) bit:
17. Szabv�nyos t�rol�k 661
kulcs �rt�k t�r�lt k�vetkezo
kulcs �rt�k t�r�lt k�vetkezo
...
Ez deklar�ci� form�j�ban a k�vetkezok�ppen n�z ki.
template<class Key, class T, class H = Hash<Key>,
class EQ = equal_to<Key>, class A = allocator< pair<const Key,T> > >
class hash_map {
// ...
private: // �br�zol�s
struct Entry {
key_type key;
mapped_type val;
bool erased;
Entry* next; // hash-t�lcsordul�s eset�re
Entry(key_type k, mapped_type v, Entry* n)
: key(k), val(v), next(n), erased(false) { }
};
vector<Entry> v; // az aktu�lis bejegyz�sek
vector<Entry*> b; // a has�t� t�bla: mutat� v-be
// ...
};
Vizsg�ljuk meg az erased bit szerep�t. Az ugyanolyan has�t�k�ddal rendelkezo
elemek kezel
�s�nek m�dja miatt nagyon neh�z lenne egy bizonyos elemet t�r�lni. Ez�rt a
t�nyleges
t�rl�s helyett az erase() megh�v�sakor csak az erased bitet jel�lj�k be, �s az
elemet mindaddig
figyelmen k�v�l hagyjuk, am�g a t�bl�t �t nem m�retezz�k.
A fo adatszerkezet mellett a hash_map oszt�lynak egy�b adatokra is sz�ks�ge van.
Term�-
szetesen minden konstruktornak az �sszes adattagot be kell �ll�tania:
template<class Key, class T, class H = Hash<Key>,
class EQ = equal_to<Key>, class A = allocator< pair<const Key,T> > >
class hash_map {
// ...
hash_map(const T& dv =T(), size_type n =101, const H& h =H(), const EQ& e =EQ())
: default_value(dv), b(n), no_of_erased(0), hash(h), eq(e)
{
set_load(); // alap�rtelmez�s
v.reserve(max_load*b.size()); // hely biztos�t�sa a n�veked�shez
}
void set_load(float m = 0.7, float g = 1.6) { max_load = m; grow = g; }
// ...
662 A standard k�nyvt�r
private:
float max_load; // v.size()<=b.size()*max_load megtart�sa
float grow; // ha sz�ks�ges, resize(bucket_count()*grow)
size_type no_of_erased; // v azon bejegyz�seinek sz�ma, amelyeket t�r�lt elem
foglal el
Hasher hash; // has�t� f�ggv�ny
key_equal eq; // egyenlos�g
const T default_value; // a [ ] �ltal haszn�lt alap�rtelmezett �rt�k
};
A szabv�nyos asszociat�v t�rol�k megk�vetelik, hogy a hozz�rendelt �rt�k t�pusa
alap�rtelmezett
�rt�kkel rendelkezzen (�17.4.1.7). Ez a k�vetelm�ny val�j�ban nem elengedhetetlen
�s bizonyos esetekben nagyon k�nyelmetlen is lehet. Ez�rt az alap�rtelmezett
�rt�ket param
�terk�nt vessz�k �t, ami lehetov� teszi a k�vetkezo sorok le�r�s�t:
hash_map<string,Number> phone_book1; // alap�rtelmez�s: Number()
hash_map<string,Number> phone_book2(Number(411)); // alap�rtelmez�s: Number(411)
17.6.2.1. Keres�sek
V�g�l el�rkezt�nk a kritikus keres�si f�ggv�nyekhez:
template<class Key, class T, class H = Hash<Key>,
class EQ = equal_to<Key>, class A = allocator< pair<const Key,T> > >
class hash_map {
// ...
mapped_type& operator[ ](const key_type&);
iterator find(const key_type&);
const_iterator find(const key_type&) const;
// ...
};
Az �rt�kek megtal�l�s�hoz az operator[ ]() a has�t� f�ggv�nyt haszn�lja, mellyel
kisz�m�tja
a kulcshoz tartoz� indexet a has�t� t�bl�ban. Ezut�n v�gign�zi az adott index
alatt tal�lhat
� bejegyz�seket, am�g meg nem tal�lja a k�v�nt kulcsot. Az �gy megtal�lt Entry
objektumban
tal�lhat� az a value �rt�k, amelyet kerest�nk. Ha nem tal�ltuk meg a kulcsot,
akkor
alap�rtelmezett �rt�kkel felvesz�nk egy �j elemet:
17. Szabv�nyos t�rol�k 663
template<class Key, class T, class H = Hash<Key>,
class EQ = equal_to<Key>, class A = allocator< pair<const Key,T> > >
hash_map<Key,T,H,EQ,A>::mapped_type& hash_map<Key,T,H,EQ,A>::operator[ ](const
key_type& k)
{
size_type i = hash(k)%b.size(); // has�t�s
for(Entry* p = b[i]; p; p = p->next) // keres�s a has�t�s eredm�nyek�ppen i-be
ker�lt
// elemek k�z�tt
if (eq(k,p->key)) { // megvan
if (p->erased) { // �jb�li besz�r�s
p->erased = false;
no_of_erased--;
return p->val = default_value;
}
return p->val;
}
// ha nincs meg
if (size_type(b.size()*max_load) <= v.size()) { //ha "tel�tett"
resize(b.size()*grow); // n�veked�s
return operator[ ](k); // �jrahas�t�s
}
v.push_back(Entry(k,default_value,b[i])); // Entry hozz�ad�sa
b[i] = &v.back(); // az �j elemre mutat
return b[i]->val;
}
A map megold�s�t�l elt�roen a hash_map nem a .kisebb mint. muveletbol
sz�rmaztathat�
egyenlos�gvizsg�latot (�17.1.4.1) haszn�lja, hiszen az azonos has�t�k�ddal
rendelkezo elemeket
v�gign�zo ciklusban az eq() f�ggv�ny megh�v�sa pontosan ezt a feladatot l�tja el.
Ez
a ciklus nagyon fontos a keres�s hat�konys�ga szempontj�b�l, a leggyakoribb
kulcst�pusok
(p�ld�ul a string, vagy a C st�lus� karakterl�ncok) szempontj�b�l pedig egy
felesleges
�sszehasonl�t�s ak�r jelentos teljes�tm�nyroml�st is eredm�nyezhet.
Az azonos has�t�k�ddal rendelkezo elemek t�rol�s�hoz haszn�lhattuk volna a
set<Entry>
t�rol�t is, de ha el�g j� has�t�f�ggv�ny�nk (hash()) van �s a has�t�t�bla (b)
m�rete is megfelel
o, akkor ezen halmazok t�bbs�g�ben egyetlen elem lesz. Ez�rt ezeket az elemeket
egyszer
uen az Entry oszt�ly next mezoj�vel kapcsoltam �ssze (�17.8[27]).
Figyelj�k meg, hogy a b az elemekre hivatkoz� mutat�kat t�rolja �s az elemek
val�j�ban
a v-be ker�lnek. A push_back() �ltal�ban megtehetn�, hogy �thelyezi az elemeket,
�s ezzel
664 A standard k�nyvt�r
a mutat�k �rv�nytelenn� v�ln�nak (�16.3.5), most azonban a konstruktorok (�17.6.2)
�s
a resize() f�ggv�ny elore helyet foglalnak az elemek sz�m�ra a reserve()
elj�r�ssal, �gy elker
�lj�k a v�ratlan �thelyez�seket.
17.6.2.2. T�rl�s �s �tm�retez�s
A has�t�f�ggv�nyes keres�s nagyon rossz hat�sfok�v� v�lhat, ha a t�bla t�ls�gosan
tel�tett.
Az ilyen kellemetlens�gek elker�l�se �rdek�ben az indexelo oper�tor automatikusan
�tm�-
retezheti a t�bl�t. A set_load() (�17.6.2) f�ggv�ny szab�lyozza, hogy ez az
�tm�retez�s mikor
�s hogyan menjen v�gbe, n�h�ny tov�bbi f�ggv�nnyel pedig lehetov� tessz�k a
programoz
� sz�m�ra, hogy lek�rdezze a hash_map �llapot�t:
template<class Key, class T, class H = Hash<Key>,
class EQ = equal_to<Key>, class A = allocator< pair<const Key,T> > >
class hash_map {
// ...
void resize(size_type n); // a has�t� t�bla m�ret�nek n-re �ll�t�sa
void erase(iterator position); // a mutatott elem t�rl�se
size_type size() const { return v.size()-no_of_erased; } // az elemek sz�ma
size_type bucket_count() const { return b.size(); } // a has�t� t�bla m�rete
Hasher hash_fun() const { return hash; } // a haszn�lt has�t� f�ggv�ny
key_equal key_eq() const { return eq; } // a haszn�lt egyenlos�gvizsg�lat
// ...
};
A resize() f�ggv�ny rendk�v�l fontos, viszonylag egyszeru, de n�ha rendk�v�l
.dr�ga.
muvelet:
template<class Key, class T, class H = Hash<Key>,
class EQ = equal_to<Key>, class A = allocator< pair<const Key,T> > >
void hash_map<Key,T,H,EQ,A>::resize(size_type s)
{
size_type i = v.size();
while (no_of_erased) { // a "t�r�lt" elemek t�nyleges elt�vol�t�sa
if (v[--i].erased) {
v.erase(&v[i]);
--no_of_erased;
}
}
17. Szabv�nyos t�rol�k 665
if (s <= b.size()) return;
b.resize(s); // s-b.size() sz�m� mutat� hozz�ad�sa
fill(b.begin(),b.end(),0); // bejegyz�sek t�rl�se (�18.6.6)
v.reserve(s*max_load); // ha v-nek �jb�li mem�riafoglal�sra van sz�ks�ge, most
// t�rt�njen meg
if (no_of_erased) { // a "t�r�lt" elemek t�nyleges elt�vol�t�sa
for (size_type i = v.size()-1; 0<=i; i--)
if (v[i].erased) {
v.erase(&v[i]);
if (--no_of_erased == 0) break;
}
}
for (size_type i = 0; i<v.size(); i++) { // �jrahas�t�s
size_type ii = hash(v[i].key)%b.size(); // has�t�s
v[i].next = b[ii]; // l�ncol�s
b[ii] = &v[i];
}
}
Ha sz�ks�g van r�, a programoz� maga is megh�vhatja a resize() elj�r�st, �gy
biztos�thatja,
hogy az idovesztes�g kisz�m�that� helyen k�vetkezzen be. Tapasztalataim szerint
bizonyos
alkalmaz�sokban a resize() muvelet rendk�v�l fontos, de a has�t�t�bl�k
szempontj�b�l nem
n�lk�l�zhetetlen. Egyes megval�s�t�si m�dszerek egy�ltal�n nem haszn�lj�k.
Mivel a t�nyleges munka nagy r�sze m�shol t�rt�nik (�s csak akkor, amikor
�tm�retezz�k
a hash_map t�rol�t), az erase() f�ggv�ny nagyon egyszeru:
template<class Key, class T, class H = Hash<Key>,
class EQ = equal_to<Key>, class A = allocator< pair<const Key,T> > >
void hash_map<Key,T,H,EQ,A>::erase(iterator p) // a mutatott elem t�rl�se
{
if (p->erased == false) no_of_erased++;
p->erased = true;
}
17.6.2.3. Has�t�s
A hash_map::operator[ ]() teljess� t�tel�hez m�g meg kell hat�roznunk a hash() �s
az eq()
f�ggv�nyt. Bizonyos okokb�l (amelyeket majd a �18.4 pontban r�szletez�nk) a has�t�
f�ggv
�nyt �rdemesebb egy f�ggv�nyobjektum operator()() muveletek�nt elk�sz�ten�nk:
template <class T> struct Hash : unary_function<T, size_t> {
size_t operator()(const T& key) const;
};
666 A standard k�nyvt�r
A j� has�t� f�ggv�ny param�ter�ben egy kulcsot kap �s egy eg�sz �rt�ket ad vissza,
amely
k�l�nb�zo kulcsok eset�ben nagy val�sz�nus�ggel k�l�nb�zo. A j� has�t�f�ggv�ny
kiv�-
laszt�sa nagyon neh�z. Gyakran az vezet elfogadhat� eredm�nyhez, ha a kulcsot
jel�lo biteken
�s egy elore meghat�rozott eg�sz �rt�ken .kiz�r� vagy. muveletet hajtunk v�gre:
template <class T> size_t Hash<T>::operator()(const T& key) const
{
size_t res = 0;
size_t len = sizeof(T);
const char* p = reinterpret_cast<const char*>(&key); //objektumok el�r�se b�jtok
// sorozatak�nt
while (len--) res = (res<<1)^*p++; // a kulcs�br�zol�s b�jtjainak haszn�lata
return res;
}
A reinterpret_cast (�6.2.7) haszn�lata j�l jelzi, hogy valami .cs�nya. dolgot
muvelt�nk, �s
ha t�bbet tudunk a has�tott �rt�krol, akkor enn�l hat�konyabb megold�st is
tal�lhatunk.
P�ld�ul, ha az objektum mutat�t tartalmaz, ha nagy objektumr�l van sz�, vagy ha az
adattagok
igaz�t�sa miatt az objektum �br�zol�s�ban felhaszn�latlan ter�letek (.lyukak.,
holes)
vannak, mindenk�ppen jobb has�t�f�ggv�nyt k�sz�thet�nk (�17.8[29]).
A C st�lus� karakterl�ncok mutat�k (a karakterekre) �s a string is tartalmaz
mutat�t.
A specializ�ci�k ezekre az esetekre sorrendben a k�vetkezok:
size_t Hash<char*>::operator()(const char* key) const
{
size_t res = 0;
while (*key) res = (res<<1)^*key++; // a karakterek eg�sz �rt�k�nek haszn�lata
return res;
}
template <class C>
size_t Hash< basic_string<C> >::operator()(const basic_string<C>& key) const
{
size_t res = 0;
typedef basic_string<C>::const_iterator CI;
CI p = key.begin();
CI end = key.end();
while (p!=end) res = (res<<1)^*p++; // a karakterek eg�sz �rt�k�nek haszn�lata
return res;
}
17. Szabv�nyos t�rol�k 667
A hash_map minden megval�s�t�s�ban legal�bb az eg�sz �s a karakterl�nc t�pus�
kulcsokhoz
szerepelni�k kell has�t�f�ggv�nynek. Komolyabb kulcsok eset�ben a programoz�t seg
�thetj�k megfelelo specializ�ci�kkal is. A j� has�t�f�ggv�ny kiv�laszt�s�ban sokat
seg�thet
a megfelelo m�rosz�mokra t�maszkod� k�s�rletez�s. Meg�rz�seinkre nagyon ritk�n
hagyatkozhatunk
ezen a ter�leten.
A hash_map akkor v�lik teljess�, ha bej�r�kat is defini�lunk �s n�h�ny tov�bbi
egyszeru
f�ggv�nyt is k�sz�t�nk. Ez azonban maradjon meg feladatnak (�17.8[34]).
17.6.3. Tov�bbi has�tott asszociat�v t�rol�k
Az egys�gess�g �s a teljess�g �rdek�ben mindenk�ppen el kell k�sz�ten�nk a
hash_map
.testv�reit. is: a hash_set, a hash_multimap �s a hash_multiset t�rol�t. Ezek
l�trehoz�sa
a hash_map, a map, a multimap, a set �s a multiset alapj�n egyszeru, �gy ezeket is
meghagyom
feladatnak �17.8[34]. Ezeknek a has�tott asszociat�v t�rol�knak komoly irodalma
van
�s k�sz kereskedelmi v�ltozatok is el�rhetok belol�k. T�nyleges programokban ezek
a v�ltozatok
jobban haszn�lhat�k, mint a h�zilag �sszeeszk�b�ltak (k�zt�k az �ltalam bemutatott

is).
17.7. Tan�csok
[1] Ha t�rol�ra van sz�ks�g�nk, �ltal�ban a vector oszt�lyt haszn�ljuk. �17.1.
[2] Ha gyakran haszn�lunk egy muveletet, �rdemes ismerni annak k�lts�geit
(bonyolults�g, .nagy O. m�rt�k) �17.1.2.
[3] A t�rol� fel�lete, megval�s�t�sa �s �br�zol�sa k�l�n-k�l�n fogalom. Ne keverj
�k �ssze oket. �17.1.3.
[4] Keres�st vagy rendez�st b�rmilyen szempont szerint megval�s�thatunk.
�17.1.4.1.
[5] Ne haszn�ljunk kulcsk�nt C st�lus� karakterl�ncokat, vagy biztos�tsunk
megfelel
o �sszehasonl�t�si muveletet. �17.1.4.1.
[6] Az �sszehasonl�t�si szemponttal elemek egyen�rt�kus�g�t hat�rozhatjuk meg,
ami elt�rhet att�l, hogy a kulcsok teljesen egyenlok-e. �17.1.4.1.
[7] Lehetoleg haszn�ljuk a sorozat v�g�t m�dos�t� f�ggv�nyeket (back-muveletek),
ha elemek besz�r�s�ra vagy t�rl�s�re van sz�ks�g�nk. �17.1.4.1.
668 A standard k�nyvt�r
[8] Ha sok besz�r�sra, illetve t�rl�sre van sz�ks�g a sorozat elej�n vagy
belsej�ben,
haszn�ljuk a list t�rol�t.
[9] Ha az elemeket legt�bbsz�r kulcs alapj�n �rj�k el, haszn�ljuk a map vagy
a multimap szerkezetet. �17.4.1.
[10] A leheto legnagyobb rugalmass�got �gy �rhetj�k el, ha a leheto legkevesebb
muveletet haszn�ljuk. �17.1.1.
[11] Ha fontos az elemek sorrendje, a hash_map helyett haszn�ljuk a map oszt�lyt.
�17.6.1.
[12] Ha a keres�s sebess�ge a legfontosabb, a hash_map hasznosabb, mint a map.
�17.6.1.
[13] Ha nem tudunk az elemekre .kisebb mint. muveletet megadni, a hash_map
t�rol�t haszn�lhatjuk. �17.6.1.
[14] Ha azt akarjuk ellenorizni, hogy egy kulcs megtal�lhat�-e egy asszociat�v
t�rol�-
ban, haszn�ljuk a find() f�ggv�nyt. �17.4.1.6.
[15] Ha az adott kulccsal rendelkezo �sszes elemet meg akarjuk tal�lni, haszn�ljuk

az equal_range()-et. �17.4.1.6.
[16] Ha ugyanazzal a kulccsal t�bb elem is szerepelhet, haszn�ljuk a multimap
t�rol
�t. �17.4.2.
[17] Ha csak a kulcsot kell nyilv�ntartanunk, haszn�ljuk a set vagy a multiset
oszt
�lyt. �17.4.3.
17.8. Gyakorlatok
Az itt szereplo gyakorlatok t�bbs�g�nek megold�sa kider�l a standard k�nyvt�r
b�rmely
v�ltozat�nak forr�sk�dj�b�l. Mielott azonban megn�zn�nk, hogy a k�nyvt�r
megalkot�i
hogyan k�zel�tett�k meg az adott probl�m�t, �rdemes saj�t megold�st k�sz�ten�nk.
V�g�l
n�zz�k �t, hogy saj�t rendszer�nkben milyen t�rol�k �s milyen muveletek �llnak
rendelkez
�s�nkre.
1. (*2.5) �rts�k meg az O( ) jel�l�st (�17.1.2). V�gezz�nk n�h�ny m�r�st a szabv�-

nyos t�rol�k muveleteire �s hat�rozzuk meg a konstans szorz�kat.


2. (*2) Sok telefonsz�m nem �br�zolhat� egy long �rt�kkel. K�sz�ts�nk egy
phone_number t�pust �s egy oszt�lyt, amely meghat�rozza az �sszes olyan mu-
veletet, melyeknek egy telefonsz�mokat t�rol� t�rol�ban haszn�t vehetj�k.
3. (*2) �rjunk programot, amely ki�rja egy f�jl szavait �b�c�sorrendben.
K�sz�ts�nk
k�t v�ltozatot: az egyikben a sz� egyszeruen �reshely karakterekkel hat�rolt
karaktersorozat
legyen, a m�sikban olyan betusorozat, melyet nem betu karakterek
sorozata hat�rol.
17. Szabv�nyos t�rol�k 669
4. (*2.5) �rjunk egy egyszeru Paszi�nsz k�rtyaj�t�kot.
5. (*1.5) �rjunk programot, amely eld�nti, hogy egy sz� palindrom-e (azaz �br�zol
�sa szimmetrikus-e, p�ld�ul: ada, otto, tat). �rjuk elj�r�st, amely egy eg�sz
sz�mr�l d�nti el ugyanezt, majd k�sz�ts�nk mondatokat vizsg�l� f�ggv�nyt.
�ltal�nos�tsunk.
6. (*1.5) K�sz�ts�nk egy sort (queue) k�t verem seg�ts�g�vel.
7. (*1.5) K�sz�ts�nk egy vermet, amely majdnem olyan, mint a stack, csak nem
m�solja az elemeit �s lehetov� teszi bej�r�k haszn�lat�t.
8. (*3) Sz�m�t�g�p�nk minden bizonnyal t�mogat valamilyen konkurens (p�rhuzamos
v�grehajt�si) lehetos�get: sz�lakat (thread), taszkokat (task) vagy folyamatokat
(process). Der�ts�k ki, hogyan muk�dik ez. A konkurens hozz�f�r�st
lehetov� tevo rendszer valamilyen m�dot ad r�, hogy megakad�lyozzuk, hogy
k�t folyamat ugyanazt a mem�riater�letet egyszerre haszn�lja. Saj�t rendszer�nk
z�rol�si elj�r�sa alapj�n k�sz�ts�nk egy oszt�lyt, amely a programoz� sz�m�ra
egyszeruen el�rhetov� teszi ezt a lehetos�get.
9. (*2.5) Olvassuk be d�tumok egy sorozat�t (p�ld�ul: Dec85, Dec50, Jan76),
majd jelen�ts�k meg azt �gy, hogy a legk�sobbi idopont legyen az elso a sorban.
A d�tum form�tuma a k�vetkezo legyen: h�napn�v h�rom karakteren,
majd �vsz�m k�t karakteren. T�telezz�k fel, hogy mindegyik d�tum ugyanarra
az �vsz�zadra vonatkozik.
10. (*2.5) �ltal�nos�tsuk a d�tumok bemeneti form�tum�t �gy, hogy felismerje az
al�bbi d�tumform�tumokat: Dec1985, 12/3/1990, (Dec,30,1950), 3/6/2001, stb.
M�dos�tsuk a �17.8[9] feladatot �gy, hogy muk�dj�n ezekre a form�tumokra is.
11. (*1.5) Haszn�ljuk a bitset t�rol�t n�h�ny sz�m bin�ris alakj�nak ki�rat�s�hoz.

P�ld�ul 0, 1, -1, 18, -18 �s a legnagyobb pozit�v int �rt�k.


12. (*1.5) A bitset seg�ts�g�vel �br�zoljuk, hogy egy oszt�ly mely tanul�i voltak
jelen egy adott napon. Olvassuk be 12 nap bitset objektum�t �s �llap�tsuk meg,
kik voltak jelen minden nap, �s kik voltak legal�bb 8 napot az iskol�ban.
13. (*1.5) K�sz�ts�nk egy olyan mutat�kb�l �ll� list�t, amely t�rli a mutatott
objektumokat
is, ha egy mutat�t t�rl�nk belole vagy ha az eg�sz list�t megsz�ntetj�k.
14. (*1.5) �rassuk ki rendezve egy adott stack objektum elemeit an�lk�l, hogy az
eredeti vermet megv�ltoztatn�nk.
15. (*2.5) Fejezz�k be a hash_map (�17.6.1) megval�s�t�s�t. Ehhez meg kell �rnunk
a find() �s az equal_range() f�ggv�nyt, valamint m�dot kell adnunk a k�sz sablon
ellenorz�s�re. Pr�b�ljuk ki a hash_map oszt�lyt legal�bb egy olyan kulcst�-
pusra, melyre az alap�rtelmezett has�t�f�ggv�ny nem haszn�lhat�.
16. (*2.5) K�sz�ts�nk el egy list�t a szabv�nyos list st�lus�ban �s tesztelj�k.
17. (*2) Bizonyos helyzetekben a list t�lzott mem�ria-felhaszn�l�sa probl�m�t
jelent. K�sz�ts�nk egy egyir�ny� l�ncolt list�t a szabv�nyos t�rol�k st�lus�ban.
670 A standard k�nyvt�r
18. (*2.5) K�sz�ts�nk el egy list�t, amely olyan, mint a szabv�nyos list, csak
t�mogatja
az indexel�st is. Hasonl�tsunk �ssze n�h�ny list�ra az indexel�s k�lts�g�t
egy ugyanilyen m�retu vector indexel�si k�lts�g�vel.
19. (*2) K�sz�ts�nk egy sablon f�ggv�nyt, amely k�t t�rol�t �sszef�s�l.
20. (*1.5) �llap�tsuk meg, hogy egy C st�lus� karakterl�nc palindrom-e. Vizsg�ljuk

meg, hogy a karakterl�nc (legal�bb) elso h�rom szav�b�l �ll� sorozat palindrom-
e.
21. (*2) Olvassuk be (name,value) (n�v, �rt�k) p�rok egy sorozat�t �s k�sz�ts�nk
egy rendezett list�t (name, total, mean, median) (n�v, �sszesen, �tlag, k�z�p-
�rt�k) sorokb�l.
22. (*2.5) Vizsg�ljuk meg, mekkora az �ltalunk k�sz�tett t�rol�k t�rig�nye.
23. (*3.5) Gondolkozzunk el azon, milyen megval�s�t�si strat�gi�t haszn�lhatn�nk
egy olyan hash_map t�rol�hoz, melyn�l a leheto legkisebb t�rig�ny a legfobb
k�vetelm�ny. Hogyan k�sz�thetn�nk olyan hash_map oszt�lyt, melynek keres�-
si ideje minim�lis? N�zz�k �t, mely muveleteket �rdemes kihagyni a megval�s�-
t�sb�l az optim�lishoz (felesleges mem�riafoglal�s, illetve idovesztes�g n�lk�li)
k�zeli megold�s el�r�s�hez. Seg�ts�g: a has�t�t�bl�knak igen kiterjedt irodalma
van.
24. (*2) Dolgozzunk ki olyan elvet a hash_map t�lcsordul�s�nak (k�l�nb�zo �rt�-
kek ugyanazon has�t�k�dra ker�l�s�nek) kezel�s�re, amely az equal_range()
elk�sz�t�s�t egyszeruv� teszi.
25. (*2.5) Becs�lj�k meg a hash_map t�rig�ny�t, majd m�rj�k is le azt. Hasonl�tsuk

�ssze a becs�lt �s a sz�m�tott �rt�keket. Hasonl�tsuk �ssze az �ltalunk megval�-


s�tott hash_map �s map t�rig�ny�t.
26. (*2.5) Vizsg�ljuk meg saj�t hash_map oszt�lyunkat abb�l a szempontb�l, hogy
melyik muvelettel telik el a legt�bb ido. Tegy�k meg ugyanezt saj�t map t�rol
�nkra, illetve a hash_map kereskedelmi v�ltozataira is.
27. (*2.5) K�sz�ts�k el a hash_map t�rol�t egy vector<map<K,V>*> szerkezet seg�ts
�g�vel. Minden map t�rolja az �sszes olyan kulcsot, melyek has�t�k�dja megegyezik.

28. (*3) K�sz�ts�k el a hash_map oszt�lyt Splay f�k seg�ts�g�vel. (L�sd: D.


Sleator,
R. E. Tarjan:Self-Adjusting Binary Search Trees, JACM, 32. k�tet, 1985)
29. (*2) Adott egy strukt�ra, amely egy karakterl�nc-szeru egyedet �r le:
struct St {
int size;
char type_indicator;
char* buf; // m�retre mutat
St(const char* p); // mem�riafoglal�s �s a buf felt�lt�se
};
17. Szabv�nyos t�rol�k 671
K�sz�ts�nk 1000 St objektumot �s haszn�ljuk ezeket egy hash_map kulcsak�nt.
K�sz�ts�nk programot, mellyel tesztelni lehet a hash_map hat�konys�g�t.
�rjunk egy has�t�f�ggv�nyt (Hash, �17.6.2.3) kifejezetten az St t�pus� kulcsok
kezel�s�hez.
30. (*2) Adjunk legal�bb n�gyf�le megold�st a t�rl�sre kijel�lt (erased) elemek
elt�-
vol�t�s�ra a hash_map t�rol�b�l. Ciklus helyett haszn�ljuk a standard k�nyvt�r
algoritmusait. (�3.8, 18. fejezet)
31. (*3) K�sz�ts�nk olyan hash_map t�rol�t, amely azonnal t�rli az elemeket.
32. (*2) A �17.6.2.3 pontban bemutatott has�t�f�ggv�ny nem mindig haszn�lja
a kulcs teljes �br�zol�s�t. Mikor hagy figyelmen k�v�l r�szleteket ez a megold�s?
�rjunk olyan has�t�f�ggv�nyt, amely mindig a kulcs teljes �br�zol�s�t haszn�lja.
Adjunk r� p�ld�t, mikor lehet jogos a kulcs egy r�sz�nek .elfelejt�se. �s �rjunk
olyan has�t�f�ggv�nyt, amely a kulcsnak csak azt a r�sz�t veszi figyelembe,
amelyet fontosnak nyilv�n�tunk.
33. (*2.5) A has�t�f�ggv�nyek forr�sk�dja meglehetosen hasonl�: egy ciklus sorra
veszi az adatokat, majd elo�ll�tja a has�t��rt�ket. K�sz�ts�nk olyan Hash
(�17.6.2.3) f�ggv�nyt, amely az adatokat egy, a felhaszn�l� �ltal megadott f�ggv
�ny ism�telt megh�v�s�val gyujti �ssze. P�ld�ul:
size_t res = 0;
while (size_t v = hash(key)) res = (res<<3)^v;
Itt a felhaszn�l� a hash(K) f�ggv�nyt minden olyan K t�pusra megadhatja, amely
alapj�n has�tani akar.
34. (*3) A hash_map n�h�ny megval�s�t�s�b�l kiindulva k�sz�ts�k el
a hash_multimap, a hash_set �s a hash_multiset t�rol�t.
35. (*2.5) K�sz�ts�nk olyan has�t�f�ggv�nyt, amely egyenletes eloszl�s� int
�rt�keket
k�pez le egy k�r�lbel�l 1024 m�retu has�t�t�bl�ra. Ezen has�t�f�ggv�ny ismeret
�ben adjunk meg 1024 olyan kulcs�rt�ket, amelyet a f�ggv�ny ugyanarra
a has�t�k�dra k�pez le.
672 A standard k�nyvt�r
Algoritmusok �s f�ggv�nyobjektumok
.A forma szabadd� tesz..
(a m�rn�k�k k�zmond�sa)
Bevezeto . A szabv�nyos algoritmusok �ttekint�se . Sorozatok . F�ggv�nyobjektumok
. Predik�tumok . Aritmetikai objektumok . Lek�tok . Tagf�ggv�ny-objektumok .
for_each . Elemek keres�se . count . Sorozatok �sszehasonl�t�sa . Keres�s .
M�sol�s .
transform . Elemek lecser�l�se �s elt�vol�t�sa . Sorozatok felt�lt�se . �trendez�s
. swap .
Rendezett sorozatok . binary_search . merge . Halmazmuveletek . min �s max . Kupac
.
Permut�ci�k . C st�lus� algoritmusok . Tan�csok . Gyakorlatok
18.1. Bevezeto
Egy t�rol� �nmag�ban nem t�ls�gosan �rdekes dolog. Ahhoz, hogy t�nyleg hasznoss�
v�ljon,
sz�mos alapveto muveletre is sz�ks�g van, melyekkel p�ld�ul lek�rdezhetj�k a
t�rol�
m�ret�t, bej�rhatjuk, m�solhatjuk, rendezhetj�k, vagy elemeket kereshet�nk benne.
Szerencs
�re a standard k�nyvt�r biztos�tja mindazokat a szolg�ltat�sokat, melyekre a
programoz
�knak sz�ks�g�k van a t�rol�k haszn�lat�hoz.
18
Ebben a fejezetben a szabv�nyos algoritmusokat foglaljuk �ssze �s n�h�ny p�ld�t
mutatunk
be haszn�latukra. Kiemelj�k azokat a legfontosabb elveket �s m�dszereket, melyeket
ismern
�nk kell az algoritmusok lehetos�geinek a C++-ban val� kiakn�z�s�hoz. N�h�ny
alapvet
o algoritmust r�szletesen is megvizsg�lunk.
Azokat az elj�r�sokat, melyek seg�ts�g�vel a programoz�k saj�t ig�nyeikhez
alak�thatj�k
a szabv�nyos algoritmusok viselked�s�t, a f�ggv�nyobjektumok biztos�tj�k. Ezek
adj�k
meg azokat az alapveto inform�ci�kat is, melyekre a felhaszn�l�k adatainak
kezel�s�hez
sz�ks�g van.
�ppen ez�rt nagy hangs�lyt helyez�nk arra, hogy bemutassuk a f�ggv�nyobjektumok
l�trehoz
�s�nak �s haszn�lat�nak m�dszereit.
18.2. A standard k�nyvt�r algoritmusainak �ttekint�se
Elso pillant�sra �gy tunhet, hogy a standard k�nyvt�r algoritmusainak sz�ma szinte
v�gtelen,
pedig .mind�ssze. 60 darab van belol�k. Tal�lkoztam m�r olyan oszt�llyal, melynek
�nmag�ban t�bb tagf�ggv�nye volt. R�ad�sul nagyon sok algoritmus ugyanazt az
�ltal�nos
viselked�sform�t, illetve fel�letst�lust mutatja, �s ez nagym�rt�kben
leegyszerus�ti meg�rt�-
s�ket. Ugyan�gy, mint a programnyelvi lehetos�gek eset�ben, a programoz�nak itt is
csak
azokat az elemeket kell haszn�lnia, amelyekre �ppen sz�ks�ge van �s amelyek
muk�d�s�t
ismeri. Semmilyen elonyt nem jelent, ha minden apr�s�ghoz szabv�nyos algoritmust
keres
�nk, �s az�rt sem kapunk jutalmat, ha az algoritmusokat rendk�v�l .okosan., de
�ttekinthetetlen
�l alkalmazzuk. Ne felejts�k el, hogy a programk�d le�r�s�nak elsodleges c�lja,
hogy a k�sobbi olvas�k sz�m�ra a program muk�d�se �rtheto legyen (A .k�sobbi
olvas�k.
val�sz�nuleg mi magunk lesz�nk n�h�ny �v m�lva.) M�sr�szt, ha egy t�rol� elemeivel
valamilyen
feladatot kell elv�gezn�nk, gondoljuk v�gig, hogy a muvelet nem fogalmazhat�-e
meg a standard k�nyvt�r algoritmusainak st�lus�ban. Az is elk�pzelheto, hogy az
algoritmus
m�r meg is van, csak olyan �ltal�nos form�ban, hogy elso r�n�z�sre r� sem
ismer�nk. Ha
megszokjuk az �ltal�nos�tott (generikus) algoritmusok vil�g�t, nagyon sok
felesleges munk
�t�l k�m�lhetj�k meg magunkat.
674 A standard k�nyvt�r
Mindegyik algoritmus egy sablon f�ggv�ny (template function) (�13.3) form�j�ban
jelenik
meg vagy sablon f�ggv�nyek egy csoportjak�nt. Ez a megold�s lehetov� teszi, hogy
az algoritmusok
sokf�le elemsorozaton legyenek k�pesek muk�dni �s term�szetesen az elemek
t�pusa is m�dos�that� legyen. Azok az algoritmusok, melyek eredm�nyk�ppen egy
bej�r�t
(iterator) (�19.1) adnak vissza, �ltal�ban a bemeneti sorozat v�g�t haszn�lj�k a
sikertelen
v�grehajt�s jelz�s�re:
void f(list<string>& ls)
{
list<string>::const_iterator p = find(ls.begin(),ls.end(),"Frici");
if (p == ls.end()) {
// "Frici" nem tal�lhat�
}
else {
// p "Frici"-re mutat
}
}
Az algoritmusok nem v�geznek tartom�nyellenorz�st a be- vagy kimenet�k�n. A rossz
tartom�nyb�l eredo hib�kat m�s m�dszerekkel kell elker�ln�nk (�18.3.1, �19.3) Ha
az algoritmus
egy bej�r�t ad vissza, annak t�pusa ugyanolyan lesz, mint a bemeneti sorozat
valamelyik
bej�r�j�nak. Teh�t p�ld�ul az algoritmus param�tere hat�rozza meg, hogy a visszat
�r�si �rt�k const_iterator vagy nem konstans iterator lesz-e:
void f(list<int>& li, const list<string>& ls)
{
list<int>::iterator p = find(li.begin(),li.end(),42);
list<string>::const_iterator q = find(ls.begin(),ls.end(),"Ring");
}
A standard k�nyvt�r algoritmusai k�z�tt megtal�ljuk a t�rol�k leggyakoribb
�ltal�nos mu-
veleteit, p�ld�ul a bej�r�sokat, keres�seket, rendez�seket, illetve az elemek
besz�r�s�t �s
t�rl�s�t is. A szabv�nyos algoritmusok kiv�tel n�lk�l az std n�vt�rben tal�lhat�k
�s az
<algorithm> fej�llom�ny deklar�lja oket. �rdekes, hogy az igaz�n �ltal�nos
algoritmusok
nagy r�sze annyira egyszeru, hogy �ltal�ban helyben kifejtett (inline) sablon
f�ggv�nyek
val�s�tj�k meg azokat. Ez�rt az algoritmusok ciklusait a hat�kony, f�ggv�nyen
bel�li
optimaliz�ci�s elj�r�sok jelentosen jav�thatj�k.
A szabv�nyos f�ggv�nyobjektumok is az std n�vt�rben tal�lhat�k, de ezek
deklar�ci�j�t
a <functional> fej�llom�nyban �rhetj�k el. A f�ggv�nyobjektumok fel�p�t�se is
olyan, hogy
k�nnyen haszn�lhat�k helyben kifejtett f�ggv�nyk�nt.
18. Algoritmusok �s f�ggv�nyobjektumok 675
A nem m�dos�t� sorozatmuveletek arra haszn�lhat�k, hogy adatokat nyerj�nk ki egy
sorozatb
�l vagy bizonyos elemek hely�t meghat�rozzuk benn�k:
A legt�bb algoritmus lehetov� teszi, hogy a programoz� hat�rozza meg azt a
feladatot, amelyet
minden elemen, illetve elemp�ron el akar v�gezni. Ez�ltal az algoritmusok sokkal
�ltal
�nosabbak �s hasznosabbak, mint azt elso r�n�z�sre gondolhatn�nk. A programoz�
hat�-
rozhatja meg, mikor tekint�nk k�t elemet azonosnak �s mikor k�l�nb�zonek
(�18.4.2), �s
a leggyakrabban v�grehajtott, leghasznosabb muveletet alap�rtelmezettk�nt is
kijel�lheti.
A sorozatm�dos�t� muveletek k�z�tt igen kev�s hasonl�s�got tal�lhatunk azon k�v�l,
hogy
megv�ltoztatj�k a sorozat egyes elemeinek �rt�k�t:
676 A standard k�nyvt�r
Nem m�dos�t� sorozatmuveletek (�18.5) <algorithm>
for_each() Muvelet v�grehajt�sa egy sorozat �sszes elem�re.
find() Egy �rt�k elso elofordul�s�nak megkeres�se egy
sorozatban.
find_if() Az elso olyan elem megkeres�se egy sorozatban, amire
egy �ll�t�s teljes�l.
find_first_of() Egy sorozat egy elem�nek megkeres�se egy m�sik
sorozatban.
adjacent_find() K�t szomsz�dos �rt�k keres�se.
count() Egy �rt�k elofordul�sainak sz�ma egy sorozatban.
count_if() Azon elemek sz�ma egy sorozatban, melyre teljes�l egy
�ll�t�s.
mismatch() Az elso olyan elemek keres�se, ahol k�t sorozat
k�l�nb�zik.
equal() Igazat ad vissza, ha k�t sorozat elemei p�ronk�nt megegyeznek.
search() Egy sorozat elso elofordul�s�t keresi meg
r�szsorozatk�nt.
find_end() Egy sorozat r�szsorozatk�nt val� utols� elofordul�s�t
keresi meg.
search_n() Egy �rt�k n-edik elofordul�s�t keresi meg egy sorozatban.
Minden j� rendszer mag�n viseli megalkot�j�nak �rdeklod�si k�r�t, illetve
szem�lyes jellemvon
�sait. A standard k�nyvt�r t�rol�i �s algoritmusai t�k�letesen t�kr�zik a
klasszikus
adatszerkezetek m�g�tti elveket �s az algoritmusok tervez�si szempontjait. A
standard
k�nyvt�r nem csak a t�rol�k �s algoritmusok legalapvetobb fajt�it biztos�tja,
melyekre minden
programoz�nak sz�ks�ge van, hanem olyan eszk�z�ket is, melyekkel ezek az
algoritmusok
megval�s�that�k, �s lehetos�get ad a k�nyvt�r bov�t�s�re is.
18. Algoritmusok �s f�ggv�nyobjektumok 677
Sorozatm�dos�t� muveletek (�18.6) <algorithm>
transform() Muvelet v�grehajt�sa a sorozat minden elem�n.
copy() Sorozat m�sol�sa az elso elemtol kezdve.
copy_backward() Sorozat m�sol�sa az utols� elemtol kezdve.
swap() K�t elem felcser�l�se.
iter_swap() Bej�r�k �ltal kijel�lt k�t elem felcser�l�se.
swap_ranges() K�t sorozat elemeinek felcser�l�se.
replace() Adott �rt�ku elemek helyettes�t�se.
replace_if() �ll�t�st kiel�g�to elemek helyettes�t�se.
replace_copy() Sorozat m�sol�sa adott �rt�ku elemek
helyettes�t�s�vel.
replace_copy_if() Sorozat m�sol�sa �ll�t�st kiel�g�to elemek
helyettes�t�s�vel.
fill() Az �sszes elem helyettes�t�se egy adott �rt�kre.
fill_n() Az elso n elem helyettes�t�se egy adott �rt�kkel.
generate() Az �sszes elem helyettes�t�se egy muvelettel elo�ll�-
tott �rt�kre.
generate_n() Az elso n elem helyettes�t�se egy muvelettel elo�ll�-
tott �rt�kre.
remove() Adott �rt�kkel rendelkezo elemek t�rl�se.
remove_if() �ll�t�st kiel�g�to elemek t�rl�se.
remove_copy() Sorozat m�sol�sa adott �rt�ku elemek t�rl�s�vel.
remove_copy_if() Sorozat m�sol�sa �ll�t�st kiel�g�to elemek t�rl�s�vel.
unique() Szomsz�dos egyen�rt�ku elemek t�rl�se.
unique_copy() Sorozat m�sol�sa szomsz�dos egyen�rt�ku elemek
t�rl�s�vel.
reverse() Az elemek sorrendj�nek megford�t�sa.
reverse_copy() Elemek m�sol�sa ford�tott sorrendben.
rotate() Elemek k�rbeforgat�sa.
rotate_copy() Sorozat m�sol�sa az elemek k�rbeforgat�s�val.
random_shuffle() Elemek �trendez�se egyenletes eloszl�s szerint.
A hangs�ly most nem igaz�n azon van, hogy ezek az algoritmusok hogyan val�s�that�k

meg, sot . a legegyszerubb algoritmusokt�l eltekintve . nem is azok haszn�lat�n.


Ha az algoritmusok
szerkezet�rol �s elk�sz�t�si m�djair�l t�bbet szeretn�nk megtudni, m�s k�nyveket
kell fellapoznunk (p�ld�ul [Knuth, 1968] vagy [Tarjan, 1983]). Itt azzal
foglalkozunk,
mely algoritmusok �llnak rendelkez�s�nkre a standard k�nyvt�rban �s ezek hogyan
jelennek
meg a C++ nyelvben. Ez a n�zopont lehetov� teszi, hogy . amennyiben tiszt�ban
vagyunk
az algoritmusokkal . hat�konyan haszn�ljuk a standard k�nyvt�rat, illetve olyan
szellemben fejlessz�k azt tov�bb, ahogy megsz�letett.
A standard k�nyvt�r sok-sok olyan elj�r�st k�n�l, melyekkel sorozatokat
rendezhet�nk, kereshet
�nk benn�k, vagy m�s, sorrenden alapul� muveleteket v�gezhet�nk vel�k:
678 A standard k�nyvt�r
Rendezett sorozatok muveletei (�18.7) <algorithm>
sort() �tlagos hat�konys�ggal rendez.
stable_sort() Az egyen�rt�ku elemek sorrendj�nek megtart�s�val
rendez.
partial_sort() Egy sorozat elej�t rendezi.
partial_sort_copy() M�sol a sorozat elej�nek rendez�s�vel.
nth_element() Az n-edik elemet a megfelelo helyre teszi.
lower_bound() Egy �rt�k elso elofordul�s�t keresi meg.
upper_bound() Egy �rt�k utols� elofordul�s�t keresi meg.
equal_range() Egy adott �rt�ket tartalmaz� r�szsorozatot ad meg.
binary_search() Igazat ad vissza, ha a megadott �rt�k szerepel
a sorozatban.
merge() K�t rendezett sorozatot f�s�l �ssze.
inplace_merge() K�t egym�st k�veto rendezett r�szsorozatot f�s�l
�ssze.
partition() Elemeket helyez el egy �ll�t�snak (felt�telnek)
megfeleloen.
stable_partition() Elemeket helyez el egy �ll�t�snak megfeleloen,
a relat�v sorrend megtart�s�val.
A kupacmuveletek (heap-muveletek) olyan �llapotban tartj�k a sorozatot, hogy az
k�nnyen
rendezheto legyen, amikor arra sz�ks�g lesz:
A k�nyvt�r biztos�t n�h�ny olyan elj�r�st is, melyek �sszehasonl�t�ssal
kiv�lasztott elemeket
adnak meg:
18. Algoritmusok �s f�ggv�nyobjektumok 679
Halmazmuveletek (�18.7.5) <algorithm>
includes() Igazat ad vissza, ha egy sorozat r�szsorozata
egy m�siknak.
set_union() Rendezett uni�t �ll�t elo.
set_intersection() Rendezett metszetet �ll�t elo.
set_difference() Azon elemek rendezett sorozat�t �ll�tja elo,
melyek az elso sorozatban megtal�lhat�k, de
a m�sodikban nem.
set_symmetric_difference() Azon elemek rendezett sorozat�t �ll�tja elo, melyek
csak az egyik sorozatban tal�lhat�k meg.
Kupacmuveletek (�18.8) <algorithm>
make_heap() Egy sorozatot felk�sz�t kupack�nt val� haszn�latra.
push_heap() Elemet ad a kupachoz.
pop_heap() Elemet t�r�l a kupacb�l.
sort_heap() Rendezi a kupacot.
Minimum �s maximum (�18.9) <algorithm>
min() K�t �rt�k k�z�l a kisebb.
max() K�t �rt�k k�z�l a nagyobb.
min_element() A legkisebb �rt�k egy sorozatban.
max_element() A legnagyobb �rt�k egy sorozatban.
lexicographical_compare() K�t sorozat k�z�l az �b�c�sorrend szerint
kor�bbi.
V�g�l a k�nyvt�r lehetov� teszi azt is, hogy elo�ll�tsuk egy sorozat permut�ci�it
(az elemek
�sszes lehets�ges sorrendj�t):
Ezeken k�v�l, a <numeric> (�22.6) fej�llom�nyban n�h�ny �ltal�nos matematikai
algoritmust
is tal�lhatunk.
Az algoritmusok le�r�s�ban a sablonparam�terek neve nagyon fontos. Az In, Out,
For, Bi �s
Ran elnevez�sek sorrendben bemeneti bej�r�t, kimeneti bej�r�t, elore halad�
bej�r�t, k�tir
�ny� bej�r�t, illetve k�zvetlen el�r�su (v�letlen el�r�su) bej�r�t jelentenek
(�19.2.1).
A Pred egyparam�teru, a BinPred k�tparam�teru predik�tumot (�ll�t�st, logikai
�rt�ku
f�ggv�nyt, �18.4.2) hat�roz meg, m�g a Cmp �sszehasonl�t� f�ggv�nyre utal. Az Op
egyoperandos
� muveletet, a BinOp k�toperandos�t v�r. A hagyom�nyok szerint sokkal
hosszabb neveket kellett volna haszn�lnom a sablonparam�terek megnevez�s�re, de
�gy
vettem �szre, hogy ha m�r egy kicsit is ismerj�k a standard k�nyvt�rat, a hossz�
nevek ink
�bb csak rontj�k az olvashat�s�got.
A k�zvetlen el�r�su bej�r�k haszn�lhat�k k�tir�ny� bej�r�k�nt is, a k�tir�ny�
bej�r�k elore
halad� bej�r�k�nt, az elore halad� bej�r�k pedig ak�r bemeneti, ak�r kimeneti
bej�r�k�nt
(�19.2.1). Ha a sablonnak olyan t�pust adunk �t, amely nem biztos�tja a sz�ks�ges
muveleteket,
a sablon p�ld�nyos�t�sakor hiba�zenetet kapunk (�C.13.7). Ha olyan t�pust
haszn�lunk,
amelyben megvannak a sz�ks�ges muveletek, de jelent�s�k (szerep�k) nem a
megfelelo,
akkor kisz�m�thatatlan fut�si ideju viselked�sre kell felk�sz�ln�nk (�17.1.4).
680 A standard k�nyvt�r
Permut�ci�k (�18.10) <algorithm>
next_permutation() Az �b�c�sorrend szerinti rendez�s alapj�n k�vetkez
o permut�ci�.
prev_permutation() Az �b�c�sorrend szerinti rendez�s alapj�n elozo
permut�ci�.
18.3. Sorozatok �s t�rol�k
�ltal�nos szab�ly, hogy mindennek a leggyakoribb felhaszn�l�si m�dja legyen a
legr�videbb,
a legegyszerubb �s a legbiztons�gosabb. A standard k�nyvt�r az �ltal�noss�g �rdek
�ben itt-ott megs�rti ezt a szab�lyt, de egy szabv�nyos k�nyvt�r eset�ben az
�ltal�noss�g
mindenn�l fontosabb. A 42 elso k�t elofordul�s�t egy sorozatban p�ld�ul az al�bbi
programr
�szlettel kereshetj�k meg
void f(list<int>& li)
{
list<int>::iterator p = find(li.begin(),li.end(),42); // elso elofordul�s
if (p != li.end()) {
list<int>::iterator q = find(++p,li.end(),42); // m�sodik elofordul�s
// ...
}
// ...
}
Mivel a find() egy t�rol�kon muk�do muvelet, valamilyen tov�bbi eszk�z
seg�ts�g�vel lehet
ov� kell tenn�nk, hogy a m�sodik elofordul�st is el�rhess�k. A .tov�bbi eszk�z.
fogalm
�t �ltal�nos�tani minden t�rol�ra �s algoritmusra nagyon neh�z lenne, ez�rt a
standard
k�nyvt�r algoritmusai csak sorozatokon muk�dnek. Az algoritmusok bemenet�t gyakran

egy bej�r�-p�r adja, amely egy sorozatot hat�roz meg. Az elso bej�r� az elso
elemet jel�li
ki, m�g a m�sodik az utols� ut�ni elemet (�3.8, �19.2). Az ilyen sorozatot .f�lig
ny�ltnak. nevezz
�k, mivel az elso megadott elemet tartalmazza, de a m�sodikat nem. A f�lig ny�lt
sorozatok
lehetov� teszik, hogy a legt�bb algoritmusnak ne kelljen egyedi esetk�nt kezelnie
az
�res sorozatot.
Egy sorozatot gyakran tekinthet�nk tartom�nynak (range) is, foleg ha elemeit
k�zvetlen�l
el�rhetj�k. A f�lig ny�lt tartom�nyok hagyom�nyos matematikai jel�l�se az
[elso,utols�)
vagy az [elso, utols�[. Fontos, hogy egy ilyen sorozat lehet t�rol� vagy annak
r�szsorozata
is, de bizonyos sorozatok, p�ld�ul a ki- �s bemeneti adatfolyamok, egy�ltal�n nem
kapcsol
�dnak t�rol�khoz. A sorozatokkal kifejezett algoritmusok mindegyik esetben
t�k�letesen
muk�dnek.
18. Algoritmusok �s f�ggv�nyobjektumok 681
18.3.1. Bemeneti sorozatok
Az x.begin(), x.end() p�rral gyakran jel�lj�k azt, hogy az x �sszes elem�re
sz�ks�g�nk van,
pedig ez a jel�l�s hosszadalmas, r�ad�sul sok hibalehetos�get hordoz mag�ban.
P�ld�ul ha
t�bb bej�r�t is haszn�lunk, nagyon k�nnyen h�vunk meg egy algoritmust sorozatot
nem alkot
� param�terp�rral:
void f(list<string>& fruit, list<string>& citrus)
{
typedef list<string>::const_iterator LI;
LI p1 = find(fruit.begin(),citrus.end(),"alma"); // helytelen! (k�l�nb�zo
sorozatok)
LI p2 = find(fruit.begin(),fruit.end(),"alma"); // rendben
LI p3 = find(citrus.begin(),citrus.end(),"k�rte"); // rendben
LI p4 = find(p2,p3,"peach"); // helytelen! (k�l�nb�zo sorozatok)
// ...
}
A p�ld�ban k�t hiba is szerepel. Az elso m�g el�g nyilv�nval� (foleg ha v�rjuk a
hib�t), de
a ford�t� m�r ezt sem k�nnyen tal�lja meg. A m�sodik hib�t viszont egy val�di
programban
nagyon neh�z felder�teni, m�g egy gyakorlott programoz� sz�m�ra is. Ha a bej�r�k
sz�m�t
siker�l cs�kkenten�nk, akkor ezen hib�k elofordul�s�nak val�sz�nus�g�t is
cs�kkenthetj
�k. Az al�bbiakban k�rvonalazunk egy megk�zel�t�st, amely a bemeneti sorozatok
fogalm
�nak bevezet�s�vel ezt a probl�m�t pr�b�lja megoldani. Az algoritmusok k�sobbi
bemutat
�sakor azonban nem haszn�ljuk majd a bemeneti sorozatokat, mert azok a standard
k�nyvt�rban nem szerepelnek, �s ebben a fejezetben kiz�r�lag a standard
k�nyvt�rral akarunk
foglalkozni.
Az alap�tlet az, hogy param�terk�nt egy sorozatot adunk meg:
template<class In, class T> In find(In first, In last, const T& v) // szabv�nyos
{
while (first!=last && *first!=v) ++first;
return first;
}
template<class In, class T> In find(Iseq<In> r, const T& v) // bov�t�s
{
return find(r.first,r.second,v);
}
A t�lterhel�s (overloading) (�13.3.2) �ltal�ban lehetov� teszi, hogy az algoritmus
bemeneti
sorozat form�j�t haszn�ljuk, ha Iseq param�tert adunk �t.
682 A standard k�nyvt�r
A bemeneti sorozatot term�szetesen bej�r�-p�rk�nt (�17.4.1.2) val�s�tjuk meg:
template<class In> struct Iseq : public pair<In,In> {
Iseq(In i1, In i2) : pair<In,In>(i1,i2) { }
};
A find() f�ggv�ny m�sodik v�ltozat�nak haszn�lat�hoz k�zvetlen�l is elo�ll�thatunk
Iseq
bemeneti sorozatot:
LI p = find(Iseq<LI>(fruit.begin(),fruit.end()),"alma");
Ez a megold�s azonban m�g k�r�lm�nyesebb, mint az eredeti find() f�ggv�ny. Ahhoz,
hogy ennek a megold�snak haszn�t vehess�k, m�g egy egyszeru seg�df�ggv�nyre van
sz�ks�g. Egy t�rol�hoz megadott Iseq val�j�ban nem m�s, mint az elemek sorozata az
elso-
tol (begin()) az utols�ig (end()):
template<class C> Iseq<C::iterator> iseq(C& c) // t�rol�ra
{
return Iseq<C::iterator>(c.begin(),c.end());
}
Ez a f�ggv�ny lehetov� teszi, hogy a teljes t�rol�kra vonatkoz� algoritmusokat
t�m�ren, ism
�tl�sek n�lk�l �rjuk le:
void f(list<string>& ls)
{
list<string>::iterator p = find(ls.begin(),ls.end(),"szabv�nyos");
list<string>::iterator q = find (iseq(ls),"bov�t�s");
// ..
}
Az iseq() f�ggv�nynek k�nnyen elk�sz�thetj�k olyan v�ltozatait is, amelyek
t�mb�kh�z,
bemeneti adatfolyamokhoz, vagy b�rmely m�s t�rol�hoz (�18.13[6]) ny�jtanak ilyen
hozz�-
f�r�st.
Az Iseq legfontosabb elonye, hogy a bemeneti sorozat l�nyeg�t vil�goss� teszi.
Gyakorlati
haszna abban �ll, hogy az iseq() megsz�nteti a k�nyelmetlen �s hibalehetos�get
mag�ban
hordoz� ism�tlod�st, amelyet a bemeneti sorozat k�t bej�r�val val� megad�sa
jelent.
A kimeneti sorozat fogalm�nak meghat�roz�sa szint�n hasznos lehet, b�r kev�sb�
egyszer
u �s kev�sb� k�zvetlen�l haszn�lhat�, mint a bemeneti sorozatok (�18.13[7], l�sd
m�g:
�19.2.4).
18. Algoritmusok �s f�ggv�nyobjektumok 683
18.4. F�ggv�nyobjektumok
Nagyon sok olyan algoritmus van, amely a sorozatokat csak bej�r�k �s �rt�kek
seg�ts�g�-
vel kezeli. A 7 elso elofordul�s�t egy sorozatban p�ld�ul az al�bbi m�don
tal�lhatjuk meg:
void f(list<int>& c)
{
list<int>::iterator p = find(c.begin(),c.end(),7);
// ...
}
Egy kicsit �rdekesebb eset, ha mi adunk meg egy f�ggv�nyt, amelyet az algoritmus
haszn�l
(�3.8.4). Az elso, h�tn�l kisebb elemet p�ld�ul a k�vetkezo programr�szlet keresi
meg:
bool less_than_7(int v)
{
return v<7;
}
void f(list<int>& c)
{
list<int>::iterator p = find_if(c.begin(),c.end(),less_than_7);
// ...
}
Nagyon sok egyszeru helyzetben ny�jtanak seg�ts�get a param�terk�nt �tadott
f�ggv�nyek:
logikai felt�telk�nt (predik�tum), aritmetikai muveletk�nt, olyan elj�r�sk�nt,
mellyel inform
�ci�t nyerhet�nk ki az elemekbol stb. Nem szok�s �s nem is hat�kony minden
felhaszn�-
l�si ter�letre k�l�n f�ggv�nyt �rni. M�sr�szt egyetlen f�ggv�ny n�ha nem is k�pes
megval
�s�tani ig�nyeinket. Gyakran elofordul p�ld�ul, hogy a minden egyes elemre
megh�vott
f�ggv�nynek a lefut�sok k�z�tt meg kell tartania valamilyen inform�ci�t. Az
oszt�lyok tagf
�ggv�nyei az ilyen feladatokat jobban v�gre tudj�k hajtani, mint az �n�ll�
elj�r�sok, hiszen
az objektumok k�pesek adatok t�rol�s�ra �s lehetos�get adnak azok kezdeti
�rt�k�nek be-
�ll�t�s�ra is.
N�zz�k, hogyan is k�sz�thet�nk egy f�ggv�nyt . vagy pontosabban egy f�ggv�nyszeru
oszt
�lyt . egy �sszegz�shez:
template<class T> class Sum {
T res;
public:
Sum(T i = 0) : res(i) { } // kezdeti �rt�kad�s
void operator()(T x) { res += x; } // �sszegz�s
684 A standard k�nyvt�r
T result() const { return res; } // �sszegz�s visszaad�sa
};
L�that�, hogy a Sum oszt�ly olyan aritmetikai t�pusokhoz haszn�lhat�, melyek
kezdo�rt�-
ke nulla lehet �s alkalmazhat� r�juk a += muvelet:
void f(list<double>& ld)
{
Sum<double> s;
s = for_each(ld.begin(),ld.end(),s); // s() megh�v�sa ld minden elem�re
cout << "Az �sszeg: " << s.result() << '\n';
}
Ebben a programr�szletben a for_each() (�18.5.1) f�ggv�ny az ld minden egyes
elem�re
megh�vja a Sum<double>::operator()(double) tagf�ggv�nyt, �s eredm�ny�l a harmadik
param
�terben megadott objektumot adja vissza.
Annak, hogy ez az utas�t�s egy�ltal�n muk�dik, az az oka, hogy a for_each() nem
teszi k�-
telezov�, hogy harmadik param�tere t�nyleg egy f�ggv�ny legyen. Mind�ssze annyit
felt�-
telez, hogy ez a valami megh�vhat� a megfelelo param�terrel. Ezt a szerepet egy
meghat�-
rozott objektum is bet�ltheti, sokszor hat�konyabban is, mint egy egyszeru
f�ggv�ny. Egy
oszt�ly f�ggv�nyh�v� oper�tor�t p�ld�ul k�nnyebb optimaliz�lni, mint egy
f�ggv�nyt, melyet
f�ggv�nyre hivatkoz� mutat�k�nt adtunk �t. Ez�rt a f�ggv�nyobjektumok gyakran
gyorsabban futnak, mint a szok�sos f�ggv�nyek. Azon oszt�lyok objektumait,
melyekhez
elk�sz�tett�k a f�ggv�nyh�v� oper�tort (�11.9), f�ggv�nyszeru objektumoknak,
funktoroknak
(functor) vagy egyszeruen f�ggv�nyobjektumoknak nevezz�k.
18.4.1. F�ggv�nyobjektumok b�zisoszt�lyai
A standard k�nyvt�r sz�mos hasznos f�ggv�nyobjektumot k�n�l. A f�ggv�nyobjektumok
elk
�sz�t�s�nek megk�nny�t�s�hez a k�nyvt�r k�t b�zisoszt�lyt tartalmaz:
template <class Arg, class Res> struct unary_function {
typedef Arg argument_type;
typedef Res result_type;
};
template <class Arg, class Arg2, class Res> struct binary_function {
typedef Arg first_argument_type;
typedef Arg2 second_argument_type;
typedef Res result_type;
};
18. Algoritmusok �s f�ggv�nyobjektumok 685
Ezen oszt�lyok c�lja, hogy szabv�nyos neveket adjanak a param�tereknek �s a
visszat�r�si
�rt�k t�pus�nak, �gy a unary_function �s a binary_function oszt�ly lesz�rmazottait
haszn�-
l� programoz�k el�rhetik azokat. A standard k�nyvt�r k�vetkezetesen haszn�lja
ezeket az
oszt�lyokat, ami abban is seg�ti a programoz�t, hogy meg�llap�tsa, mire is j� az
adott f�ggv
�nyobjektum (�18.4.4.1).
18.4.2. Predik�tumok
A predik�tum (�ll�t�s, felt�tel; predicate) egy olyan f�ggv�nyobjektum (vagy
f�ggv�ny),
amely logikai (bool) �rt�ket ad vissza. A <functional> fej�llom�nyban p�ld�ul az
al�bbi defin
�ci�kat tal�lhatjuk:
template <class T> struct logical_not : public unary_function<T,bool> {
bool operator()(const T& x) const { return !x; }
};
template <class T> struct less : public binary_function<T,T,bool> {
bool operator()(const T& x, const T& y) const { return x<y; }
};
Az egy- �s k�toperandos� (un�ris/bin�ris) predik�tumokra gyakran van sz�ks�g a
szabv�-
nyos algoritmusok eset�ben. P�ld�ul �sszehasonl�thatunk k�t sorozatot �gy, hogy
megkeress
�k az elso elemet, amely az egyik sorozatban nem kisebb, mint a neki megfelelo
elem
a m�sikban:
void f(vector<int>& vi, list<int>& li)
{
typedef list<int>::iterator LI;
typedef vector<int>::iterator VI;
pair<VI,LI> p1 = mismatch(vi.begin(),vi.end(),li.begin(),less<int>());
// ...
}
A mismatch() f�ggv�ny a sorozatok �sszetartoz� elemeire alkalmazza a megadott
k�toperandus� predik�tumot, mindaddig, am�g az igaz �rt�ket nem ad vissza
(�18.5.4).
A visszat�r�si �rt�k az a k�t bej�r�, amelyeket az �sszehasonl�t�s nem
�sszetartoz�nak tal
�lt. Mivel nem t�pust, hanem objektumot kell �tadnunk, a less<int>() kifejez�st
haszn�ljuk
(z�r�jelekkel) a less<int> forma helyett.
686 A standard k�nyvt�r
Elk�pzelheto, hogy az elso olyan elem helyett, amely nem kisebb a p�rj�n�l, pont
arra van
sz�ks�g�nk, amely kisebb ann�l. Ezt a feladatot az elso olyan elemp�r
megkeres�s�vel v�gezhetj
�k el, amelyre a nagyobb vagy egyenlo (greater_equal) kieg�sz�to felt�tel nem
teljes�l:
p1 = mismatch(vi.begin(),vi.end(),li.begin(),greater_equal<int>());
Egy m�sik lehetos�g, hogy a sorozatokat ford�tott sorrendben adjuk meg �s a kisebb
vagy
egyenlo (less_equal) muveletet haszn�ljuk:
pair<LI,VI> p2 = mismatch(li.begin(),li.end(),vi.begin(),less_equal<int>());
A �18.4.4.4 pontban azt is megn�zz�k, hogyan �rhatjuk le k�zvetlen�l a .nem
kisebb. felt�telt.
18.4.2.1. A predik�tumok �ttekint�se
A <functional> fej�llom�nyban n�h�ny �ltal�nos predik�tum tal�lhat�:
Az un�ris egyparam�teru, a bin�ris k�tparam�teru f�ggv�nyt jelent, az arg
(argumentum)
a param�tereket jel�li. A less �s a logical_not muveletet a �18.4.2 pont elej�n
�rtuk le.
A k�nyvt�r �ltal k�n�lt predik�tumokon k�v�l a programoz� saj�t maga is
l�trehozhat ilyen
f�ggv�nyeket. Ezek a programoz� �ltal megadott predik�tumok nagy szerepet
j�tszanak
a standard k�nyvt�r algoritmusainak egyszeru �s eleg�ns haszn�lat�ban. A
predik�tumok
meghat�roz�s�nak lehetos�ge k�l�n�sen fontos akkor, ha olyan oszt�lyra akarunk
haszn�lni
egy algoritmust, amely teljesen f�ggetlen a standard k�nyvt�rt�l �s annak
algoritmusait
�l. P�ld�ul k�pzelj�k el a �10.4.6 pontban bemutatott Club oszt�ly k�vetkezo
v�ltozat�t:
18. Algoritmusok �s f�ggv�nyobjektumok 687
Predik�tumok <functional>
equal_to bin�ris arg1==arg2
not_equal_to bin�ris arg1!=arg2
greater bin�ris arg1>arg2
less bin�ris arg1<arg2
greater_equal bin�ris arg1>=arg2
less_equal bin�ris arg1<=arg2
logical_and bin�ris arg1&&arg2
logical_or bin�ris arg1||arg2
logical_not un�ris !arg
class Person { /* ... */ };
struct Club {
string name;
list<Person*> members;
list<Person*> officers;
// ...
Club(const string& n);
};
Igen logikus feladat lenne, hogy megkeress�nk egy adott nevu klubot egy list<Club>
t�rol
�ban. A standard k�nyvt�r find_if() algoritmusa azonban egy�ltal�n nem ismeri a
Club
oszt�lyt. A k�nyvt�ri algoritmusok tudj�k, hogyan lehet egyenlos�get vizsg�lni, de
a klubot
mi nem a teljes �rt�ke alapj�n akarjuk megtal�lni, mind�ssze a Club::name
adattagot akarjuk
kulcsk�nt haszn�lni. Teh�t �runk egy olyan predik�tumot, amely ezt a felt�telt
t�kr�zi:
class Club_eq : public unary_function<Club,bool> {
string s;
public:
explicit Club_eq(const string& ss) : s(ss) { }
bool operator()(const Club& c) const { return c.name==s; }
};
A megfelelo predik�tumok meghat�roz�sa �ltal�ban nagyon egyszeru, �s ha az
�ltalunk l�trehozott
t�pusokhoz megadtuk a megfelelo predik�tumokat, akkor ezekre a szabv�nyos
algoritmusok
ugyanolyan egyszeruen �s hat�konyan haszn�lhat�k lesznek, mint az egyszeru
t�pusokb�l fel�p�tett t�rol�k eset�ben:
void f(list<Club>& lc)
{
typedef list<Club>::iterator LCI;
LCI p = find_if(lc.begin(),lc.end(),Club_eq("�tkezo filoz�fusok"));
// ...
}
18.4.3. Aritmetikai f�ggv�nyobjektumok
Amikor numerikus oszt�lyokat haszn�lunk, gyakran van sz�ks�g�nk a szok�sos
aritmetikai
muveletekre f�ggv�nyobjektumok form�j�ban. Ez�rt a <functional> �llom�nyban a
k�vetkez
o muveletek deklar�ci�ja is szerepel:
688 A standard k�nyvt�r
A multiplies muveletet haszn�lhatjuk p�ld�ul arra, hogy k�t vector elemeit
�sszeszorozzuk
�s ezzel egy harmadik vektort hozzunk l�tre:
void discount(vector<double>& a, vector<double>& b, vector<double>& res)
{
transform(a.begin(),a.end(),b.begin(),back_inserter(res),multiplies<double>());
}
A back_inserter() elj�r�sr�l a �19.2.4. pontban lesz sz�. Az aritmetikai
algoritmusok n�melyik
�vel a �22.6 fejezetben r�szletesen foglalkozunk.
18.4.4. Lek�tok, �talak�t�k �s tagad�k
Haszn�lhatunk olyan predik�tumokat �s aritmetikai f�ggv�nyobjektumokat is,
melyeket mi
magunk �rtunk, de hivatkozunk benn�k a standard k�nyvt�r �ltal k�n�lt elj�r�sokra.
Ha azonban
egy �j predik�tumra van sz�ks�g�nk, elo�ll�thatjuk azt egy m�r l�tezo predik�tum
apr�
m�dos�t�s�val is. A standard k�nyvt�r t�mogatja a f�ggv�nyobjektumok ilyen
fel�p�t�s�t:
�18.4.4.1 A lek�tok (binder) lehetov� teszik, hogy egy k�tparam�teru
f�ggv�nyobjektumot
egyparam�teru f�ggv�nyk�nt haszn�ljuk, az�ltal, hogy az egyik
param�terhez egy r�gz�tett �rt�ket k�tnek.
�18.4.4.2 A tagf�ggv�ny-�talak�t�k (member function adapter) lehetov� teszik,
hogy tagf�ggv�nyeket haszn�ljunk az algoritmusok param�terek�nt.
�18.4.4.3 A f�ggv�nyre hivatkoz� mutat�k �talak�t�i (pointer to function adapter)
lehetov� teszik, hogy f�ggv�nyre hivatkoz� mutat�kat haszn�ljunk algoritmusok
param�terek�nt.
�18.4.4.4 A tagad�k (negater) seg�ts�g�vel egy �ll�t�s (predik�tum) tagad�s�t,
ellent�t�t (neg�ltj�t) fejezhetj�k ki.
Ezeket a f�ggv�nyobjektumokat egy�tt �talak�t�knak (adapter) nevezz�k. Mindegyik
�talak
�t� azonos fel�p�t�su �s a unary_function �s binary_function f�ggv�nyobjektum-
b�zisoszt
�lyokon (�18.4.1) alapul. Mindegyikhez rendelkez�s�nkre �ll egy seg�df�ggv�ny,
mely
18. Algoritmusok �s f�ggv�nyobjektumok 689
Aritmetikai muveletek <functional>
plus bin�ris arg1+arg2
minus bin�ris arg1.arg2
multiplies bin�ris arg1*arg2
divides bin�ris arg1/arg2
modulus bin�ris arg1%arg2
negate un�ris .arg
param�terenk�nt egy f�ggv�nyobjektumot kap �s a megfelelo f�ggv�nyobjektumot adja
vissza. Ha ezeket az oszt�lyokat az operator()() muvelettel h�vjuk meg, akkor a
k�v�nt feladat
ker�l v�grehajt�sra. Teh�t az �talak�t� egyszeruen egy magasabb szintu f�ggv�ny:
egy
f�ggv�nyt kap param�terk�nt �s ebbol egy m�sik f�ggv�nyt �ll�t elo:
690 A standard k�nyvt�r
Lek�tok, �talak�t�k, tagad�k <functional>
bind2nd(y) binder2nd K�tparam�teru f�ggv�ny megh
�v�sa �gy, hogy y a m�sodik
param�ter.
bind1st(x) binder1st K�tparam�teru f�ggv�ny megh
�v�sa �gy, hogy x az elso param
�ter.
mem_fun() mem_fun_t Param�ter n�lk�li tagf�ggv�ny
megh�v�sa mutat�n kereszt�l.
mem_fun1_t Egyparam�teru tagf�ggv�ny
megh�v�sa mutat�n kereszt�l.
const_mem_fun_t Param�ter n�lk�li konstans
tagf�ggv�ny megh�v�sa mutat
�n kereszt�l.
const_mem_fun1_t Egyparam�teru konstans tagf
�ggv�ny megh�v�sa mutat�n
kereszt�l.
mem_fun_ref() mem_fun-ref_t Param�ter n�lk�li tagf�ggv�ny
megh�v�sa referenci�n kereszt
�l.
mem_fun1_ref_t Egyparam�teru tagf�ggv�ny
megh�v�sa referenci�n kereszt
�l.
const_mem_fun_ref_t Param�ter n�lk�li konstans
tagf�ggv�ny megh�v�sa
referenci�n kereszt�l.
const_mem_fun1_ref_t Egyparam�teru konstans tagf
�ggv�ny megh�v�sa referenci
�n kereszt�l.
ptr_fun() pointer_to_unary_function Egyparam�teru f�ggv�nyre
hivatkoz� mutat� megh�v�sa.
ptr_fun() pointer_to_binary_function K�tparam�teru f�ggv�nyre
hivatkoz� mutat� megh�v�sa.
not1() unary_negate Egyparam�teru predik�tum
neg�l�sa.
not2() binary_negate K�tparam�teru predik�tum
neg�l�sa.
18.4.4.1. Lek�tok
Az olyan k�tparam�teru predik�tumok, mint a less (�18.4.2), igen hasznosak �s
rugalmasak.
Gyakran tapasztaljuk azonban, hogy a legk�nyelmesebb predik�tum az lenne, amely
a t�rol� minden elem�t ugyanahhoz a r�gz�tett elemhez hasonl�tan�. A �18.4.
pontban bemutatott
less_than_7() egy jellemzo p�lda erre. A less muveletnek mindenk�ppen k�t param
�tert kell megadnunk minden egyes h�v�skor, �gy k�zvetlen�l nem haszn�lhatjuk ezt
az
elj�r�st. A megold�s a k�vetkezo lehet:
template <class T> class less_than : public unary_function<T,bool> {
T arg2;
public:
explicit less_than(const T& x) : arg2(x) { }
bool operator()(const T& x) const { return x<arg2; }
};
Ezek ut�n m�r le�rhatjuk a k�vetkezot:
void f(list<int>& c)
{
list<int>::const_iterator p = find_if(c.begin(),c.end(),less_than<int>(7));
// ...
}
A less_than(7) forma helyett a less_than<int>(7) alakot kell haszn�lnunk, mert az
<int>
sablonparam�ter nem vezetheto le a konstruktor param�ter�nek (7) t�pus�b�l
(�13.3.1).
A less_than predik�tum �ltal�ban igen hasznos. A fenti muvelet viszont �gy j�tt
l�tre, hogy
r�gz�tett�k, lek�t�tt�k (bind) a less f�ggv�ny m�sodik param�ter�t. Az ilyen
szerkezet, melyben
teh�t egy param�tert r�gz�t�nk, minden helyzetben ugyan�gy megval�s�that�, �s
annyira
�ltal�nos �s hasznos, hogy a standard k�nyvt�r egy k�l�n oszt�lyt k�n�l erre a
c�lra:
template <class BinOp>
class binder2nd : public unary_function<BinOp::first_argument_type,
BinOp::result_type> {
protected:
BinOp op;
typename BinOp::second_argument_type arg2;
public:
binder2nd(const BinOp& x, const typename BinOp::second_argument_type& v)
: op(x), arg2(v) { }
result_type operator()(const argument_type& x) const { return op(x,arg2); }
};
18. Algoritmusok �s f�ggv�nyobjektumok 691
template <class BinOp, class T> binder2nd<BinOp> bind2nd(const BinOp& op, const T&
v)
{
return binder2nd<BinOp>(op,v);
}
A bind2nd() f�ggv�nyobjektumot haszn�lhatjuk p�ld�ul arra, hogy meghat�rozzuk a
.kisebb,
mint 7. egyparam�teru felt�telt a less f�ggv�ny �s a 7 �rt�k felhaszn�l�s�val:
void f(list<int>& c)
{
list<int>::const_iterator p = find_if(c.begin(),c.end(),bind2nd(less<int>(),7));
// ...
}
El�g olvashat� ez a megold�s? El�g hat�kony? Egy �tlagos C++-v�ltozat
megval�s�t�s�val
�sszehasonl�tva bizony hat�konyabb, mint az eredeti, melyben a �18.4. pont
less_than_7()
f�ggv�ny�t haszn�ltuk . ak�r idoig�ny, ak�r t�rhaszn�lat szempontj�b�l! Az
�sszehasonl�-
t�s r�ad�sul k�nnyen ford�that� helyben kifejtett f�ggv�nyk�nt.
A jel�l�s logikus, de megszok�s�hoz kell egy kis ido, ez�rt �rdemes konkr�t n�vvel
megadni
a k�t�tt param�teru muveletet is:
template <class T> struct less_than : public binder2nd< less<T> > {
explicit less_than(const T& x) : binder2nd(less<T>(),x) { }
};
void f(list<int>& c)
{
list<int>::const_iterator p = find_if(c.begin(),c.end(),less_than<int>(7));
// ...
}
Fontos, hogy a less_than elj�r�st a less muvelettel hat�rozzuk meg, �s nem
k�zvetlen�l a <
oper�torral, mert �gy a less_than haszn�lni tudja a less b�rmely elk�pzelheto
specializ�ci�j�t
(�13.5, �19.2.2).
A bind2nd() �s a binder2nd mellett a <functional> fej�llom�nyban megtal�lhatjuk
a bind1st() �s binder1st oszt�lyt is, melyekkel egy k�tparam�teru f�ggv�ny elso
param�ter
�t r�gz�thetj�k.
Egy param�ter lek�t�se, amit a bind1st() �s a bind2nd() ny�jt, nagyon hasonl�t
ahhoz az
�ltal�nos szolg�ltat�shoz, amelyet Currying-nek neveznek.
692 A standard k�nyvt�r
18.4.4.2. Tagf�ggv�ny-�talak�t�k
A legt�bb algoritmus felhaszn�l valamilyen szabv�nyos vagy programoz� �ltal
megadott
muveletet. Term�szetesen gyakran tagf�ggv�nyt szeretn�nk megh�vni. P�ld�ul
(�3.8.5):
void draw_all(list<Shape*>& c)
{
for_each(c.begin(),c.end(),&Shape::draw); // hopp�! hiba
}
A probl�m�t az jelenti, hogy egy mf() tagf�ggv�ny megh�v�s�hoz az objektumot is
meg kell
adnunk: p->mf(). Az olyan algoritmusok azonban, mint a for_each(), a param�terk�nt
kapott
f�ggv�nyeket az egyszeru f�ggv�nyh�v� utas�t�ssal hajtj�k v�gre: f(). Ez�rt
sz�ks�g�nk
van egy olyan k�vetkezetes �s hat�kony m�dszerre, amivel l�trehozhatunk valamit,
ami k�-
pes r�venni az algoritmusokat, hogy tagf�ggv�nyeket h�vjanak meg. Egy lehets�ges
megold
�s az lenne, hogy minden algoritmusnak k�t p�ld�ny�t hozzuk l�tre: az egyik a
tagf�ggv
�nyekkel lenne haszn�lhat�, a m�sik az egyszeru f�ggv�nyekkel. A helyzet m�g enn�l
is
rosszabb, mert olyan v�ltozatokra is sz�ks�g�nk lenne, amelyek objektumok t�rol�in
mu-
k�dn�nek (nem objektumokra hivatkoz� mutat�kon). Ugyan�gy, mint a lek�tok
(�18.4.4.1)
eset�ben, a megold�st itt is egy �j oszt�ly �s egy f�ggv�ny meg�r�sa jelenti.
Elosz�r vizsg�ljuk
meg azt az �ltal�nos esetet, amikor egy tagf�ggv�nyt param�terek n�lk�l szeretn�nk

megh�vni egy mutat�kat tartalmaz� t�rol� minden elem�re:


template<class R, class T> class mem_fun_t : public unary_function<T*,R> {
R (T::*pmf)();
public:
explicit mem_fun_t(R (T::*p)()) :pmf(p) {}
R operator()(T* p) const { return (p->*pmf)(); } // megh�v�s mutat�n kereszt�l
};
template<class R, class T> mem_fun_t<R,T> mem_fun(R (T::*f)())
{
return mem_fun_t<R,T>(f);
}
Ez megoldja a p�ld�ban szereplo Shape::draw() h�v�st:
void draw_all(list<Shape*>& lsp) // param�ter n�lk�li tag megh�v�sa objektumra
// hivatkoz� mutat�n kereszt�l
{
for_each(lsp.begin(),lsp.end(),mem_fun(&Shape::draw)); // minden alakzat
// kirajzol�sa
}
18. Algoritmusok �s f�ggv�nyobjektumok 693
Ezenk�v�l sz�ks�g�nk van egy olyan oszt�lyra �s mem_fun() f�ggv�nyre is, amelyek a
param
�teres tagf�ggv�nyek kezel�s�re k�pesek. Olyan v�ltozatok is kellenek, melyekkel
k�zvetlen
�l objektumokat haszn�lhatunk, nem pedig objektumokra hivatkoz� mutat�kat. Ezek
neve mem_fun_ref(). V�g�l sz�ks�g van a const tagf�ggv�nyeket kezelo v�ltozatokra
is:
template<class R, class T> mem_fun_t<R,T> mem_fun(R (T::*f)());
// �s az egyparam�teru tagokra, a const tagokra, �s az egyparam�teru const tagokra

// vonatkoz� v�ltozatok (l�sd a �18.4.4 t�bl�zatot)


template<class R, class T> mem_fun_ref_t<R,T> mem_fun_ref(R (T::*f)());
// �s az egyparam�teru tagokra, a const tagokra, �s az egyparam�teru const tagokra

// vonatkoz� v�ltozatok (l�sd a �18.4.4 t�bl�zatot)


A <functional> fej�llom�ny tagf�ggv�ny-�talak�t�inak felhaszn�l�s�val a
k�vetkezoket
�rhatjuk:
void f(list<string>& ls) // param�ter n�lk�li tagf�ggv�ny haszn�lata objektumra
{
typedef list<string>::iterator LSI;
LSI p = find_if(ls.begin(),ls.end(),mem_fun_ref(&string::empty)); // "" keres�se
}
void rotate_all(list<Shape*>& ls, int angle)
// egyparam�teru tagf�ggv�ny haszn�lata objektumra hivatkoz� mutat�n kereszt�l
{
for_each(ls.begin(),ls.end(),bind2nd(mem_fun(&Shape::rotate),angle));
}
A standard k�nyvt�rnak nem kell foglalkoznia azokkal a tagf�ggv�nyekkel, melyek
egyn�l
t�bb param�tert v�rnak, mert a standard k�nyvt�rban nincs olyan algoritmus, amely
ketto-
n�l t�bb param�teru f�ggv�nyt v�rna operandusk�nt.
18.4.4.3. F�ggv�nyre hivatkoz� mutat�k �talak�t�i
Egy algoritmus nem foglalkozik azzal, hogy a .f�ggv�nyparam�ter. milyen form�ban
adott:
f�ggv�ny, f�ggv�nyre hivatkoz� mutat� vagy f�ggv�nyobjektum. Ellenben a lek�tok
(�18.4.4.1) sz�m�ra ez fontos, mert t�rolniuk kell egy m�solatot a k�sobbi
felhaszn�l�shoz.
A standard k�nyvt�r k�t �talak�t�t k�n�l a f�ggv�nyekre hivatkoz� mutat�k
szabv�nyos algoritmusokban
val� felhaszn�l�s�hoz. A defin�ci� �s a megval�s�t�s nagyon hasonl�t a tagf
�ggv�ny-�talak�t�kn�l (�18.4.4.2) haszn�lt megold�sra. Most is k�t f�ggv�nyt �s
k�t oszt
�lyt haszn�lunk:
694 A standard k�nyvt�r
template <class A, class R> pointer_to_unary_function<A,R> ptr_fun(R (*f)(A));
template <class A, class A2, class R>
pointer_to_binary_function<A,A2,R> ptr_fun(R (*f)(A, A2));
A f�ggv�nyre hivatkoz� mutat�k ezen �talak�t�i lehetov� teszik, hogy a szok�sos
f�ggv�-
nyeket a lek�tokkel egy�tt haszn�ljuk:
class Record { /* ... */ };
bool name_key_eq(const Record&, const char*);// �sszehasonl�t�s nevek alapj�n
bool ssn_key_eq(const Record&, long); // �sszehasonl�t�s sz�mok alapj�n
void f(list<Record>& lr) // f�ggv�nyre hivatkoz� mutat� haszn�lata
{
typedef typename list<Record>::iterator LI;
LI p = find_if(lr.begin(),lr.end(),bind2nd(ptr_fun(name_key_eq),"John Brown"));
LI q = find_if(lr.begin(),lr.end(),bind2nd(ptr_fun(ssn_key_eq),1234567890));
// ...
}
A fenti utas�t�sok azokat az elemeket keresik meg az lr list�ban, melyekben a John
Brown,
illetve az 1234567890 kulcs�rt�k szerepel.
18.4.4.4. Tagad�k
A predik�tum-tagad�k (negater) a lek�tokh�z kapcsol�dnak abb�l a szempontb�l, hogy

egy muveletet kapnak param�terk�nt �s ebbol egy m�sik muveletet �ll�tanak elo. A
tagad
�k defin�ci�ja �s megval�s�t�sa k�veti a tagf�ggv�ny-�talak�t�kn�l (�18.4.4.2)
alkalmazott
form�t. Meghat�roz�suk rendk�v�l egyszeru, de ezt az egyszerus�get kicsit
elhom�lyos�tja
a hossz� szabv�nyos nevek haszn�lata:
template <class Pred>
class unary_negate : public unary_function<typename Pred::argument_type,bool> {
Pred op;
public:
explicit unary_negate(const Pred& p) : op(p) { }
bool operator()(const argument_type& x) const { return !op(x); }
};
template <class Pred>
class binary_negate : public binary_function<typename Pred::first_argument_type,
typename Pred::second_argument_type, bool> {
18. Algoritmusok �s f�ggv�nyobjektumok 695
typedef first_argument_type Arg;
typedef second_argument_type Arg2;
Pred op;
public:
explicit binary_negate(const Pred& p) : op(p) { }
bool operator()(const Arg& x, const Arg2& y) const { return !op(x,y); }
};
template<class Pred> unary_negate<Pred> not1(const Pred& p); // un�ris tagad�sa
template<class Pred> binary_negate<Pred> not2(const Pred& p); // bin�ris tagad�sa
Ezek az oszt�lyok �s f�ggv�nyek is a <functional> fej�llom�nyban kaptak helyet.
A first_argument_type, second_argument_type stb. elnevez�sek a unary_function,
illetve
a binary_function szabv�nyos b�zisoszt�lyokb�l erednek.
Ugyan�gy, mint a lek�tok, a tagad�k is k�nyelmesen haszn�lhat�k seg�df�ggv�nyeiken

kereszt�l. P�ld�ul a .nem kisebb, mint. k�tparam�teru predik�tumot is egyszeruen


le�rhatjuk,
�s megkereshetj�k vele az elso k�t olyan szomsz�dos elemet, melyek k�z�l az elso
nagyobb
vagy egyenlo, mint a m�sodik:
void f(vector<int>& vi, list<int>& li) // a �18.4.2 p�ld�j�nak jav�tott v�ltozata
{
// ...
p1 = mismatch(vi.begin(),vi.end(),li.begin(),not2(less<int>()));
// ...
}
Teh�t a p1 kapja meg az elso olyan elemp�rt, melyre a .nem kisebb, mint. muvelet
hamis
�rt�ket ad vissza.
A predik�tumok logikai �rt�kekkel dolgoznak, �gy a bitenk�nti oper�toroknak (|, &,
^, ~)
nincs megfeleloj�k.
Term�szetesen a lek�tok, az �talak�t�k �s a tagad�k egy�tt is haszn�lhat�k:
extern "C" int strcmp(const char*,const char*); // a <cstdlib> fej�llom�nyb�l
void f(list<char*>& ls) // f�ggv�nyre hivatkoz� mutat� haszn�lata
{
typedef typename list<char*>::const_iterator LI;
LI p = find_if(ls.begin(),ls.end(),not1(bind2nd(ptr_fun(strcmp),"vicces")));
}
696 A standard k�nyvt�r
Ez a k�dr�szlet az elso olyan elemet keresi meg az ls list�ban, amely a .vicces. C
st�lus� karakterl
�ncot tartalmazza. A tagad�ra az�rt van sz�ks�g, mert a strcmp() f�ggv�ny akkor ad

vissza 0 �rt�ket, ha a k�t karakterl�nc egyenlo.


18.5. Nem m�dos�t� algoritmusok sorozatokon
A sorozatok nem m�dos�t� algoritmusai elsosorban arra szolg�lnak, hogy a
sorozatokban
an�lk�l kereshess�nk meg bizonyos elemeket, hogy ciklust �rn�nk. Ezen k�v�l
lehetos�get
adnak arra, hogy az elemekrol megtudjunk minden l�tezo inform�ci�t. Ezek az
algoritmusok
csak konstans bej�r�kat (�19.2.1) haszn�lnak �s a for_each() kiv�tel�vel nem
haszn�lhat
�k olyan muveletek elv�gz�s�re, melyek a sorozat elemeit megv�ltoztatn�k.
18.5.1. A for_each
K�nyvt�rakat az�rt haszn�lunk, hogy ne nek�nk kelljen azzal f�radozni, amit valaki
m�s
m�r megval�s�tott. Egy k�nyvt�r f�ggv�nyeinek, oszt�lyainak, algoritmusainak stb.
haszn�-
lata megk�nny�ti egy program megtervez�s�t, meg�r�s�t, tesztel�s�t �s
dokument�l�s�t is.
A standard k�nyvt�r haszn�lata ezenk�v�l olvashat�bb� is teszi programunkat
olyanok sz�-
m�ra, akik ismerik a k�nyvt�rat, hiszen nem kell idot t�lteni�k a .h�zilag
�sszeeszk�b�lt.
algoritmusok �rtelmez�s�vel.
A standard k�nyvt�r algoritmusainak legfobb elonye, hogy a programoz�nak nem kell
meg�rnia bizonyos ciklusokat. A ciklusok neh�zkesek �s k�nnyen k�vethet�nk el
benn�k
hib�kat. A for_each() algoritmus a legegyszerubb algoritmus, abban az �rtelemben,
hogy
semmi m�st nem csin�l, minthogy egy ciklust helyettes�t, egy sorozat minden
elem�re v�grehajtva
a param�ter�ben megadott muveletet:
template<class In, class Op> Op for_each(In first, In last, Op f)
{
while (first != last) f(*first++);
return f;
}
Milyen f�ggv�nyeket akarunk ilyen form�ban megh�vni? Ha az elemekrol akarunk
inform�-
ci�kat �sszegyujteni, az accumulate() f�ggv�nyt (�22.6) haszn�lhatjuk. Ha meg
akarunk tal
�lni valamit egy sorozatban, rendelkez�s�nkre �ll a find() �s a find_if()
algoritmus. Ha bi-
18. Algoritmusok �s f�ggv�nyobjektumok 697
zonyos elemeket t�r�lni vagy m�dos�tani szeretn�nk, a remove() (�18.6.5), illetve
a replace() (�18.6.4) jelent egyszerubb megold�st. Teh�t mielott haszn�lni kezdj�k

a for_each() elj�r�st, gondoljuk v�gig, nincs-e c�ljainknak jobban megfelelo


algoritmus.
A for_each() eredm�nye az a f�ggv�ny vagy f�ggv�nyobjektum, amelyet harmadik param
�terk�nt megadtunk. A �18.4 pontban a Sum p�lda bemutatta, hogy ez a megold�s
lehet
ov� teszi az eredm�nyek visszaad�s�t a h�v�nak.
A for_each() gyakori felhaszn�l�si ter�lete az, hogy egy sorozat elemeibol
bizonyos inform
�ci�kat fejt�nk ki. P�ld�ul �sszegyujthet�nk neveket klubok egy list�j�b�l:
void extract(const list<Club>& lc, list<Person*>& off)
// hivatalnokok �thelyez�se 'lc'-bol 'off'-ba
{
for_each(lc.begin(),lc.end(),Extract_officers(off));
}
A �18.4 �s a �18.4.2. pontban szereplo p�ld�knak megfeleloen k�sz�thet�nk egy
f�ggv�nyoszt
�lyt, amely kikeresi a k�v�nt inform�ci�t. Ebben az esetben a kigyujtendo neveket
a list<Person*> tartalmazza a Club objektumokon bel�l, ez�rt az Extract_officers
f�ggv�nynek
ki kell m�solnia a hivatalnokokat (officer) a Club objektumok officers list�j�b�l
a gyujt
o list�ba:
class Extract_officers {
list<Person*>& lst;
public:
explicit Extract_officers(list<Person*>& x) : lst(x) { }
void operator()(const Club& c)
{ copy(c.officers.begin(),c.officers.end(),back_inserter(lst)); }
};
A nevek ki�rat�s�t szint�n a for_each() f�ggv�nnyel v�gezhetj�k:
void extract_and_print(const list<Club>& lc)
{
list<Person*> off;
extract(lc,off);
for_each(off.begin(),off.end(),Print_name(cout));
}
A Print_name f�ggv�ny meg�r�s�t meghagyjuk feladatnak (�18.13[4]).
698 A standard k�nyvt�r
A for_each() algoritmust a nem m�dos�t� elj�r�sok k�z� soroltuk, mert k�zvetlen�l
nem
m�dos�t. Ha azonban egy nem konstans sorozatra h�vjuk meg, akkor a harmadik
param�-
terben megadott muvelet m�dos�thatja a sorozatot. (N�zz�k meg p�ld�ul a negate()
f�ggv
�ny haszn�lat�t a �11.9 pontban.)
18.5.2. A find f�ggv�nycsal�d
A find() algoritmusok v�gign�znek egy sorozatot (vagy sorozatp�rt), �s megkeresnek
egy
konkr�t �rt�ket vagy egy olyan elemet, amelyre valamilyen �ll�t�s (predik�tum)
teljes�l.
A find() legegyszerubb v�ltozatai csak ezt a feladatot v�gzik el:
template<class In, class T> In find(In first, In last, const T& val);
template<class In, class Pred> In find_if(In first, In last, Pred p);
A find() �s a find_if() egy bej�r�t ad vissza, amely az elso olyan elemre mutat,
amely a keres
�s felt�tel�nek megfelel. Val�j�ban a find() felfoghat� a find_if() egy olyan
v�ltozat�nak
is, ahol a vizsg�lt predik�tum az ==. Mi�rt nem lett mindk�t f�ggv�ny neve find()?
Az�rt,
mert f�ggv�ny-t�lterhel�ssel nem mindig tudunk k�l�nbs�get tenni k�t azonos
param�tersz
�m� sablon f�ggv�ny k�z�tt:
bool pred(int);
void f(vector<bool(*f)(int)>& v1, vector<int>& v2)
{
find(v1.begin(),v1.end(),pred); // 'pred' keres�se
find_if(v2.begin(),v2.end(),pred); // azon int keres�se, amelyre pred() igazat ad
vissza
}
Ha a find() �s a find_if() f�ggv�nynek ugyanaz lenne a neve, akkor igen meglepo
t�bb�rtelm
us�ggel tal�lkoztunk volna. �ltal�ban az _if ut�tag azt jelzi, hogy az algoritmus
egy predik
�tumot v�r param�terk�nt.
A find_first_of() algoritmus egy sorozat elso olyan elem�t keresi meg, amely
megtal�lhat�
a m�sodik sorozatban is:
template<class For, class For2>
For find_first_of(For first, For last, For2 first2, For2 last2);
template<class For, class For2, class BinPred>
For find_first_of(For first, For last, For2 first2, For2 last2, BinPred p);
18. Algoritmusok �s f�ggv�nyobjektumok 699
P�ld�ul:
int x[ ] = { 1,3,4 };
int y[ ] = { 0,2,3,4,5};
void f()
{
int* p = find_first_of(x,x+3,y,y+5); // p = &x[1]
int* q = find_first_of(p+1,x+3,y,y+5); // q = &x[2]
}
A p mutat� az x[1] elemre fog mutatni, mert a 3 az elso olyan eleme az x-nek,
amely megtal
�lhat� az y-ban. Hasonl�an a q az x[2]-re fog mutatni.
Az adjacent_find() algoritmus k�t egym�s ut�ni, egyezo elemet keres:
template<class For> For adjacent_find(For first, For last);
template<class For, class BinPred> For adjacent_find(For first, For last, BinPred
p);
A visszat�r�si �rt�k egy bej�r�, amely az elso megfelelo elemre mutat:
void f(vector<string>& text)
{
vector<string>::iterator p = adjacent_find(text.begin(),text.end());
if (p!=text.end() && *p=="az") { // M�r megint k�tszer szerepel az "az"!
text.erase(p);
// ...
}
}
18.5.3. A count()
A count() �s a count_if() f�ggv�ny egy �rt�k elofordul�sainak sz�m�t adja meg egy
sorozatban:
template<class In, class T>
typename iterator_traits<In>::difference_type count(In first, In last, const T&
val);
template<class In, class Pred>
typename iterator_traits<In>::difference_type count_if(In first, In last, Pred p);

700 A standard k�nyvt�r


A count() visszat�r�si �rt�ke nagyon �rdekes. K�pzelj�k el, hogy a count()-ot az
al�bbi
egyszeru f�ggv�nnyel val�s�tjuk meg:
template<class In, class T> int count(In first, In last, const T& val)
{
int res = 0;
while (first != last) if (*first++ == val) ++res;
return res;
}
A gond az, hogy egy int lehet, hogy nem felel meg visszat�r�si �rt�knek. Egy olyan
sz�m�-
t�g�pen, ahol az int t�pus el�g kicsi, elk�pzelheto, hogy t�l sok elem van a
sorozatban, �gy
a count() azt nem tudja egy int-be helyezni. Egy nagyteljes�tm�nyu programban,
egyedi
rendszeren viszont �rdemesebb a sz�ml�l� �ltal visszaadott �rt�ket egy short-ban
t�rolni.
Abban biztosak lehet�nk, hogy egy sorozat elemeinek sz�ma nem nagyobb, mint a k�t
bej�r�ja k�z�tti legnagyobb k�l�nbs�g (�19.2.1). Ez�rt az elso gondolatunk a
probl�ma
megold�s�ra az lehet, hogy a visszat�r�si �rt�k t�pus�t a k�vetkezok�ppen
hat�rozzuk meg:
typename In::difference_type
Egy szabv�nyos algoritmusnak azonban a be�p�tett t�mb�kre ugyan�gy kell muk�dnie,
mint a szabv�nyos t�rol�kra:
void f(const char* p, int size)
{
int n = count(p,p+size,'e'); // az 'e' betu elofordul�sainak megsz�ml�l�sa
}
Sajnos az int*::difference_type kifejez�s a C++-ban nem �rtelmezheto. Ez a
probl�ma az
iterator_traits t�pus (�19.2.2) r�szleges specializ�ci�j�val oldhat� meg.
18.5.4. Egyenlos�g �s elt�r�s
Az equal() �s a mismatch() f�ggv�ny k�t sorozatot hasonl�t �ssze:
template<class In, class In2> bool equal(In first, In last, In2 first2);
template<class In, class In2, class BinPred>
bool equal(In first, In last, In2 first2, BinPred p);
18. Algoritmusok �s f�ggv�nyobjektumok 701
template<class In, class In2> pair<In, In2> mismatch(In first, In last, In2
first2);
template<class In, class In2, class BinPred>
pair<In, In2> mismatch(In first, In last, In2 first2, BinPred p);
Az equal() algoritmus egyszeruen azt mondja meg, hogy a k�t sorozat minden k�t
megfelel
o eleme megegyezik-e, m�g a mismatch() az elso olyan elemp�rt keresi, melyek nem
egyenloek, �s ezekre mutat� bej�r�kat ad vissza. A m�sodik sorozat v�g�t nem kell
megadnunk
(teh�t nincs last2), mert a rendszer azt felt�telezi, hogy az legal�bb olyan
hossz�,
mint az elso sorozat �s a last2 �rt�ket a first2+(last-first) kifejez�ssel
sz�m�tja ki. Ezt a m�dszert
gyakran l�thatjuk a standard k�nyvt�rban, amikor k�t sorozat �sszetartoz� elemei
k�-
z�tt v�gz�nk valamilyen muveletet.
A �18.5.1 pontban m�r eml�tett�k, hogy ezek az algoritmusok sokkal hasznosabbak,
mint
azt elso r�n�z�sre gondoln�nk, mert a programoz� hat�rozhatja meg azt a
predik�tumot,
melyet az elemek egyen�rt�kus�g�nek eld�nt�s�hez akar haszn�lni.
A sorozatoknak nem is kell ugyanolyan t�pus�aknak lenni�k:
void f(list<int>& li, vector<double>& vd)
{
bool b = equal(li.begin(),li.end(),vd.begin());
}
Az egyetlen kik�t�s, hogy a predik�tum param�tereik�nt haszn�lhassuk az elemeket.
A mismatch() k�t v�ltozata csak a predik�tumok haszn�lat�ban k�l�nb�zik. Val�j�ban

megval�s�thatjuk oket egyetlen f�ggv�nnyel is, amelynek van alap�rtelmezett


sablonparam
�tere:
template<class In, class In2, class BinPred>
pair<In, In2> mismatch(In first, In last, In2 first2,
BinPred p = equal_to<In::value_type>()) // �18.4.2.1
{
while (first != last && p(*first,*first2)) {
++first;
++first2;
}
return pair<In,In2>(first,first2);
}
702 A standard k�nyvt�r
A k�t k�l�n f�ggv�ny megad�sa �s az egyetlen, alap�rtelmezett param�terrel
meghat�rozott
f�ggv�ny k�z�tt akkor l�thatjuk a k�l�nbs�get, ha mutat�kat adunk �t a
f�ggv�nyeknek. Ennek
ellen�re, ha �gy gondolunk a szabv�nyos algoritmusok k�l�nb�zo v�ltozataira, mint
egy alap�rtelmezett predik�tummal rendelkezo f�ggv�nyre, akkor k�r�lbel�l
feleannyi sablon
f�ggv�nyre kell eml�kezn�nk.
18.5.5. Keres�s
A search(), a search_n() �s a find_end() algoritmus egy r�szsorozatot keres egy
m�sik
sorozatban:
template<class For, class For2>
For search(For first, For last, For2 first2, For2 last2);
template<class For, class For2, class BinPred>
For search(For first, For last, For2 first2, For2 last2, BinPred p);
template<class For, class For2>
For find_end(For first, For last, For2 first2, For2 last2);
template<class For, class For2, class BinPred>
For find_end(For first, For last, For2 first2, For2 last2, BinPred p);
template<class For, class Size, class T>
For search_n(For first, For last, Size n, const T& val);
template<class For, class Size, class T, class BinPred>
For search_n(For first, For last, Size n, const T& val, BinPred p);
A search() f�ggv�ny a m�sodikk�nt megadott sorozatot keresi az elsoben. Ha
megtal�lhat
� ez a r�szsorozat, egy bej�r�t kapunk eredm�ny�l, amely az elso illeszkedo elemet
jel�li
ki az elso sorozatban. Ha a keres�s sikertelen, akkor a sorozat v�g�t (last)
kapjuk eredm
�nyk�ppen. Teh�t a visszat�r�si �rt�k mindig a [first,last] tartom�nyban van:
string quote("Minek vesztegess�k az idot tanul�sra, mikor a tudatlans�g
azonnali?");
bool in_quote(const string& s)
{
typedef string::const_iterator I;
I p = search(quote.begin(),quote.end(),s.begin(),s.end()); // s keres�se az
id�zetben (quote)
return p!=quote.end();
}
18. Algoritmusok �s f�ggv�nyobjektumok 703
void g()
{
bool b1 = in_quote("tanul�sra"); // b1 = true
bool b2 = in_quote("tan�t�sra"); // b2 = false
}
Teh�t a search() muvelettel egy r�szsorozatot kereshet�nk mindenf�le sorozatra
�ltal�nos
�tva. Ebbol m�r �rezhetj�k, hogy a search() egy nagyon hasznos algoritmus.
A find_end() is a m�sodikk�nt megadott sorozatot keresi r�szsorozatk�nt az
elsoben. Ha sikeres
a keres�s, a find_end() az illeszkedo r�sz utols� elem�re mutat� bej�r�t adja
vissza.
Mondhatjuk azt is, hogy a find_end() visszafel� v�gzi ugyanazt a keres�st, mint a
search().
Teh�t nem a r�szsorozat elso elofordul�s�t kapjuk meg, hanem az utols�t. A
search_n() elj
�r�s egy olyan r�szsorozatot keres, amely legal�bb n hosszon a value param�terben
megadott
�rt�ket tartalmazza. A visszat�r�si �rt�k egy olyan bej�r�, amely az n darab
illeszked
�s elso elem�re mutat a sorozatban.
18.6. M�dos�t� algoritmusok sorozatokra
Ha meg akarunk v�ltoztatni egy sorozatot, akkor megtehetj�k, hogy egyes�vel
v�gign�zz�k
az elemeket �s k�zben m�dos�tjuk a megfelelo �rt�keket. De ha lehetos�g van r�,
akkor ezt
a programoz�si st�lust �rdemes elker�ln�nk. Helyette egyszerubb �s
rendszerezettebb megold
�s �ll a rendelkez�s�nkre: haszn�ljuk a szabv�nyos algoritmusokat a sorozatok
bej�r�-
s�ra �s a m�dos�t� muveletek elv�gz�s�re. A nem m�dos�t� algoritmusok (�18.5)
ugyan�gy
mennek v�gig az elemeken, de csak kiolvass�k az inform�ci�kat. A m�dos�t�
algoritmusok
seg�ts�g�vel a leggyakoribb friss�t�si feladatokat v�gezhetj�k el. Ezek egy r�sze
az eredeti
sorozatot m�dos�tja, m�g m�sok �j sorozatot hoznak l�tre az �ltalunk megadott
sorozat
alapj�n.
A szabv�nyos algoritmusok a bej�r�k seg�ts�g�vel f�rnek hozz� az
adatszerkezetekhez. Ebb
ol k�vetkezik, hogy egy �j elem besz�r�sa egy t�rol�ba vagy egy elem t�rl�se nem
egyszer
u feladat. P�ld�ul, ha csak egy bej�r� �ll rendelkez�s�nkre, hogyan tal�lhatjuk
meg azt
a t�rol�t, amelybol a kijel�lt elemet t�r�lni kell? Hacsak nem haszn�lunk egyedi
bej�r�kat
(p�ld�ul besz�r�kat, inserter, �3.8, �19.2.4), a bej�r�kon kereszt�l v�gzett
muveletek nem
v�ltoztathatj�k meg a t�rol� m�ret�t. Az elemek besz�r�sa �s t�rl�se helyett az
algoritmusok
csak az elemek �rt�k�t v�ltoztatj�k meg, illetve felcser�lnek vagy m�solnak
elemeket.
M�g a remove() is �gy muk�dik, hogy csak fel�l�rja a t�r�lni k�v�nt elemeket
(�18.6.5).
704 A standard k�nyvt�r
Az alapveto m�dos�t� algoritmusok �ltal�ban egy m�dos�tott m�solatot hoznak l�tre
a megadott
sorozatb�l. Azok az algoritmusok, melyek sorozatm�dos�t�knak tunnek, val�j�ban
csak a m�sol�k m�dos�tott v�ltozatai.
18.6.1. M�sol�s
A m�sol�s a legegyszerubb m�dszer arra, hogy egy sorozatb�l egy m�sikat �ll�tsunk
elo.
Az alapveto m�sol� muveletek rendk�v�l egyszeruek:
template<class In, class Out> Out copy(In first, In last, Out res)
{
while (first != last) *res++ = *first++;
return res;
}
template<class Bi, class Bi2> Bi2 copy_backward(Bi first, Bi last, Bi2 res)
{
while (first != last) *--res = *--last;
return res;
}
A m�sol� algoritmus kimenet�nek nem kell felt�tlen�l t�rol�nak lennie. B�rmit
haszn�lhatunk,
amihez kimeneti bej�r� (�19.2.6) megadhat�:
void f(list<Club>& lc, ostream& os)
{
copy(lc.begin(),lc.end(),ostream_iterator<Club>(os));
}
Egy sorozat beolvas�s�hoz meg kell adnunk, hogy hol kezdodik �s hol �r v�get. Az
�r�shoz
csak az az egy bej�r� kell, amelyik megmondja, hov� �rjunk. Arra azonban ilyenkor
is figyeln
�nk kell, hogy ne �rjunk a fogad� t�rol� hat�rain t�lra. A probl�ma egyik
lehets�ges
megold�sa a besz�r� (inserter) bej�r�k (�19.2.4) haszn�lata, mellyel a fogad�
adatszerkezetet
bov�thetj�k, ha arra sz�ks�g van:
void f(vector<char>& vs)
{
vector<char> v;
copy(vs.begin(),vs.end(),v.begin()); // t�l�rhat v v�g�n
copy(vs.begin(),vs.end(),back_inserter(v)); // elemek hozz�ad�sa vs-bol v v�g�hez
}
18. Algoritmusok �s f�ggv�nyobjektumok 705
A bemeneti �s a kimeneti sorozat �tfedhetik egym�st. Ha a sorozatok k�z�tt nincs
�tfed�s
vagy a kimeneti sorozat v�ge a bemeneti sorozat belsej�ben van, akkor a copy()
f�ggv�nyt
haszn�ljuk. A copy_backward() utas�t�sra akkor van sz�ks�g, ha a kimeneti sorozat
eleje
van a bemeneti sorozatban. Ez a f�ggv�ny ilyen helyzetben addig nem �rja fel�l az
elemeket,
am�g azokr�l m�solat nem k�sz�lt (l�sd m�g �18.13[13]).
Term�szetesen ahhoz, hogy valamit visszafel� m�soljunk le, egy k�tir�ny� bej�r�ra
(�19.2.1) van sz�ks�g�nk, mind a bemeneti, mind a kimeneti sorozatban:
void f(vector<char>& vc)
{
vector<char> v(vc.size());
copy_backward(vc.begin(),vc.end(),ostream_iterator<char>(cout)); // hiba
copy_backward(vc.begin(),vc.end(),v.end()); // rendben
copy(v.begin(),v.end(),ostream_iterator<char>(cout)); // rendben
}
Gyakran olyan elemeket szeretn�nk m�solni, amelyek egy bizonyos felt�telt
teljes�tenek.
Sajnos a copy_if() f�ggv�ny valahogy kimaradt a standard k�nyvt�r �ltal ny�jtott
algoritmusok
sor�b�l (mea culpa). De ha sz�ks�g�nk van r�, pillanatok alatt meg�rhatjuk:
template<class In, class Out, class Pred> Out copy_if(In first, In last, Out res,
Pred p)
{
while (first != last) {
if (p(*first)) *res++ = *first;
++first;
}
return res;
}
Ezut�n ha az n �rt�kn�l nagyobb elemeket akarjuk megjelen�teni, a k�vetkezo
elj�r�st
haszn�lhatjuk:
void f(list<int>&ld, int n, ostream& os)
{
copy_if(ld.begin(),ld.end(),ostream_iterator<int>(os),bind2nd(greater<int>(),n));
}
(L�sd m�g a remove_copy_if()le�r�s�t is a �18.6.5 pontban.)
706 A standard k�nyvt�r
18.6.2. Transzform�ci�k
Egy kicsit f�lrevezeto a neve, ugyanis a transform() nem felt�tlen�l v�ltoztatja
meg a bemenet
�t. Ehelyett egy olyan kimenetet �ll�t elo, amely a bemeneten v�gzett felhaszn�l�i
muvelet
eredm�nye:
template<class In, class Out, class Op>
Out transform(In first, In last, Out res, Op op)
{
while (first != last) *res++ = op(*first++);
return res;
}
template<class In, class In2, class Out, class BinOp>
Out transform(In first, In last, In2 first2, Out res, BinOp op)
{
while (first != last) *res++ = op(*first++,*first2++);
return res;
}
A transform() f�ggv�ny elso v�ltozata, amely csak egy sorozatot olvas be, nagyon
hasonl�t
az egyszeru m�sol�sra. A k�l�nbs�g mind�ssze annyi, hogy a k�zvetlen ki�r�s
helyett elobb
egy transzform�ci�t (�talak�t�st) is elv�gez az elemen. �gy a copy() elj�r�st a
transform()
f�ggv�nnyel is meghat�rozhattuk volna, �gy, hogy az elemm�dos�t� muvelet
egyszeruen
csak visszaadja a param�ter�t:
template<class T> T identity(const T& x) { return x; }
template<class In, class Out> Out copy(In first, In last, Out res)
{
return transform(first,last,res,identity);
}
Az identity explicit minos�t�se ahhoz sz�ks�ges, hogy a f�ggv�nysablonb�l konkr�t
f�ggv
�nyt kapjunk, az iterator_traits sablont (�19.2.2) pedig az�rt haszn�ltuk, hogy az
In elemt
�pus�hoz jussunk.
A transform() f�ggv�nyt tekinthetj�k a for_each() egy v�ltozat�nak is, amely
k�zvetlen�l
�ll�tja elo kimenet�t. P�ld�ul klubok list�j�b�l a transform() seg�ts�g�vel
k�sz�thet�nk egy
olyan list�t, amely csak a klubok neveit t�rolja:
string nameof(const Club& c) // n�v kinyer�se
{
return c.name;
}
18. Algoritmusok �s f�ggv�nyobjektumok 707
void f(list<Club>& lc)
{
transform(lc.begin(),lc.end(),ostream_iterator<string>(cout),nameof);
}
A transform() f�ggv�ny elnevez�s�nek egyik oka az, hogy az eredm�nyt gyakran
vissza�rjuk
oda, ahonnan a param�tert kaptuk. P�ld�ul ha olyan objektumokat akarunk t�r�lni,
melyekre
mutat�k hivatkoznak, a k�vetkezo elj�r�st haszn�lhatjuk:
struct Delete_ptr { //f�ggv�nyobjektum haszn�lata helyben kifejt�shez (inline
ford�t�shoz)
template<class T> T* operator() (T* p) { delete p; return 0; }
};
void purge(deque<Shape*>& s)
{
transform(s.begin(),s.end(),s.begin(),Delete_ptr);
}
A transform() algoritmus eredm�nye mindig egy kimeneti sorozat. A fenti p�ld�ban
az
eredm�nyt az eredeti bemeneti sorozatba ir�ny�tottuk vissza, �gy a Delete_ptr()(p)
jelent�-
se p=Delete_ptr()(p) lesz. Ez indokolja a 0 visszat�r�si �rt�ket a
Delete_ptr::operator()()
f�ggv�nyben.
A transform() algoritmus m�sik v�ltozata k�t bemeneti sorozattal dolgozik. Ez
lehetov� teszi,
hogy k�t sorozat adatait haszn�ljuk fel az �j sorozat l�trehoz�s�hoz. Egy
anim�ci�s
programban p�ld�ul sz�ks�g lehet egy olyan elj�r�sra, amely alakzatok sorozat�nak
hely�t
friss�ti valamilyen �talak�t�ssal:
Shape* move_shape(Shape* s, Point p) // *s += p
{
s->move_to(s->center()+p);
return s;
}
void update_positions(list<Shape*>& ls, vector<Point>& oper)
{
// muvelet v�grehajt�sa a megfelelo objektumon
transform(ls.begin(),ls.end(),oper.begin(),ls.begin(),move_shape);
}
Val�j�ban nem lenne sz�ks�g�nk arra, hogy a move_shape() f�ggv�nynek visszat�r�si
�rt
�ke legyen, de a transform() ragaszkodik a muvelet eredm�ny�nek felhaszn�l�s�hoz,
�gy
a move_shape() visszaadja az elso operandus�t, amelyet vissza�rhatunk az eredeti
hely�re.
708 A standard k�nyvt�r
Bizonyos helyzetekben ezt a probl�m�t nem oldhatjuk meg �gy. Ha a muveletet
p�ld�ul
nem mi �rtuk vagy nem akarjuk megv�ltoztatni, akkor nem �ll rendelkez�s�nkre a
megfelel
o visszat�r�si �rt�k. M�skor a bemeneti sorozat const. Ezekben az esetekben egy
k�tsorozatos
for_each() f�ggv�nyt k�sz�thet�nk, amely a k�tsorozatos transform() p�rj�nak
tekintheto:
template<class In, class In2, class BinOp>
BinOp for_each(In first, In last, In2 first2, BinOp op)
{
while (first != last) op(*first++,*first2++);
return op;
}
void update_positions(list<Shape*>& ls, vector<Point>& oper)
{
for_each(ls.begin(),ls.end(),oper.begin(),move_shape);
}
Esetenk�nt olyan kimeneti bej�r� is hasznos lehet, amely val�j�ban semmit sem �r
(�19.6[2]).
A standard k�nyvt�r nem tartalmaz olyan algoritmusokat, melyek h�rom vagy n�gy
sorozatb
�l olvasnak, b�r ezek is k�nnyen elk�sz�thetok. Helyett�k haszn�lhatjuk t�bbsz�r
egym
�s ut�n a transform() f�ggv�nyt.
18.6.3. Ism�tlodo elemek t�rl�se
Amikor inform�ci�kat gyujt�nk, k�nnyen elofordulhatnak ism�tlod�sek. A unique() �s

a unique_copy() algoritmusokkal az egym�s ut�n elofordul� azonos �rt�keket


t�vol�thatjuk el:
template<class For> For unique(For first, For last);
template<class For, class BinPred> For unique(For first, For last, BinPred p);
template<class In, class Out> Out unique_copy(In first, In last, Out res);
template<class In, class Out, class BinPred>
Out unique_copy(In first, In last, Out res, BinPred p);
A unique() megsz�nteti a sorozatban egym�s ut�n elofordul� �rt�kism�tlod�seket,
a unique_copy() pedig egy m�solatot k�sz�t az ism�tlod�sek elhagy�s�val:
18. Algoritmusok �s f�ggv�nyobjektumok 709
void f(list<string>& ls, vector<string>& vs)
{
ls.sort(); // listarendez�s (�17.2.2.1)
unique_copy(ls.begin(),ls.end(),back_inserter(vs));
}
Ezzel a programr�szlettel az ls list�t �tm�solhatjuk a vs vektorba �s menet k�zben
kiszurhetj
�k az ism�tlod�seket. A sort() utas�t�sra az�rt van sz�ks�g, hogy az egyen�rt�ku
elemek
egym�s mell� ker�ljenek.
A t�bbi szabv�nyos algoritmushoz hasonl�an a unique() is bej�r�kkal dolgozik. Azt
nem
lehet meg�llap�tani, hogy ezek a bej�r�k milyen t�pus� t�rol�ra mutatnak, �gy a
t�rol�t nem
v�ltoztathatjuk meg, csak az annak elemeiben t�rolt �rt�keket m�dos�thatjuk. Ebbol
k�vetkezik,
hogy a unique() nem t�rli az ism�tlod�seket a sorozatb�l, ahogy azt na�van rem�ln
�nk. Ehelyett az egyedi elemeket a sorozat elej�re helyezi �s visszaad egy
bej�r�t, amely
az egyedi elemek r�szsorozat�nak v�g�re mutat:
template <class For> For unique(For first, For last)
{
first = adjacent_find(first,last); // �18.5.2
return unique_copy(first,last,first);
}
A r�szsorozat ut�ni elemek v�ltozatlanok maradnak, teh�t egy vektor eset�ben ez a
megold
�s nem sz�nteti meg az ism�tlod�seket:
void f(vector<string>& vs) // vigy�zat: rossz k�d!
{
sort(vs.begin(),vs.end()); // vektorrendez�s
unique(vs.begin(),vs.end()); // ism�tlod�sek elt�vol�t�sa (nem muk�dik!)
}
Sot azzal, hogy a unique() a sorozat v�g�n �ll� elemeket elore helyezi az
�rt�kism�tlod�-
sek megsz�ntet�s�hez, ak�r �j ism�tlod�sek is keletkezhetnek:
int main()
{
char v[ ] = "abbcccde";
char* p = unique(v,v+strlen(v));
cout << v << ' ' << p-v << '\n';
}
710 A standard k�nyvt�r
Az eredm�ny a k�vetkezo lesz:
abcdecde 5
Teh�t a p a m�sodik c beture mutat.
Azoknak az algoritmusoknak, melyeknek t�r�lnie kellene elemeket (de ezt nem tudj�k

megtenni), �ltal�ban k�t v�ltozata van. Az egyik a uniqe() m�dszer�vel �trendezi


az elemeket,
a m�sik egy �j sorozatot hoz l�tre a unique_copy() muk�d�s�hez hasonl�an. A _copy
ut�tag ezen k�t v�ltozat megk�l�nb�ztet�s�re szolg�l.
Ahhoz hogy az ism�tlod�seket t�nylegesen kiszurj�k egy t�rol�b�l, m�g egy tov�bbi
utas�-
t�sra van sz�ks�g:
template<class C> void eliminate_duplicates(C& c)
{
sort(c.begin(),c.end()); // rendez�s
typename C::iterator p = unique(c.begin(),c.end()); // t�m�r�t�s
c.erase(p,c.end()); // zsugor�t�s
}
Sajnos az eliminate_duplicates() f�ggv�ny a be�p�tett t�mb�kh�z nem haszn�lhat�,
m�g
a unique() azokn�l is muk�dik.
A unique_copy() haszn�lat�ra a �3.8.3. pontban mutattunk p�ld�t.
18.6.3.1. Rendez�si szempont
Az �sszes ism�tlod�s megsz�ntet�s�hez a bemeneti sorozatot rendezn�nk kell
(�18.7.1).
Alap�rtelmez�s szerint a unique() �s a unique_copy() is az == oper�tort haszn�lja
az egyenl
os�gvizsg�lathoz, de lehetov� teszik, hogy a programoz� m�s muveletet adjon meg.
A �18.5.1 pontban szereplo programr�szletet p�ld�ul �talak�thatjuk �gy, hogy
kiszurje az
ism�tlodo neveket. Miut�n a klubok hivatalnokainak nev�t �sszegyujt�tt�k, az off
list�hoz
jutottunk, melynek t�pusa list<Person*> (�18.5.1). Ebbol a list�b�l az
ism�tlod�seket a k�-
vetkezo utas�t�ssal t�r�lhetj�k:
eliminate_duplicates(off);
Ez a megold�s azonban mutat�kat rendez, �s csak akkor fog c�ljainknak megfeleloen
mu-
k�dni, ha felt�telezz�k, hogy minden Person objektumra egyetlen mutat� hivatkozik.

18. Algoritmusok �s f�ggv�nyobjektumok 711


Az egyen�rt�kus�g eld�nt�s�hez �ltal�ban magukat a Person rekordokat kell
megvizsg�lnunk.
Ehhez a k�vetkezo programr�szletet kell meg�rnunk:
bool operator==(const Person& x, const Person& y) // "egyenlos�g" objektumra
{
// x �s y �sszehasonl�t�sa egyenlos�gre
}
bool operator<(const Person& x, const Person& y) // "kisebb mint" objektumra
{
// x �s y �sszehasonl�t�sa rendezetts�gre
}
bool Person_eq(const Person* x, const Person* y) // "egyenlos�g" mutat�n kereszt�l

{
return *x == *y;
}
bool Person_lt(const Person* x, const Person* y) // "kisebb mint" mutat�n
kereszt�l
{
return *x < *y;
}
void extract_and_print(const list<Club>& lc)
{
list<Person*> off;
extract(lc,off);
off.sort(off,Person_lt);
list<Club>::iterator p = unique(off.begin(),off.end(),Person_eq);
for_each(off.begin(),p,Print_name(cout));
}
�rdemes mindig gondoskodnunk arr�l, hogy a rendez�shez haszn�lt felt�tel ugyanaz
legyen,
mint az ism�tlod�sek kiszur�s�re szolg�l� elj�r�s. A < �s az == oper�torok
alap�rtelmezett
jelent�se mutat�k eset�ben �ltal�ban nem felel meg sz�munkra a mutatott objektumok

�sszehasonl�t�s�hoz.
18.6.4. Helyettes�t�s
A replace() algoritmusok v�gighaladnak a megadott sorozaton, �s egyes �rt�keket
�jakra
cser�lnek, a mi ig�nyeinknek megfeleloen. Ugyanazt a mint�t k�vetik, mint a
find/find_if
�s a unique/unique_copy, �gy �sszesen n�gy v�ltozatra van sz�ks�g. A f�ggv�nyek
megval
�s�t�sa most is el�g egyszeru ahhoz, hogy j�l magyar�zza szerep�ket:
712 A standard k�nyvt�r
template<class For, class T>
void replace(For first, For last, const T& val, const T& new_val)
{
while (first != last) {
if (*first == val) *first = new_val;
++first;
}
}
template<class For, class Pred, class T>
void replace_if(For first, For last, Pred p, const T& new_val)
{
while (first != last) {
if (p(*first)) *first = new_val;
++first;
}
}
template<class In, class Out, class T>
Out replace_copy(In first, In last, Out res, const T& val, const T& new_val)
{
while (first != last) {
*res++ = (*first == val) ? new_val : *first;
++first;
}
return res;
}
template<class In, class Out, class Pred, class T>
Out replace_copy_if(In first, In last, Out res, Pred p, const T& new_val)
{
while (first != last) {
*res++ = p(*first) ? new_val : *first;
++first;
}
return res;
}
Surun elofordul, hogy karakterl�ncok egy list�j�n v�gighaladva sz�lov�rosom
szok�sos angol
�t�r�s�t (Aarhus) a helyes Arhus v�ltozatra kell cser�lnem:
void f(list<string>& towns)
{
replace(towns.begin(),towns.end(),"Aarhus","Arhus");
}
Term�szetesen ehhez egy kibov�tett karakterk�szletre van sz�ks�g (�C.3.3)
18. Algoritmusok �s f�ggv�nyobjektumok 713
18.6.5. T�rl�s
A remove() algoritmusok elemeket t�r�lnek egy sorozatb�l, �rt�k vagy felt�tel
alapj�n:
template<class For, class T> For remove(For first, For last, const T& val);
template<class For, class Pred> For remove_if(For first, For last, Pred p);
template<class In, class Out, class T>
Out remove_copy(In first, In last, Out res, const T& val);
template<class In, class Out, class Pred>
Out remove_copy_if(In first, In last, Out res, Pred p);
Tegy�k fel p�ld�ul, hogy a Club oszt�lyban szerepel egy c�m mezo is �s feladatunk
az, hogy
�sszegyujts�k a koppenh�gai klubokat:
class located_in : public unary_function<Club,bool> {
string town;
public:
located_in(const string& ss) :town(ss) { }
bool operator()(const Club& c) const { return c.town == town; }
};
void f(list<Club>& lc)
{
remove_copy_if(lc.begin(),lc.end(),
ostream_iterator<Club>(cout),not1(located_in("Kobenhavn")));
}
A remove_copy_if() ugyanaz, mint a copy_if(), csak ford�tott felt�tellel. Teh�t
a remove_copy_if() akkor helyez egy elemet a kimenetre, ha az nem el�g�ti ki a
felt�telt.
A .sima. remove()a sorozat elej�re gyujti a nem t�rlendo elemeket �s az �gy
k�pzett r�szsorozat
v�g�re mutat� bej�r�t ad vissza (l�sd m�g �18.6.3).
18.6.6. Felt�lt�s �s l�trehoz�s
A fill() �s a generate() algoritmusok seg�ts�g�vel rendszerezetten t�lthet�nk fel
egy sorozatot
�rt�kekkel:
template<class For, class T> void fill(For first, For last, const T& val);
template<class Out, class Size, class T> void fill_n(Out res, Size n, const T&
val);
714 A standard k�nyvt�r
template<class For, class Gen> void generate(For first, For last, Gen g);
template<class Out, class Size, class Gen> void generate_n(Out res, Size n, Gen
g);
A fill() f�ggv�ny megadott �rt�keket ad a sorozat elemeinek, m�g a generate()
algoritmus
�gy �ll�tja elo az �rt�keket, hogy mindig megh�vja a megadott f�ggv�nyt. Teh�t a
fill()
a generate() egyedi v�ltozata, amikor az �rt�keket elo�ll�t� (l�trehoz�,
gener�tor) f�ggv�ny
mindig ugyanazt az �rt�ket adja vissza. Az _n v�ltozatok a sorozat elso n elem�nek
adnak
�rt�ket.
A �22.7 pont Randint �s Urand v�letlensz�m-elo�ll�t�j�nak felhaszn�l�s�val p�ld�ul
a k�-
vetkezot �rhatjuk:
int v1[900];
int v2[900];
vector v3;
void f()
{
fill(v1,&v1[900],99); // v1 minden elem�nek 99-re �ll�t�sa
generate(v2,&v2[900],Randint()); // v�letlen �rt�kekre �ll�t�s (�22.7)
// 200 v�letlen eg�sz k�ld�se a kimenetre a [0..99] tartom�nyb�l
generate_n(ostream_iterator<int>(cout),200,Urand(100));
fill_n(back_inserter(v3),20,99); // 20 darab 99 �rt�ku elem hozz�ad�sa v3-hoz
}
A generate() �s a fill() nem kezdeti, hanem egyszeru �rt�kad�st v�gez. Ha nyers
t�rol�ter�-
letet akarunk felhaszn�lni (p�ld�ul egy mem�riaszeletet meghat�rozott t�pus� �s
�llapot�
objektumm� szeretn�nk alak�tani), haszn�lhatjuk p�ld�ul az uninitialized_fill()
f�ggv�nyt,
a <memory> fej�llom�nyb�l (�19.4.4). Az <algorithm> �llom�ny algoritmusai ilyen
c�lokra
nem felelnek meg.
18.6.7. Megford�t�s �s elforgat�s
Idonk�nt sz�ks�g�nk van r�, hogy egy sorozat elemeit �trendezz�k:
template<class Bi> void reverse(Bi first, Bi last);
template<class Bi, class Out> Out reverse_copy(Bi first, Bi last, Out res);
template<class For> void rotate(For first, For middle, For last);
template<class For, class Out> Out rotate_copy(For first, For middle, For last,
Out res);
18. Algoritmusok �s f�ggv�nyobjektumok 715
template<class Ran> void random_shuffle(Ran first, Ran last);
template<class Ran, class Gen> void random_shuffle(Ran first, Ran last, Gen& g);
A reverse() algoritmus megford�tja az elemek sorrendj�t, teh�t az elso elem lesz
az utols�
stb. A reverse_copy() szok�s szerint egy m�solatban �ll�tja ero bemeneti
sorozat�nak megford
�t�s�t.
A rotate() algoritmus a [first, last[ sorozatot k�rk�nt kezeli, �s addig forgatja
az elemeket,
m�g a kor�bbi middle elem a sorozat elej�re nem ker�l. Teh�t az az elem, amely
eddig
a first+i poz�ci�n volt, a muvelet ut�n a first+ (i+ (last.middle)) %(last-first)
helyre ker�l.
A % (modulus) oper�tor teszi a forgat�st ciklikuss� az egyszeru balral�ptet�s
helyett:
void f()
{
string v[ ] = { "B�ka", "�s","Barack" };
reverse(v,v+3); // Barack �s B�ka
rotate(v,v+1,v+3); // �s B�ka Barack
}
A rotate_copy() egy m�solatban �ll�tja elo bemeneti sorozat�nak elforgatott
v�ltozat�t.
Alap�rtelmez�s szerint a random_shuffle() megkeveri a param�ter�ben megadott
sorozatot
egy egyenletes eloszl�s� v�letlensz�mokat elo�ll�t� elj�r�s seg�ts�g�vel. Teh�t az
elemek
sorozat�nak egy permut�ci�j�t (lehets�ges elemsorrendj�t) v�lasztja ki �gy, hogy
mindegyik
permut�ci�nak ugyanakkora es�lye van. Ha m�s eloszl�st szeretn�nk el�rni vagy
egyszer
uen csak jobb v�letlensz�m-elo�ll�t�nk van, akkor azt megadhatjuk a
random_shuffle()
f�ggv�nynek. A �22.7. pont Urand elj�r�s�val p�ld�ul a k�vetkezok�ppen keverhetj�k
meg
egy k�rtyapakli lapjait:
void f(deque<Card>& dc, My_rand& r)
{
random_shuffle(dc.begin(),dc.end(),r);
// ...
}
Az elemek �thelyez�s�t a rotate() �s m�s f�ggv�nyek a swap() f�ggv�ny (�18.6.8)
seg�ts�-
g�vel hajtj�k v�gre.
716 A standard k�nyvt�r
18.6.8. Elemek felcser�l�se
Ha b�rmi �rdekeset szeretn�nk v�grehajtani egy t�rol� elemeivel, akkor mindig �t
kell helyezn
�nk azokat. Ezt az �thelyez�st legjobban . teh�t a legegyszerubben �s a
leghat�konyabban
. a swap() f�ggv�nnyel fejezhetj�k ki:
template<class T> void swap(T& a, T& b)
{
T tmp = a;
a = b;
b = tmp;
}
template<class For, class For2> void iter_swap(For x, For2 y);
template<class For, class For2> For2 swap_ranges(For first, For last, For2 first2)

{
while (first != last) iter_swap(first++, first2++);
return first2;
}
Ahhoz, hogy felcser�lj�nk elemeket, egy ideiglenes t�rol�ra van sz�ks�g�nk. Egyes
esetekben
lehetnek �gyes tr�kk�k, melyekkel ez elker�lheto, de az egyszerus�g �s �rthetos�g
�rdek
�ben �rdemes elker�lni az ilyesmit. A swap() algoritmus rendelkezik egyedi c�l�
v�ltozatokkal
azokhoz a t�pusokhoz, ahol erre sz�ks�g lehet (�16.3.9, �13.5.2).
Az iter_swap() algoritmus bej�r�kkal kijel�lt elemeket cser�l fel, a swap_ranges()
pedig k�t
bemeneti param�tere �ltal meghat�rozott tartom�nya elemeit cser�li fel.
18.7. Rendezett sorozatok
Miut�n �sszegyujt�tt�k az adatokat, �ltal�ban szeretn�nk rendezni azokat. Ha
rendezett sorozat
�ll rendelkez�s�nkre, sokkal t�bb lehetos�g�nk lesz arra, hogy adatainkat
k�nyelmesen
kezelj�k.
Egy sorozat rendez�s�hez valahogyan �ssze kell hasonl�tanunk az elemeket. Ehhez
egy
k�tparam�teru predik�tumot (�18.4.2) haszn�lhatunk. Az alap�rtelmezett
�sszehasonl�t�
muvelet a less (�18.4.2), amely viszont alap�rtelmez�s szerint a < oper�tort
haszn�lja.
18. Algoritmusok �s f�ggv�nyobjektumok 717
18.7.1. Rendez�s
A sort() rendezo algoritmusoknak k�zvetlen el�r�su (v�letlen el�r�su) bej�r�kra
(�19.2.1)
van sz�ks�g�k. Ebbol k�vetkezik, hogy a vektorok (�16.3) �s az ahhoz hasonl�
szerkezetek
eset�ben muk�dnek a leghat�konyabban:
template<class Ran> void sort(Ran first, Ran last);
template<class Ran, class Cmp> void sort(Ran first, Ran last, Cmp cmp);
template<class Ran> void stable_sort(Ran first, Ran last);
template<class Ran, class Cmp> void stable_sort(Ran first, Ran last, Cmp cmp);
A szabv�nyos list (�17.2.2) oszt�ly nem biztos�t k�zvetlen hozz�f�r�su bej�r�kat,
�gy azokat
megfelelo listamuveletekkel (�17.2.2.1) kell rendezn�nk.
Az egyszeru sort() elj�r�s el�g hat�kony . �tlagosan N*log(N) . de a legrosszabb
esetre vett
hat�konys�g el�g rossz: O(N*N). Szerencs�re a .legrosszabb. eset el�g ritka. Ha a
legrosszabb
esetben is garant�lt muk�d�sre vagy stabil rendez�sre van sz�ks�g�nk, haszn�ljuk
a stable_sort() f�ggv�nyt. Ennek hat�konys�ga N*log(N)*log(N), ami N*log(N)
�rt�kre
javul, ha a rendszerben el�g mem�ria �ll rendelkez�s�nkre. A stable_sort() . a
sort() f�ggv
�nnyel ellent�tben . megtartja az egyen�rt�kunek minos�tett elemek sorrendj�t.
Bizonyos helyzetekben a rendezett sorozatnak csak elso n�h�ny elem�re van
sz�ks�g�nk.
Ebben az esetben van �rtelme annak, hogy a sorozatot csak olyan hosszon rendezz�k,
amilyenre
�ppen sz�ks�g�nk van. Ezt nevezz�k r�szleges (parci�lis) rendez�snek:
template<class Ran> void partial_sort(Ran first, Ran middle, Ran last);
template<class Ran, class Cmp>
void partial_sort(Ran first, Ran middle, Ran last, Cmp cmp);
template<class In, class Ran>
Ran partial_sort_copy(In first, In last, Ran first2, Ran last2);
template<class In, class Ran, class Cmp>
Ran partial_sort_copy(In first, In last, Ran first2, Ran last2, Cmp cmp);
A partial_sort() algoritmus alapv�ltozata a first �s a middle k�z�tti elemeket
rendezi el.
A partial_sort_copy() algoritmusok egy N elemu sorozatot hoznak l�tre, ahol N a
bemeneti
�s kimeneti sorozat elemei sz�m�nak minimuma. Ebbol k�vetkezik, hogy meg kell
adnunk
az eredm�nysorozat elej�t �s v�g�t is, hiszen ez hat�rozza meg, h�ny elemet kell
elrendezni:
718 A standard k�nyvt�r
class Compare_copies_sold {
public:
int operator()(const Book& b1, const Book& b2) const
{ return b1.copies_sold()>b2.copies_sold(); } // rendez�s cs�kkeno sorrendben
};
void f(const vector<Book>& sales) // a t�z legjobban fogy� k�nyv megker�se
{
vector<Book> bestsellers(10);
partial_sort_copy(sales.begin(),sales.end(),
bestsellers.begin(),bestsellers.end(),Compare_copies_sold());
copy(bestsellers.begin(),bestsellers.end(),ostream_iterator<Book>(cout,"\n"));
}
Mivel a partial_sort_copy() kimenet�nek egy v�letlen el�r�su bej�r�nak kell
lennie, nem
rendezhet�nk egy sorozatot egyenesen a cout adatfolyamra.
V�g�l n�zz�k azokat az algoritmusokat, melyekkel pontosan csak annyi elemet
rendezhet
�nk el, amennyi az N-edik elem hely�nek meg�llap�t�s�hoz sz�ks�ges. Ezek azonnal
befejezik
muk�d�s�ket, ha a k�v�nt elemet megtal�lt�k:
template<class Ran> void nth_element(Ran first, Ran nth, Ran last);
template<class Ran, class Cmp> void nth_element(Ran first, Ran nth, Ran last, Cmp
cmp);
Ez a f�ggv�ny k�l�n�sen hasznos azoknak, akiknek k�z�p�rt�kre, sz�zal�kar�nyra
stb. van
sz�ks�g�k (m�rn�k�knek, szociol�gusoknak, tan�roknak).
18.7.2. Bin�ris keres�s
A sorban t�rt�no (soros, szekvenci�lis) keres�s, amit a find() is v�gez, sz�rnyen
rossz hat
�sfok� nagy sorozatok eset�ben, m�gis ez a legjobb megold�s, ha sem rendez�s, sem
has
�t�s (�17.6) nem �ll rendelkez�s�nkre. Ha azonban rendezett sorozatban keres�nk,
akkor
annak meg�llap�t�s�ra, hogy egy �rt�k szerepel-e a sorozatban, haszn�lhatjuk a
bin�ris keres
�st:
template<class For, class T> bool binary_search(For first, For last, const T&
val);
template<class For, class T, class Cmp>
bool binary_search(For first, For last, const T& value, Cmp cmp);
18. Algoritmusok �s f�ggv�nyobjektumok 719
P�ld�ul:
void f(list<int>& c)
{
if (binary_search(c.begin(),c.end(),7)) { // Van 7 a c-ben?
// ...
}
// ...
}
A binary_search() egy logikai �rt�ket ad vissza, jelezv�n, hogy az �rt�k szerepel-
e a sorozatban.
Ugyan�gy, mint a find() eset�ben, itt is gyakran tudni szeretn�nk, hogy az adott
�rt
�kkel rendelkezo elem hol tal�lhat�. Egy sorozatban azonban t�bb megfelelo �rt�k
is lehet,
�s nek�nk �ltal�ban vagy az elsore, vagy az �sszesre van sz�ks�g�nk. Ez�rt
szerepelnek
a standard k�nyvt�rban azok az elj�r�sok, melyekkel az elso (lower_bound()), az
utols
� (upper_bound()) vagy az �sszes (equal_range()) megfelelo (egyen�rt�ku) elemet
kiv�-
laszthatjuk:
template<class For, class T> For lower_bound(For first, For last, const T& val);
template<class For, class T, class Cmp>
For lower_bound(For first, For last, const T& val, Cmp cmp);
template<class For, class T> For upper_bound(For first, For last, const T& val);
template<class For, class T, class Cmp>
For upper_bound(For first, For last, const T& val, Cmp cmp);
template<class For, class T> pair<For, For> equal_range(For first, For last, const
T& val);
template<class For, class T, class Cmp>
pair<For, For> equal_range(For first, For last, const T& val, Cmp cmp);
Ezek az algoritmusok a multimap (�17.4.2) muveletei k�z� tartoznak. A
lower_bound()
f�ggv�nyt �gy k�pzelhetj�k el, mint a find(), illetve a find_if() gyors v�ltozat�t
rendezett
sorozatokra:
void g(vector<int>& c)
{
typedef vector<int>::iterator VI;
VI p = find(c.begin(),c.end(),7); // val�sz�nuleg lass�: O(N); c-t nem kell
// rendezni
VI q = lower_bound(c.begin(),c.end(),7); // val�sz�nuleg gyors: O(log(N)); c-t
// rendezni kell
// ...
}
720 A standard k�nyvt�r
Ha a lower_bound(first, last, k) nem tal�lja meg a k �rt�ket, akkor egy olyan
bej�r�t ad
vissza, amely az elso, k-n�l nagyobb kulccsal rendelkezo elemre mutat, vagy a last
bej�r�t,
ha nincs k-n�l nagyobb �rt�k. Az upper_bound() �s az equal_range() szint�n ezt a
hibajelz
�si m�dszert haszn�lja. Ezekkel az algoritmusokkal meghat�rozhatjuk, hogy hov�
kell az
�j elemet besz�rnunk, ha a sorozat rendezetts�g�t nem akarjuk elrontani.
18.7.3. �sszef�s�l�s
Ha van k�t rendezett sorozatunk, akkor a merge() seg�ts�g�vel egy �j rendezett
sorozatot
hozhatunk l�tre belol�k, az inplace_merge() f�ggv�ny felhaszn�l�s�val pedig egy
sorozat
k�t r�sz�t f�s�lhetj�k �ssze:
template<class In, class In2, class Out>
Out merge(In first, In last, In2 first2, In2 last2, Out res);
template<class In, class In2, class Out, class Cmp>
Out merge(In first, In last, In2 first2, In2 last2, Out res, Cmp cmp);
template<class Bi> void inplace_merge(Bi first, Bi middle, Bi last);
template<class Bi, class Cmp> void inplace_merge(Bi first, Bi middle, Bi last, Cmp
cmp);
Ezek az �sszef�s�lo algoritmusok abban t�rnek el jelentosen a list oszt�ly hasonl�
elj�r�sait
�l (�17.2.2.1), hogy nem t�rlik az elemeket a bemeneti sorozatokb�l. Minden
elemrol k�-
l�n m�solat k�sz�l.
Az egyen�rt�ku elemek sorrendj�rol azt mondhatjuk el, hogy az elso sorozatban l�vo
elemek
mindig megelozik a m�sodik sorozat azonos elemeit.
Az inplace_merge() algoritmus elsosorban akkor hasznos, ha egy sorozatot t�bb
szempont
szerint is rendezni akarunk. K�pzelj�k el p�ld�ul .halaknak egy vektor�t., amely
fajok (hering,
tokehal stb.) szerint rendezett. Ha a halak minden fajon bel�l s�ly szerint
rendezettek,
akkor az inplace_merge() seg�ts�g�vel k�nnyen rendezhetj�k az eg�sz vektort a
s�lyok
alapj�n, hiszen csak az egyes fajt�k r�szsorozatait kell �sszef�s�ln�nk
(�18.13[20]).
18.7.4. Feloszt�s
Egy sorozat feloszt�sa (partition) azt jelenti, hogy minden olyan elemet, amely
kiel�g�t egy
adott felt�telt, a sorozat elej�re helyez�nk, a felt�telt ki nem el�g�toket pedig
a v�g�re.
A standard k�nyvt�rban rendelkez�s�nkre �ll a stable_partition() f�ggv�ny, amely
megtartja
azon elemek egym�shoz viszony�tott sorrendj�t, melyek egyform�n megfelelnek vagy
18. Algoritmusok �s f�ggv�nyobjektumok 721
egyform�n nem felelnek meg a predik�tumnak. A k�nyvt�rban szerepel a partition()
elj�-
r�s is, amely ezt a sorrendet nem orzi meg, de egy kicsit gyorsabban fut le, ha
kevesebb mem
�ria �ll rendelkez�s�nkre.
template<class Bi, class Pred> Bi partition(Bi first, Bi last, Pred p);
template<class Bi, class Pred> Bi stable_partition(Bi first, Bi last, Pred p);
A feloszt�st �gy k�pzelhetj�k el, mint egy nagyon egyszeru felt�tel szerinti
rendez�st:
void f(list<Club>& lc)
{
list<Club>::iterator p = partition(lc.begin(),lc.end(),located_in("Kobenhavn"));
// ...
}
Ez az elj�r�s �gy .rendezi. a list�t, hogy a koppenh�gai klubok szerepeljenek
elosz�r.
A visszat�r�si �rt�k (eset�nkben a p) az elso olyan elemet hat�rozza meg, amely
nem el�-
g�ti ki a felt�telt, illetve ha ilyen nincs, akkor a sorozat v�g�re mutat.
18.7.5. Halmazmuveletek sorozatokon
A sorozatokat tekinthetj�k halmaznak is. Ebbol a szempontb�l viszont illik a
sorozatokhoz
is elk�sz�ten�nk az olyan alapveto halmazmuveleteket, mint az uni� vagy a metszet.
M�sr
�szt viszont ezek a muveletek rendk�v�l k�lts�gesek, hacsak nem rendezett
sorozatokkal
dolgozunk. Ez�rt a standard k�nyvt�r halmazkezelo algoritmusai csak rendezett
sorozatokkal
haszn�lhat�k. Term�szetesen nagyon j�l muk�dnek a set (�17.4.3) �s a multiset
(�17.4.4)
t�rol� eset�ben is, melyek szint�n rendezettek.
Ha ezeket az algoritmusokat nem rendezett sorozatokra alkalmazzuk, az
eredm�nysorozatok
nem fognak megfelelni a szok�sos halmazelm�leti szab�lyoknak. A f�ggv�nyek nem
v�ltoztatj�k meg bemeneti sorozataikat �s a kimeneti sorozat rendezett lesz.
Az includes() algoritmus azt vizsg�lja, hogy a m�sodik sorozat minden eleme (a
[first2,last2[
tartom�nyb�l) megtal�lhat�-e az elso sorozat elemei k�z�tt (a [first,
last[ tartom�nyban):
template<class In, class In2>
bool includes(In first, In last, In2 first2, In2 last2);
template<class In, class In2, class Cmp>
bool includes(In first, In last, In2 first2, In2 last2, Cmp cmp);
722 A standard k�nyvt�r
A set_union() rendezett sorozatok uni�j�t, a set_intersection() f�ggv�ny pedig
metszet�ket
�ll�tja elo:
template<class In, class In2, class Out>
Out set_union(In first, In last, In2 first2, In2 last2, Out res);
template<class In, class In2, class Out, class Cmp>
Out set_union(In first, In last, In2 first2, In2 last2, Out res, Cmp cmp);
template<class In, class In2, class Out>
Out set_intersection(In first, In last, In2 first2, In2 last2, Out res);
template<class In, class In2, class Out, class Cmp>
Out set_intersection(In first, In last, In2 first2, In2 last2, Out res, Cmp cmp);
A set_difference() algoritmus olyan elemek sorozat�t hozza l�tre, melyek az elso
bemeneti
sorozatban megtal�lhat�k, de a m�sodikban nem. A set_symmetric_difference()
algoritmus
olyan sorozatot �ll�t elo, melynek elemei a k�t bemeneti sorozat k�z�l csak az
egyikben
szerepelnek:
template<class In, class In2, class Out>
Out set_difference(In first, In last, In2 first2, In2 last2, Out res);
template<class In, class In2, class Out, class Cmp>
Out set_difference(In first, In last, In2 first2, In2 last2, Out res, Cmp cmp);
template<class In, class In2, class Out>
Out set_symmetric_difference(In first, In last, In2 first2, In2 last2, Out res);
template<class In, class In2, class Out, class Cmp>
Out set_symmetric_difference(In first, In last, In2 first2, In2 last2, Out res,
Cmp cmp);
P�ld�ul:
char v1[ ] = "abcd";
char v2[ ] = "cdef";
void f(char v3[ ])
{
set_difference(v1,v1+4,v2,v2+4,v3); // v3 = "ab"
set_symmetric_difference(v1,v1+4,v2,v2+4,v3); // v3 = "abef"
}
18. Algoritmusok �s f�ggv�nyobjektumok 723
18.8. A kupac
A kupac (halom, heap) sz�t k�l�nb�zo helyzetekben k�l�nb�zo dolgokra haszn�ljuk
a sz�m�t�stechnik�ban. Amikor algoritmusokr�l besz�l�nk, a .kupac. egy sorozat
elemeinek
olyan elrendez�s�t jelenti, melyben az elso elem a sorozat legnagyobb �rt�ku
eleme.
Ebben az adatszerkezetben viszonylag gyorsan lehet elv�gezni az elemek besz�r�s�t
(a
push_heap() f�ggv�ny seg�ts�g�vel), illetve t�rl�s�t (a pop_heap() elj�r�ssal).
Mindketto
a legrosszabb esetben is O(log(N)) hat�konys�ggal muk�dik, ahol N a sorozat
elemeinek
sz�ma. A rendez�s (a sort_heap() felhaszn�l�s�val) szint�n j� hat�konys�g�:
O(N*log(N)).
A kupacot ezek a f�ggv�nyek val�s�tj�k meg:
template<class Ran> void push_heap(Ran first, Ran last);
template<class Ran, class Cmp> void push_heap(Ran first, Ran last, Cmp cmp);
template<class Ran> void pop_heap(Ran first, Ran last);
template<class Ran, class Cmp> void pop_heap(Ran first, Ran last, Cmp cmp);
template<class Ran> void make_heap(Ran first, Ran last); // sorozat kupacc�
// alak�t�sa
template<class Ran, class Cmp> void make_heap(Ran first, Ran last, Cmp cmp);
template<class Ran> void sort_heap(Ran first, Ran last); // kupac sorozatt�
// alak�t�sa
template<class Ran, class Cmp> void sort_heap(Ran first, Ran last, Cmp cmp);
A kupac-algoritmusok st�lusa egy kiss� meglepo. Term�szetes megold�s lenne, hogy
ezt
a n�gy f�ggv�nyt egy oszt�lyba foglaljuk �ssze. Ha ezt tenn�nk, a priority_queue
(�17.3.3)
t�rol�hoz nagyon hasonl� szerkezetet kapn�nk. Val�j�ban a priority_queue-t szinte
majdnem
biztosan egy kupac k�pviseli rendszer�nkben.
A push_heap(first, last) �ltal beillesztett elem a *(last-1). Azt felt�telezz�k,
hogy a [first, last-
1[ tartom�ny m�r kupac, �gy a push_heap() csak kieg�sz�ti a sorozatot a [first,
last[ tartom
�nyra a k�vetkezo elem besz�r�s�val. Teh�t egy kupacot l�trehozhatunk egy
sorozatb�l
�gy, hogy minden elemre megh�vjuk a push_heap() muveletet. A pop_heap(first, last)
�gy
t�vol�tja el a kupac elso elem�t, hogy felcser�li azt a (*(last-1)) elemmel, majd
a [first, last-
1[ tartom�nyt �jra kupacc� alak�tja.
724 A standard k�nyvt�r
18.9. Minimum �s maximum
Az itt le�rt algoritmusok �sszehasonl�t�s alapj�n v�lasztanak ki �rt�keket egy
sorozatb�l. Nagyon
sokszor van sz�ks�g�nk arra, hogy k�t �rt�k k�z�l kiv�lasszuk a kisebbet vagy
nagyobbat:
template<class T> const T& max(const T& a, const T& b)
{
return (a<b) ? b : a;
}
template<class T, class Cmp> const T& max(const T& a, const T& b, Cmp cmp)
{
return (cmp(a,b)) ? b : a;
}
template<class T> const T& min(const T& a, const T& b);
template<class T, class Cmp> const T& min(const T& a, const T& b, Cmp cmp);
A min() �s a max() f�ggv�ny �ltal�nos�that� �gy, hogy teljes sorozatokb�l
v�lassz�k ki
a megfelelo �rt�ket:
template<class For> For max_element(For first, For last);
template<class For, class Cmp> For max_element(For first, For last, Cmp cmp);
template<class For> For min_element(For first, For last);
template<class For, class Cmp> For min_element(For first, For last, Cmp cmp);
V�g�l az �b�c�sorrendu (lexikografikus) rendez�s �ltal�nos�t�s�t is bemutatjuk,
amely karakterl
�ncok helyett tetszoleges �rt�ksorozatra ad meg �sszehasonl�t�si felt�telt:
template<class In, class In2>
bool lexicographical_compare(In first, In last, In2 first2, In2 last2);
template<class In, class In2, class Cmp>
bool lexicographical_compare(In first, In last, In2 first2, In2 last2, Cmp cmp)
{
while (first != last && first2 != last2) {
if (cmp(*first,*first2)) return true;
if (cmp(*first2++,*first++)) return false;
}
return first == last && first2 != last2;
}
18. Algoritmusok �s f�ggv�nyobjektumok 725
Ez nagyon hasonl�t az �ltal�nos karakterl�ncokn�l (�13.4.1) bemutatott f�ggv�nyre,
de
a lexicographical_compare() tetszoleges k�t sorozatot k�pes �sszehasonl�tani, nem
csak
karakterl�ncokat. Egy m�sik k�l�nbs�g, hogy ez az algoritmus csak egy bool �s nem
egy int
�rt�ket ad vissza, b�r az t�bb inform�ci�t tartalmazhatna. Az eredm�ny kiz�r�lag
akkor lesz
true, ha az elso sorozat kisebb (<), mint a m�sodik. Teh�t akkor is false
visszat�r�si �rt�ket
kapunk, ha a k�t sorozat egyenlo.
A C st�lus� karakterl�ncok �s a string oszt�ly is sorozat, �gy a
lexicographical_compare()
haszn�lhat� ezekre is �sszehasonl�t� felt�telk�nt:
char v1[ ] = "igen";
char v2[ ] = "nem";
string s1 = "Igen";
string s2 = "Nem";
void f()
{
bool b1 = lexicographical_compare(v1,v1+strlen(v1),v2,v2+strlen(v2));
bool b2 = lexicographical_compare(s1.begin(),s1.end(),s2.begin(),s2.end());
bool b3 = lexicographical_compare(v1,v1+strlen(v1),s1.begin(),s1.end());
bool b4 = lexicographical_compare(s1.begin(),s1.end(),v1,v1+strlen(v1),Nocase());
}
A sorozatoknak nem kell azonos t�pus�aknak lenni�k, hiszen csak elemeket kell
tudnunk
�sszehasonl�tani, �s az �sszehasonl�t� predik�tumot mi adhatjuk meg. Ez a
lehetos�g
a lexicographical_compare() elj�r�st sokkal �ltal�nosabb� . �s egy kicsit lassabb�
. teszi
a string oszt�ly �sszehasonl�t� muveletein�l. L�sd m�g: �20.3.8.
18.10. Permut�ci�k
Egy n�gy elembol �ll� sorozatot �sszesen 4*3*2 f�lek�ppen rendezhet�nk el.
Mindegyik
elrendez�s egy-egy permut�ci�ja a n�gy elemnek. N�gy karakterbol (abcd) p�ld�ul az

al�bbi 24 permut�ci�t �ll�thatjuk elo:


abcd abdc acbd acdb adbc adcb bacd badc
bcad bcda bdac bdca cabd cadb cbad cbda
cdab cdba dabc dacb dbac dbca dcab dcba
726 A standard k�nyvt�r
A next_permutation() �s a prev_permutation() f�ggv�ny ilyen permut�ci�kat �ll�t
elo egy
sorozatb�l:
template<class Bi> bool next_permutation(Bi first, Bi last);
template<class Bi, class Cmp> bool next_permutation(Bi first, Bi last, Cmp cmp);
template<class Bi> bool prev_permutation(Bi first, Bi last);
template<class Bi, class Cmp> bool prev_permutation(Bi first, Bi last, Cmp cmp);
Az abcd sorozat permut�ci�it a k�vetkezok�ppen �rathatjuk ki:
int main()
{
char v[ ] = "abcd";
cout << v << '\t';
while(next_permutation(v,v+4)) cout << v << '\t';
}
A permut�ci�kat �b�c�sorrendben kapjuk meg (�18.9). A next_permutation() f�ggv�ny
visszat�r�si �rt�ke azt hat�rozza meg, hogy van-e m�g tov�bbi permut�ci�. Ha
nincs, false
�rt�ket kapunk �s azt a permut�ci�t, melyben az elemek �b�c�sorrendben �llnak.
A prev_permutation() f�ggv�ny visszat�r�si �rt�ke azt adja meg, hogy van-e elozo
permut
�ci�, �s ha nincs, akkor az elemeket ford�tott �b�c�sorrendben tartalmaz�
permut�ci�t
kapjuk.
18.11. C st�lus� algoritmusok
A C++ standard k�nyvt�ra �r�k�lt n�h�ny algoritmust a C standard k�nyvt�r�t�l is.
Ezek a C
st�lus� karakterl�ncokat kezelo f�ggv�nyek (�20.4.1), illetve a gyorsrendez�s
(quicksort) �s
a bin�ris keres�s, melyek csak t�mb�kre haszn�lhat�k.
A qsort() �s a bsearch() f�ggv�ny a <cstdlib> �s az <stdlib.h> fej�llom�nyban
tal�lhat� meg.
Mindketto t�mb�k�n muk�dik �s n darab elem_size m�retu elemet dolgoznak fel egy
f�ggv
�nyre hivatkoz� mutat�val megadott .kisebb, mint. �sszehasonl�t� muvelet
seg�ts�g�vel.
Az elemek t�pus�nak nem lehet felhaszn�l� �ltal megadott m�sol� konstruktora,
m�sol� �rt
�kad�sa, illetve destruktora:
18. Algoritmusok �s f�ggv�nyobjektumok 727
typedef int(*__cmp)(const void*, const void*); // a typedef-et csak a bemutat�shoz

// haszn�ljuk
void qsort(void* p, size_t n, size_t elem_size, __cmp); // p rendez�se
void* bsearch(const void* key, void* p, size_t n, size_t elem_size, __cmp); //
kulcs keres�se
// p-ben
A qsort() f�ggv�ny haszn�lat�r�l a �7.7 pontban m�r r�szletesebben is sz� volt.
Ezek az algoritmusok kiz�r�lag a C-vel val� kompatibilit�s miatt maradtak meg a
nyelvben.
A sort() (�18.7.1) �s a search() (�18.5.5) sokkal �ltal�nosabbak �s �ltal�ban
sokkal hat�konyabbak
is.
18.12. Tan�csok
[1] Ciklusok helyett haszn�ljunk ink�bb algoritmusokat (�18.5.1).
[2] Ha ciklust �runk, mindig gondoljuk v�gig, hogy feladatunk nem fogalmazhat�-e
meg egy �ltal�nos algoritmussal (�18.2).
[3] Rendszeresen n�zz�k �t az algoritmusokat, hogy felismerj�k, ha valamilyen
feladat
trivi�lis (�18.2).
[4] Mindig ellenorizz�k, hogy az �ltalunk megadott bej�r�-p�r t�nyleg meghat�roz-e

egy sorozatot (�18.3.1).


[5] Tervezz�k �gy programjainkat, hogy a leggyakrabban haszn�lt elj�r�sok legyenek

a legegyszerubbek �s leggyorsabbak (�18.3, �18.3.1).


[6] Az �rt�kvizsg�latokat �gy fogalmazzuk meg, hogy predik�tumk�nt is
haszn�lhassuk
azokat (�18.4.2).
[7] Mindig gondoljunk arra, hogy a predik�tumok f�ggv�nyek vagy objektumok,
de semmik�ppen sem t�pusok (�18.4.2).
[8] A lek�tok (binder) seg�ts�g�vel a k�tparam�teru predik�tumokb�l egyparam�-
teru predik�tumokat �ll�thatunk elo (�18.4.4.1).
[9] A mem_fun() �s a mem_fun_ref() f�ggv�ny seg�t abban, hogy az algoritmusokat
t�rol�kra alkalmazzuk (�18.4.4.2).
[10] Ha egy f�ggv�ny valamelyik param�ter�t r�gz�ten�nk kell, haszn�ljuk
a ptr_fun() f�ggv�nyt.
[11] A strcmp() legnagyobb elt�r�se az == oper�tort�l, hogy 0 visszat�r�si �rt�k
jelzi
az .egyenlos�get. (�18.4.4.4).
728 A standard k�nyvt�r
[12] A for_each() �s a transform() algoritmust csak akkor haszn�ljuk, ha nem tal�-

lunk feladatunkhoz jobban illeszkedo elj�r�st (�18.5.1).


[13] Haszn�ljunk predik�tumokat, ha egy algoritmusban egyedi �sszehasonl�t�si felt
�telre van sz�ks�g�nk (�184.2.1, �18.6.3.1).
[14] A predik�tumok �s m�s f�ggv�nyobjektumok seg�ts�g�vel a szabv�nyos
algoritmusok
sokkal t�bb ter�leten haszn�lhat�k, mint elso r�n�z�sre gondoln�nk
(�18.4.2).
[15] A mutat�k eset�ben az alap�rtelmezett == �s < oper�tor igen ritk�n felel meg
ig�nyeinknek a szabv�nyos algoritmusokban (�18.6.3.1).
[16] Az algoritmusok nem tudnak k�zvetlen�l beilleszteni vagy kivenni elemet a
param
�terk�nt megadott sorozatokb�l.
[17] Mindig ellenorizz�k, hogy a sorozatok �sszehasonl�t�sakor a megfelelo
.kisebb,
mint., illetve .egyenlos�g. muveletet haszn�ljuk-e (�18.6.3.1).
[18] A rendezett sorozatok gyakran hat�konyabb� �s eleg�nsabb� teszik
programjainkat.
[19] A qsort() �s a bsearch() f�ggv�nyeket csak a C programokkal val�
�sszeegyeztethet
os�g biztos�t�sa �rdek�ben haszn�ljuk (�18.11).
18.13. Gyakorlatok
A fejezetben elofordul� gyakorlatok t�bbs�g�nek megold�s�t megtal�lhatjuk a
standard
k�nyvt�r b�rmely v�ltozat�nak forr�sk�dj�ban, de mielott megn�zn�nk, hogy a
k�nyvt�r alkot
�i hogyan k�zel�tett�k meg a probl�m�t, pr�b�lkozzunk saj�t megold�sok
kidolgoz�s�val.
1. (*2)Ismerkedj�nk az O( ) jel�l�ssel. Adjunk megval�s�that� p�ld�t arra, amikor
N>10 �rt�kre egy O(N*N) algoritmus gyorsabb, mint egy O(N) algoritmus.
2. (*2)K�sz�ts�k el �s ellenorizz�k a n�gy mem_fun(), illetve mem_fun_ref() f�ggv
�nyt (�18.4.4.2)
3. (*1)�rjuk meg a match() algoritmust, amely hasonl�t a mismatch() f�ggv�nyre,
csak �ppen azoknak az elemeknek a bej�r�j�t adja vissza, amelyek elsok�nt
el�g�tik ki a predik�tumot.
4. (*1.5)�rjuk meg �s pr�b�ljuk ki a �18.5.1 pontban eml�tett Print_name()
f�ggv�nyt.
5. (*1)Rendezz�nk egy list�t a standard k�nyvt�r algoritmusaival.
6. (*2.5)�rjuk meg az iseq() f�ggv�nynek (�18.3.1) azon v�ltozatait, amelyek
be�p�-
tett t�mb�kre, istream t�pusokra, illetve bej�r�-p�rokra haszn�lhat�k. Adjuk
meg a sz�ks�ges t�lterhel�seket is a standard k�nyvt�r nem m�dos�t� algorit-
18. Algoritmusok �s f�ggv�nyobjektumok 729
musainak (�18.5) sz�m�ra. Gondolkodjunk el rajta, hogyan ker�lhetoek el
a t�bb�rtelmus�gek, �s hogyan ker�lhetj�k el t�l nagy sz�m� sablon f�ggv�ny
l�trehoz�s�t.
7. (*2)Hat�rozzuk meg az iseq() komplementer�t, az oseq() f�ggv�nyt. A kimeneti
sorozatot, amelyet az oseq()param�terk�nt kap, �t kell alak�tanunk az algoritmus
�ltal visszaadott kimenetre. Adjuk meg a sz�ks�ges t�lterhel�seket is, legal
�bb h�rom, �ltalunk kiv�lasztott szabv�nyos algoritmusra.
8. (*1.5)K�sz�ts�nk egy vektort, amely 1-tol 100-ig t�rolja a sz�mok n�gyzeteit.
Jelen
�ts�k meg a n�gyzetsz�mokat egy t�bl�zatban. Sz�m�tsuk ki ezen vektor elemeinek
n�gyzetgy�k�t �s jelen�ts�k meg az �gy kapott eredm�nyeket is.
9. (*2)�rjuk meg azokat a f�ggv�nyobjektumokat, melyek bitenk�nti logikai
muveleteket
v�geznek operandusaikon. Pr�b�ljuk ki ezeket az objektumokat olyan
vektorokon, melyek elemeinek t�pusa char, int, illetve bitset<67>.
10. (*1)�rjuk meg a binder3() elj�r�st, amely r�gz�ti egy h�romparam�teru f�ggv�ny

m�sodik �s harmadik param�ter�t, �s �gy �ll�t elo belole egyparam�teru predik


�tumot. Adjunk p�ld�t olyan esetre, ahol a binder3() hasznos lehet.
11. (*1.5)�rjunk egy r�vid programot, amely amely elt�vol�tja egy f�jlb�l f�jlb�l
a szomsz�dos szomsz�dos ism�tlodo szavakat. (A programnak az elozo mondatb
�l p�ld�ul el kell t�vol�tania az amely, a f�jlb�l �s a szomsz�dos sz� egy-egy
elofordul�s�t.)
12. (*2.5)Hozzunk l�tre egy t�pust, amellyel �js�gokra �s k�nyvekre mutat�
hivatkoz
�sok rekordjait t�rolhatjuk egy f�jlban. �rjunk olyan programot, amely ki
tudja �rni a f�jlb�l azokat a rekordokat, amelyeknek megadjuk a kiad�si �v�t,
a szerzo nev�t, egy, a c�mben szereplo kulcsszav�t, vagy a kiad� nev�t. Adjunk
lehetos�get arra is, hogy a felhaszn�l� az eredm�nyeket k�l�nb�zo szempontok
szerint rendezhesse.
13. (*2)K�sz�ts�k el a move() algoritmust a copy() st�lus�ban, gondolva arra, hogy

a bemeneti �s kimeneti sorozat esetleg �tfedik egym�st. Gondoskodjunk az elj�-


r�s megfelelo hat�konys�g�r�l arra az esetre, ha param�terekk�nt k�zvetlen
hozz�f�r�su bej�r�kat kapn�nk.
14. (*1.5)�ll�tsuk elo a food sz� anagramm�it, azaz az f, o, o �s d betuk
n�gybetus
kombin�ci�it. �ltal�nos�tsuk ezt a programot �gy, hogy egy felhaszn�l�t�l bek
�rt sz� anagramm�it �ll�tsa elo.
15. (*1.5)K�sz�ts�nk programot, amely mondatok anagramm�it �ll�tja elo, azaz
a mondat szavainak minden permut�ci�j�t elk�sz�ti. (Ne a szavak betuinek permut
�ci�ival foglalkozzunk!)
16. (*1.5)�rjuk meg a find_if() (�18.5.2) f�ggv�nyt, majd ennek felhaszn�l�s�val
a find() algoritmust. Tal�ljunk ki olyan megold�st, hogy a k�t f�ggv�nynek ne
kelljen k�l�nb�zo nevet adnunk.
730 A standard k�nyvt�r
17. (*2)K�sz�ts�k el a search() (�18.5.5) algoritmust. K�sz�ts�nk egy kifejezetten

k�zvetlen hozz�f�r�su bej�r�khoz igaz�tott v�ltozatot is.


18. (*2)V�lasszunk egy rendez�si elj�r�st (p�ld�ul a qsort()-ot a standard
k�nyvt�rb
�l vagy a �13.5.2 pontb�l a Shell rendez�st) �s alak�tsuk �t �gy, hogy minden
elemcsere ut�n jelenjen meg a sorozat aktu�lis �llapota.
19. (*2)A k�tir�ny� bej�r�khoz nem �ll rendelkez�s�nkre rendezo elj�r�s. Sejt�-
s�nk az, hogy gyorsabb az elemeket �tm�solni egy vektorba, �s ott rendezni
azokat, mint k�tir�ny� bej�r�kkal k�zvetlen�l rendezni a sorozatot. K�sz�ts�nk
egy �ltal�nos rendezo elj�r�st k�tir�ny� bej�r�kkal �s ellenorizz�k a felt�telez
�st.
20. (*2.5)K�pzelj�k el, hogy sporthorg�szok egy csoportj�nak rekordjait tartjuk
nyilv�n. Minden fog�s eset�ben t�roljuk a hal fajt�j�t, hossz�t, s�ly�t, a fog�s
idopontj�t, d�tum�t, a horg�sz nev�t stb. Rendezz�k a rekordokat k�l�nb�zo
szempontok szerint az inplace_merge() algoritmus felhaszn�l�s�val.
21. (*2)K�sz�ts�nk list�t azokr�l a tanul�kr�l, akik matematik�t, angolt,
sz�m�t�stechnik
�t vagy biol�gi�t tanulnak. Mindegyik t�rgyhoz v�lasszunk ki 20 nevet
egy 40 fos oszt�lyb�l. Soroljuk fel azokat a tanul�kat, akik matematik�t �s sz�-
m�t�stechnik�t is tanulnak. V�lasszuk ki azokat, akik tanulnak sz�m�t�stechnik
�t, de matematik�t �s biol�gi�t nem. �rassuk ki azokat, akik tanulnak
sz�m�t�stechnik
�t �s matematik�t, de nem tanulnak sem angolt, sem biol�gi�t.
22. (*1.5)K�sz�ts�nk egy remove() f�ggv�nyt, amely t�nyleg elt�vol�tja a t�rlendo
elemeket egy t�rol�b�l.
18. Algoritmusok �s f�ggv�nyobjektumok 731
Bej�r�k �s mem�riafoglal�k
.Annak oka, hogy az adatszerkezetek �s
az algoritmusok ilyen t�k�letesen egy�tt tudnak
muk�dni az, . hogy semmit sem tudnak egym�sr�l..
(Alex Stepanov)
Bej�r�k �s sorozatok . Muveletek bej�r�kon . Bej�r�-jellemzok . Bej�r�-
kateg�ri�k . Besz�-
r�k . Visszafel� halad� bej�r�k . Adatfolyam-bej�r�k . Ellenorz�tt bej�r�k . A
kiv�telek �s
az algoritmusok . Mem�riafoglal�k . A szabv�nyos allocator . Felhaszn�l�i
mem�riafoglal�k
. Alacsonyszintu mem�riamuveletek . Tan�csok . Gyakorlatok
19
19.1. Bevezet�s
A bej�r� (iter�tor, iterator) az a csavar, amely a t�rol�kat �s az algoritmusokat
�sszetartja.
Ezek seg�ts�g�vel az adatokat elvont form�ban �rhetj�k el, �gy az algoritmusok
k�sz�toinek
nem kell rengeteg adatszerkezet konkr�t r�szleteivel foglalkozniuk. A m�sik
oldalr�l n�zve
pedig a bej�r�k �ltal k�n�lt szabv�nyos adatel�r�si modell megk�m�li a t�rol�kat
att�l, hogy
sokkal bovebb adatel�r�si muvelethalmazt kelljen biztos�taniuk. A mem�riafoglal�k
(allok
�tor, allocator) ugyan�gy szigetelik el a t�rol�k konkr�t megval�s�t�sait a
mem�riael�r�s
r�szleteitol.
A bej�r�k elvont adatmodellje az objektumsorozat (�19.2). A mem�riafoglal�k azt
teszik lehet
ov�, hogy az alacsonyszintu .b�jtt�mb adatmodell. helyett a sokkal magasabb szintu
objektummodellt
haszn�ljuk (�19.4) A leggyakoribb alacsonyszintu mem�riamodell haszn�lat
�t n�h�ny szabv�nyos f�ggv�ny t�mogatja (�19.4.4).
A bej�r�k olyan fogalmat k�pviselnek, amellyel bizony�ra minden programoz�
tiszt�ban
van. Ezzel ellent�tben a mem�riafoglal�k olyan elj�r�sokat biztos�tanak,
amelyekkel egy
programoz�nak igen ritk�n kell foglalkoznia, �s igen kev�s olyan programoz� van,
akinek
�let�ben ak�r csak egyszer is mem�riafoglal�t kellene �rnia.
19.2. Bej�r�k �s sorozatok
A bej�r� (iter�tor, iterator) tiszt�n elvont fogalom. Azt mondhatjuk, hogy minden,
ami bej
�r�k�nt viselkedik, bej�r�nak tekintheto (�3.8.2). A bej�r� a sorozat elemeire
hivatkoz�
mutat� fogalm�nak elvont �br�zol�sa. Legfontosabb fogalmai a k�vetkezok:
� .az �ppen kijel�lt elem. (indirekci�, jele a * �s a ->)
� .a k�vetkezo elem kiv�laszt�sa. (n�vel�s, jele a ++)
� egyenlos�g (jele az ==)
A be�p�tett int* t�pus p�ld�ul az int[ ]-nek, m�g a list<int>::iterator egy
listaoszt�lynak
a bej�r�ja.
734 A standard k�nyvt�r
A sorozat (sequence) is elvont fogalom: olyan valamit jel�l, amelyen
v�gighaladhatunk az
elej�tol a v�g�ig, a .k�vetkezo elem. muvelettel:
Ilyen sorozat a t�mb (�5.2), a vektor (�16.3), az egyir�ny� (l�ncolt) lista
(�17.8[17]), a k�tir�-
ny� (l�ncolt) lista (�17.2.2), a fa (�17.4.1), a bemeneti sorozat (�21.3.1) �s a
kimeneti sorozat
(�21.2.1). Mindegyiknek megvan a saj�t, megfelelo bej�r�ja.
A bej�r�-oszt�lyok �s -f�ggv�nyek az std n�vt�rhez tartoznak �s az <iterator>
fej�llom�nyban
tal�lhat�k.
A bej�r� nem �ltal�nos�tott mutat�. Sokkal ink�bb a t�mbre alkalmazott mutat�
elvont �br�-
zol�sa. Nincs olyan fogalom, hogy .null-bej�r�. (teh�t elemre nem mutat� bej�r�).
Ha meg
akarjuk �llap�tani, hogy egy bej�r� l�tezo elemre mutat-e vagy sem, �ltal�ban a
sorozat end
elem�hez kell hasonl�tanunk (teh�t nem valamilyen null elemhez). Ez a szeml�let
sok algoritmust
leegyszerus�t, mert nem kell az eml�tett egyedi esettel foglalkozniuk, r�ad�sul
t�k�-
letesen megval�s�that�k b�rmilyen t�pus� elemek sorozat�ra.
Ha egy bej�r� l�tezo elemre mutat, akkor �rv�nyesnek (valid) nevezz�k �s
alkalmazhat� r�
az indirekci� (a *, a [ ] vagy a -> oper�tor). Egy bej�r� �rv�nytelens�g�nek t�bb
oka is lehet:
m�g nem adtunk neki kezdo�rt�ket; olyan t�rol�ba mutat, amelynek m�rete
megv�ltozott
(�16.3.6., �16.3.8); teljes eg�sz�ben t�r�lt�k a t�rol�t, amelybe mutat; vagy a
sorozat v�g�-
re mutat (�18.2). A sorozat v�g�t �gy k�pzelhetj�k el, mint egy bej�r�t, amely egy
olyan
k�pzeletbeli elemre mutat, melynek helye a sorozatban az utols� elem ut�n van.
19.2.1. A bej�r�k muveletei
Nem minden bej�r� (iterator) engedi meg pontosan ugyanannak a muvelethalmaznak
a haszn�lat�t. Az olvas�shoz p�ld�ul m�sfajta muveletekre van sz�ks�g, mint az
�r�shoz,
a vektorok pedig lehetov� teszik, hogy b�rmikor b�rmelyik elemet k�nyelmesen �s
hat�konyan
el�rhess�k, m�g a list�kn�l �s adatfolyamokn�l ez a muvelet rendk�v�l k�lts�ges.
Ez�rt
a bej�r�kat �t oszt�lyba soroljuk, aszerint, hogy milyen muveleteket k�pesek
hat�konyan
(azaz �lland� (konstans) ido alatt, �17.1) megval�s�tani:
19. Bej�r�k �s mem�riafoglal�k 735
elem[0] elem[1] elem[2] ... elem[n-1]
begin() end()
Az �r�s �s az olvas�s is a * indirekci� oper�torral lek�pezett bej�r�n kereszt�l
t�rt�nik:
*p = x; // x �r�sa p-n kereszt�l
x = *p; // olvas�s p-n kereszt�l x-be
Ahhoz, hogy egy t�pust bej�r�nak nevezz�nk, biztos�tania kell a megfelelo
muveleteket.
Ezeknek a muveleteknek pedig a hagyom�nyos jelent�s szerint kell viselkedni�k,
teh�t
ugyanazt az eredm�nyt kell adniuk, mint a szok�sos mutat�knak.
Egy bej�r�nak . kateg�ri�j�t�l f�ggetlen�l . lehetov� kell tennie const �s nem
konstans el-
�r�st is ahhoz az objektumhoz, amelyre mutat. Egy elemet nem v�ltoztathatunk meg
egy
const bej�r�n kereszt�l, legyen az b�rmilyen kateg�ri�j�. A bej�r� k�n�l bizonyos
oper�torokat,
de a mutatott elem t�pusa hat�rozza meg, hogy mely muveleteket lehet t�nylegesen
v�grehajtani.
Az olvas�s �s az �r�s v�grehajt�s�hoz az objektumok m�sol�s�ra van sz�ks�g, �gy
ilyenkor
az elemek t�pus�nak a szok�sos m�sol�st kell biztos�taniuk (�17.1.4).
Csak k�zvetlen el�r�su (random access) bej�r�kat n�velhet�nk, illetve
cs�kkenthet�nk
tetszoleges eg�sz �rt�kkel a relat�v c�mz�s megval�s�t�s�hoz. A kimeneti (output)
bej�r�k
kiv�tel�vel azonban k�t bej�r� k�z�tti t�vols�g mindig meg�llap�that� �gy, hogy
v�gighaladunk
a k�z�tt�k l�vo elemeken, �gy a distance() f�ggv�ny megval�s�that�:
template<class In> typename iterator_traits<In>::difference_type distance(In
first, In last)
{
typename iterator_traits<In>::difference_type d = 0;
while (first++!=last) d++;
return d;
}
736 A standard k�nyvt�r
Bej�r�-muveletek �s -kateg�ri�k
Kateg�ria: �r� olvas� elore k�tir�ny� k�zvetlen
(kimeneti) (bemeneti) halad� el�r�su
R�vid�t�s: Out In For Bi Ran
Olvas�s: =*p =*p =*p =*p
Hozz�f�r�s: -> -> -> -> [ ]
�r�s: *p= *p= *p= *p=
Halad�s: ++ ++ ++ ++ -- ++ -- + - += -=
�sszehasonl�t�s: == != == != == != == != < > <= >=
Az iterator_traits<In>::difference_type minden bemeneti (input) bej�r�hoz
rendelkez�sre
�ll, hogy k�t elem k�z�tti t�vols�got t�rolhassunk (�19.2.2).
A f�ggv�ny neve distance() �s nem operator-(), mert el�g k�lts�ges muvelet lehet
�s
a bej�r�k eset�ben az oper�torokat fenntartjuk azoknak az elj�r�soknak, melyek
konstans
ido alatt elv�gezhetok (�17.1). Az elemek egyes�vel t�rt�no megsz�ml�l�sa nem
olyan mu-
velet, amelyet nagy sorozatokon j�hiszemuen v�gre szeretn�nk hajtani. A k�zvetlen
el�r�-
su bej�r�khoz a standard k�nyvt�r a distance() f�ggv�ny sokkal hat�konyabb
megval�s�-
t�s�t biztos�tja.
Hasonl�an, az advance() f�ggv�ny szolg�l a += oper�tor lass�, de mindenhol
alkalmazhat
� v�ltozat�nak megnevez�s�re:
template <class In, class Dist> void advance(In& i, Dist n); // i+=n
19.2.2. A bej�r� jellemzoi
A bej�r�kat arra haszn�ljuk, hogy inform�ci�kat tudjunk meg az objektumr�l,
amelyre mutatnak,
illetve a sorozatr�l, amelyhez kapcsol�dnak. A bej�r� hivatkoz�s�n kereszt�l
kapott
objektumot p�ld�ul �talak�thatjuk, vagy meg�llap�thatjuk a sorozatban szereplo
elemek
sz�m�t a sorozatot kijel�lo bej�r�k seg�ts�g�vel. Az ilyen muveletek kifejez�s�hez
k�pesnek
kell lenn�nk megnevezni a bej�r�khoz kapcsol�d� t�pusokat. P�ld�ul .azon objektum
t�pusa, melyre a bej�r� mutat., vagy .k�t bej�r� k�z�tti t�vols�g t�pusa.. Ezeket
a t�pusokat
egy bej�r� sz�m�ra az iterator_traits (bej�r� jellemzok) sablon oszt�ly �rja le:
template<class Iter> struct iterator_traits {
typedef typename Iter::iterator_category iterator_category; // �19.2.3
typedef typename Iter::value_type value_type; // az elem t�pusa
typedef typename Iter::difference_type difference_type;
typedef typename Iter::pointer pointer; // a ->() oper�tor visszat�r�si t�pusa
typedef typename Iter::reference reference; // a *() oper�tor visszat�r�si t�pusa
};
A difference_type k�t bej�r� k�z�tti t�vols�g megjel�l�s�re szolg�l� t�pus, az
iterator_category pedig olyan, amellyel le�rhat�, hogy a bej�r� milyen muveleteket
t�mogat.
A szok�sos mutat�k eset�ben egy-egy egyedi c�l� v�ltozat (specializ�ci�, �13.5)
�ll rendelkez
�s�nkre a <T*> �s a <const T*> t�pushoz:
19. Bej�r�k �s mem�riafoglal�k 737
template<class T> struct iterator_traits<T*> { // specializ�ci� mutat�khoz
typedef random_access_iterator_tag iterator_category;
typedef T value_type;
typedef ptrdiff_t difference_type;
typedef T* pointer;
typedef T& reference;
};
Teh�t a mutat�k k�zvetlen el�r�st (v�letlen el�r�st, random-access, �19.2.3)
tesznek leheto-
v�, �s a k�z�tt�k l�vo t�vols�got a standard k�nyvt�r ptrdiff_t t�pus�val
�br�zolhatjuk, amelyet
a <cstddef> (�6.2.1) fej�llom�nyban tal�lhatunk meg. Az iterator_traits oszt�ly
seg�ts�-
g�vel olyan elj�r�sokat �rhatunk, amelyek a bej�r�k param�tereinek jellemzoitol
f�ggnek.
Erre klasszikus p�lda a count() f�ggv�ny:
template<class In, class T>
typename iterator_traits<In>::difference_type count(In first, In last, const T&
val)
{
typename iterator_traits<In>::difference_type res = 0;
while (first != last) if (*first++ == val) ++res;
return res;
}
Itt az eredm�ny t�pus�t az iterator_traits<In> oszt�ly�nak fogalmaival hat�roztuk
meg. Erre
a megold�sra az�rt van sz�ks�g, mert nincs olyan nyelvi elem, amellyel egy
tetszoleges
t�pust egy m�sik t�pus fogalmaival fejezhetn�nk ki.
Mutat�k eset�ben az iterator_traits oszt�ly haszn�lata helyett specializ�ci�t
k�sz�thetn�nk
a count() f�ggv�nybol:
template<class In, class T>
typename In::difference_type count(In first, In last, const T& val);
template<class In, class T> ptrdiff_t count<T*,T>(T* first, T* last, const T&
val);
Ez a megold�s azonban csak a count() probl�m�j�n seg�tene. Ha a m�dszert egy tucat
algoritmushoz
haszn�ltuk volna, a t�vols�gok t�pus�nak inform�ci�it tucatszor kellene megism
�teln�nk. �ltal�ban sokkal jobb megk�zel�t�s, ha egy tervez�si d�nt�st egyszer,
egy helyen
�runk le (�23.4.2); �gy ha ezt a d�nt�st k�sobb k�nytelenek vagyunk
megv�ltoztatni,
csak erre az egy helyre kell figyeln�nk.
738 A standard k�nyvt�r
Mivel az itrator_traits<Iterator> minden bej�r� eset�ben defini�lt, �j bej�r�
k�sz�t�sekor mindig
l�tre kell hoznunk a h�tt�rben egy iterator_traits oszt�lyt is. Ha az
alap�rtelmezett oszt�ly
. amely az iterator_traits sablon p�ld�nya . nem felel meg ig�nyeinknek, szabadon
k�sz�thet
�nk belole specializ�lt v�ltozatot, �gy, ahogy a standard k�nyvt�r teszi a mutat�k
eset�ben.
Az automatikusan l�trehozott iterator_traits oszt�ly felt�telezi, hogy a bej�r�-
oszt�lyban kifejtett
�k a difference_type, value_type stb. tagt�pusokat. Az <iterator> fej�llom�nyban a
k�nyvt
�r megad egy t�pust, melyet felhaszn�lhatunk a tagt�pusok l�trehoz�s�hoz:
template<class Cat, class T, class Dist = ptrdiff_t, class Ptr = T*, class Ref =
T&>
struct iterator {
typedef Cat iterator_category; // �19.2.3
typedef T value_type; // az elem t�pusa
typedef Dist difference_type; // a bej�r�-k�l�nbs�g t�pusa
typedef Ptr pointer; // a -> visszat�r�si t�pusa
typedef Ref reference; // a * visszat�r�si t�pusa
};
Jegyezz�k meg, hogy itt a reference �s a pointer nem bej�r�k, csak bizonyos
bej�r�k eset
�ben egyszeru visszat�r�si �rt�kk�nt szolg�lnak az operator*(), illetve az
operator->() mu-
velethez.
Az iterator_traits oszt�ly sz�mos olyan fel�let elk�sz�t�s�t leegyszerus�ti, amely
bej�r�kkal
dolgozik, �s sok algoritmus eset�ben hat�kony megold�sokat tesz lehetov�.
19.2.3. Bej�r�-kateg�ri�k
A bej�r�k k�l�nb�zo fajt�i (kateg�ri�i) hierarchikus rend szerint
csoportos�tottak:
19. Bej�r�k �s mem�riafoglal�k 739
Bemeneti
(Input)
Kimeneti
(Output)
Elore halad�
(Forward)
K�tir�ny�
(Bidirectional)
K�zvetlen �l�r�su
(Random-access)
Itt nem oszt�lyok lesz�rmaz�si hierarchi�j�r�l van sz�. A bej�r�k kateg�ri�i csak
egy csoportos
�t�st jelentenek a t�pus �ltal k�n�lt muveletek alapj�n. Nagyon sok, egym�st�l
teljesen f�ggetlen
t�pus tartozhat ugyanahhoz a bej�r�-kateg�ri�hoz. A k�z�ns�ges mutat�k (�19.2.2)
vagy a Checked_iters (�19.3) p�ld�ul egyar�nt k�zvetlen el�r�su bej�r�k.
A 18. fejezetben m�r felh�vtuk r� a figyelmet, hogy a k�l�nb�zo algoritmusok
k�l�nb�zo
fajt�j� bej�r�kat haszn�lnak param�terk�nt. Sot, m�g ugyanannak az algoritmusnak
is lehet
t�bb v�ltozata, k�l�nb�zo bej�r�-fajt�kkal, hogy mindig a leghat�konyabb megold�st
haszn
�lhassuk. Annak �rdek�ben, hogy a bej�r�-kateg�ri�k alapj�n k�nnyen
t�lterhelhess�nk
f�ggv�nyeket, a standard k�nyvt�r �t oszt�lyt k�n�l, amelyek az �t bej�r�-
kateg�ri�t �br�-
zolj�k:
struct input_iterator_tag {};
struct output_iterator_tag {};
struct forward_iterator_tag : public input_iterator_tag {};
struct bidirectional_iterator_tag : public forward_iterator_tag {};
struct random_access_iterator_tag : public bidirectional_iterator_tag {};
Ha megn�zz�k a bemeneti vagy az elore halad� bej�r�k utas�t�sk�szlet�t (�19.2.1),
akkor
azt v�rhatn�nk, hogy a forward_iterator_tag az output_iterator_tag oszt�ly
lesz�rmazottja
legyen, sot az input_iterator_tag-� is. A k�nyvt�rban m�gsem ez a megold�s
szerepel, aminek
az az oka, hogy ez t�l zavaross� �s val�sz�nuleg hib�ss� teheti a rendszert. Ennek
ellen
�re m�r l�ttam olyan megval�s�t�st, ahol az ilyen sz�rmaztat�s t�nylegesen
leegyszerus�-
tette a programk�dot.
Ezen oszt�lyok egym�sb�l val� sz�rmaztat�s�nak egyetlen elonye, hogy
f�ggv�nyeinknek
nem kell t�bb v�ltozat�t elk�sz�ten�nk, ha ugyanazt az algoritmust szeretn�nk
alkalmazhat
�v� tenni t�bb, de nem az �sszes bej�r�ra. P�ld�ul gondoljuk v�gig, hogyan
val�s�that�
meg a distance:
template<class In>
typename iterator_traits<In>::difference_type distance(In first, In last);
K�t nyilv�nval� lehetos�g�nk van:
1. Ha az In k�zvetlen el�r�su bej�r�, egyszeruen kivonhatjuk a first �rt�ket a
last
�rt�kbol.
2. Ellenkezo esetben a t�vols�g meg�llap�t�s�hoz k�l�n bej�r�val v�gig kell
haladnunk
a sorozaton a first elemtol a last �rt�kig.
Ezt a k�t v�ltozatot k�t seg�df�ggv�ny haszn�lat�val fejezhetj�k ki:
740 A standard k�nyvt�r
template<class In>
typename iterator_traits<In>::difference_type
dist_helper(In first, In last, input_iterator_tag)
{
typename iterator_traits<In>::difference_type d = 0;
while (first++!=last) d++; // csak n�vel�s
return d;
}
template<class Ran>
typename iterator_traits<Ran>::difference_type
dist_helper(Ran first, Ran last, random_access_iterator_tag)
{
return last-first; // v�letlen el�r�sre t�maszkodik
}
A bej�r� kateg�ri�j�t jelzo param�ter pontosan meghat�rozza, milyen bej�r�ra van
sz�ks�g,
�s m�sra nem is haszn�ljuk a f�ggv�nyben, csak arra, hogy a t�lterhelt f�ggv�ny
megfelel
o v�ltozat�t kiv�lasszuk. A param�terre a sz�m�t�sok elv�gz�s�hez nincs sz�ks�g.
Ez
a megold�s tiszt�n ford�t�si ideju v�laszt�st tesz lehetov�, �s amellett, hogy
automatikusan
kiv�lasztja a megfelelo seg�df�ggv�nyt, m�g t�pusellenorz�st is v�gez (�13.2.5).
Ezut�n a distance() f�ggv�ny meg�r�sa m�r nagyon egyszeru, csak a megfelelo
seg�df�ggv
�nyt kell megh�vnunk:
template<class In>
typename iterator_traits<In>::difference_type distance(In first, In last)
{
return dist_helper(first,last,iterator_traits<In>::iterator_category());
}
Egy dist_helper() f�ggv�ny megh�v�s�hoz a megadott
iterator_traits<In>::iterator_category
oszt�lynak vagy input_iterator_tag, vagy random_access-iterator_tag t�pus�nak kell
lennie.
Ennek ellen�re nincs sz�ks�g k�l�n dist_helper() f�ggv�nyre az elore halad�
(forward)
�s a k�tir�ny� (bidirectional) bej�r�k eset�ben, mert a sz�rmaztat�snak
k�sz�nhetoen
a dist_helper() f�ggv�ny azon v�ltozata, amely input_iterator_tag param�tert v�r,
ezeket is
kezeli. Az output_iterator_tag t�pust fogad� v�ltozat hi�nya pedig pontosan azt
fejezi ki,
hogy a distance() f�ggv�ny nem �rtelmezheto kimeneti (output) bej�r�kra:
void f(vector<int>& vi,
list<double>& ld,
istream_iterator<string>& is1, istream_iterator<string>& is2,
ostream_iterator<char>& os1, ostream_iterator<char>& os2)
{
19. Bej�r�k �s mem�riafoglal�k 741
distance(vi.begin(),vi.end()); // kivon� algoritmus haszn�lata
distance(ld.begin(),ld.end()); // n�velo algoritmus haszn�lata
distance(is1,is2); // n�velo algoritmus haszn�lata
distance(os1,os2); // hiba: rossz bej�r�-kateg�ria,
// a dist_helper() param�ter�nek t�pusa
// nem megfelelo
}
A distance() f�ggv�ny megh�v�sa egy istream_iterator oszt�lyra muk�dik, de
val�sz�nuleg
teljesen �rtelmetlen egy val�s programban, hiszen v�gigolvassuk vele a bemenetet,
de minden
elemet azonnal el is dobunk, �s az eldobott elemek sz�m�t adjuk vissza.
Az iterator_traits<T>::iterator_category lehetov� teszi, hogy a programoz� olyan
v�ltozatokat
�rjon egy algoritmushoz, melyek k�z�l mindig automatikusan a megfelelo ker�l
v�grehajt
�sra, amikor a megval�s�t�ssal egy�ltal�n nem foglalkoz� felhaszn�l� valamilyen
adatszerkezettel
megh�vja a f�ggv�nyt. M�s sz�val elrejthetj�k a megval�s�t�s r�szleteit egy egys
�ges fel�let m�g�tt, a helyben kifejtett (inline) f�ggv�nyek haszn�lata pedig
biztos�tja,
hogy ez az elegancia nem megy a fut�si ideju hat�konys�g rov�s�ra.
19.2.4. Besz�r� bej�r�k
Ha egy t�rol�ba egy bej�r� seg�ts�g�vel �rni akarunk, fel kell k�sz�ln�nk arra,
hogy a bej�r�
�ltal kijel�lt elemtol kezdve a t�rol� megv�ltozik. Ennek k�vetkezt�ben
t�lcsordul�s �s �gy
hib�s mem�ria�r�s is bek�vetkezhet:
void f(vector<int>& vi)
{
fill_n(vi.begin(),200,7); // 7 �rt�k�l ad�sa vi[0]..[199]-nek
}
Ha a vi t�rol�nak 200-n�l kevesebb eleme van, ez az elj�r�s nagy bajokat okozhat.
Az <iterator> fej�llom�nyban a standard k�nyvt�r le�r h�rom sablon oszt�lyt, amely
ezzel
a probl�m�val foglalkozik, k�nyelmes haszn�latukhoz pedig h�rom f�ggv�ny is
rendelkez
�s�nkre �ll:
template <class Cont> back_insert_iterator<Cont> back_inserter(Cont& c);
template <class Cont> front_insert_iterator<Cont> front_inserter(Cont& c);
template <class Cont, class Out> insert_iterator<Cont> inserter(Cont& c, Out p);
742 A standard k�nyvt�r
A back_inserter() arra szolg�l, hogy elemeket adjunk egy t�rol� v�g�hez, a
front_inserter()
seg�ts�g�vel a sorozat elej�re helyezhet�nk elemeket, m�g az .egyszeru. inserter()
a param�-
terk�nt megadott bej�r� el� sz�rja be az elemeket. �ppen ez�rt az inserter(c,p)
utas�t�sban
a p-nek �rv�nyes bej�r�nak kell lennie a c t�rol�ban. Term�szetesen a t�rol�
m�rete mindig
megno, amikor egy besz�r� bej�r� seg�ts�g�vel �rt�ket �runk bele.
A besz�r� bej�r�k (inserter) nem �rnak fel�l l�tezo elemeket, hanem �jakat sz�rnak
be
a push_back(), a push_front(), illetve az insert() (�16.3.6) utas�t�ssal:
void g(vector<int>& vi)
{
fill_n(back_inserter(vi),200,7); // 200 darab 7-es hozz�ad�sa vi v�g�hez
}
A besz�r� bej�r�k nem csak hasznosak, hanem egyszeruek �s hat�konyak is:
template <class Cont>
class insert_iterator : public iterator<output_iterator_tag,void,void,void,void> {

protected:
Cont& container; // a c�lt�rol�, amelybe besz�runk
typename Cont::iterator iter; // a t�rol�ba mutat
public:
explicit insert_iterator(Cont& x, typename Cont::iterator i)
: container(x), iter(i) {}
insert_iterator& operator=(const typename Cont::value_type& val)
{
iter = container.insert(iter,val);
++iter;
return *this;
}
insert_iterator& operator*() { return *this; }
insert_iterator& operator++() { return *this; } // prefix ++
insert_iterator operator++(int) { return *this; } // postfix ++
};
Teh�t a besz�r�k val�j�ban kimeneti (output) bej�r�k.
Az insert_iterator a kimeneti sorozatok k�l�nleges esete. A �18.3.1 pontban
bevezetett iseq
f�ggv�nyhez hasonl�an meg�rhatjuk a k�vetkezot:
19. Bej�r�k �s mem�riafoglal�k 743
template<class Cont>
insert_iterator<Cont>
oseq(Cont& c, typename Cont::iterator first, typename Cont::iterator last)
{
return insert_iterator<Cont>(c,c.erase(first,last)); // az erase magyar�zat�t l�sd
�16.3.6
}
Teh�t a kimeneti sorozat t�rli a r�gi elemeket, majd az aktu�lis eredm�nnyel
helyettes�ti
azokat:
void f(list<int>& li,vector<int>& vi) // vi m�sodik fel�nek helyettes�t�se li
m�solat�val
{
copy(li.begin(),li.end(),oseq(vi,vi+vi.size()/2,vi.end()));
}
Az oseq() f�ggv�nynek �t kell adnunk param�terk�nt mag�t a t�rol�t is, mert csak
bej�r�k
seg�ts�g�vel nem lehet cs�kkenteni egy t�rol� m�ret�t (�18.6., �18.6.3).
19.2.5. Visszafel� halad� bej�r�k
A szabv�nyos t�rol�kban megtal�lhat� az rbegin() �s az rend() f�ggv�ny, melyekkel
ford�-
tott sorrendben haladhatunk v�gig az elemeken (�16.3.2). Ezek az elj�r�sok
reverse_iterator
�rt�ket adnak vissza:
template <class Iter>
class reverse_iterator : public iterator<iterator_traits<Iter>::iterator_category,

iterator_traits<Iter>::value_type,
iterator_traits<Iter>::difference_type,
iterator_traits<Iter>::pointer,
iterator_traits<Iter>::reference> {
protected:
Iter current; // a current a *this �ltal hivatkozott ut�ni elemre mutat
public:
typedef Iter iterator_type;
reverse_iterator() : current() { }
explicit reverse_iterator(Iter x) : current(x) { }
template<class U> reverse_iterator(const reverse_iterator<U>& x) :
current(x.base()) { }
Iter base() const { return current; } // a bej�r� aktu�lis �rt�ke
744 A standard k�nyvt�r
reference operator*() const { Iter tmp = current; return *--tmp; }
pointer operator->() const;
reference operator[ ](difference_type n) const;
reverse_iterator& operator++() { --current; return *this; } // vigy�zzunk: nem ++
reverse_iterator operator++(int) { reverse_iterator t = current; --current; return
t; }
reverse_iterator& operator--() { ++current; return *this; } // vigy�zzunk: nem --
reverse_iterator operator--(int) { reverse_iterator t = current; ++current; return
t; }
reverse_iterator operator+(difference_type n) const;
reverse_iterator& operator+=(difference_type n);
reverse_iterator operator-(difference_type n) const;
reverse_iterator& operator-=(difference_type n);
};
A reverse_iterator t�pust egy iterator seg�ts�g�vel val�s�tjuk meg, melynek neve
current. Ez
a bej�r� csak a megfelelo sorozat elemeire vagy az utols� ut�ni elemre mutathat,
de nek�nk
a reverse_iterator utols� ut�ni eleme az eredeti sorozat .elso elotti. eleme, amit
nem �rhet
�nk el. �gy a tiltott hozz�f�r�sek elker�l�se �rdek�ben a current val�j�ban
a reverse_iterator �ltal kijel�lt elem ut�ni �rt�kre mutat. Ez�rt a * oper�tor a
*(current-1)
elemet adja vissza. Az oszt�ly jelleg�nek megfeleloen a ++ muveletet a current
�rt�kre alkalmazott
-- elj�r�s val�s�tja meg.
A reverse_iterator csak azokat a muveleteket teszi el�rhetov�, amelyeket a current
bej�r�
t�mogat:
void f(vector<int>& v, list<char>& lst)
{
v.rbegin()[3] = 7; // rendben: k�zvetlen el�r�su bej�r�
lst.rbegin()[3] = '4'; // hiba: a k�tir�ny� bej�r�k nem t�mogatj�k
// a [ ] haszn�lat�t
*(++++++lst.rbegin()) = '4'; // rendben!
}
Ezeken k�v�l a k�nyvt�r a reverse_iterator t�pushoz az ==, a !=, a <, a >, a <=, a
>=, a + �s
a - muveleteket is tartalmazza.
19.2.6. Adatfolyamok bej�r�i
Az adatok ki- �s bevitel�t h�rom m�dszer valamelyik�vel val�s�tjuk meg: vagy az
adatfolyamok
k�nyvt�r�val (21. fejezet), vagy a grafikus felhaszn�l�i fel�let eszk�zeivel (ezt
a C++-
szabv�ny nem tartalmazza), vagy a C bemeneti/kimeneti (I/O) muveleteivel (�21.8).
Ezek
19. Bej�r�k �s mem�riafoglal�k 745
a ki- �s bemeneti eszk�z�k elsosorban arra szolg�lnak, hogy k�l�nb�zo t�pus�
�rt�keket
egyes�vel �rjunk vagy olvassunk. A standard k�nyvt�r n�gy bej�r�-t�pussal a ki- �s
bemeneti
adatfolyamokat is beilleszti a t�rol�k �s az algoritmusok �ltal k�rvonalazott
egys�ges
rendszerbe:
1. Az ostream_iterator seg�ts�g�vel egy ostream adatfolyamba �rhatunk (�3.4,
�21.2.1).
2. Az istream_iterator seg�ts�g�vel egy istream adatfolyamba �rhatunk (�3.6,
�21.3.1).
3. Az ostreambuf_iterator egy adatfolyam-puffer (�tmeneti t�r) �r�s�hoz haszn�lhat
� (�21.6.1).
4. Az istreambuf_iterator egy adatfolyam-puffer olvas�s�hoz haszn�lhat� (�21.6.2).

Az �tlet csak annyi, hogy a gyujtem�nyek ki- �s bevitel�t sorozatokk�nt jelen�tj�k


meg:
template <class T, class Ch = char, class Tr = char_traits<Ch> >
class ostream_iterator : public iterator<output_iterator_tag,void,void,void,void>
{
public:
typedef Ch char_type;
typedef Tr traits_type;
typedef basic_ostream<Ch,Tr> ostream_type;
ostream_iterator(ostream_type& s);
ostream_iterator(ostream_type& s, const Ch* delim); // delim �r�sa minden kimeneti

// �rt�k ut�n
ostream_iterator(const ostream_iterator&);
~ostream_iterator();
ostream_iterator& operator=(const T& val); // val �r�sa a kimenetre
ostream_iterator& operator*();
ostream_iterator& operator++();
ostream_iterator& operator++(int);
};
Ez a bej�r� a kimeneti bej�r�k szok�sos .�r�s. �s .tov�bbl�p�s. muvelet�t �gy
hajtja v�gre,
hogy az ostream megfelelo muveleteiv� alak�tja azokat:
void f()
{
ostream_iterator<int> os(cout); // int-ek �r�sa a cout-ra os-en kereszt�l
*os = 7; // a kimenet 7
++os; // felk�sz�l�s a k�vetkezo kimenetre
*os = 79; // a kimenet 79
}
746 A standard k�nyvt�r
A ++ oper�tor t�nyleges kimeneti muveletet is v�grehajthat, de elk�pzelheto olyan
megold
�s is, ahol semmilyen hat�sa sincs. A k�l�nb�zo nyelvi v�ltozatok k�l�nb�zo
m�dszereket
alkalmazhatnak, ez�rt ha .hordozhat�. programot akarunk k�sz�teni, mindenk�ppen
haszn�ljuk a ++ muveletet k�t ostream_iterator-�rt�kad�s k�z�tt. Term�szetesen
minden
szabv�nyos algoritmus �gy k�sz�lt, hiszen ellenkezo esetben m�r vektorra sem
lenn�nek
haszn�lhat�k, �s ez az oka az ostream_iterator oszt�ly ilyet�n meghat�roz�s�nak
is.
Az ostream_iterator elk�sz�t�se nagyon egyszeru, �gy feladatk�nt is szerepel a
fejezet v�g�n
(�19.6[4]). A szabv�nyos ki- �s bemenet t�bbf�le karaktert�pust is t�mogat. A
char_traits
oszt�ly (�20.2) egy karaktert�pus azon jellemzoit �rja le, melyek fontosak
lehetnek a string
oszt�ly vagy a ki- �s bemenet szempontj�b�l.
Az istream bemeneti bej�r�j�t hasonl�an hat�rozhatjuk meg:
template <class T, class Ch = char, class Tr = char_traits<Ch>, class Dist =
ptrdiff_t>
class istream_iterator : public iterator<input_iterator_tag, T, Dist, const T*,
const T&> {
public:
typedef Ch char_type;
typedef Tr traits_type;
typedef basic_istream<Ch,Tr> istream_type;
istream_iterator(); // a bemenet v�ge
istream_iterator(istream_type& s);
istream_iterator(const istream_iterator&);
~istream_iterator();
const T& operator*() const;
const T* operator->() const;
istream_iterator& operator++();
istream_iterator operator++(int);
};
Ez a bej�r� is olyan form�j�, hogy k�nyelmesen olvashassunk be adatokat (a >>
seg�ts�g�-
vel) a bemeneti adatfolyamb�l egy t�rol�ba:
void f()
{
istream_iterator<int> is(cin); // int-ek beolvas�sa a cin-rol az is-en kereszt�l
int i1 = *is; // egy int beolvas�sa
++is; // felk�sz�l�s a k�vetkezo bemenetre
int i2 = *is; // egy int beolvas�sa
}
19. Bej�r�k �s mem�riafoglal�k 747
Az alap�rtelmezett istream_iterator a bemenet v�g�t �br�zolja, �gy ennek
felhaszn�l�s�val
megadhatunk bemeneti sorozatot is:
void f(vector<int>& v)
{
copy(istream_iterator<int>(cin),istream_iterator<int>(),back_inserter(v));
}
Ahhoz, hogy ez az elj�r�s muk�dj�n, a standard k�nyvt�r az istream_iterator
oszt�lyhoz
tartalmazza az == �s a != muveletet is.
A fentiekbol l�that�, hogy az istream_iterator megval�s�t�sa nem annyira egyszeru,
mint az
ostream_iterator oszt�ly�, de az�rt nem is t�ls�gosan bonyolult. Egy
istream_iterator meg-
�r�sa szint�n szerepel feladatk�nt (�19.6[5]).
19.2.6.1. �tmeneti t�rak adatfolyamokhoz
A �21.6 pontban �rjuk le r�szletesen, hogy az adatfolyam alap� ki- �s bemenet .
amelyet az
istream �s az ostream megval�s�t . val�j�ban egy �tmeneti t�rral (pufferrel)
tartja a kapcsolatot,
amely az alacsonyszintu, fizikai ki- �s bemenetet k�pviseli. Lehetos�g�nk van
azonban
arra, hogy a szabv�nyos adatfolyamok form�z�si muveleteit elker�lj�k, �s
k�zvetlen�l
az �tmeneti t�rakkal dolgozzunk (�21.6.4). Ez a lehetos�g a szabv�nyos
algoritmusok sz�-
m�ra is adott az istrembuf_iterator �s az ostreambuf_iterator seg�ts�g�vel:
template<class Ch, class Tr = char_traits<Ch> >
class istreambuf_iterator
: public iterator<input_iterator_tag,Ch,typename Tr::off_type,Ch*,Ch&> {
public:
typedef Ch char_type;
typedef Tr traits_type;
typedef typename Tr::int_type int_type;
typedef basic_streambuf<Ch,Tr> streambuf_type;
typedef basic_istream<Ch,Tr> istream_type;
class proxy; // seg�dt�pus
istreambuf_iterator() throw(); // �tmeneti t�r v�ge
istreambuf_iterator(istream_type& is) throw(); // olvas�s is streambuf-j�b�l
istreambuf_iterator(streambuf_type*) throw();
istreambuf_iterator(const proxy& p) throw(); // olvas�s p streambuf-j�b�l
748 A standard k�nyvt�r
Ch operator*() const;
istreambuf_iterator& operator++(); // elotag
proxy operator++(int); // ut�tag
bool equal(istreambuf_iterator&); // mindk�t streambuf-nak v�ge (eof) vagy
egyiknek
sem
};
A fentieken k�v�l rendelkez�s�nkre �ll az == �s a != oper�tor is.
Egy streambuf olvas�sa alacsonyabb szintu muvelet, mint egy istream olvas�sa.
Ennek k�-
vetkezt�ben az istreambuf_iterator fel�lete kicsit bonyolultabb, mint az
istream_iterator -�.
Ennek ellen�re, ha egyszer siker�lt hib�tlanul kezdo�rt�ket adnunk egy
istreambuf_iterator
objektumnak, akkor a *, a ++ �s az = muveletek a szok�sos helyeken, a szok�sos
jelent�ssel
haszn�lhat�k.
A proxy t�pus egy megval�s�t�st�l f�ggo seg�dt�pus, amely lehetov� teszi az
ut�tagk�nt
haszn�lt ++ oper�tor alkalmaz�s�t an�lk�l, hogy felesleges korl�toz�sokat tenne
a streambuf-ra vonatkoz�an. A proxy t�rolja az eredm�ny�rt�ket addig, am�g a
bej�r�t tov
�bbl�ptetj�k:
template<class Ch, class Tr = char_traits<Ch> >
class istreambuf_iterator<Ch,Tr>::proxy {
Ch val;
basic_streambuf<Ch,Tr>* buf;
proxy(Ch v, basic_streambuf<Ch,Tr>* b) :val(v), buf(b) { }
public:
Ch operator*() { return val; }
};
Az ostreambuf_iterator oszt�lyt hasonl�an defini�lhatjuk:
template <class Ch, class Tr = char_traits<Ch> >
class ostreambuf_iterator : public
iterator<output_iterator_tag,void,void,void,void>{
public:
typedef Ch char_type;
typedef Tr traits_type;
typedef basic_streambuf<Ch,Tr> streambuf_type;
typedef basic_ostream<Ch,Tr> ostream_type;
ostreambuf_iterator(ostream_type& os) throw(); // �r�s os streambuf-j�ba
ostreambuf_iterator(streambuf_type*) throw();
ostreambuf_iterator& operator=(Ch);
19. Bej�r�k �s mem�riafoglal�k 749
ostreambuf_iterator& operator*();
ostreambuf_iterator& operator++();
ostreambuf_iterator& operator++(int);
bool failed() const throw(); // igaz, ha Tr::eof()-hoz �rt�nk
};
19.3. Ellenorz�tt bej�r�k
A standard k�nyvt�r �ltal biztos�tottak mellett a programoz� saj�t maga is
l�trehozhat
bej�r�kat. Erre gyakran sz�ks�g is van, amikor egy �j t�pus� t�rol�t hozunk l�tre.
P�ldak�ppen
bemutatunk egy olyan bej�r�t, amely ellenorzi, hogy �rv�nyes tartom�nyban f�r�nk-e

hozz� a t�rol�hoz.
A szabv�nyos t�rol�kat haszn�lva sokkal ritk�bban kell magunknak foglalkozni a
mem�riakezel
�ssel, a szabv�nyos algoritmusok seg�ts�g�vel pedig a t�rol�k elemeinek megc�mz�-
s�re sem kell olyan gyakran gondolnunk. A standard k�nyvt�r �s a nyelvi eszk�z�k
egy�ttes
haszn�lat�val ford�t�si idoben elv�gezhet�nk sok t�pusellenorz�si feladatot, �gy a
fut�si
ideju hib�k sz�ma jelentosen kevesebb, mint a hagyom�nyos, C st�lus� programokban.
Ennek
ellen�re a standard k�nyvt�r m�g mindig a programoz�ra h�r�tja azt a feladatot,
hogy
elker�lje egy t�rol� mem�riahat�rainak �tl�p�s�t. Ha p�ld�ul v�letlen�l valamilyen
x t�rol
�nak az x[x.size()+7] elem�t pr�b�ljuk meg el�rni, akkor megj�solhatatlan . de
�ltal�ban
rossz . esem�nyek k�vetkezhetnek be. Egy tartom�nyellenorz�tt vector haszn�lata
(p�ld�-
ul a �3.7.1 pontban bemutatott Vec-�) n�ha seg�thet ezen a probl�m�n, sokkal
�ltal�nosabb
megold�st jelent azonban, ha a bej�r�kon kereszt�l t�rt�no minden hozz�f�r�st
ellenorz
�nk.
Ahhoz, hogy ilyen szintu ellenorz�st �rhess�nk el an�lk�l, hogy jelentos terhet
helyezn�nk
a programoz� v�ll�ra, ellenorz�tt bej�r�kra van sz�ks�g�nk, �s valamilyen
k�nyelmes m�dszerre,
amellyel ezeket a t�rol�khoz kapcsolhatjuk. A Checked_iter megval�s�t�s�hoz sz�ks
�g�nk van egy t�rol�ra �s egy bej�r�ra, amely ebbe a t�rol�ba mutat. Ugyan�gy,
mint a lek
�tok (binder, �18.4.4.1) vagy a besz�r� bej�r�k (inserter, �19.2.4) eset�ben, most
is k�l�n
f�ggv�nyekkel seg�tj�k az ellenorz�tt bej�r�k l�trehoz�s�t:
template<class Cont, class Iter> Checked_iter<Cont,Iter> make_checked(Cont& c,
Iter i)
{
return Checked_iter<Cont,Iter>(c,i);
}
750 A standard k�nyvt�r
template<class Cont> Checked_iter<Cont,typename Cont::iterator> make_checked(Cont&
c)
{
return Checked_iter<Cont,typename Cont::iterator>(c,c.begin());
}
Ezek a f�ggv�nyek sokat seg�tenek abban, hogy a t�pusokat a param�terekbol
�llap�tsuk
meg, �s ne k�l�n kelljen azokat megadni:
void f(vector<int>& v, const vector<int>& vc)
{
typedef Checked_iter<vector<int>,vector<int>::iterator> CI;
CI p1 = make_checked(v,v.begin()+3);
CI p2 = make_checked(v); // alap�rtelmez�s szerint az elso elemre mutat
typedef Checked_iter<const vector<int>,vector<int>::const_iterator> CIC;
CIC p3 = make_checked(vc,vc.begin()+3);
CIC p4 = make_checked(vc);
const vector<int>& vv = v;
CIC p5 = make_checked(v,vv.begin());
}
Alap�rtelmez�s szerint a const t�rol�knak minden bej�r�ja is konstans, �gy az
ezekhez tartoz
� Checked_iter oszt�lyoknak is �lland�nak kell lenni�k. A p5 bej�r� arra mutat
p�ld�t,
hogyan hozhatunk l�tre const bej�r�t nem konstans t�rol�b�l.
Ez magyar�zza azt is, hogy mi�rt van sz�ks�ge a Checked_iter t�pusnak k�t
sablonparam�terre:
az egyik a t�rol� t�pus�t adja meg, a m�sik a konstans/nem konstans k�l�nbs�get
fejezi ki.
Ezen Checked_iter t�pusok nevei el�g hossz�ak (�s cs�ny�k), de ez nem sz�m�t, ha
a bej�r�kat �ltal�nos�tott (generikus) algoritmusok param�terek�nt haszn�ljuk:
template<class Iter> void mysort(Iter first, Iter last);
void f(vector<int>& c)
{
try {
mysort(make_checked(c), make_checked(c,c.end());
}
catch (out_of_bounds) {
cerr<<"hopp�: hiba a mysort()-ban\n";
abort();
}
}
19. Bej�r�k �s mem�riafoglal�k 751
Ez pont egy olyan algoritmus, melynek elso v�ltozataiban k�nnyen elofordulhat,
hogy kil
�p�nk a megengedett tartom�nyb�l, �gy az ellenorz�tt bej�r�k haszn�lata nagyon is
indokolt.
A Checked_iter oszt�lyt egy t�rol�ra hivatkoz� mutat�val �s egy olyan bej�r�val
�br�zolhatjuk,
amely ebbe a t�rol�ba mutat:
template<class Cont, class Iter = typename Cont::iterator>
class Checked_iter : public iterator_traits<Iter> {
Iter curr; // az aktu�lis poz�ci�ra mutat� bej�r�
Cont* c; // az aktu�lis t�rol�ra hivatkoz� mutat�
// ...
};
Az iterator_traits oszt�lyb�l val� sz�rmaztat�s az egyik lehets�ges m�dszer a
sz�ks�ges
t�pusok (typedef) meghat�roz�s�hoz. A m�sik egyszeru megold�s . az iterator
oszt�lyb�l
val� sz�rmaztat�s . ebben az esetben t�lzott lenne (A reverse_iterator eset�ben
ezt a megold
�st v�lasztottuk a �19.2.5 pontban). Ugyan�gy, ahogy egy bej�r�nak nem kell
felt�tlen�l
oszt�lynak lennie, egy oszt�lyk�nt meghat�rozott bej�r�nak sem kell felt�tlen�l az
iterator
oszt�ly lesz�rmazottj�nak lennie.
A Checked_iter oszt�ly minden muvelete egy�rtelmu:
template<class Cont, class Iter = typename Cont::iterator>
class Checked_iter : public iterator_traits<Iter> {
// ...
public:
void valid(Iter p) const
{
if (c->end() == p) return;
for (Iter pp = c->begin(); pp!=c->end(); ++pp) if (pp == p) return;
throw out_of_bounds();
}
friend bool operator==(const Checked_iter& i, const Checked_iter& j)
{
return i.c==j.c && i.curr==j.curr;
}
// nincs alap�rtelmezett kezdo�rt�k-ad�
// alap�rtelmezett m�sol� konstruktor �s �rt�kad�s haszn�lata
752 A standard k�nyvt�r
Checked_iter(Cont& x, Iter p) : c(&x), curr(p) { valid(p); }
reference_type operator*() const
{
if (curr==c->end()) throw out_of_bounds();
return *curr;
}
pointer_type operator->() const
{
if (curr==c->end()) throw out_of_bounds();
return &*curr;
}
Checked_iter operator+(Dist d) const // csak k�zvetlen el�r�su bej�r�khoz
{
if (c->end()-curr<d || d<curr-c->begin()) throw out_of_bounds();
return Checked_iter(c,curr+d);
}
reference_type operator[ ](Dist d) const // csak k�zvetlen el�r�su bej�r�khoz
{
if (c->end()-curr<=d || d<curr-c->begin()) throw out_of_bounds();
return curr[d];
}
Checked_iter& operator++() // prefix ++
{
if (curr == c->end()) throw out_of_bounds();
++curr;
return *this;
}
Checked_iter operator++(int) // postfix ++
{
Checked_iter tmp = *this;
++*this; // prefix ++ �ltal ellenorz�tt
return tmp;
}
Checked_iter& operator--() // prefix --
{
if (curr == c->begin()) throw out_of_bounds();
--curr;
return *this;
}
19. Bej�r�k �s mem�riafoglal�k 753
Checked_iter operator--(int) // postfix --
{
Checked_iter tmp = *this;
--*this; // prefix -- �ltal ellenorz�tt
return tmp;
}
difference_type index() const { return curr-c.begin(); } // csak k�zvetlen el�r�s
eset�n
Iter unchecked() const { return curr; }
// +, -, < stb. (�19.6[6])
};
Egy Checked_iter objektumot mindig egy bizonyos t�rol� egy bizonyos bej�r�j�hoz
k�t�nk.
Egy alaposabb megval�s�t�sban a valid() f�ggv�nynek hat�konyabb v�ltozat�t kell
l�trehoznunk
a k�zvetlen el�r�su bej�r�khoz (�19.6[6]). Miut�n kezdo�rt�ket adtunk
a Checked_iter objektumnak, minden muveletet ellenorz�nk, amely elmozd�thatja a
bej�r�t,
�gy mindig biztosak lehet�nk abban, hogy az a t�rol� egy l�tezo elem�re mutat. Ha
megpr
�b�lunk egy ilyen bej�r�t a t�rol� �rv�nyes tartom�ny�n k�v�lre vinni,
out_of_bounds kiv
�telt kapunk:
void f(list<string>& ls)
{
int count = 0;
try {
Checked_iter< list<string> > p(ls,ls.begin());
while (true) {
++p; // elobb-ut�bb a v�g�re �r
++count;
}
}
catch(out_of_bounds) {
cout << "T�ll�p�s a t�rol�n " << count << " pr�b�lkoz�s ut�n.\n";
}
}
A Checked_iter objektum pontosan tudja, melyik t�rol�ba mutat. Ez lehetov� teszi,
hogy az
olyan eseteket kezelj�k, amikor egy t�rol�ba mutat� bej�r� �rv�nytelenn� v�lik
valamilyen
muvelet hat�s�ra (�16.3.8). M�g �gy sem vesz�nk minden lehetos�get figyelembe,
teh�t ha
az �sszes hibalehetos�gre fel akarunk k�sz�lni, akkor egy m�sik, bonyolultabb
bej�r�t kell
k�sz�ten�nk (l�sd �19.6[7]).
754 A standard k�nyvt�r
Figyelj�k meg, hogy az ut�tagk�nt haszn�lt ++ oper�tor megval�s�t�s�hoz sz�ks�g
van egy
ideiglenes t�rol�elemre, m�g az elotag-form�n�l erre nincs sz�ks�g. Ez�rt bej�r�k
eset�ben
mindig �rdemes a p++ forma helyett a ++p alakot haszn�lni, ha az ellenkezoj�re
nincs k�-
l�n�sebb okunk.
Mivel a Checked_iter egy t�rol�ra hivatkoz� mutat�t t�rol, k�zvetlen�l nem
haszn�lhat�
a be�p�tett t�mb�k kezel�s�hez. Ha m�gis ilyesmire van sz�ks�g�nk, a c_array
t�pust
(�17.5.4) haszn�lhatjuk.
Ahhoz, hogy az ellenorz�tt bej�r�k megval�s�t�s�t teljess� tegy�k, haszn�latukat
egyszeru-
v� kell tenn�nk. K�t megk�zel�t�ssel pr�b�lkozhatunk:
1. Meghat�rozunk egy ellenorz�tt t�rol� t�pust, amely ugyan�gy viselkedik, mint
az �tlagos t�rol�k, att�l eltekintve, hogy kevesebb konstruktor �ll benne
rendelkez
�s�nkre �s a begin(), end() stb. elj�r�sok mind Check_iter objektumot adnak
vissza a szok�sos bej�r�k helyett.
2. K�sz�t�nk egy kezelooszt�lyt, amelynek valamilyen t�rol�val adhatunk kezdo�rt
�ket, �s amely ehhez a t�rol�hoz a k�sobbiekben csak ellenorz�tt hozz�f�r�seket
enged�lyez (�19.6[8]).
Az al�bbi sablon egy ellenorz�tt bej�r�t k�t egy t�rol�hoz:
template<class C> class Checked : public C {
public:
explicit Checked(size_t n) :C(n) { }
Checked() :C() { }
typedef Checked_iter<C> iterator;
typedef Checked_iter<C,C::const_iterator> const_iterator;
iterator begin() { return iterator(*this,C::begin()); }
iterator end() { return iterator(*this,C::end()); }
const_iterator begin() const { return const_iterator(*this,C::begin()); }
const_iterator end() const { return const_iterator(*this,C::end()); }
reference_type operator[ ](size_t n) { return Checked_iter<C>(*this)[n]; }
C& base() { return static_cast<C&>(*this); } // r�gz�t�s az alapt�rol�hoz
};
19. Bej�r�k �s mem�riafoglal�k 755
Ezut�n haszn�lhatjuk az al�bbi programr�szletet:
Checked< vector<int> > vec(10);
Checked< list<double> > lst;
void f()
{
int v1 = vec[5]; // rendben
int v2 = vec[15]; // out_of_bounds kiv�telt v�lt ki
// ...
lst.push_back(v2);
mysort(vec.begin(),vec.end());
copy(vec.begin(),vec.end(),lst.begin());
}
A l�tsz�lag felesleges base() f�ggv�ny szerepe az, hogy a Checked() fel�let�t a
t�rol�k
kezeloinek (handle) fel�let�hez igaz�tsa, ezek ugyanis �ltal�ban nem tesznek
lehetov� automatikus
konverzi�kat.
Ha a t�rol� m�rete megv�ltozik, bej�r�i �rv�nytelenn� v�lnak. Ez t�rt�nik a
Checked_iter
objektumokkal is. Ebben az esetben a Checked_iter-nek a k�vetkezo k�dr�szlettel
adhatunk
�j kezdo�rt�ket:
void g(vector<int>& vi)
{
Checked_iter<int> p(vi,vi.begin());
// ..
int i = p.index(); // aktu�lis poz�ci� lek�r�se
vi.resize(100); // p �rv�nytelen lesz
p = Checked_iter<int>(vi,vi.begin()+i); // az aktu�lis poz�ci� vissza�ll�t�sa
}
A r�gi .aktu�lis poz�ci�. �rv�nytelenn� v�lik, ez�rt sz�ks�g�nk van az index()
f�ggv�nyre,
amely egy Checked_iter t�rol�s�ra �s vissza�ll�t�s�ra haszn�lhat�.
19.3.1. Kiv�telek, t�rol�k �s algoritmusok
K�nnyen �gy tunhet, hogy a szabv�nyos algoritmusok �s az ellenorz�tt bej�r�k
egy�ttes
haszn�lata olyan felesleges, mint az �v �s a nadr�gtart� egy�ttes visel�se:
mindketto �nmag
�ban is megv�d minket a .balesetektol.. Ennek ellen�re a tapasztalat azt mutatja,
hogy sok
ember �s sok alkalmaz�s sz�m�ra indokolt ilyen szintu paranoia, k�l�n�sen akkor,
ha egy
gyakran v�ltoz� programot sokan haszn�lnak rendszeresen.
756 A standard k�nyvt�r
A fut�si ideju ellenorz�sek haszn�lat�nak egyik m�dja, hogy csak a tesztel�s
idej�re hagyjuk
azokat programunkban. Teh�t ezek az ellenorz�sek eltunnek a programb�l, mielott az

.�les. k�r�lm�nyek k�z� ker�lne. Ez az elj�r�s ahhoz hasonl�that�, mint amikor a


mento-
mell�nyt addig hordjuk, am�g partk�zelben pancsolunk, �s levessz�k, amikor a ny�lt

tengerre mer�szked�nk. Ugyanakkor igaz, hogy a fut�si ideju ellenorz�sek jelentos


mennyis�gu idot �s mem�ri�t ig�nyelhetnek, �gy folyamatosan ilyen fel�gyeletet
biztos�tani
nem lehet val�s elv�r�s. Jelent�ktelen haszon �rdek�ben optimaliz�lni mindig
felesleges,
teh�t mielott v�glegesen t�rl�nk bizonyos ellenorz�seket, pr�b�ljuk ki, hogy
jelentos m�rt
�ku teljes�tm�nyjavul�st �r�nk-e el �gy. Ahhoz, hogy a programoz� t�nyleg
pr�b�lkozhasson
ilyesmivel, k�nnyuv� kell tenn�nk sz�m�ra a fut�si ideju ellenorz�sek
elt�vol�t�s�t
(�24.3.7.1). Ha elv�gezt�k a sz�ks�ges m�r�seket, a fut�si ideju ellenorz�seket a
l�tfontoss
�g� . �s rem�lhetoleg a legalaposabban tesztelt . helyekrol t�r�lhetj�k, m�g
m�shol az ellen
orz�st egy viszonylag olcs� biztos�t�snak tekinthetj�k.
A Checked_iter haszn�lata sz�mtalan hib�ra felh�vhatja figyelm�nket, de nem sokat
seg�t
abban, hogy ezeket a hib�kat kijav�tsuk. A programoz�k ritk�n �rnak olyan
programokat,
amelyek minden lehetos�gre felk�sz�lnek �s ellenoriznek minden muveletet, amely
kiv�-
telt okozhat (++, --, *, [ ], -> �s =). �gy k�t nyilv�nval� strat�gia k�z�l
v�laszthatunk:
1. A kiv�teleket keletkez�si hely�k k�zel�ben kapjuk el, �gy a kiv�telkezelo meg-
�r�ja pontosabban meg�llap�thatja a hiba ok�t �s hat�kony ellenl�p�seket tehet.
2. A kiv�teleket a programban viszonylag magas szinten kapjuk el, az eddigi sz�-
m�t�soknak egy jelentos r�sz�t eldobjuk, �s minden adatszerkezetet gyan�snak
minos�t�nk, amelybe �r�s t�rt�nt a hib�t kiv�lt� sz�m�t�s k�zben. (Lehet, hogy
ilyen adatszerkezetek nincsenek is, esetleg k�nnyen kiz�rhat�k a hibaforr�sok
k�r�bol.)
Felelotlens�g elkapni egy kiv�telt, amelyrol azt sem tudjuk, hogy a program mely
r�sz�n
keletkezett, �s tov�bbl�pni azzal a felt�telez�ssel, hogy egyetlen
adatszerkezet�nk sem
ker�lt nemk�v�natos �llapotba, hacsak nincs egy tov�bbi hibakezelo, amely az
ezut�n keletkez
o hib�kat feldolgozza. Egy egyszeru p�lda az ilyen helyzetre, amikor az eredm�nyek

tov�bbad�sa elott egy v�gso ellenorz�st v�gz�nk (ak�r sz�m�t�g�prol, ak�r emberi
munkav
�gz�srol van sz�). Ilyenkor egyszerubb �s olcs�bb �rtatlanul tov�bbhaladni,
minthogy
alacsony szinten minden hibalehetos�get megvizsg�ljunk. Ezzel egyben arra is
p�ld�t
mutattunk, hogy a t�bbszintu hibakezel�s (�14.9) hogyan teszi lehetov� a programok

egyszerus�t�s�t.
19. Bej�r�k �s mem�riafoglal�k 757
19.4. Mem�riafoglal�k
A mem�riafoglal�k (allok�torok, allocator) szerepe az, hogy a fizikai mem�ria
kezel�s�nek
gondj�t levegy�k azon algoritmusok �s t�rol�k k�sz�toinek v�ll�r�l, melyek sz�m�ra
mem�-
ri�t kell lefoglalnunk. A mem�riafoglal�k szabv�nyos fel�letet adnak a
mem�riater�letek
lefoglal�s�hoz �s felszabad�t�s�hoz, valamint szabv�nyos neveket adnak azoknak a
t�pusoknak,
melyeket mutat�k�nt vagy referenciak�nt haszn�lhatunk. A bej�r�hoz hasonl�an
a mem�riafoglal� fogalma is tiszt�n elvont, �gy mindent mem�riafoglal�nak
nevez�nk, ami
mem�riafoglal�k�nt viselkedik.
A standard k�nyvt�r egy szabv�nyos mem�riafoglal�t biztos�t, amely a legt�bb
felhaszn�l�
sz�m�ra megfelelo, de ha sz�ks�g van r�, a programoz�k maguk is l�trehozhatnak
egy�ni
v�ltozatokat, melyekkel a mem�ri�t m�s szerkezetunek t�ntethetik fel. K�sz�thet�nk
p�ld�-
ul olyan mem�riafoglal�t, amely osztott mem�ri�t haszn�l, szem�tgyujto algoritmust
val�s�t
meg, elore lefoglalt mem�riaszeletbol hozza l�tre az objektumokat (�19.4.2) �s �gy
tov�bb.
A szabv�nyos t�rol�k �s algoritmusok a muk�d�s�kh�z sz�ks�ges mem�ri�t mindig mem
�riafoglal� seg�ts�g�vel foglalj�k le �s �rik el. �gy ha �j mem�riafoglal�t
k�sz�t�nk, a szabv
�nyos t�rol�kat is felruh�zzuk azzal a k�pess�ggel, hogy a mem�ri�t megv�ltozott
szemsz
�gbol l�ss�k.
19.4.1. A szabv�nyos mem�riafoglal�
A szabv�nyos allocator sablon a <memory> fej�llom�nyban tal�lhat� �s a
mem�riafoglal�st
a new() oper�tor (�6.2.6) seg�ts�g�vel v�gzi. Alap�rtelmez�s szerint mindegyik
szabv�nyos
t�rol� ezt haszn�lja:
template <class T> class std::allocator {
public:
typedef T value_type;
typedef size_t size_type;
typedef ptrdiff_t difference_type;
typedef T* pointer;
typedef const T* const_pointer;
typedef T& reference;
typedef const T& const_reference;
pointer address(reference r) const { return &r; }
758 A standard k�nyvt�r
const_pointer address(const_reference r) const { return &r; }
allocator() throw();
template <class U> allocator(const allocator<U>&) throw();
~allocator() throw();
pointer allocate(size_type n, allocator<void>::const_pointer hint = 0); // hely n
darab
// Ts sz�m�ra
void deallocate(pointer p, size_type n); // n darab Ts hely�nek felszabad�t�sa,
// megsemmis�t�s n�lk�l
void construct(pointer p, const T& val) { new(p) T(val); } // *p felt�lt�se val-
lal
void destroy(pointer p) { p->~T(); } // *p megsemmis�t�se a hely felszabad�t�sa
// n�lk�l
size_type max_size() const throw();
template <class U>
struct rebind { typedef allocator<U> other; }; // val�j�ban typedef allocator<U>
other
};
template<class T> bool operator==(const allocator<T>&, const allocator<T>&)
throw();
template<class T> bool operator!=(const allocator<T>&, const allocator<T>&)
throw();
Az allocate(n) muvelettel n objektum sz�m�ra foglalhatunk helyet, p�rja pedig
a deallocate(p,n), mellyel felszabad�thatjuk az �gy lefoglalt ter�letet. Figyelj�k
meg, hogy
a deallocate() f�ggv�nynek is �tadjuk az n param�tert. Ezzel a megold�ssal k�zel
optim�-
lis mem�riafoglal�kat k�sz�thet�nk, amelyek csak a felt�tlen�l sz�ks�ges
inform�ci�kat t�-
rolj�k a lefoglalt ter�letrol. M�sr�szt viszont ezek a mem�riafoglal�k
megk�vetelik, hogy
a programoz� mindig a megfelelo n �rt�ket adja meg a deallocate() h�v�sakor.
Megjegyzend
o, hogy a deallocate() k�l�nb�zik az operator delete()-tol, amennyiben mutat�
param�tere
nem lehet nulla.
Az alap�rtelmezett allocator a new(size_t) oper�tort haszn�lja a mem�ria
lefoglal�s�hoz �s
a delete(void*) muveletet a felszabad�t�s�hoz. Ebbol k�vetkezik, hogy sz�ks�g
lehet
a new_handler() megh�v�s�ra �s a std::bad_alloc kiv�tel kiv�lt�s�ra, ha elfogyott
a mem�-
ria (�6.2.6.2).
Jegyezz�k meg, hogy az allocate() f�ggv�nynek nem kell felt�tlen�l megh�vnia egy
alacsonyszint
u mem�riafoglal�t. Gyakran jobb megold�st jelent egy mem�riafoglal� sz�m�ra,
ha o maga tartja nyilv�n a kioszt�sra k�sz, szabad mem�riaszeleteket, �s ezeket
minim�lis
idovesztes�ggel adja ki (�19.4.2).
A nem k�telezo hint param�ter az allocate() f�ggv�nyben mindig az adott
megval�s�t�st�l
f�gg. Mindenk�ppen arra szolg�l, hogy seg�tse a mem�riafoglal�t azokban a
rendszerek-
19. Bej�r�k �s mem�riafoglal�k 759
ben, ahol fontos a lokalit�s (vagyis az adott rendszerhez igazod�s). Egy
mem�riafoglal�t�l
p�ld�ul elv�rhatjuk, hogy egy lapoz�s rendszerben az �sszef�ggo objektumoknak
azonos
lapon foglaljon helyet. A hint param�ter t�pusa pointer, az al�bbi eroteljesen
egyszerus�tett
specializ�ci�nak megfeleloen:
template <> class allocator<void> {
public:
typedef void* pointer;
typedef const void* const_pointer;
// megj.: nincs referencia
typedef void value_type;
template <class U>
struct rebind { typedef allocator<U> other; }; // val�j�ban typedef allocator<U>
other
};
Az allocator<void>::pointer t�pus �ltal�nos mutat�t�pusk�nt szolg�l �s minden
szabv�nyos
mem�riafoglal� eset�ben a const void* t�pusnak felel meg.
Ha a mem�riafoglal� dokument�ci�ja m�st nem mond, a programoz� k�t lehetos�g k�z�l

v�laszthat az allocate() f�ggv�ny haszn�latakor:


1. Nem adja meg a hint param�tert.
2. A hint param�terben egy olyan objektumra hivatkoz� mutat�t ad meg, amelyet
gyakran haszn�l majd az �j objektummal egy�tt. Egy sorozatban p�ld�ul megadhatjuk
az elozo elem c�m�t.
A mem�riafoglal�k arra szolg�lnak, hogy megk�m�lj�k a t�rol�k k�sz�toit a fizikai
mem�ria
k�zvetlen kezel�s�tol. P�ldak�ppen vizsg�ljuk meg, hogy egy vector
megval�s�t�s�ban hogyan
haszn�ljuk a mem�ri�t:
template <class T, class A = allocator<T> > class vector {
public:
typedef typename A::pointer iterator;
// ...
private:
A alloc; // mem�riafoglal� objektum
iterator v; // mutat� az elemekre
// ...
public:
explicit vector(size_type n, const T& val = T(), const A& a = A())
: alloc(a)
{
760 A standard k�nyvt�r
v = alloc.allocate(n);
for(iterator p = v; p<v+n; ++p) alloc.construct(p,val);
// ...
}
void reserve(size_type n)
{
if (n<=capacity()) return;
iterator p = alloc.allocate(n);
iterator q = v;
while (q<v+size()) { // l�tezo elemek m�sol�sa
alloc.construct(p++,*q);
alloc.destroy(q++);
}
alloc.deallocate(v,capacity()); // r�gi hely felszabad�t�sa
v = p-size();
// ...
}
// ...
};
A mem�riafoglal�k muveleteit a pointer �s reference typedef-ek seg�ts�g�vel
fejezz�k ki, �gy
megadjuk a programoz�nak azt a lehetos�get, hogy m�s t�pusokat haszn�ljon a
mem�ria
el�r�s�hez. Ezt �ltal�ban nagyon neh�z megoldani. A C++ nyelv seg�ts�g�vel p�ld�ul
nincs
lehetos�g�nk arra, hogy egy t�k�letes hivatkoz�st�pust hat�rozzunk meg. A nyelv �s

a k�nyvt�rak alkot�i viszont ezeket a typedef-eket olyan t�pusok l�trehoz�s�hoz


haszn�lhatj
�k, amelyeket egy �tlagos felhaszn�l� nem tudna elk�sz�teni. P�ldak�nt egy olyan
mem�-
riafoglal�t eml�thet�nk, amely �lland� adatter�let el�r�s�re szolg�l, de
gondolhatunk egy
.nagy. mutat�ra is, amellyel a mem�ri�nak azt a ter�let�t is el�rhetj�k, amit a
szok�sos (�ltal
�ban 32 bites) mutat�k m�r nem k�pesek megc�mezni.
Egy �tlagos felhaszn�l� a mem�riafoglal�nak egyedi c�lra megadhat a szok�sost�l
elt�ro
mutat�t�pust is. Ugyanezt nem tehetj�k meg referenci�kkal, de ez a korl�toz�s
k�s�rletez�sn
�l vagy egyedi rendszerekben nem okoz nagy gondot.
Mem�riafoglal�t az�rt hozunk l�tre, hogy k�nnyen kezelhess�nk olyan objektumokat,
melyeknek
t�pus�t a mem�riafoglal� sablonparam�terek�nt adtuk meg. A legt�bb t�rol� megval
�s�t�s�ban azonban sz�ks�g van m�s t�pus� objektumok l�trehoz�s�ra is. P�ld�ul a
list
megval�s�t�s�hoz sz�ks�g van Link objektumok l�trehoz�s�ra. Az ilyen Link jellegu
objektumokat
a megfelelo list oszt�ly mem�riafoglal�j�val hozzuk l�tre.
19. Bej�r�k �s mem�riafoglal�k 761
A furcsa rebind t�pus arra szolg�l, hogy mem�riafoglal� k�pes legyen b�rmilyen
t�pus� objektum
hely�nek lefoglal�s�ra:
typedef typename A::template rebind<Link>::other Link_alloc; // "sablon", l�sd
�C.13.6
Ha A egy allocator, akkor a rebind<Link>::other t�pus-meghat�roz�s jelent�se
allocator<Link>, teh�t a fenti typedef egy k�zvetett megfogalmaz�sa az al�bbinak:
typedef allocator<Link> Link_alloc;
A k�zvetett megfogalmaz�s azonban megk�m�l minket att�l, hogy az allocator
kulcssz�t
k�zvetlen�l haszn�ljuk. A Link_alloc t�pust csak az A sablonparam�teren kereszt�l
hat�rozzuk
meg. P�ld�ul:
template <class T, class A = allocator<T> > class list {
private:
class Link { /* ... */ };
typedef typename A::rebind<Link>::other Link_alloc; // allocator<Link>
Link_alloc a; // "link" mem�riafoglal�
A alloc; // "list" mem�riafoglal�
// ...
public:
typedef typename A::pointer iterator;
// ...
iterator insert(iterator pos, const T& x )
{
Link_alloc::pointer p = a.allocate(1); // egy Link megszerz�se
// ...
}
// ...
};
Mivel a Link a list oszt�ly tagja, param�tere egy mem�riafoglal�. Ennek
k�vetkez�ben a k�-
l�nb�zo mem�riafoglal�kkal rendelkezo list�k Link objektumai k�l�nb�zo t�pus�ak,
ugyan�gy, ahogy maguk a list�k is k�l�nb�znek (�17.3.3).
762 A standard k�nyvt�r
19.4.2. Felhaszn�l�i mem�riafoglal�k
A t�rol� k�sz�toj�nek gyakran van sz�ks�ge arra, hogy egyes�vel hozzon l�tre
(allocate())
vagy semmis�tsen meg (deallocate()) objektumokat. Ha az allocate() f�ggv�nyt
meggondolatlanul
k�sz�tj�k el, nagyon sokszor kell megh�vnunk a new oper�tort, pedig a new oper�-
tor ilyen haszn�latra gyakran kis hat�konys�g�. A felhaszn�l�i mem�riafoglal�k
p�ld�jak
�nt az al�bbiakban olyan m�dszerrel �l�nk, mellyel egy .k�szletet. hozunk l�tre,
amely
r�gz�tett m�retu mem�riaszeleteket t�rol. A mem�riafoglal� ennek felhaszn�l�s�val
hat�konyabban
hajtja v�gre az allocate() elj�r�st, mint a hagyom�nyos (b�r �ltal�nosabb) new()
oper�tor.
V�letlen�l �n m�r kor�bban is l�trehoztam egy ilyen k�szletes mem�riafoglal�t,
amely k�-
r�lbel�l azt csin�lja, amire most sz�ks�g�nk van, de nem a megfelelo fel�letet
ny�jtja (hiszen
�vekkel azelott k�sz�lt, hogy a mem�riafoglal�k �tlete megsz�letett volna). Ez a
Pool
oszt�ly meghat�rozza a r�gz�tett m�retu elemek k�szlet�t, amelybol a programoz�
gyorsan
foglalhat le ter�leteket �s gyorsan fel is szabad�thatja azokat. Ez egy
alacsonyszintu t�pus,
amely k�zvetlen�l a mem�ri�t kezeli �s az igaz�t�si (alignment) probl�m�kkal is
foglalkozik:
class Pool {
struct Link { Link* next; };
struct Chunk {
enum { size = 8*1024-16 }; // valamivel kevesebb 8K-n�l, �gy egy
// "Chunk" belef�r 8K-ba
char mem[size]; // elosz�r a lefoglaland� ter�let az igaz�t�s
// miatt
Chunk* next;
};
Chunk* chunks;
const unsigned int esize;
Link* head;
Pool(Pool&); // m�sol�sv�delem
void operator=(Pool&); // m�sol�sv�delem
void grow(); // a k�szlet n�vel�se
public:
Pool(unsigned int n); // n az elemek m�rete
~Pool();
void* alloc(); // hely foglal�sa egy elem sz�m�ra
void free(void* b); // elem visszahelyez�se a k�szletbe
};
19. Bej�r�k �s mem�riafoglal�k 763
inline void* Pool::alloc()
{
if (head==0) grow();
Link* p = head; // az elso elem visszaad�sa
head = p->next;
return p;
}
inline void Pool::free(void* b)
{
Link* p = static_cast<Link*>(b);
p->next = head; // b visszahelyez�se elso elemk�nt
head = p;
}
Pool::Pool(unsigned int sz)
: esize(sz<sizeof(Link)?sizeof(Link):sz)
{
head = 0;
chunks = 0;
}
Pool::~Pool() // minden 'chunk' felszabad�t�sa
{
Chunk* n = chunks;
while (n) {
Chunk* p = n;
n = n->next;
delete p;
}
}
void Pool::grow() // hely foglal�sa �j 'chunk' sz�m�ra, melyet 'esize' m�retu
elemek
// l�ncolt list�jak�nt rendez�nk
{
Chunk* n = new Chunk;
n->next = chunks;
chunks = n;
const int nelem = Chunk::size/esize;
char* start = n->mem;
char* last = &start[(nelem-1)*esize];
for (char* p = start; p<last; p+=esize)
reinterpret_cast<Link*>(p)->next = reinterpret_cast<Link*>(p+esize);
reinterpret_cast<Link*>(last)->next = 0;
head = reinterpret_cast<Link*>(start);
}
764 A standard k�nyvt�r
A val�s �letben zajl� munka szeml�ltet�s�re a Pool oszt�lyt v�ltozatlan form�ban
haszn�ljuk
fel az �j mem�riafoglal� megval�s�t�s�hoz, nem csak �t�rjuk, hogy a nek�nk
megfelelo
fel�letet ny�jtsa. A k�szletes mem�riafoglal� c�lja, hogy objektumaink egyes�vel
t�rt�no
l�trehoz�sa �s megsemmis�t�se gyors legyen. A Pool oszt�ly mindezt biztos�tja. A
megval�-
s�t�st azzal kell m�g kieg�sz�ten�nk, hogy egyszerre tetszoleges sz�m�, illetve
( a rebind()
ig�nyeinek megfeleloen) tetszoleges m�retu objektumokat is l�trehozhassunk. Ezt a
k�t
probl�m�t feladatnak hagyjuk (�19.6[9]).
A Pool oszt�ly felhaszn�l�s�val a Pool_alloc megval�s�t�sa m�r egyszeru:
template <class T> class Pool_alloc {
private:
static Pool mem; // elemk�szlet sizeof(T) m�rettel
public:
// mint a szabv�nyos allocator (�19.4.1)
};
template <class T> Pool Pool_alloc<T>::mem(sizeof(T));
template <class T> Pool_alloc<T>::Pool_alloc() { }
template <class T>
T* Pool_alloc<T>::allocate(size_type n, void* = 0)
{
if (n == 1) return static_cast<T*>(mem.alloc());
// ...
}
template <class T>
void Pool_alloc<T>::deallocate(pointer p, size_type n)
{
if (n == 1) {
mem.free(p);
return;
}
// ...
}
A mem�riafoglal�t ezut�n m�r a megszokott form�ban haszn�lhatjuk:
vector< int,Pool_alloc<int> > v;
map<string,number,Pool_alloc< pair<const string,number> > > m;
// ugyan�gy mint szoktuk
vector<int> v2 = v; // hiba: k�l�nb�zo mem�riafoglal�-param�terek
19. Bej�r�k �s mem�riafoglal�k 765
A Pool_Alloc megval�s�t�s�hoz statikus Pool objektumot haszn�lunk. Az�rt d�nt�ttem
�gy,
mert a standard k�nyvt�r a mem�riafoglal�kra egy korl�toz�st k�nyszer�t, m�gpedig
azzal,
hogy a szabv�nyos t�rol�k megval�s�t�s�nak megengedi, hogy minden objektumot
egyen-
�rt�kunek tekintsenek, amelynek t�pusa az adott t�rol� mem�riafoglal�ja. Ez
val�j�ban
igen jelentos hat�konys�gi elony�ket jelent: ennek a korl�toz�snak k�sz�nhetoen a
Link
objektumok mem�riafoglal�inak p�ld�ul nem kell k�l�n mem�riater�letet f�lretenn�nk

(annak ellen�re, hogy a Link oszt�ly �ltal�ban param�terk�nt egy mem�riafoglal�t


kap
ahhoz a t�rol�hoz, amelyben szerepel, �19.4.1). Egy m�sik elony, hogy azokban a
muveletekben,
ahol k�t sorozat elemeit kell el�rn�nk (p�ld�ul a swap() f�ggv�nyben), nem kell
megvizsg�lnunk, hogy a haszn�lt elemek ugyanolyan mem�riafoglal�kkal rendelkeznek-
e.
A h�tr�ny, hogy a korl�toz�s k�vetkezt�ben az ilyen mem�riafoglal�k nem
haszn�lhatnak
objektumszintu adatokat.
Mielott ilyen optimaliz�ci�t haszn�ln�nk, gondoljuk v�gig, hogy sz�ks�g van-e r�.
�n rem�-
lem, hogy az alap�rtelmezett allocator legt�bb megval�s�t�s�ban elv�gzik ezt a
klasszikus
C++ optimaliz�ci�t, �gy megk�m�lnek minket ettol a probl�m�t�l.
19.4.3. �ltal�nos�tott mem�riafoglal�k
Az allocator val�j�ban nem m�s, mint annak az �tletnek az egyszerus�tett �s
optimaliz�lt v�ltozata,
miszerint egy t�rol�nak egy sablonparam�teren kereszt�l adjuk meg az inform�ci�-
kat (�13.4.1., �16.2.3). Logikus elv�r�s p�ld�ul, hogy a t�rol� minden elem�nek
hely�t a t�-
rol� mem�riafoglal�j�val foglaljuk le. Ha azonban ilyenkor lehetov� tessz�k, hogy
k�t
ugyanolyan t�pus� list t�rol�nak k�l�nb�zo mem�riafoglal�ja legyen, akkor a
splice()
(�17.2.2.1) nem val�s�that� meg egyszeru �tl�ncol�ssal, hanem szab�lyos m�sol�st
kell meghat
�roznunk, mert v�dekezn�nk kell azon (ritka) esetek ellen, amikor a k�t list�ban a
mem
�riafoglal�k nem azonosak, annak ellen�re, hogy t�pusuk megegyezik. Hasonl�
probl�ma,
hogy ha a mem�riafoglal�k t�k�letesen �ltal�nosak, akkor a rebind() elj�r�snak
(amely tetsz
oleges t�pus� elemek l�trehoz�s�t teszi lehetov� a mem�riafoglal� sz�m�ra) sokkal
bonyolultabbnak
kell lennie. Ez�rt a .norm�lis. mem�riafoglal�kr�l azt felt�telezz�k, hogy
nem t�rolnak objektumszintu adatokat, az algoritmusok pedig kihaszn�lhatj�k ezt.
Meglepo m�don ez a dr�k�i korl�toz�s az objektumszintu inform�ci�kra n�zve nem
t�ls�-
gosan vesz�lyes a mem�riafoglal�k eset�ben. A legt�bb mem�riafoglal�nak nincs is
sz�ks
�ge objektumszintu adatokra, sot ilyen adatok n�lk�l m�g gyorsabbak is lehetnek,
r�ad�-
sul a mem�riafoglal�k az�rt tudnak adatokat t�rolni, a mem�riafoglal�-t�pusok
szintj�n.
Ha k�l�n adatelemekre van sz�ks�g, k�l�nb�zo mem�riafoglal�-t�pusokat
haszn�lhatunk:
766 A standard k�nyvt�r
template<class T, class D> class My_alloc { // T mem�riafoglal�j�t D haszn�lat�val

// hozzuk l�tre
D d; // a My_alloc<T,D> sz�m�ra sz�ks�ges adatok
// ...
};
typedef My_alloc<int,Persistent_info> Persistent;
typedef My_alloc<int,Shared_info> Shared;
typedef My_alloc<int,Default_info> Default;
list<int,Persistent> lst1;
list<int,Shared> lst2;
list<int,Default> lst3;
Az lst1, az lst2 �s az lst3 list�k k�l�nb�zo t�pus�ak, �gy ha k�z�l�k kettot
akarunk felhaszn
�lni valamilyen muveletben, akkor �ltal�nos algoritmusokat kell haszn�lnunk
(18.fejezet),
nem pedig specializ�lt lista muveleteket (�17.2.2.1). Ebbol k�vetkezik, hogy az
�tl�ncol�s
helyett m�sol�st kell haszn�lnunk, �gy a k�l�nb�zo mem�riafoglal�k haszn�lata nem
okoz
probl�m�t.
Az objektumszintu adatokra vonatkoz� korl�toz�sokra a mem�riafoglal�kban az�rt van

sz�ks�g, mert �gy tudjuk kiel�g�teni a standard k�nyvt�r szigor� hat�konys�gi


k�vetelm�-
nyeit, mind fut�si ido, mind t�rhaszn�lat szempontj�b�l. Egy lista
mem�riafoglal�ja p�ld�-
ul nem foglal jelentosen t�bb mem�ri�t a sz�ks�gesn�l, de ha minden listaelemn�l
jelentkezne
egy kis .felesleg., akkor ez jelentos vesztes�get okozna.
Gondoljuk v�gig, hogyan haszn�lhatn�nk a mem�riafoglal�kat akkor, ha a standard
k�nyvt
�r hat�konys�gi k�vetelm�nyeitol eltekinten�nk. Ez a helyzet olyan nem szabv�nyos
k�nyvt�r eset�ben fordulhat elo, melyben nem volt fontos tervez�si szempont a nagy
hat�-
konys�g az adatszerkezetek �s t�pusok l�trehoz�sakor, vagy ak�r a standard
k�nyvt�r bizonyos
egyedi c�l� megval�s�t�saiban. Ilyenkor a mem�riafoglal� felhaszn�lhat� olyan
jelleg
u inform�ci�k t�rol�s�ra is, melyek �ltal�ban �ltal�nos b�zisoszt�lyokban kapnak
helyet
(�16.2.2). K�sz�thet�nk p�ld�ul olyan mem�riafoglal�kat, melyek v�laszt tudnak
adni arra
a k�rd�sre, hogy az objektumok hol kaptak helyet, k�n�lhatnak olyan inform�ci�kat,
melyek
az objektumok elrendez�s�re vonatkoznak, vagy megk�rdezhetj�k tol�k, hogy egy
adott elem benne van-e a t�rol�ban. Seg�ts�g�kkel elk�sz�theto egy olyan
t�rol�fel�gyelo
is, amely gyors�t�t�rk�nt szolg�l a h�tt�rt�rhoz vagy kapcsolatokat biztos�t a
t�rol� �s m�s
objektumok k�z�tt �s �gy tov�bb.
Ezzel a m�dszerrel teh�t tetszoleges szolg�ltat�sokat biztos�thatunk a szok�sos
t�rol�muveletek h�tter�ben. Ennek ellen�re �rdemes k�l�nbs�get tenn�nk az adatok
t�ro-
19. Bej�r�k �s mem�riafoglal�k 767
l�s�nak �s az adatok felhaszn�l�s�nak feladatai k�z�tt. Ez ut�bbi nem tartozik egy
�ltal�nos
�tott mem�riafoglal� hat�sk�r�be, �gy ink�bb egy k�l�n sablonparam�ter
seg�ts�g�vel illik
megval�s�tanunk.
19.4.4. Elok�sz�tetlen mem�ria
A szabv�nyos allocator mellett a <memory> fej�llom�nyban tal�lhatunk n�h�ny olyan
f�ggv
�nyt is, melyek az elok�sz�tetlen (�rt�kkel nem felt�lt�tt) mem�ria probl�m�ival
foglalkoznak.
Azt a vesz�lyes, de gyakran nagyon fontos lehetos�get biztos�tj�k, hogy a T t�pusn
�vvel hivatkozhatunk egy olyan mem�riater�letre, amely el�g nagy egy T t�pus�
objektum
t�rol�s�ra, de nem teljesen szab�lyosan l�trehozott T objektumot tartalmaz.
A k�nyvt�rban h�rom f�ggv�nyt tal�lunk, mellyel elok�sz�tetlen ter�letre �rt�keket

m�solhatunk:
template <class In, class For>
For uninitialized_copy(In first, In last, For res) // m�sol�s res-be
{
typedef typename iterator_traits<For>::value_type V;
while (first != last)
new (static_cast<void*>(&*res++)) V(*first++); // l�trehoz�s res-ben (�10.4.11)
return res;
}
template <class For, class T>
void uninitialized_fill(For first, For last, const T& val) //m�sol�s [first,last)-
ba
{
typedef typename iterator_traits<For>::value_type V;
while (first != last) new (static_cast<void*>(&*first++)) V(val); // l�trehoz�s
first-ben
}
template <class For, class Size, class T>
void uninitialized_fill_n(For first, Size n, const T& val) //m�sol�s
[first,first+n)-be
{
typedef typename iterator_traits<For>::value_type V;
while (n--) new (static_cast<void*>(&*first++)) V(val); // l�trehoz�s first-ben
}
Ezek a f�ggv�nyek elsosorban t�rol�k �s algoritmusok k�sz�t�s�n�l hasznosak. A
reserve()
�s a resize() (�16.3.8) p�ld�ul legk�nnyebben ezen f�ggv�nyek felhaszn�l�s�val
val�s�tha-
768 A standard k�nyvt�r
t� meg (�19.6[10]). Igen nagy probl�ma, ha egy ilyen kezdo�rt�kkel nem rendelkezo
objektum
valahogy kiszabadul a t�rol� belso megval�s�t�s�b�l �s �tlagos felhaszn�l�k kez�be

ker�l (l�sd m�g �E.4.4).


Az algoritmusoknak gyakran van sz�ks�g�k ideiglenes t�rter�letre feladataik helyes
v�grehajt
�s�hoz. Ezeket a ter�leteket gyakran �rdemes egyetlen muvelettel lefoglalni, annak
ellen
�re, hogy �rt�kkel felt�lteni csak akkor fogjuk azokat, amikor t�nylegesen sz�ks�g
lesz
r�juk. Ez�rt a k�nyvt�r tartalmaz egy f�ggv�nyp�rt, mellyel elok�sz�tetlen
mem�riater�letet
foglalhatunk le, illetve szabad�thatunk fel:
template <class T> pair<T*,ptrdiff_t> get_temporary_buffer(ptrdiff_t); //
lefoglal�s
// kezdeti �rt�kad�s
// n�lk�l
template <class T> void return_temporary_buffer(T*); // felszabad�t�s
// megsemmis�t�s
// n�lk�l
A get_temporary_buffer<X>(n) muvelet megpr�b�l helyet foglalni n vagy t�bb X
t�pus� objektum
sz�m�ra. Ha ez siker�l, akkor az elso kezdo�rt�k n�lk�li objektumra hivatkoz�
mutat
�t �s a lefoglalt ter�leten elf�ro, X t�pus� objektumok sz�m�t adja vissza. Ha
nincs el�g mem
�ria, a visszaadott p�r m�sodik (second) tagja nulla lesz. Az �tlet az, hogy a
rendszer a gyors
helyfoglal�s �rdek�ben r�gz�tett m�retu �tmeneti t�rat tart k�szenl�tben. Ennek
k�vetkezt�-
ben elofordulhat, hogy n objektum sz�m�ra ig�nyl�nk ter�letet, de az �tmeneti
t�rban enn�l
t�bb is elf�r. A gond az, hogy az is elk�pzelheto, hogy kevesebb ter�letet kapunk
az ig�nyeltn
�l, �gy a get_temporary_buffer() felhaszn�l�si m�dja az, hogy kelloen nagy t�rat
ig�nyl�nk,
azt�n ebbol annyit haszn�lunk fel, amennyit megkaptunk. A get_temporary_buffer()
�ltal lefoglalt
ter�letet fel kell szabad�tanunk a return_temporary_buffer() f�ggv�ny
seg�ts�g�vel.
Ugyan�gy, ahogy a get_temporary_buffer() a konstruktor megh�v�sa n�lk�l foglal le
ter�letet,
a return_temporary_buffer() a destruktor megh�v�sa n�lk�l szabad�t fel. Mivel
a get_temporary_buffer() alacsonyszintu muvelet �s kifejezetten ideiglenes t�rak
lefoglal�s�-
ra szolg�l, nem haszn�lhatjuk a new vagy az allocator::allocate() helyett,
hosszabb �letu objektumok
l�trehoz�s�ra.
Azok a szabv�nyos algoritmusok, melyek egy sorozatba �rnak, felt�telezik, hogy a
sorozat
elemei kor�bban m�r kaptak kezdo�rt�ket. Teh�t az algoritmusok az �r�shoz egyszeru

�rt�kad�st haszn�lnak �s nem m�sol� konstruktort. Ennek k�vetkezt�ben viszont nem


haszn�lhatunk elok�sz�tetlen ter�letet egy algoritmus kimenete c�lj�ra. Ez sokszor
igen kellemetlen,
mert az egyszeru �rt�kad�s j�val .k�lts�gesebb., mint a kezdeti, r�ad�sul nem is
�rdekel minket, milyen �rt�keket fogunk fel�l�rni (ha �rdekelne, nem �rn�nk
fel�l). A megold
�st a raw_storage_iterator jelenti, amely szint�n a <memory> fej�llom�nyban
tal�lhat�
�s egyszeru helyett kezdeti �rt�kad�st v�gez:
19. Bej�r�k �s mem�riafoglal�k 769
template <class Out, class T>
class raw_storage_iterator : public
iterator<output_iterator_tag,void,void,void,void> {
Out p;
public:
explicit raw_storage_iterator(Out pp) : p(pp) { }
raw_storage_iterator& operator*() { return *this; }
raw_storage_iterator& operator=(const T& val) {
T* pp = &*p;
new(pp) T(val); // val pp-be helyez�se (�10.4.11)
return *this;
}
raw_storage_iterator& operator++() {++p; return *this; }
raw_storage_iterator operator++(int) {
raw_storage_iterator t = *this;
++p;
return t;
}
};
P�ld�ul k�sz�thet�nk egy sablon f�ggv�nyt, amely egy vector elemeit egy �tmeneti
t�rba
m�solja:
template<class T, class A> T* temporary_dup(vector<T,A>& v)
{
pair<T*,ptrdiff_t> p = get_temporary_buffer<T>(v.size());
if (p.second < v.size()) { // ellenorizz�k, hogy el�g volt-e az el�rheto mem�ria
if (p.first != 0) return_temporary_buffer(p.first);
return 0;
}
copy(v.begin(),v.end(),raw_storage_iterator<T*,T>(p.first));
return p.first;
}
Ha a get_temporary_buffer() helyett a new oper�tort haszn�ltuk volna, az �tmeneti
t�r kezdeti
felt�lt�s�re sor ker�lt volna. Mivel kiker�lt�k az elok�sz�t�st, a
raw_storage_iterator
oszt�lyra van sz�ks�g�nk a nem felt�lt�tt ter�let kezel�s�hez. Ebben a p�ld�ban
a temporary_dump() f�ggv�ny megh�v�j�nak feladata marad, hogy megh�vja
a return_temporary_buffer() elj�r�st a visszaadott mutat�ra.
770 A standard k�nyvt�r
19.4.5. Dinamikus mem�ria
A <new> fej�llom�nyban olyan lehetos�gek szerepelnek, melyekkel a new �s delete
oper�-
tort val�s�thatjuk meg:
class bad_alloc : public exception { /* ... */ };
struct nothrow_t {};
extern const nothrow_t nothrow; // kiv�telt ki nem v�lt� mem�riafoglal�
typedef void (*new_handler)();
new_handler set_new_handler(new_handler new_p) throw();
void* operator new(size_t) throw(bad_alloc);
void operator delete(void*) throw();
void* operator new(size_t, const nothrow_t&) throw();
void operator delete(void*, const nothrow_t&) throw();
void* operator new[ ](size_t) throw(bad_alloc);
void operator delete[ ](void*) throw();
void* operator new[ ](size_t, const nothrow_t&) throw();
void operator delete[ ](void*, const nothrow_t&) throw();
void* operator new (size_t, void* p) throw() { return p; } // elhelyez�s
(�10.4.11)
void operator delete (void* p, void*) throw() { } //nem csin�l semmit
void* operator new[ ](size_t, void* p) throw() { return p; }
void operator delete[ ](void* p, void*) throw() { } //nem csin�l semmit
Egy �res kiv�tel-specifik�ci�val (�14.6) defini�lt operator new() vagy operator
new[ ]() nem
jelezheti a mem�ria elfogy�s�t az std::bad_alloc kiv�tel kiv�lt�s�val. Ehelyett,
ha sikertelen
a helyfoglal�s, 0 �rt�ket adnak vissza. A new kifejez�s (�6.2.6.2) az �res
kiv�tel-specifik
�ci�val rendelkezo mem�riafoglal�k �ltal visszaadott �rt�ket mindig ellenorzi, �s
ha 0 �rt
�ket kap, nem h�vja meg a konstruktort, hanem azonnal szint�n 0 �rt�ket ad vissza.

A nothrow mem�riafoglal�k p�ld�ul 0 �rt�ket adnak vissza a sikertelen helyfoglal�s


jelz�-
s�re, �s nem egy bad_alloc kiv�telt v�ltanak ki:
void f()
{
int* p = new int[100000]; // bad_alloc-ot v�lthat ki
if (int* q = new(nothrow) int[100000]) { // nem v�lt ki kiv�telt
// lefoglal�s sikeres
}
19. Bej�r�k �s mem�riafoglal�k 771
else {
// lefoglal�s sikertelen
}
}
Ez a m�dszer lehetov� teszi, hogy kiv�tel elotti hibakezel�st haszn�ljunk a
helyfoglal�s sor�n.
19.4.6. C st�lus� helyfoglal�s
A C++ a C-tol �r�k�lt egy dinamikusmem�ria-kezelo fel�letet, melyet a <cstdlib>
fej�llom
�nyban tal�lhatunk meg:
void* malloc(size_t s); // s b�jt lefoglal�sa
void* calloc(size_t n, size_t s); // n-szer s b�jt felt�lt�se 0 kezdo�rt�kkel
void free(void* p); // a malloc() vagy calloc() �ltal lefoglalt szabad ter�let
felszabad�t�sa
void* realloc(void* p, size_t s); // a p �ltal mutatott t�mb m�ret�nek m�dos�t�sa
s-re;
Ezen f�ggv�nyek helyett haszn�ljuk ink�bb a new vagy a delete oper�tort, vagy a
szabv�-
nyos t�rol�k m�g magasabb szintu szolg�ltat�sait. A fenti elj�r�sok elok�sz�tetlen
mem�ri-
�val foglalkoznak, �gy a free() p�ld�ul nem h�v meg semmilyen destruktort a
mem�riater�-
let felszabad�t�s�ra. A new �s a delete megval�s�t�sai haszn�lhatj�k ezeket a
f�ggv�nyeket,
de sz�mukra sem k�telezo. Ha egy objektumot p�ld�ul a new oper�torral hozunk
l�tre,
majd a free() f�ggv�nnyel pr�b�lunk meg megsemmis�teni, s�lyos probl�m�kba
�tk�zhet
�nk. Ha a realloc() f�ggv�ny szolg�ltat�saira lenne sz�ks�g�nk, haszn�ljunk ink�bb
szabv
�nyos t�rol�kat, melyek az ilyen jellegu feladatokat �ltal�ban sokkal egyszerubben
�s legal
�bb olyan hat�konyan hajtj�k v�gre (�16.3.5).
A k�nyvt�r tartalmaz n�h�ny olyan f�ggv�nyt is, melyekkel hat�konyan v�gezhet�nk
b�jtszint
u muveleteket. Mivel a C a t�pus n�lk�li b�jtokat eredetileg char* mutat�kon
kereszt�l
�rte el, ezek a f�ggv�nyek a <cstring> fej�llom�nyban tal�lhat�k. Ezekben a
f�ggv�nyekben
a void* mutat�kat char* mutat�kk�nt kezelj�k:
void* memcpy(void* p, const void* q, size_t n); // nem �tfedo ter�letek m�sol�sa
void* memmove(void* p, const void* q, size_t n); // esetleg �tfedo ter�letek
m�sol�sa
A strcpy() (�20.4.1) f�ggv�nyhez hasonl�an ezek a muveletek is n darab b�jtot
m�solnak
a q c�mrol a p c�mre, majd a p mutat�t adj�k vissza. A memove() �ltal kezelt
mem�riater�-
letek �tfedhetik egym�st, de a memcpy() felt�telezi, hogy a k�t ter�let teljesen
k�l�n�ll�, �s
�ltal�ban ki is haszn�lja ezt a felt�telez�st.
772 A standard k�nyvt�r
Hasonl�an muk�dnek az al�bbi f�ggv�nyek is:
void* memchr(const void* p, int b, size_t n); // mint a strchr() (�20.4.1):
// b keres�se p[0]..p[n-1]-ben
int memcmp(const void* p, const void* q, size_t n); // mint a strcmp():
b�jtsorozatok
// �sszehasonl�t�sa
void* memset(void* p, int b, size_t n); // n b�jt b-re �ll�t�sa, p
// visszaad�sa
Sz�mos C++-v�ltozatban ezeknek az elj�r�soknak erosen optimaliz�lt v�ltozatai is
megtal�lhat�k.
19.5. Tan�csok
[1] Amikor egy algoritmust meg�runk, d�nts�k el, milyen bej�r�ra van sz�ks�g�nk
az elj�r�s kelloen hat�kony megval�s�t�s�hoz, majd folyamatosan figyelj�nk,
hogy csak olyan muveleteket haszn�ljunk, melyek az adott bej�r�-kateg�ria
eset�ben rendelkez�s�nkre �llnak. �19.2.1
[2] Az algoritmusok hat�konyabb megval�s�t�s�ra haszn�ljunk t�lterhel�st, ha a
param
�terk�nt megadott bej�r� a minim�lis k�vetelm�nyn�l t�bb szolg�ltat�st
ny�jt. �19.2.3.
[3] A k�l�nb�zo bej�r�-kateg�ri�kra haszn�lhat� algoritmusok meg�r�s�hoz haszn
�ljuk az iterator_traits oszt�lyokat. �19.2.2.
[4] Ne felejts�k el haszn�lni a ++ oper�tort az istream_iterator �s az
ostream_iterator objektumok eset�ben sem. �19.2.6.
[5] A t�rol�k t�lcsordul�s�nak elker�l�se �rdek�ben haszn�ljunk besz�r� (inserter)

bej�r�kat. �19.2.4.
[6] Tesztel�s alatt v�gezz�nk min�l t�bb ellenorz�st, �s a v�gleges v�ltozatb�l is

csak azokat t�vol�tsuk el, melyeket felt�tlen�l sz�ks�ges. �19.3.1.


[7] Ha tehetj�k, haszn�ljuk a ++p form�t a p++ helyett. �19.3.
[8] Az adatszerkezeteket bov�to algoritmusok hat�konys�g�t n�velhetj�k, ha elok�-
sz�tetlen mem�riater�leteket haszn�lunk. �19.4.4.
[9] Ha egy algoritmus ideiglenes adatszerkezeteket haszn�l, a hat�konys�got
ideiglenes
t�r (puffer) haszn�lat�val n�velhetj�k. �19.4.4.
[10] K�tszer is gondoljuk meg, mielott saj�t mem�riafoglal� �r�s�ba kezd�nk.
�19.4.
[11] Ker�lj�k a malloc(), a free(), a realloc() stb. f�ggv�nyek haszn�lat�t.
�19.4.6.
[12] A sablonok typedef-jeinek haszn�lat�t a rebind f�ggv�nyn�l bemutatott m�dszer

seg�ts�g�vel ut�nozhatjuk. �19.4.1.


19. Bej�r�k �s mem�riafoglal�k 773
19.6. Gyakorlatok
1. (*1.5) K�sz�ts�k el a �18.6.7. reverse() f�ggv�ny�t. Seg�ts�g: �19.2.3.
2. (*1.5) K�sz�ts�nk egy kimeneti bej�r�t, amely val�j�ban sehova sem �r. Mikor
lehet �rtelme egy ilyen bej�r�nak?
3. (*2) �rjuk meg a reverse_iterator oszt�lyt (�19.2.5).
4. (*1.5) K�sz�ts�k el az ostream_iterator oszt�lyt (�19.2.6).
5. (*2) K�sz�ts�k el az istream_iterator oszt�lyt (�19.2.6).
6. (*2.5) Fejezz�k be a Checked_iter oszt�lyt (�19.3).
7. (*2.5) Alak�tsuk �t a Checked_iter oszt�lyt �gy, hogy ellenorizze az
�rv�nytelenn
� v�lt bej�r�kat is.
8. (*2) Tervezz�nk meg �s k�sz�ts�nk el egy olyan kezelooszt�lyt, amely egy t�rol
�t k�pes helyettes�teni �gy, hogy annak teljes fel�let�t biztos�tja. Az
�br�zol�sban
t�rolnunk kell egy mutat�t egy t�rol�ra, valamint meg kell �rnunk a t�rol�
muveleteit tartom�nyellenorz�ssel.
9. (*2.5) Fejezz�k be vagy �rjuk �jra a Pool_alloc (�19.4.2) oszt�lyt �gy, hogy az

a standard k�nyvt�r allocator (�19.4.1) oszt�ly�nak minden lehetos�g�t t�mogassa.


Hasonl�tsuk �ssze az allocator �s a Pool_alloc hat�konys�g�t, �s �llap�tsuk
meg, hogy saj�t rendszer�nkben sz�ks�g van-e a Pool_alloc haszn�lat�ra.
10. (*2.5) K�sz�ts�nk el egy vector oszt�lyt �gy, hogy mem�riafoglal�kat haszn�-
lunk a new �s a delete oper�tor helyett.
774 A standard k�nyvt�r
Karakterl�ncok
.J�rt utat a j�ratlan�rt el ne hagyj!.
Karakterl�ncok . Karakterek . char_traits . basic_string . Bej�r�k . Elemek
el�r�se .
Konstruktorok . Hibakezel�s . �rt�kad�s . Koverzi� . �sszehasonl�t�s . Besz�r�s
. �sszefuz�s . Keres�s �s csere . M�ret �s kapacit�s . Karakterl�ncok ki- �s
bevitele
. C st�lus� karakterl�ncok . Karakterek oszt�lyoz�sa . A C k�nyvt�r f�ggv�nyei .
Tan�-
csok . Gyakorlatok
20.1. Bevezet�s
A karakterl�nc (string) karakterek sorozata. A standard k�nyvt�r string oszt�lya
mindazokat
az elj�r�sokat el�rhetov� teszi, amelyekre a karakterl�ncokkal kapcsolatban
sz�ks�g�nk lehet:
indexel�s (�20.3.3), �rt�kad�s (�20.3.6), �sszehasonl�t�s (�20.3.8), hozz�fuz�s
(�20.3.9),
�sszefuz�s (�20.3.10), r�szl�ncok keres�se (�20.3.11). Nincs viszont �ltal�nos
r�szl�nc-kezel
o, ez�rt . a szabv�nyos string haszn�lat�t is bemutatand� . k�sz�t�nk majd egyet
(�20.3.11). Egy szabv�nyos karakterl�nc szinte b�rmilyen karakterek sorozata lehet
(�20.2).
20
A tapasztalatok azt mutatj�k, hogy nem lehet t�k�letes string t�pust
megval�s�tani. Ehhez az
emberek �zl�se, elv�r�saik, ig�nyeik t�l nagy m�rt�kben k�l�nb�znek. �gy a
standard
k�nyvt�r string oszt�lya sem t�k�letes. Bizonyos tervez�si k�rd�sekben m�shogy is
d�nthettem
volna az oszt�ly l�trehoz�sakor. Ennek ellen�re azt hiszem, sok elv�r�st kiel�g�t
�s
k�nnyen elk�sz�thetok azok a kieg�sz�to f�ggv�nyek, melyekkel a tov�bbi feladatok
megoldhat
�k. Nagy elonyt jelent az is, hogy az std::string oszt�ly �ltal�nosan ismert �s
mindenhol
el�rheto. Ezek a jellemzok a legt�bb esetben fontosabbak, mint azok tulajdons�gok,

amelyekkel az oszt�lyt esetleg m�g kieg�sz�thetn�nk. A k�l�nb�zo karakterl�nc-


oszt�lyok
elk�sz�t�se gyakorl�snak nagyszeru (�11.12, �13.2), de ha sz�les k�rben
haszn�lhat� v�ltozatot
akarunk, akkor a standard k�nyvt�r string oszt�ly�ra lesz sz�ks�g�nk.
A C++ a C-tol �r�k�lt, null�val lez�rt karaktert�mbk�nt �rtelmezett karakterl�ncok
(vagyis
a C st�lus� karakterl�ncok) kezel�s�re a standard k�nyvt�rban sz�mos k�l�n
f�ggv�nyt biztos
�t (�20.4.1).
20.2. Karakterek
A .karakter. (character) m�r �nmag�ban is �rdekes fogalom. Figyelj�k meg p�ld�ul a
C karaktert.
Ezt a C betut, amely val�j�ban egy egyszeru f�lk�r�v a pap�ron (vagy a k�pernyon),

h�napokkal ezelott g�peltem be a sz�m�t�g�pembe. Ott egy 8 bites b�jtban a 67


sz�m�rt
�kk�nt t�rol�dott. Elmondhatjuk r�la, hogy a latin �b�c� harmadik betuje, a
hatodik atom
(a sz�n, carbon) szok�sos r�vid�t�se �s mellesleg egy programoz�si nyelv neve is
(�1.6).
A karakterl�ncok programokban val� felhaszn�l�sakor csak az sz�m�t, hogy e
kacskaring�s
alakzathoz kapcsol�dik egy hagyom�nyos jelent�s, amit karakternek nevez�nk, �s egy

sz�m�rt�k, amit a sz�m�t�g�p haszn�l. Hogy bonyol�tsuk a dolgokat, ugyanahhoz a


karakterhez
a k�l�nb�zo karakterk�szletekben m�s-m�s sz�m�rt�k tartozhat, sot, nem is minden
karakterk�szletben tal�lunk sz�m�rt�ket minden karakterhez, r�ad�sul sok k�l�nb�zo
karakterk
�szletet haszn�lunk rendszeresen. A karakterk�szlet nem m�s, mint a karakterek
(a hagyom�nyos szimb�lumok) egy lek�pez�se eg�sz �rt�kekre.
A C++ programoz�k �ltal�ban felt�telezik, hogy a szabv�nyos amerikai
karakterk�szlet
(ASCII) rendelkez�s�nkre �ll, de a C++ felk�sz�lt arra az esetre is, ha bizonyos
karakterek
hi�nyozn�nak a programoz�si k�rnyezetbol. P�ld�ul ha olyan karakterek hi�nyoznak,
mint
a [ vagy a {, haszn�lhatunk helyett�k kulcsszavakat vagy digr�f . k�t tagb�l
�ll� . jeleket
(�C.3.1).
776 A standard k�nyvt�r
Nagy kih�v�st jelentenek azok a karakterk�szletek is, melyekben olyan karakterek
szerepelnek,
amelyek az ASCII-ban nem fordulnak elo. Az olyan nyelvek karakterei, mint a k�nai,

a d�n, a francia, az izlandi vagy a jap�n, nem �rhat�k le hib�tlanul az ASCII


karakterk�szlet
seg�ts�g�vel. M�g nagyobb probl�ma, hogy az e nyelvekhez haszn�lt
karakterk�szletek is
k�l�nb�znek. A latin �b�c�t haszn�l� eur�pai nyelvek karakterei p�ld�ul majdnem
elf�rnek
egy 256 karakteres karakterk�szletben, de sajnos a k�l�nb�zo nyelvekhez k�l�nb�zo
k�szleteket haszn�lunk �s ezekben n�ha k�l�nb�zo karaktereknek ugyanaz az eg�sz
�rt�k
jutott. A francia karakterk�szlet (amely Latin1-et haszn�l) p�ld�ul nem teljesen
egyeztethet
o �ssze az izlandi karakterekkel (�gy azok haszn�lat�hoz a Latin2 k�szletre van
sz�ks�-
g�nk). Azok a nagyrat�ro k�s�rletek, melyek sor�n megpr�b�ltak minden, emberek
�ltal
ismert karaktert egyetlen karakterk�szletben felsorolni, sok probl�m�t
megoldottak, de
m�g a 16 bites k�szletek (p�ld�ul a Unicode) sem el�g�tettek ki minden ig�nyt. A
32 bites
karakterk�szletek, melyek . ismereteim szerint . az �sszes karakter megjel�l�s�re
alkalmasak
lenn�nek, m�g nem terjedtek el sz�les k�rben.
A C++ alapvetoen azt a megk�zel�t�st k�veti, hogy a programoz�nak megengedj�k
b�rmelyik
karakterk�szlet haszn�lat�t a karakterl�ncok karaktert�pus�nak megad�s�hoz.
Haszn�lhatunk
bov�tett karakterk�szleteket �s m�s rendszerre �t�ltetheto sz�mk�dol�st is
(�C.3.3)
20.2.1. Karakterjellemzok
A �13.2 pontban m�r bemutattuk, hogy egy karakterl�nc elm�letileg tetszoleges
t�pust k�-
pes .karakterk�nt. haszn�lni, ha az megfelelo m�sol�si muveleteket biztos�t. Csak
azokat
a t�pusokat tudjuk azonban igaz�n hat�konyan �s egyszeruen kiakn�zni, melyeknek
nincs
felhaszn�l�i m�sol� muvelete. Ez�rt a szabv�nyos string oszt�ly megk�veteli, hogy
a benne
karakterk�nt haszn�lt t�pusnak ne legyen felhaszn�l�i m�sol� muvelete. Ez azt is
lehet
ov� teszi, hogy a karakterl�ncok ki- �s bevitele egyszeru �s hat�kony legyen.
Egy karaktert�pus jellemzoit (traits) a hozz� tartoz� char_traits oszt�ly �rja le,
amely az
al�bbi sablon specializ�ci�ja:
template<class Ch> struct char_traits { };
Minden char_traits az std n�vt�rben szerepel �s a szabv�nyos v�ltozatok a <string>
fej�llom
�nyb�l �rhetok el. Az �ltal�nos char_traits oszt�ly egyetlen jellemzot sem
tartalmaz,
azokkal csak az egyes karaktert�pusokhoz k�sz�tett v�ltozatok rendelkeznek.
A char_traits<char> defin�ci�ja p�ld�ul a k�vetkezo:
20. Karakterl�ncok 777
template<> struct char_traits<char> { // a char_traits muveleteknek nem szabad
// kiv�telt kiv�ltaniuk
typedef char char_type; // a karakter t�pusa
static void assign(char_type&, const char_type&); // az = meghat�roz�sa a
// char_type sz�m�ra
// a karakterek eg�sz �rt�ku �br�zol�sa
typedef int int_type; // a karakter-�rt�kek eg�sz t�pusa
static char_type to_char_type(const int_type&); // �talak�t�s int-rol char-ra
static int_type to_int_type(const char_type&); // �talak�t�s char-r�l int-re
static bool eq_int_type(const int_type&, const int_type&); // ==
// char_type �sszehasonl�t�sok
static bool eq(const char_type&, const char_type&); // ==
static bool lt(const char_type&, const char_type&); // <
// muveletek s[n] t�mb�n
static char_type* move(char_type* s, const char_type* s2, size_t n);
static char_type* copy(char_type* s, const char_type* s2, size_t n);
static char_type* assign(char_type* s, size_t n, char_type a);
static int compare(const char_type* s, const char_type* s2, size_t n);
static size_t length(const char_type*);
static const char_type* find(const char_type* s, int n, const char_type&);
// bemeneti/kimeneti muveletek
typedef streamoff off_type; // eltol�s az adatfolyamban
typedef streampos pos_type; // poz�ci� az adatfolyamban
typedef mbstate_t state_type; // t�bb b�jtos adatfolyam �llapota
static int_type eof(); // f�jl v�ge
static int_type not_eof(const int_type& i); // i, hacsak i �rt�ke nem eof();
static state_type get_state(pos_type p); // p poz�ci�n levo karakter
// �llapota a t�bb b�jtos �talak�t�s sor�n
};
A szabv�nyos karakterl�nc-sablon, a basic_string (�20.3) megval�s�t�sa e t�pusokon
�s
f�ggv�nyeken alapul. A basic_string-hez haszn�lt karaktert�pusnak rendelkeznie
kell egy
olyan char_traits specializ�ci�val, amely mindezeket t�mogatja.
778 A standard k�nyvt�r
Ahhoz, hogy egy t�pus char_type lehessen, k�pes kell legyen arra, hogy minden
karakterhez
hozz�rendeljen egy eg�sz �rt�ket, melynek t�pusa int_type. Az int_type �s a
char_type
t�pus k�z�tti �talak�t�st a to_char_type() �s a to_int_type() f�ggv�ny hajtja
v�gre. A char t�-
pus eset�ben ez a �talak�t�s igen egyszeru.
A move(s,s2,n) �s a copy(s,s2,n) f�ggv�nyek egyar�nt az s2 c�mrol m�solnak �t n
karaktert
az s c�mre, �s mindketten az assign(s[i], s2[i]) utas�t�st haszn�lj�k. A k�l�nbs�g
az, hogy
a move() akkor is helyesen muk�dik, ha s2 az [s,s+n[ tartom�nyba esik, a copy()
viszont kicsit
gyorsabb. Ez a muk�d�si elv pontosan megegyezik a C standard k�nyvt�r memcpy(),
illetve memmove() (�19.4.6) f�ggv�nyeinek muk�d�s�vel. Az assign(s,n,x)
f�ggv�nyh�v�s
az x karakter n darab m�solat�t �rja az s c�mre az assign(s[i],x) utas�t�s
seg�ts�g�vel.
A compare() f�ggv�ny a lt(), illetve az eq() elj�r�sokat haszn�lja a karakterek
�sszehasonl
�t�s�hoz. Visszat�r�si �rt�ke egy int, amely 0, ha a k�t karakterl�nc pontosan
megegyezik;
negat�v sz�m, ha az elso param�ter �b�c�sorrendben elobb k�vetkezik, mint a
m�sodik;
ford�tott esetben pozit�v sz�m. A visszat�r�si �rt�k ilyen haszn�lata a C standard
k�nyvt�r
strcmp() f�ggv�ny�nek muk�d�s�t k�veti (�20.4.1).
A ki- �s bemenethez kapcsol�d� f�ggv�nyeket az alacsonyszintu I/O muveletek
haszn�lj�k
(�21.6.4).
A sz�les karakterek (amelyek a wchar_t oszt�ly p�ld�nyai, �4.3) nagyon
hasonl�tanak az
egyszeru char t�pushoz, de ketto vagy m�g t�bb b�jtot haszn�lnak. A wchar_t t�pus
tulajdons
�gait a char_traits<wchar_t> oszt�ly �rja le:
template<> struct char_traits<wchar_t> {
typedef wchar_t char_type;
typedef wint_t int_type;
typedef wstreamoff off_type;
typedef wstreampos pos_type;
// mint a char_traits<char>
};
A wchar_t t�pust elsosorban a 16 bites karakterk�szletek (p�ld�ul a Unicode)
karaktereinek
t�rol�s�hoz haszn�ljuk.
20. Karakterl�ncok 779
20.3. A basic_string oszt�ly
A standard k�nyvt�r karakterl�ncokhoz kapcsol�d� szolg�ltat�sai a basic_string
sablonon
(template) alapulnak, amely hasonl� t�pusokat �s muveleteket biztos�t, mint a
szabv�nyos
t�rol�k (�16.3):
template<class Ch, class Tr = char_traits<Ch>, class A = allocator<Ch> >
class std::basic_string {
public:
// ...
};
A sablon �s a hozz� kapcsol�d� szolg�ltat�sok az std n�vt�rhez tartoznak �s a
<string> fej-
�llom�nyon kereszt�l �rhetok el.
A leggyakoribb karakterl�nc-t�pusok haszn�lat�t k�t typedef k�nny�ti meg:
typedef basic_string<char> string;
typedef basic_string<wchar_t> wstring;
A basic_string sok mindenben hasonl�t a vector (�16.3) oszt�lyra. A legfontosabb
elt�r�s,
hogy a basic_string nem tartalmazza az �sszes elj�r�st, amely a vector oszt�lyban
megtal�lhat
�, helyett�k n�h�ny, jellegzetesen karakterl�ncokra vonatkoz� muveletet (p�ld�ul
r�szl
�nc-keres�st) biztos�t. A string oszt�lyt nem �rdemes egy egyszeru t�mbbel vagy a
vector
t�pussal megval�s�tani; a karakterl�ncok nagyon sok felhaszn�l�si m�dja jobban
biztos�that
� �gy, ha a m�sol�sok mennyis�g�t a leheto legkevesebbre cs�kkentj�k, nem
haszn�lunk
dinamikus adatter�letet a r�vid karakterl�ncokhoz, a hosszabbakn�l egyszeru
m�dos�that
�s�got biztos�tunk �s �gy tov�bb (�20.6[12]). A string oszt�ly f�ggv�nyeinek sz�ma
jelzi
a karakterl�ncok kezel�s�nek fontoss�g�t, �s azt is, hogy bizonyos sz�m�t�g�pek
k�l�nleges
hardverutas�t�sokkal seg�tik ezeket a muveleteket. A k�nyvt�rak k�sz�toi akkor
haszn�lhatj
�k ki legjobban az ilyen f�ggv�nyek elonyeit, ha a standard k�nyvt�rban tal�lnak
hasonl�kat.
A standard k�nyvt�r m�s t�pusaihoz hasonl�an a basic_string<T> is egy konkr�t
t�pus
(�2.5.3, �10.3), virtu�lis f�ggv�nyek n�lk�l. B�tran felhaszn�lhatjuk tagk�nt egy
magasabb
szintu sz�vegfeldolgoz� oszt�lyban, de arra nem val�, hogy m�s oszt�lyok
b�zisoszt�lya legyen
(�25.2.1, l�sd m�g �20.6[10]).
780 A standard k�nyvt�r
20.3.1. T�pusok
A vector oszt�lyhoz hasonl�an a basic_string is t�pusneveken kereszt�l teszi
el�rhetov�
a vele kapcsolatban �ll� t�pusokat:
template<class Ch, class Tr = char_traits<Ch>, class A = allocator<Ch> >
class basic_string {
public:
// t�pusok (mint a vector-n�l, a list-n�l stb., �16.3.1)
typedef Tr traits_type; // a basic_string-re jellemzo
typedef typename Tr::char_type value_type;
typedef A allocator_type;
typedef typename A::size_type size_type;
typedef typename A::difference_type difference_type;
typedef typename A::reference reference;
typedef typename A::const_reference const_reference;
typedef typename A::pointer pointer;
typedef typename A::const_pointer const_pointer;
typedef megval�s�t�s_f�ggo iterator;
typedef megval�s�t�s_f�ggo const_iterator;
typedef std::reverse_iterator<iterator> reverse_iterator;
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
// ...
};
A basic_string az egyszeru basic_string<char> t�pus mellett (melyet string n�ven
ismer�nk)
sz�mos karaktert�pusb�l tud karakterl�ncot k�pezni:
typedef basic_string<unsigned char> Ustring;
struct Jchar { /* ... */ }; // jap�n karaktert�pus
typedef basic_string<Jchar> Jstring;
Az ilyen karakterekbol k�pzett karakterl�ncok ugyan�gy haszn�lhat�k, mint a char
t�puson
alapul�k, csak a karakterek szerepe szabhat hat�rt:
Ustring first_word(const Ustring& us)
{
Ustring::size_type pos = us.find(' '); // �20.3.11
20. Karakterl�ncok 781
return Ustring(us,0,pos); // �20.3.4
}
Jstring first_word(const Jstring& js)
{
Jstring::size_type pos = js.find(' '); // �20.3.11
return Jstring(js,0,pos); // �20.3.4
}
Term�szetesen haszn�lhatunk olyan sablonokat is, melyek karakterl�nc-param�tereket

haszn�lnak:
template<class S> S first_word(const S& s)
{
typename S::size_type pos = s.find(' '); // �20.3.11
return S(s,0,pos); // �20.3.4
}
A basic_string<Ch> b�rmilyen karaktert tartalmazhat, amely szerepel a Ch t�pusban,
teh�t
p�ld�ul a 0 (nulla) karakter is elofordulhat a karakterl�nc belsej�ben. A Ch
.karaktert�pusnak
. �gy kell viselkednie, mint egy karakternek, teh�t nem lehet felhaszn�l�i m�sol�
konstruktora, destruktora, vagy m�sol� �rt�kad�sa.
20.3.2. Bej�r�k
A t�bbi t�rol�hoz hasonl�an a string oszt�ly is biztos�t n�h�ny bej�r�t
(iter�tort), melyekkel
v�gighaladhatunk az elemeken, ak�r a szok�sos, ak�r ford�tott sorrendben:
template<class Ch, class Tr = char_traits<Ch>, class A = allocator<Ch> >
class basic_string {
public:
// ...
// bej�r�k (mint a vector-n�l, a list-n�l stb., �16.3.2)
iterator begin();
const_iterator begin() const;
iterator end();
const_iterator end() const;
reverse_iterator rbegin();
const_reverse_iterator rbegin() const;
reverse_iterator rend();
const_reverse_iterator rend() const;
// ...
};
782 A standard k�nyvt�r
Mivel a string oszt�lyban megtal�lhat�k a bej�r�k kezel�s�hez sz�ks�ges tagt�pusok
�s
-f�ggv�nyek, a szabv�nyos algoritmusok (18. fejezet) string objektumokra is
haszn�lhat�k:
void f(string& s)
{
string::iterator p = find(s.begin(),s.end(),'a');
// ...
}
A karakterl�ncokra leggyakrabban alkalmazott muveleteket k�zvetlen�l a string
oszt�lyban
tal�lhatjuk meg. Rem�lhetoleg ezeket a muveleteket kifejezetten a
karakterl�ncokhoz igaz
�tott�k, �gy jobbak, mint az �ltal�nos algoritmusok.
A szabv�nyos algoritmusok (18. fejezet) a karakterl�ncok eset�ben nem annyira
hasznosak,
mint elso r�n�z�sre gondoln�nk. Az �ltal�nos muveletek azt felt�telezik, hogy a
t�rol�k elemei
�nmagukban is �rtelmes egys�get alkotnak, de a karakterl�ncok eset�ben a teljes
karaktersorozat
hordozza a l�nyeges inform�ci�t. Egy karakterl�nc rendez�se (pontosabban
a karakterl�nc karaktereinek rendez�se) szinte teljesen megsemmis�ti a benne
t�rolt inform
�ci�kat, annak ellen�re, hogy az �ltal�nos t�rol�kban a rendez�s ink�bb m�g
haszn�lhat
�bb� szokta tenni az adatokat.
A string oszt�ly bej�r�i sem ellenorzik, hogy �rv�nyes tartom�nyban �llnak-e.
20.3.3. Az elemek el�r�se
A string-ek karaktereit egyes�vel is el�rhetj�k, indexel�s seg�ts�g�vel:
template<class Ch, class Tr = char_traits<Ch>, class A = allocator<Ch> >
class basic_string {
public:
// ...
// elemek el�r�se (mint a vector-n�l, �16.3.3):
const_reference operator[ ](size_type n) const; // nem ellenorz�tt hozz�f�r�s
reference operator[ ](size_type n);
const_reference at(size_type n) const; // ellenorz�tt hozz�f�r�s
reference at(size_type n);
// ...
};
20. Karakterl�ncok 783
Ha az at() f�ggv�ny haszn�latakor a megengedett tartom�nyon k�v�li index�rt�ket
(sorsz�-
mot) adunk meg, out_of_range kiv�tel v�lt�dik ki.
A vector oszt�lyt�l elt�roen a string nem tartalmazza a front() �s a back()
f�ggv�nyt. Ha
a karakterl�nc elso vagy utols� elem�re akarunk hivatkozni, az s[0] vagy az
s[s.length()-1]
kifejez�st kell haszn�lnunk. A mutat�.t�mb egyen�rt�kus�g (�5.3) a karakterl�ncok
eset�-
ben nem teljes�l: ha s egy string, akkor a &s[0] nem egyezik meg s �rt�k�vel.
20.3.4. Konstruktorok
A kezdeti �rt�kad�shoz, illetve a m�sol�si muveletek elv�gz�s�hez a string m�s
f�ggv�nyeket
k�n�l, mint az egy�b t�rol�k (�16.3.4):
template<class Ch, class Tr = char_traits<Ch>, class A = allocator<Ch> >
class basic_string {
public:
// ...
// konstruktorok stb. (csak nagyj�b�l �gy, mint a vector-n�l �s a list-n�l,
�16.3.4)
explicit basic_string(const A& a = A());
basic_string(const basic_string& s,
size_type pos = 0, size_type n = npos, const A& a = A());
basic_string(const Ch* p, size_type n, const A& a = A());
basic_string(const Ch* p, const A& a = A());
basic_string(size_type n, Ch c, const A& a = A());
template<class In> basic_string(In first, In last, const A& a = A());
~basic_string();
static const size_type npos; // "minden karakter"
// ...
};
Egy string objektumnak C st�lus� karakterl�nccal, m�sik string objektummal, annak
egy
r�sz�vel, vagy karakterek egy sorozat�val adhatunk kezdo�rt�ket, karakterrel vagy
eg�sz
�rt�kkel nem:
void f(char* p,vector<char>&v)
{
string s0; // �res karakterl�nc
string s00 = ""; // ez is �res karakterl�nc
784 A standard k�nyvt�r
string s1 = 'a'; // hiba: nincs konverzi� char-r�l string-re
string s2 = 7; // hiba: nincs konverzi� int-rol string-re
string s3(7); // hiba: a konstruktornak nem lehet egy int param�tere
string s4(7,'a'); // 7 darab 'a', vagyis "aaaaaaa"
string s5 = "Frodo"; // "Frodo" m�solata
string s6 = s5; // s5 m�solata
string s7(s5,3,2); // s5[3] �s s5[4], vagyis "do"
string s8(p+7,3); // p[7], p[8], �s p[9]
string s9(p,7,3); // string(string(p),7,3), val�sz�nuleg "k�lts�ges"
string s10(v.begin(),v.end()); // v minden karakter�nek m�sol�sa
}
A karakterek hely�t null�t�l kezdve indexelj�k, teh�t egy karakterl�nc nem m�s,
mint 0-t�l
length()-1-ig sz�mozott karakterek sorozata.
A length() f�ggv�ny a string eset�ben a size() megfeleloje: mindketto a
karakterl�ncban
szereplo karakterek sz�m�t adja meg. Figyelj�nk r�, hogy ezek nem egy C st�lus�
karakterl
�nc hossz�t �llap�tj�k meg, teh�t nem sz�molj�k a lez�r� nullkaraktert (�20.4.1).
A basic_string oszt�lyt a lez�r� karakter alkalmaz�sa helyett a karakterl�nc
hossz�nak t�rol
�s�val illik megval�s�tani.
A r�szl�ncokat a kezdopoz�ci� �s a karaktersz�m megad�s�val azonos�thatjuk. Az
alap�rtelmezett
npos �rt�ke a leheto legnagyobb sz�m, jelent�se .az �sszes elem..
Nincs olyan konstruktor, amely n darab meghat�rozatlan karakterbol hoz l�tre
karakterl�ncot.
Ehhez legk�zelebb tal�n az a konstruktor �ll, amely egy adott karakter n
p�ld�ny�b�l
�p�t fel egy karakterl�ncot. Az olyan konstruktorok hi�nya, melyeknek egyetlen
karaktert
vagy csak a karakterl�ncban l�vo karakterek sz�m�t adn�nk meg, lehetov� teszi,
hogy a ford
�t� �szrevegyen olyan hibalehetos�geket, amilyeneket az s2 �s az s3 fenti
meghat�roz�sa
rejt mag�ban.
A m�sol� konstruktor egy n�gyparam�teru konstruktor. E param�terek k�z�l h�romnak
alap�rtelmezett �rt�ke van. A hat�konys�g �rdek�ben k�t k�l�n�ll� konstruktork�nt
is elk
�sz�thetj�k; a felhaszn�l� nem lesz k�pes k�l�nbs�get tenni a k�t megold�s k�z�tt,
ha a leford
�tott k�dot meg nem n�zi.
20. Karakterl�ncok 785
A leg�ltal�nosabb konstruktor egy sablon tagf�ggv�nye. Ez lehetov� teszi, hogy a
karakterl
�nc kezdo�rt�k�t tetszoleges sorozatb�l �ll�tsuk elo, p�ld�ul egy m�s
karaktert�pust haszn
�l� karakterl�nc seg�ts�g�vel, amennyiben a karaktert�pusok k�z�tti konverzi�
rendelkez
�s�nkre �ll:
void f(string s)
{
wstring ws(s.begin(),s.end()); // s minden karakter�nek m�sol�sa
// ...
}
A ws karakterl�nc minden wchar_t karakter�nek az s megfelelo char eleme ad
kezdo�rt�ket.
20.3.5. Hib�k
A karakterl�ncokat igen egyszeruen olvashatjuk, �rhatjuk, megjelen�thetj�k,
t�rolhatjuk,
�sszehasonl�thatjuk, lem�solhatjuk stb. Ez �ltal�ban nem okoz probl�m�kat,
legfeljebb
a hat�konys�ggal t�madhatnak gondjaink. Ha azonban elkezd�nk karakterl�ncok egyes
r�szl�ncaival, karaktereivel foglalkozni �s �gy l�tezo karakterl�ncokb�l akarunk
�jakat
�ssze�ll�tani, elobb-ut�bb hib�kat fogunk elk�vetni, melynek k�vetkezt�ben a
karakterl�nc
hat�rain k�v�lre pr�b�lunk meg �rni.
Az egyes karakterek k�zvetlen el�r�s�re szolg�l� at() f�ggv�ny ellenorzi az ilyen
hib�kat
�s out-of_range kiv�telt v�lt ki, ha �rv�nytelen hivatkoz�st adunk meg. A [ ]
oper�tor ilyen
vizsg�latot nem v�gez.
A legt�bb karakterl�nc-muveletnek egy karakterpoz�ci�t �s egy karaktersz�mot kell
megadnunk.
Ha a megadott poz�ci��rt�k nagyobb, mint a karakterl�nc m�rete, azonnal
out_of_range kiv�telt kapunk; ha a karaktersz�m .t�l nagy., �rtelmez�se �ltal�ban
az lesz,
hogy az �sszes h�tral�vo karaktert haszn�lni akarjuk:
void f()
{
string s = "Snobol4";
string s2(s,100,2); // a megadott karakterpoz�ci� a l�nc v�g�n t�l van:
// out_of_range() v�lt�dik ki
string s3(s,2,100); // a karaktersz�m t�l nagy: egyen�rt�ku a s3(s,2,s.size()-2)
// kifejez�ssel
string s4(s,2,string::npos); // az s[2]-tol kezdodo �sszes karakter
}
786 A standard k�nyvt�r
A .t�l nagy. karakterpoz�ci�kat ki kell szurn�nk, de a .t�l nagy. karaktersz�m
hasznos lehet
a programokban. Val�j�ban az npos a leheto legnagyobb size_type t�pus� �rt�k.
�rdemes kipr�b�lnunk, mi t�rt�nik akkor, ha negat�v karakterpoz�ci�t vagy
karaktersz�mot
adunk meg:
void g(string& s)
{
string s5(s,-2,3); // nagy poz�ci��rt�k!: out_of_range()
string s6(s,3,-2); // nagy karaktersz�m!: rendben
}
Mivel a size_type t�pust arra haszn�ljuk, hogy poz�ci�kat vagy darabsz�mokat
adjunk meg,
unsigned t�pusk�nt defini�lt, �gy a negat�v sz�mok haszn�lata csak f�lrevezeto
m�dja a nagy
pozit�v sz�mok megad�s�nak (�16.3.4).
Azok a f�ggv�nyek, amelyek egy string r�szl�nc�t keresik meg (�20.3.11), az npos
�rt�ket
adj�k vissza, ha nem tal�lj�k meg a megfelelo r�szt. Teh�t maguk nem v�ltanak ki
kiv�telt,
de ha ezt az npos �rt�ket karakterpoz�ci�k�nt akarjuk felhaszn�lni a k�vetkezo
muveletben,
akkor m�r kiv�telt kapunk.
Egy r�szl�nc kijel�l�s�nek m�sik m�dja, hogy k�t bej�r�t (iterator) adunk meg. Az
elso hat
�rozza meg a poz�ci�t, m�g a k�t bej�r� k�l�nbs�ge a karaktersz�mot. Szok�s
szerint
a bej�r�k nem ellenorz�ttek.
Ha C st�lus� karakterl�ncokat haszn�lunk, a tartom�nyellenorz�s nehezebb feladat.
Ha param
�terk�nt adunk meg ilyen karakterl�ncot (teh�t egy char-ra hivatkoz� mutat�t),
a basic_string f�ggv�nyei felt�telezik, hogy a mutat� nem 0. Ha egy C st�lus�
karakterl�ncban
poz�ci�t adunk meg, a f�ggv�nyek elv�rj�k, hogy a karakterl�nc el�g hossz� legyen
a poz�ci� �rtelmez�s�hez. Mindig legy�nk nagyon �vatosak, sot kifejezetten
gyanakv�ak.
Az egyetlen kiv�tel, amikor karakterliter�lokat haszn�lunk.
Minden karakterl�nc eset�ben igaz, hogy length()<npos. N�h�ny nagyon egyedi
helyzetben
(igen ritk�n) elofordulhat, hogy egy olyan jellegu muvelet, mint egy karakterl�nc
besz�r�-
sa egy m�sikba, t�l hossz� karakterl�ncot eredm�nyez, amelyet a rendszer m�r nem
k�pes
�br�zolni. Ebben az esetben length_error kiv�tel keletkezik:
string s(string::npos,'a'); // length_error() v�lt�dik ki
20. Karakterl�ncok 787
20.3.6. �rt�kad�s
Term�szetesen a karakterl�ncok eset�ben is rendelkez�s�nkre �ll az (egyszeru)
�rt�kad�s
muvelete:
template<class Ch, class Tr = char_traits<Ch>, class A = allocator<Ch> >
class basic_string {
public:
// ...
// �rt�kad�s (kicsit hasonl�t a vector-ra �s a list-re, �16.3.4):
basic_string& operator=(const basic_string& s);
basic_string& operator=(const Ch* p);
basic_string& operator=(Ch c);
basic_string& assign(const basic_string&);
basic_string& assign(const basic_string& s, size_type pos, size_type n);
basic_string& assign(const Ch* p, size_type n);
basic_string& assign(const Ch* p);
basic_string& assign(size_type n, Ch c);
template<class In> basic_string& assign(In first, In last);
// ...
};
A t�bbi t�rol�hoz hasonl�an a string oszt�lyban is �rt�k szerinti �rtelmez�s
muk�dik, ami
azt jelenti, hogy amikor egy karakterl�ncot �rt�k�l adunk egy m�siknak, akkor az
eredeti
karakterl�ncr�l m�solat k�sz�l, �s az �rt�kad�s ut�n k�t, ugyanolyan tartalm�, de
�n�ll�
(�rt�ku) karakterl�nc �ll majd rendelkez�s�nkre:
void g()
{
string s1 = "Knold";
string s2 = "Tot";
s1 = s2; // "Tot"-b�l k�t p�ld�ny lesz
s2[1] = 'u'; // s2 "Tut", s1 marad "Tot"
}
Annak ellen�re, hogy egyetlen karakterrel nem adhatunk kezdo�rt�ket egy
karakterl�ncnak,
az ilyen m�don t�rt�no egyszeru �rt�kad�s megengedett:
void f()
{
string s = 'a'; // hiba: kezdeti �rt�kad�s char-ral
s = 'a'; // rendben: egyszeru �rt�kad�s
s = "a";
s = s;
}
788 A standard k�nyvt�r
Az a lehetos�g, hogy karakterl�ncnak �rt�k�l adhatunk egy karaktert, nem
t�ls�gosan hasznos,
�s sok hibalehetos�get rejt mag�ban. Gyakran azonban n�lk�l�zhetetlen, hogy egy
karaktert
a += muvelettel hozz�fuzhess�nk egy karakterl�nchoz (�20.3.9), �s igen furcs�n
n�zne
ki, ha az s+='c' utas�t�s v�grehajthat� lenne, m�g az s='c' nem.
Az �rt�kad�shoz az assign() nevet haszn�ljuk, amely a t�bbparam�teru konstruktorok
megfelel
oj�nek tekintheto (�176.3.4, �20.3.4).
A �11.12 pontban m�r eml�tett�k, hogy a string oszt�ly optimaliz�lhat� �gy, hogy
am�g
nincs sz�ks�g egy karakterl�nc k�t p�ld�ny�ra, addig nem hajtjuk v�gre a t�nyleges
m�sol
�st. A szabv�nyos string fel�p�t�se t�mogatja az ilyen takar�kosan m�sol�
megval�s�t�sok
l�trehoz�s�t, mert �gy hat�konyan �rhatunk le csak olvashat� karakterl�ncokat, �s
a karakterl
�ncok �tad�sa f�ggv�nyek param�terek�nt sokkal egyszerubben megval�s�that�, mint
azt elso r�n�z�sre gondoln�nk. Az azonban meggondolatlans�g lenne, ha egy
programoz�
saj�t fejlesztok�rnyezet�nek ellenorz�se n�lk�l olyan programokat �rna, amelyek a
stringek
optimaliz�lt m�sol�s�ra t�maszkodnak (�20.6[13]).
20.3.7. �talak�t�s C st�lus� karakterl�ncra
A �20.3.4 pontban bemutattuk, hogy a string objektumoknak val� kezdeti �s egyszeru

�rt�kad�sra egyar�nt haszn�lhatunk C st�lus� karakterl�ncokat. Ford�tott ir�ny�


muveletek
elv�gz�s�re is van lehetos�g, teh�t egy string karaktereit is elhelyezhetj�k egy
t�mbben:
template<class Ch, class Tr = char_traits<Ch>, class A = allocator<Ch> >
class basic_string {
public:
// ...
// �talak�t�s C st�lus� karakterl�ncc�
const Ch* c_str() const;
const Ch* data() const;
size_type copy(Ch* p, size_type n, size_type pos = 0) const;
// ...
};
A data() f�ggv�ny a string karaktereit egy t�mbbe m�solja, majd visszaad egy erre
a t�mbre
hivatkoz� mutat�t. A t�mb a string objektumhoz tartozik, teh�t a felhaszn�l�nak
nem
szabad t�r�lnie azt �s a string egy nem const f�ggv�ny�nek megh�v�sa ut�n m�r nem
tudhatja,
milyen �rt�k van benne. A c_str() f�ggv�ny szinte pontosan ugyan�gy muk�dik, csak
a karakterl�nc v�g�n elhelyez egy 0 (null) karaktert is, a C st�lus� lez�r�snak
megfeleloen:
20. Karakterl�ncok 789
void f()
{
string s = "equinox"; // s.length()==7
const char* p1 = s.data(); // p1 h�t karakterre mutat
printf("p1 = %s\n",p1); // hiba: hi�nyz� lez�r�
p1[2] = 'a'; // hiba: p1 konstans t�mbre mutat
s[2] = 'a';
char c = p1[1]; // hiba: s.data() el�r�s�nek k�s�rlete s m�dos�t�sa ut�n
const char* p2 = s.c_str(); // p2 nyolc karakterre mutat
printf("p2 = %s\n",p2); // rendben: c_str() hozz�adja a lez�r� karaktert
}
A k�l�nbs�get �gy is megfogalmazhatjuk, hogy a data() a karakterek egy t�mbj�t
adja
vissza, m�g a c_str() egy C st�lus� karakterl�ncot �ll�t elo. Ezen f�ggv�nyek
elsodleges feladata,
hogy k�nnyen haszn�lhat�v� tegy�k az olyan f�ggv�nyeket, melyek C st�lus�
karakterl
�ncot v�rnak param�terk�nt. �gy teh�t a c_str() f�ggv�nyt sokkal gyakrabban
haszn�ljuk,
mint a data() elj�r�st:
void f(string s)
{
int i = atoi(s.c_str()); // a karakterl�nc int �rt�k�nek lek�r�se (�20.4.1)
// ...
}
�ltal�ban �rdemes a karaktereket mindaddig egy string objektumban t�rolni, am�g
nincs r�-
juk sz�ks�g�nk, de ha m�gsem tudjuk azonnal feldolgozni, akkor is �rdemes
�tm�solni
azokat a c_str(), illetve a data() �ltal lefoglalt ter�letrol egy k�l�n t�mbbe. A
copy() f�ggv
�ny pontosan erre szolg�l:
char* c_string(const string& s)
{
char* p = new char[s.length()+1]; // megjegyz�s: +1
s.copy(p,string::npos);
p[s.length()] = 0; // megjegyz�s: lez�r� hozz�ad�sa
return p;
}
Az s.copy(p,n,m) f�ggv�ny legfeljebb n karaktert m�sol a p c�mre az s[m]
poz�ci�t�l kezdve.
Ha az s karakterl�ncb�l n-n�l kevesebb karaktert lehet csak �tm�solni, a copy()
egyszer
uen az �sszes karaktert �tm�solja.
790 A standard k�nyvt�r
Figyelj�nk r�, hogy a string objektumokban szerepelhet a 0 karakter. A C st�lus�
karakterl
�ncokat kezelo f�ggv�nyek az elso ilyen karaktert tekintik lez�r�nak. Teh�t mindig
figyelj
�nk, hogy 0 karaktert csak akkor haszn�ljunk, ha C st�lust haszn�l� f�ggv�nyekre
nem lesz
sz�ks�g�nk, vagy a 0-kat pontosan oda tegy�k, ahol a karakterl�ncot le szeretn�nk
z�rni.
A C st�lus� karakterl�ncra val� �talak�t�st a c_str() helyett megoldhattuk volna
egy operator
const char* () muvelettel is, az automatikus konverzi� k�nyelm�nek azonban az
lenne az
�ra, hogy meglepet�s�nkre idonk�nt akkor is v�gbemenne, amikor nem is sz�m�tunk
r�.
Ha �gy �rezz�k, hogy programunkban sokszor lesz sz�ks�g a c_str() f�ggv�nyre,
val�sz�nu-
leg t�ls�gosan ragaszkodunk a C st�lus� fel�lethez. �ltal�ban rendelkez�s�nkre
�llnak azok
az eszk�z�k, melyekkel a C st�lus� karakterl�ncokra vonatkoz� muveletek
k�zvetlen�l
string objektumokon is elv�gezhetok. Ezek haszn�lat�val sok konverzi�t
elker�lhet�nk. Egy
m�sik lehets�ges megold�s az explicit konverzi�k elker�l�s�re az, hogy
t�lterhelj�k azokat
a f�ggv�nyeket, melyek a c_str() haszn�lat�ra k�nyszer�tenek benn�nket:
extern "C" int atoi(const char*);
int atoi(const string& s)
{
return atoi(s.c_str());
}
20.3.8. �sszehasonl�t�s
Karakterl�ncokat azonos t�pus� karakterl�ncokkal vagy olyan karaktert�mb�kkel
hasonl�thatunk
�ssze, melyek szint�n ugyanolyan t�pus� karaktereket tartalmaznak:
template<class Ch, class Tr = char_traits<Ch>, class A = allocator<Ch> >
class basic_string {
public:
// ...
int compare(const basic_string& s) const; // > �s == haszn�lata egy�tt
int compare(const Ch* p) const;
int compare(size_type pos, size_type n, const basic_string& s) const;
int compare(size_type pos, size_type n,
const basic_string& s, size_type pos2, size_type n2) const;
int compare(size_type pos, size_type n, const Ch* p, size_type n2 = npos) const;
// ...
};
20. Karakterl�ncok 791
Ha a compare() megh�v�sakor a poz�ci� �s m�ret param�tereket is megadjuk, csak a
kijel�lt
r�szsorozat vesz r�szt az �sszehasonl�t�sban. P�ld�ul s.compare(pos,n,s2)
egyen�rt�ku
string(s,pos,n).compare(s2)-vel. Az �sszehasonl�t� elj�r�st a char_traits<Ch>
oszt�ly
compare() f�ggv�nye adja (�20.2.1). �gy az s.compare(s2) f�ggv�ny 0 �rt�ket ad
vissza, ha
a karakterl�ncok egyenlo �rt�kuek; negat�v sz�mot kapunk, ha s �b�c�sorrendben s2
elott
�ll; ford�tott esetben pedig pozit�v lesz az eredm�ny.
A felhaszn�l� itt nem adhat meg �gy �sszehasonl�t�si felt�telt, mint a �13.4
pontban. Ha ilyen
szintu rugalmass�gra van sz�ks�g�nk, a lexicographical_compare() (�18.9)
seg�ts�g�vel k�-
sz�ts�nk a fenti r�szben levoh�z hasonl� �sszehasonl�t� f�ggv�nyt. Egy m�sik
lehetos�g,
hogy saj�t ciklust �runk a feladat megold�s�ra. A toupper() f�ggv�ny (�20.4.2)
p�ld�ul lehet
ov� teszi, hogy kis- �s nagybetukkel nem foglalkoz� �sszehasonl�t�st val�s�tsunk
meg:
int cmp_nocase(const string& s, const string& s2)
{
string::const_iterator p = s.begin();
string::const_iterator p2 = s2.begin();
while (p!=s.end() && p2!=s2.end()) {
if (toupper(*p)!=toupper(*p2)) return (toupper(*p)<toupper(*p2)) ? -1 : 1;
++p;
++p2;
}
return (s2.size()==s.size()) ? 0 : (s.size()<s2.size()) ? -1 : 1; // 'size' elojel
n�lk�li
}
void f(const string& s, const string& s2)
{
if (s == s2) { // kis- �s nagybetuket figyelembe vevo �sszehasonl�t�s s �s s2
k�z�tt
// ...
}
if (cmp_nocase(s,s2) == 0) { // kis- �s nagybetuket figyelmen k�v�l hagy�
// �sszehasonl�t�s s �s s2 k�z�tt
// ...
}
// ...
}
A basic_string oszt�lyban rendelkez�s�nkre �llnak a szok�sos �sszehasonl�t�
oper�torok is
(==, !=, <, >, <=, >=):
792 A standard k�nyvt�r
template<class Ch, class Tr, class A>
bool operator==(const basic_string<Ch,Tr,A>&, const basic_string<Ch,Tr,A>&);
template<class Ch, class Tr, class A>
bool operator==(const Ch*, const basic_string<Ch,Tr,A>&);
template<class Ch, class Tr, class A>
bool operator==(const basic_string<Ch,Tr,A>&, const Ch*);
// �s ugyanilyen deklar�ci�k a !=, >, <, >=, �s a <= sz�m�ra
Az �sszehasonl�t� oper�torok nem tag f�ggv�nyek, �gy a konverzi�k mindk�t
operandusra
ugyan�gy vonatkoznak (�11.2.3). A C st�lus� karakterl�ncokat haszn�l� v�ltozatokra
az�rt
volt sz�ks�g, hogy a liter�lokkal val� �sszehasonl�t�st hat�konyabb� tegy�k:
void f(const string& name)
{
if (name =="Obelix" || "Asterix"==name) { // optimaliz�lt == haszn�lata
// ...
}
}
20.3.9. Besz�r�s
Miut�n elo�ll�tottunk egy karakterl�ncot, sokf�le muveletet v�gezhet�nk vele. A
karakterl
�nc �rt�k�t m�dos�t� f�ggv�nyek k�z�l tal�n a legfontosabb a hozz�fuz�s, amely a
karakterl
�nc v�g�n helyez el �j karaktereket. Az �ltal�nos besz�r� muveletekre ritk�bban
van
sz�ks�g:
template<class Ch, class Tr = char_traits<Ch>, class A = allocator<Ch> >
class basic_string {
public:
// ...
// karakterek hozz�ad�sa (*this)[length()-1] ut�n
basic_string& operator+=(const basic_string& s);
basic_string& operator+=(const Ch* p);
basic_string& operator+=(Ch c);
void push_back(Ch c);
basic_string& append(const basic_string& s);
basic_string& append(const basic_string& s, size_type pos, size_type n);
basic_string& append(const Ch* p, size_type n);
20. Karakterl�ncok 793
basic_string& append(const Ch* p);
basic_string& append(size_type n, Ch c);
template<class In> basic_string& append(In first, In last);
// karakterek besz�r�sa (*this)[pos] el�
basic_string& insert(size_type pos, const basic_string& s);
basic_string& insert(size_type pos, const basic_string& s, size_type pos2,
size_type n);
basic_string& insert(size_type pos, const Ch* p, size_type n);
basic_string& insert(size_type pos, const Ch* p);
basic_string& insert(size_type pos, size_type n, Ch c);
// karakterek besz�r�sa p el�
iterator insert(iterator p, Ch c);
void insert(iterator p, size_type n, Ch c);
template<class In> void insert(iterator p, In first, In last);
// ...
};
Nagyj�b�l ugyanazok a f�ggv�nyv�ltozatok �llnak rendelkez�s�nkre a besz�r� �s a
hozz�-
fuzo elj�r�sokn�l is, mint a konstruktorok �s az �rt�kad�s eset�ben.
A += oper�tor hagyom�nyos jel�l�se a hozz�fuz�snek:
string complete_name(const string& first_name, const string& family_name)
{
string s = first_name;
s += ' ';
s += family_name;
return s;
}
A karakterl�nc v�g�hez val� hozz�fuz�s jelentosen hat�konyabb lehet, mint a m�s
poz�ci-
�kra val� besz�r�s:
string complete_name2(const string& first_name, const string& family_name)
// szeg�nyes algoritmus
{
string s = family_name;
s.insert(s.begin(),' ');
s.insert(0,first_name);
return s;
}
794 A standard k�nyvt�r
A besz�r�s gyakran arra k�nyszer�ti a string-et, hogy lass� mem�riamuveleteket
v�gezzen
�s �thelyezzen n�h�ny karaktert.
Mivel a string oszt�lyban is szerepel a push_back() muvelet (�16.3.5), a
back_inserter
ugyan�gy haszn�lhat� string objektumokhoz, mint b�rmely �ltal�nos t�rol�hoz.
20.3.10. �sszefuz�s
A hozz�fuz�s k�l�nleges v�ltozata az �sszefuz�snek (konkaten�ci�nak). Az
�sszefuz�st
. teh�t egy karakterl�nc elo�ll�t�s�t �gy, hogy k�t m�sikat egym�s ut�n
helyez�nk . a +
oper�tor val�s�tja meg:
template<class Ch, class Tr, class A>
basic_string<Ch,Tr,A>
operator+(const basic_string<Ch,Tr,A>&, const basic_string<Ch,Tr,A>&);
template<class Ch, class Tr, class A>
basic_string<Ch,Tr,A> operator+(const Ch*, const basic_string<Ch,Tr,A>&);
template<class Ch, class Tr, class A>
basic_string<Ch,Tr,A> operator+(Ch, const basic_string<Ch,Tr,A>&);
template<class Ch, class Tr, class A>
basic_string<Ch,Tr,A> operator+(const basic_string<Ch,Tr,A>&, const Ch*);
template<class Ch, class Tr, class A>
basic_string<Ch,Tr,A> operator+(const basic_string<Ch,Tr,A>&, Ch);
Szok�s szerint, a + muveletet nem tag f�ggv�nyk�nt adjuk meg. A t�bb param�tert
haszn�-
l� sablonok eset�ben ez n�mi kellemetlens�get okoz, mert a sablonparam�tereket meg
kell
ism�teln�nk.
M�sr�szt az �sszefuz�s haszn�lata egyszeru �s k�nyelmes:
string complete_name3(const string& first_name, const string& family_name)
{
return first_name + ' ' + family_name;
}
Ez a k�nyelem meg�r egy kis fut�si ideju teljes�tm�nyvesztes�get a complete_name()
f�ggv
�nyhez viszony�tva. A complete_name3() f�ggv�nyben k�l�n ideiglenes v�ltoz�ra
(�11.3.2) van sz�ks�g�nk. V�lem�nyem szerint ez ritk�n fontos, de az�rt �rdemes
tudnunk
20. Karakterl�ncok 795
r�la, ha egy nagy ciklust �runk egy olyan programban, ahol figyeln�nk kell a
teljes�tm�nyre.
Ilyenkor esetleg �rdemes megsz�ntetn�nk a f�ggv�nyh�v�st a complete_name() helyben

(inline) kifejt�s�vel, az eredm�nyk�nt kapott karakterl�ncot �gy helyben


�p�thetj�k fel,
alacsonyabb szintu muveletek seg�ts�g�vel (�20.6[14]).
20.3.11. Keres�s
Zavarba ejto mennyis�gben �llnak rendelkez�s�nkre olyan f�ggv�nyek, melyekkel egy
karakterl
�nc r�szl�ncait kereshetj�k meg:
template<class Ch, class Tr = char_traits<Ch>, class A = allocator<Ch> >
class basic_string {
public:
// ...
// r�szsorozat ker�se (mint a search(), �18.5.5)
size_type find(const basic_string& s, size_type i = 0) const;
size_type find(const Ch* p, size_type i, size_type n) const;
size_type find(const Ch* p, size_type i = 0) const;
size_type find(Ch c, size_type i = 0) const;
// r�szsorozat keres�se visszafel� (mint a find_end(), �18.5.5)
size_type rfind(const basic_string& s, size_type i = npos) const;
size_type rfind(const Ch* p, size_type i, size_type n) const;
size_type rfind(const Ch* p, size_type i = npos) const;
size_type rfind(Ch c, size_type i = npos) const;
// karakter keres�se (mint a find_first_of(), �18.5.2)
size_type find_first_of(const basic_string& s, size_type i = 0) const;
size_type find_first_of(const Ch* p, size_type i, size_type n) const;
size_type find_first_of(const Ch* p, size_type i = 0) const;
size_type find_first_of(Ch c, size_type i = 0) const;
// karakter keres�se param�ter alapj�n visszafel�
size_type find_last_of(const basic_string& s, size_type i = npos) const;
size_type find_last_of(const Ch* p, size_type i, size_type n) const;
size_type find_last_of(const Ch* p, size_type i = npos) const;
size_type find_last_of(Ch c, size_type i = npos) const;
// param�terben nem szereplo karakter keres�se
796 A standard k�nyvt�r
size_type find_first_not_of(const basic_string& s, size_type i = 0) const;
size_type find_first_not_of(const Ch* p, size_type i, size_type n) const;
size_type find_first_not_of(const Ch* p, size_type i = 0) const;
size_type find_first_not_of(Ch c, size_type i = 0) const;
// param�terben nem szereplo karakter keres�se visszafel�
size_type find_last_not_of(const basic_string& s, size_type i = npos) const;
size_type find_last_not_of(const Ch* p, size_type i, size_type n) const;
size_type find_last_not_of(const Ch* p, size_type i = npos) const;
size_type find_last_not_of(Ch c, size_type i = npos) const;
// ...
};
Az �sszes fenti f�ggv�ny const. Teh�t arra haszn�lhat�k, hogy valamilyen c�lb�l
megkeressenek
egy r�szl�ncot, de maguk nem v�ltoztatj�k meg azt a karakterl�ncot, amelyre
alkalmaztuk
azokat.
A basic_string::find muveletek jelent�s�t �gy �rthetj�k meg legjobban, ha
meg�rtj�k a vel
�k egyen�rt�ku �ltal�nos algoritmusokat:
void f()
{
string s = "accdcde";
typedef ST;
string::size_type i1 = s.find("cd"); // i1 = 2 s[2]=='c' && s[3]=='d'
string::size_type i2 = s.rfind("cd"); // i2 = 4 s[4]=='c' && s[5]=='d'
string::size_type i3 = s.find_first_of("cd"); // i3 = 1 s[1] == 'c'
string::size_type i4 = s.find_last_of("cd"); // i4 = 5 s[5] == 'd'
string::size_type i5 = s.find_first_not_of("cd"); // i5 = 0 s[0]!='c' && s[0]!='d'

string::size_type i6 = s.find_last_not_of("cd"); // i6 = 6 s[6]!='c' && s[6]!='d'


}
Ha a find() f�ggv�nyek nem tal�lj�k meg, amit kellene, npos �rt�ket adnak vissza,
amely �rv
�nytelen karakterpoz�ci�t jelent. Ha az npos �rt�ket karakterpoz�ci�k�nt
haszn�ljuk,
range_error kiv�telt kapunk (�20.3.5). Figyelj�nk r�, hogy a find() eredm�nye
unsigned �rt�k.
20.3.12. Csere
Miut�n meghat�roztunk egy karakterpoz�ci�t a karakterl�ncban, az indexel�s
seg�ts�g�vel
az egyes karaktereket m�dos�thatjuk, de a replace() muvelet felhaszn�l�s�val
lecser�lhet
�nk teljes r�szl�ncokat is:
20. Karakterl�ncok 797
template<class Ch, class Tr = char_traits<Ch>, class A = allocator<Ch> >
class basic_string {
public:
// ...
// [ (*this)[i], (*this)[i+n] [ felcser�l�se m�s karakterekkel
basic_string& replace(size_type i, size_type n, const basic_string& s);
basic_string& replace(size_type i, size_type n,
const basic_string& s, size_type i2, size_type n2);
basic_string& replace(size_type i, size_type n, const Ch* p, size_type n2);
basic_string& replace(size_type i, size_type n, const Ch* p);
basic_string& replace(size_type i, size_type n, size_type n2, Ch c);
basic_string& replace(iterator i, iterator i2, const basic_string& s);
basic_string& replace(iterator i, iterator i2, const Ch* p, size_type n);
basic_string& replace(iterator i, iterator i2, const Ch* p);
basic_string& replace(iterator i, iterator i2, size_type n, Ch c);
template<class In> basic_string& replace(iterator i, iterator i2, In j, In j2);
// karakterek t�rl�se a l�ncb�l ("csere semmire")
basic_string& erase(size_type i = 0, size_type n = npos);
iterator erase(iterator i);
iterator erase(iterator first, iterator last);
void clear(); // az �sszes karakter t�rl�se
// ...
};
Az �j karakterek sz�m�nak nem kell megegyeznie a karakterl�ncban eddig szereplo
karakterek
sz�m�val. A karakterl�nc m�rete �gy v�ltozik, hogy az �j r�szl�nc pontosan
elf�rjen
benne. Val�j�ban az erase() f�ggv�ny sem csin�l m�st, mint hogy a megadott
r�szl�ncot
�res karakterl�ncra cser�li �s az eredeti karakterl�nc m�ret�t megfeleloen
m�dos�tja:
void f()
{
string s = "M�rpedig ez muk�dik, ha elhiszed, ha nem.";
s.erase(0,8); // a "M�rpedig " t�rl�se
s.replace(s.find("ez"),2,"Csak akkor");
s.replace(s.find(", ha nem"),8,""); // t�rl�s "" behelyettes�t�s�vel
}
Az erase() f�ggv�ny egyszeru, param�ter n�lk�li megh�v�sa a teljes karakterl�ncot
�res karakterl
�ncc� alak�tja. Ezt a muveletet az �ltal�nos t�rol�k eset�ben a clear() f�ggv�ny
val�-
s�tja meg (�16.3.6).
798 A standard k�nyvt�r
A replace() f�ggv�ny v�ltozatai az �rt�kad�s v�ltozataihoz igazodnak, hiszen a
replace() val
�j�ban nem m�s, mint �rt�kad�s egy r�szl�ncnak.
20.3.13. R�szl�ncok
A substr() f�ggv�ny lehetov� teszi, hogy kiv�lasszunk egy r�szl�ncot, amelyet
kezdopoz�-
ci�j�val �s hossz�val adunk meg:
template<class Ch, class Tr = char_traits<Ch>, class A = allocator<Ch> >
class basic_string {
public:
// ...
// r�szl�nc c�mz�se
basic_string substr(size_type i = 0, size_type n = npos) const;
// ...
};
A substr() f�ggv�ny egyszeru m�dszert biztos�t a karakterl�nc egy r�szlet�nek
kiolvas�s�-
ra. Ebbol a szemsz�gbol a p�rja a replace() f�ggv�ny, mellyel fel�l�rhatjuk a
karakterl�nc
egy r�sz�t. Mindk�t f�ggv�nynek a kezdopoz�ci�t �s a r�szl�nc hossz�t kell
megadnunk.
A find() seg�ts�g�vel viszont m�r �rt�k szerint is megtal�lhatunk r�szl�ncokat,
�gy ez a f�ggv
�nycsoport lehetov� teszi, hogy defini�ljunk egy r�szl�nc-oszt�lyt, amelyet �rni
�s olvasni
is tudunk:
template<class Ch> class Basic_substring {
public:
typedef typename basic_string<Ch>::size_type size_type;
Basic_substring(basic_string<Ch>& s, size_type i, size_type n); // s[i]..s[i+n-1]
Basic_substring(basic_string<Ch>& s, const basic_string<Ch>& s2); // s2 az s-ben
Basic_substring(basic_string<Ch>& s, const Ch* p); // *p az s-ben
Basic_substring& operator=(const basic_string<Ch>&); // �r�s *ps-be
Basic_substring& operator=(const Basic_substring<Ch>&);
Basic_substring& operator=(const Ch*);
Basic_substring& operator=(Ch);
operator basic_string<Ch>() const; // olvas�s *ps-be
operator const Ch* () const; // a c_str() haszn�lata
20. Karakterl�ncok 799
private:
basic_string<Ch>* ps;
size_type pos;
size_type n;
};
Az oszt�ly megval�s�t�sa is nagyon egyszeru:
template<class Ch>
Basic_substring<Ch>::Basic_substring(basic_string<Ch>& s, const basic_string<Ch>&
s2)
: ps(&s), n(s2.length())
{
pos = s.find(s2);
}
template<class Ch>
Basic_substring<Ch>& Basic_substring<Ch>::operator=(const basic_string<Ch>& s)
{
ps->replace(pos,n,s); // �r�s *ps-be
return *this;
}
template<class Ch> Basic_substring<Ch>::operator basic_string<Ch>() const
{
return basic_string<Ch>(*ps,pos,n); // m�sol�s *ps-be
}
Ha s2 nem tal�lhat� meg az s karakterl�ncban, pos �rt�ke npos lesz, �gy ha egy
ilyen r�szl
�ncot pr�b�lunk meg �rni vagy olvasni, range_error kiv�telt kapunk (�20.3.5).
A Basic_substring oszt�ly a k�vetkezo form�ban haszn�lhat�:
typedef Basic_substring<char> Substring;
void f()
{
string s = "Mary had a little lamb";
Substring(s,"lamb") = "fun";
Substring(s,"a little") = "no";
string s2 = "Joe" + Substring(s,s.find(' '),string::npos);
}
Term�szetesen sokkal �rdekesebb feladatokat is elv�gezhetn�nk, ha a Substring
oszt�ly
mintailleszt�st is tudna v�gezni (�20.6[7]).
800 A standard k�nyvt�r
20.3.14. M�ret �s kapacit�s
A mem�riakezel�ssel kapcsolatos k�rd�seket a string nagyj�b�l ugyan�gy kezeli,
mint
a vector (�16.3.8):
template<class Ch, class Tr = char_traits<Ch>, class A = allocator<Ch> >
class basic_string {
public:
// ...
// m�ret, kapacit�s stb. (mint a �16.3.8 pontban)
size_type size() const; // karakterek sz�ma (�20.3.4)
size_type max_size() const; // a legnagyobb lehets�ges karakterl�nc
size_type length() const { return size(); }
bool empty() const { return size()==0; }
void resize(size_type n, Ch c);
void resize(size_type n) { resize(n,Ch()); }
size_type capacity() const; // mint a vector, �16.3.8
void reserve(size_type res_arg = 0); // mint a vector, �16.3.8
allocator_type get_allocator() const;
};
A reverse(res_arg) f�ggv�ny length_error kiv�telt v�lt ki, ha res_arg>max_size().
20.3.15. Ki- �s bemeneti muveletek
A string oszt�ly egyik legfontosabb felhaszn�l�si ter�lete, hogy bemeneti
muveletek c�lja,
illetve kimeneti muveletek forr�sa legyen. A basic_string I/O oper�torait a
<string> (�s nem
az <iostream>) tartalmazza:
template<class Ch, class Tr, class A>
basic_istream<Ch,Tr>& operator>>(basic_istream<Ch,Tr>&, basic_string<Ch,Tr,A>&);
template<class Ch, class Tr, class A>
basic_ostream<Ch,Tr>& operator<<(basic_ostream<Ch,Tr>&,const
basic_string<Ch,Tr,A>&);
template<class Ch, class Tr, class A>
basic_istream<Ch,Tr>& getline(basic_istream<Ch,Tr>&, basic_string<Ch,Tr,A>&, Ch
eol);
template<class Ch, class Tr, class A>
basic_istream<Ch,Tr>& getline(basic_istream<Ch,Tr>&, basic_string<Ch,Tr,A>&);
20. Karakterl�ncok 801
A << a karakterl�ncot egy kimeneti adatfolyamra (ostream, �21.2.1) �rja, m�g a >>
oper�tor
egy �reshely karakterekkel hat�rolt sz�t olvas be a karakterl�ncba egy bemeneti
adatfolyamr
�l (�3.6, �21.3.1). A sz� elotti sz�k�z, tabul�tor, �jsor stb. karaktereket
egyszeruen �tugorja
�s a sz� ut�n k�vetkezo ilyen karakterek sem ker�lnek bele a karakterl�ncba.
A getline() f�ggv�ny megh�v�s�val egy teljes, eol karakterrel lez�rt sort
olvashatunk be a karakterl
�ncba, a karakterl�nc m�rete pedig �gy n�vekszik, hogy a sor elf�rjen benne
(�3.6).
Ha nem adjuk meg az eol param�tert, a f�ggv�ny az '\n' �jsor karaktert haszn�lja.
A sorz�-
r� karaktert beolvassa az adatfolyamr�l, de a karakterl�ncba nem ker�l be. Mivel a
string
m�rete �gy v�ltozik, hogy a beolvasott sor elf�rjen benne, nincs sz�ks�g arra,
hogy a lez�-
r� karaktert az adatfolyamban hagyjuk vagy visszaadjuk a beolvasott karakterek
sz�m�t
a h�v�nak. A karaktert�mb�k eset�ben a get() �s a getline() k�nytelen volt ilyen,
ellenorz
�st seg�to megold�sokat alkalmazni (�21.3.4).
20.3.16. Felcser�l�s
Ugyan�gy, mint a vector-n�l (�16.3.9), a swap() f�ggv�nybol a karakterl�ncokhoz is
sokkal
hat�konyabb specializ�ci�t k�sz�thet�nk, mint az �ltal�nos algoritmus:
template<class Ch, class Tr, class A>
void swap(basic_string<Ch,Tr,A>&, basic_string<Ch,Tr,A>&);
20.4. A C standard k�nyvt�ra
A C++ standard k�nyvt�ra �r�k�lte a C st�lus� karakterl�ncok kezel�s�vel
foglalkoz� f�ggv
�nyeket. Ebben a pontban felsorolunk n�h�nyat a legfontosabb, C karakterl�ncokat
kezel
o f�ggv�nyek k�z�l. A le�r�s egy�ltal�n nem terjed ki mindre; ha r�szletes
inform�ci�kat
szeretn�nk megtudni, n�zz�k meg fejlesztorendszer�nk k�zik�nyv�t. Legy�nk �vatosak

ezen f�ggv�nyek haszn�latakor, mert a k�nyvt�rak k�sz�toi gyakran saj�t, nem


szabv�nyos
f�ggv�nyeket adnak meg a szabv�nyos fej�llom�nyokban, �gy neh�z meg�llap�tani,
hogy
melyek a minden rendszerben el�rheto f�ggv�nyek.
A C standard k�nyvt�r�nak lehetos�geit le�r� fej�llom�nyok list�j�t a �16.1.2
pontban adtuk
meg. A mem�riakezelo f�ggv�nyekkel a �19.4.6 pontban foglalkozunk, a C ki- �s
bemeneti
f�ggv�nyeivel a �21.8 r�szben, a C matematikai k�nyvt�r�val pedig a �22.3 pontban.

802 A standard k�nyvt�r


A program ind�t�s�val �s befejez�s�vel kapcsolatos f�ggv�nyeket a �3.2 �s a
�9.4.1.1 pontban
mutattuk be, m�g a meghat�rozatlan f�ggv�nyparam�terek beolvas�s�t seg�to f�ggv�-
nyeket a �7.6 pont t�rgyalta. Azon C st�lus� f�ggv�nyek, melyek a sz�les
karaktereket kezelik,
a <cwchar> �s a <wchar.h> fej�llom�nyban tal�lhat�k.
20.4.1. C st�lus� karakterl�ncok
A C st�lus� karakterl�ncok kezel�s�vel foglalkoz� f�ggv�nyek a <string.h> �s a
<cstring>
fej�llom�nyban tal�lhat�k:
char* strcpy(char* p, const char* q); // m�sol�s q-b�l p-be (a lez�r�val egy�tt)
char* strcat(char* p, const char* q); // hozz�fuz�s q-b�l p-be (a lez�r�val
egy�tt)
char* strncpy(char* p, const char* q, int n); // n karakter m�sol�sa q-b�l p-be
char* strncat(char* p, const char* q, int n); // n karakter hozz�fuz�se q-b�l p-be

size_t strlen(const char* p); // p hossza (a lez�r� n�lk�l)


int strcmp(const char* p, const char* q); // p �s q �sszehasonl�t�sa
int strncmp(const char* p, const char* q, int n); // az elso n karakter
�sszehasonl�t�sa
char* strchr(char* p, int c); // az elso c keres�se p-ben
const char* strchr(const char* p, int c);
char* strrchr(char* p, int c); // az utols� c keres�se p-ben
const char* strrchr(const char* p, int c);
char* strstr(char* p, const char* q); // az elso q keres�se p-ben
const char* strstr(const char* p, const char* q);
char* strpbrk(char* p, const char* q); // q elso karakter�nek keres�se p-ben
const char* strpbrk(const char* p, const char* q);
size_t strspn(const char* p, const char* q); // p karaktereinek sz�ma az elso,
// q-ban szereplo karakter elott
size_t strcspn(const char* p, const char* q); // p karaktereinek sz�ma az elso, q-
ban
nem szereplo karakter elott
A megadott mutat�kat a f�ggv�nyek nem-null�knak felt�telezik, azoknak a char
t�mb�knek
pedig, melyekre a mutat�k mutatnak, 0 karakterrel lez�rt sorozatoknak kell
lenni�k.
Az strn f�ggv�nyek 0 karakterekkel t�ltik fel a hi�nyz� ter�letet, ha nincs n
darab feldolgozand
� karakter. A karakterl�nc-�sszehasonl�t�sok null�t adnak vissza, ha a k�t
karakterl
�nc egyenlo; negat�v sz�mot, ha az elso param�ter �b�c�sorrendben elobb
k�vetkezik,
mint a m�sodik; ford�tott esetben pedig pozit�v sz�mot.
20. Karakterl�ncok 803
Term�szetesen a C nem biztos�t t�lterhelt f�ggv�nyp�rokat, a C++-ban azonban
sz�ks�g
van ezekre a const biztons�gos megval�s�t�s�hoz:
void f(const char* pcc, char* pc) // C++
{
*strchr(pcc,'a') = 'b'; // hiba: const char-nak nem adhatunk �rt�ket
*strchr(pc,'a') = 'b'; // rendben, b�r nem t�k�letes: lehet, hogy pc-ben nincs 'a'

}
A C++ strchr() f�ggv�nye nem engedi meg, hogy const karakterl�ncba �rjunk, egy C
program
azonban .kihaszn�lhatja. a C-beli strchr() gyeng�bb t�pusellenorz�s�t:
char* strchr(const char* p, int c); /* C standard k�nyvt�rbeli f�ggv�ny, nem C++
*/
void g(const char* pcc, char* pc) /* C, a C++ nem ford�tja le */
{
*strchr(pcc,'a') = 'b'; /* const �talak�t�sa nem const-t�: C-ben j�, C++-ban hiba
*/
*strchr(pc,'a') = 'b'; /* j� C-ben �s C++-ban is */
}
Ha tehetj�k, felt�tlen�l ker�lj�k a C st�lus� karakterl�ncok haszn�lat�t �s
haszn�ljuk helyett
�k a string oszt�lyt. A C st�lus� karakterl�ncok �s a hozz�juk tartoz� szabv�nyos
f�ggv�-
nyek seg�ts�g�vel nagyon hat�kony programokat �rhatunk, de m�g a gyakorlott C �s
C++
programoz�k is gyakran k�vetnek el .buta kis hib�kat. mik�zben ezekkel dolgoznak.
Persze
minden C++ programoz� tal�lkozni fog olyan r�gebbi programokkal, melyek ezeket
a lehetos�geket haszn�lj�k. �me egy haszontalan kis p�lda, amellyel a leggyakoribb
f�ggv
�nyeket mutatjuk be:
void f(char* p, char* q)
{
if (p==q) return; // a mutat�k egyen�rt�kuek
if (strcmp(p,q)==0) { // a karakterl�nc-�rt�kek egyen�rt�kuek
int i = strlen(p); // a karakterek sz�ma (a lez�r� n�lk�l)
// ...
}
char buf[200];
strcpy(buf,p); // p m�sol�sa a buf-ba (a lez�r�val egy�tt)
// nem t�k�letes, t�lcsordulhat
strncpy(buf,p,200); // 200 karakter m�sol�sa p-bol a buf-ba
// nem t�k�letes; lehet, hogy nem m�solja �t a lez�r�t
// ...
}
804 A standard k�nyvt�r
A C st�lus� karakterl�ncok ki- �s bevitel�t �ltal�ban a printf f�ggv�nycsal�d
seg�ts�g�vel val
�s�tjuk meg (�21.8).
Az <stdlib.h> �s a <cstdlib> fej�llom�nyban a standard k�nyvt�r n�h�ny olyan
hasznos
f�ggv�nyt ny�jt, melyekkel sz�m�rt�ket jel�lo karakterl�ncokat alak�thatunk
sz�mm�:
double atof(const char* p); // p �talak�t�sa double-l�
int atoi(const char* p); // p �talak�t�sa int-t�
long atol(const char* p); // p �talak�t�sa long-g�
A bevezeto �reshely karaktereket ezek a f�ggv�nyek nem veszik figyelembe. Ha a
karakterl
�nc nem sz�mot �br�zol, a visszat�r�si �rt�k 0 lesz. (Az atoi(.h�t.) eredm�nye is
0!)
Ha a karakterl�nc sz�mot jel�l, de az nem �br�zolhat� az eredm�nyk�nt v�rt
sz�mt�pusban,
akkor az errno (�16.1.2, �22.3) v�ltoz� �rt�ke ERANGE lesz, a visszat�r�si �rt�k
pedig egy
nagyon nagy vagy nagyon kicsi sz�m, a konvert�lt �rt�knek megfeleloen.
20.4.2. Karakterek oszt�lyoz�sa
A <ctype.h> �s a <cctype> fej�llom�nyban a standard k�nyvt�r olyan hasznos
f�ggv�nyeket
k�n�l, melyek az ASCII, illetve a hasonl� karakterk�szletek karaktereit
oszt�lyozz�k:
int isalpha(int); // 'a'..'z' 'A'..'Z' betuk, C-hez (�20.2.1, �21.7)
int isupper(int); // 'A'..'Z' nagybetuk, C-hez (�20.2.1, �21.7)
int islower(int); // 'a'..'z' kisbetuk, C-hez (�20.2.1, �21.7)
int isdigit(int); // t�zes sz�mrendszeru sz�mok: '0'..'9'
int isxdigit(int); // hexadecim�lis sz�mok: '0'..'9' vagy 'a'..'f' vagy 'A'..'F'
int isspace(int); // ' ', '\t', '\v', kocsivissza, �jsor, f�ggoleges tabul�tor
int iscntrl(int); // vez�rlokarakter (ASCII 0..31 �s 127)
int ispunct(int); // k�zpontoz�s, a fentiek egyike sem tartozik bele
int isalnum(int); // isalpha() | isdigit()
int isprint(int); // nyomtathat� karakterek: ascii ' '..'~'
int isgraph(int); // isalpha() | isdigit() | ispunct()
int toupper(int c); // c nagybetus megfeleloje
int tolower(int c); // c kisbetus megfeleloje
A fentieket �ltal�ban egyszeru kiolvas�ssal val�s�tj�k meg, �gy, hogy a karaktert
indexk�nt
haszn�lj�k egy t�bl�ban, amely a karakterek jellemzoit t�rolja. Ez�rt az al�bbi
kifejez�s
amellett, hogy t�ls�gosan hossz� �s sok hibalehetos�get rejt mag�ban (p�ld�ul egy
EBCDIC
karakterk�szletet haszn�l� rendszerben nem alfabetikus karakterek is teljes�tik a
felt�telt),
nem is hat�kony:
20. Karakterl�ncok 805
if (('a'<=c && c<='z') || ('A'<=c && c<='Z')) { // betu
// ...
}
Ezek a f�ggv�nyek egy int param�tert v�rnak, �s az �tadott eg�sznek vagy
�br�zolhat�nak
kell lennie egy unsigned char t�pussal vagy az EOF �rt�knek kell lennie (ami
�ltal�ban
a .1). Ez az �rtelmez�s probl�m�t jelenthet az olyan rendszerekben, ahol a char
elojeles t�-
pus (l�sd: �20.6[11]).
Ugyanilyen szerepu f�ggv�nyek rendelkez�sre �llnak sz�les karakterekre is, a
<cwtype> �s
a <wtype.h> fej�llom�nyban.
20.5. Tan�csok
[1] A C st�lus� f�ggv�nyek helyett lehetoleg haszn�ljuk a string oszt�ly
elj�r�sait.
�20.4.1.
[2] A string lehet v�ltoz� vagy tag, de b�zisoszt�lynak nem val�. �20.3, �25.2.1.
[3] A karakterl�ncokat �rdemes �rt�k szerint �tadni �s visszaadni, mert �gy a
rendszerre
b�zzuk a mem�riakezel�st. �20.3.6.
[4] A bej�r�k �s a [ ] oper�tor helyett haszn�ljuk az at() f�ggv�nyt, ha
tartom�nyellen
orz�sre van sz�ks�g�nk. �20.3.2, �20.3.5.
[5] A bej�r�k �s a [ ] oper�tor gyorsabb, mint az at() f�ggv�ny. �20.3.2, �20.3.5.

[6] K�zvetve vagy k�zvetlen�l, a r�szl�ncok olvas�s�hoz haszn�ljuk a substr(),


�r�sukhoz a replace() f�ggv�nyt. �20.3.12, �20.3.13.
[7] Adott �rt�k megkeres�s�hez egy karakterl�ncban haszn�ljuk a find() f�ggv�nyt
(�s ne �rjunk saj�t ciklust erre a feladatra). �20.3.1.
[8] Ha hat�konyan akarunk egy karakterl�ncot karakterekkel bov�teni, haszn�ljuk
a hozz�fuz�s muveleteit. �20.3.9.
[9] Ha az ido nem l�tfontoss�g� szempont, a karakterbevitelre haszn�ljunk string
objektumokat. �20.3.1.5.
[10] Haszn�ljuk a string::npos �rt�ket a .karakterl�nc h�tral�vo r�sz�nek.
jelz�s�re.
�20.3.5.
[11] Ha gyakran haszn�lunk egy alacsonyszintu szolg�ltat�st, akkor azt k�sz�ts�k
el
a string oszt�lyhoz, ne haszn�ljunk emiatt mindenhol alacsonyszintu
adatszerkezeteket.
�20.3.10.
806 A standard k�nyvt�r
[12] Ha a string oszt�lyt haszn�ljuk, valahol mindig kapjuk el a range_error �s
out_of_range kiv�teleket. �20.3.5.
[13] Figyelj�nk r�, hogy ne adjunk �t char* mutat�t 0 �rt�kkel egy
karakterl�nckezel
o f�ggv�nynek. �20.3.7.
[14] Ha nagyon nagy sz�ks�g�nk van r�, a c_str() f�ggv�ny seg�ts�g�vel egy string
objektumb�l elo�ll�thatjuk a C st�lus� karakterl�nc megfeleloj�t. �20.3.7.
[15] Haszn�ljuk az isalpha(), isdigit() stb. f�ggv�nyeket, ha a karaktereket
oszt�lyoznunk
kell, ne �rjunk saj�t ellenorz�seket a karakter�rt�kek alapj�n. �20.4.2.
20.6. Gyakorlatok
A fejezet feladatainak t�bbs�g�hez a standard k�nyvt�r b�rmely v�ltozat�nak
forr�sk�dj�-
ban tal�lhatunk megold�st, mielott azonban megn�zn�nk, hogy a k�nyvt�r alkot�i
hogyan
k�zel�tett�k meg a probl�m�t, pr�b�ljunk saj�t megold�st keresni.
1. (*2) K�sz�ts�nk egy f�ggv�nyt, amely k�t string objektumot v�r param�terk�nt
�s egy �jabb karakterl�ncot ad vissza, amelyben a k�t karakterl�nc �sszefuz�se
szerepel �gy, hogy k�z�tt�k egy pont �ll. A file �s a write karakterl�ncokb�l
p�ld�ul a f�ggv�ny a file.write eredm�nyt �ll�tsa elo. Oldjuk meg ugyanezt a
feladatot
C st�lus� karakterl�ncokkal �s a C lehetos�geinek (p�ld�ul a malloc() �s
az strlen() f�ggv�nyek) felhaszn�l�s�val. Hasonl�tsuk �ssze a k�t f�ggv�nyt.
Milyen fontos �sszehasonl�t�si szempontokat kell megvizsg�lnunk?
2. (*2) Foglaljuk �ssze egy list�ban a vector �s a basic_string oszt�ly k�z�tti
k�-
l�nbs�geket. Mely k�l�nbs�gek igaz�n fontosak?
3. (*2) A karakterl�nc-kezelo lehetos�gek nem teljesen szab�lyosak. Egy karaktert
(char) p�ld�ul �rt�k�l adhatunk egy karakterl�ncnak, de kezdeti �rt�kad�sra
nem haszn�lhatjuk. K�sz�ts�nk egy list�t ezekrol a szab�lytalans�gokr�l. Melyeket
k�sz�b�lhett�k volna ki ezek k�z�l an�lk�l, hogy a karakterl�ncok haszn�-
lat�t t�lbonyol�tottuk volna? Milyen m�s szab�lytalans�gokat eredm�nyezne ez
az �talak�t�s?
4. (*1.5) A basic_string oszt�lynak nagyon sok tagf�ggv�nye van. Melyeket emelhetn
�nk ki az oszt�lyb�l �s tehetn�nk nem tag f�ggv�nny� ezek k�z�l an�lk�l,
hogy a hat�konys�got �s k�nyelmes haszn�lhat�s�got feladn�nk?
5. (*1.5) �rjuk meg a back_inserter() (�19.2.4) azon v�ltozat�t, amely a
basic_string
oszt�llyal muk�dik.
6. (*2) Fejezz�k be a �20.3.13 pontban bemutatott Basic_substring oszt�ly megval
�s�t�s�t �s �p�ts�k be ezt egy olyan String t�pusba, amely t�lterheli a () oper�-
tort a .r�szl�nca. jelent�ssel, de egy�bk�nt ugyan�gy viselkedik, mint a string.
20. Karakterl�ncok 807
7. (*2.5) K�sz�ts�nk egy find() f�ggv�nyt, amely egy egyszeru szab�lyos (regul�-
ris) kifejez�s elso elofordul�s�t keresi meg egy string objektumban. A
kifejez�sben
a ? egyetlen, tetszoleges karaktert jelent, a * ak�rh�ny olyan karaktert,
amely a kifejez�s tov�bbi r�sz�re nem illesztheto, az [abc] azon karakterek
b�rmelyik
�t, amely a megadott halmazban szerepel (eset�nkben a, vagy b, vagy c).
A t�bbi karakter �nmag�t �br�zolja. A find(s,.name:.) p�ld�ul egy olyan mutat
�t ad vissza, amely a name: elso elofordul�s�ra mutat, m�g
a find(s,.[nN]ame(*).) kifejez�s azt a r�szl�ncot jel�li ki az s karakterl�ncban,
amelynek elej�n a name vagy a Name sz� szerepel, majd z�r�jelek k�z�tt egy
(esetleg �res) karaktersorozat.
8. (*2.5) Gondolkodjunk el rajta, hogy az elobbi (�20.6[7]), regul�ris
kifejez�silleszt
o f�ggv�ny�nkbol milyen lehetos�gek hi�nyoznak m�g. Hat�rozzuk meg
�s val�s�tsuk meg ezeket. Hasonl�tsuk �ssze az �ltalunk l�trehozott f�ggv�ny
kifejez
ok�pess�g�t egy sz�les k�rben elterjedt regul�ris kifejez�s-illeszto kifejezo-
k�pess�g�vel. Hasonl�tsuk �ssze a k�t elj�r�st hat�konys�g szempontj�b�l is.
9. (*2.5) Egy regul�ris kifejez�s-k�nyvt�r seg�ts�g�vel k�sz�ts�nk mintailleszto
muveleteket egy String oszt�lyban, amelyhez egy Substring oszt�ly is tartozik.
10. K�pzelj�nk el egy .ide�lis. oszt�lyt az �ltal�nos sz�veg-feldolgoz�si
feladatok
elv�gz�s�hez. Legyen az oszt�ly neve Text. Milyen lehetos�geket kell megval�-
s�tanunk? Milyen korl�toz�sokat �s k�lts�geket k�nyszer�tenek az oszt�lyra az
�ltalunk elk�pzelt .ide�lis. muveletek?
11. (*1.5) Hat�rozzuk meg az isalpha(), isdigit() stb. f�ggv�nyek t�lterhel�seit
�gy,
hogy megfeleloen muk�djenek char, unsigned char �s signed char t�pusra is.
12. (*2.5) K�sz�ts�nk egy String oszt�lyt, amelyet arra optimaliz�lunk, hogy nyolc

karaktern�l r�videbb karakterl�ncokat kezeljen. Hasonl�tsuk �ssze ennek hat�-


konys�g�t a �11.12 pont String oszt�ly�val, illetve a szabv�nyos string
oszt�llyal.
K�sz�theto-e olyan karakterl�nc oszt�ly, amely egyes�ti a nagyon r�vid karakterl
�ncokra optimaliz�lt �s a t�k�letesen �ltal�nos v�ltozat elonyeit?
13. (*2) M�rj�k le egy string m�sol�s�nak hat�konys�g�t. Megfeleloen optimaliz�lt
saj�t fejlesztorendszer�nk string oszt�lya a m�sol�sra?
14. (*2.5) Hasonl�tsuk �ssze a �20.3.9 �s a �20.3.10 pontban bemutatott h�rom
complete_name() f�ggv�ny hat�konys�g�t. Pr�b�ljuk elk�sz�teni
a complete_name() f�ggv�ny azon v�ltozat�t, amely a leheto leggyorsabban fut.
Jegyezz�k fel azokat a hib�kat, amelyeket a megval�s�t�s �s tesztel�s k�zben
tapasztaltunk.
15. (*2.5) K�pzelj�k el, hogy rendszer�nk legk�nyesebb muvelete a k�zepes
hossz�s�g� (5-25 karakteres) karakterl�ncok beolvas�sa a cin adatfolyamr�l.
�rjunk egy bemeneti f�ggv�nyt, amely az ilyen karakterl�ncokat tudja beolvasni
olyan gyorsan, ahogy csak el tudjuk k�pzelni. D�nthet�nk �gy, hogy a f�gg-
808 A standard k�nyvt�r
v�ny fel�let�nek k�nyelmes haszn�lat�t fel�ldozzuk a sebess�g �rdek�ben. Hasonl
�tsuk �ssze elj�r�sunk hat�konys�g�t a string oszt�ly >> oper�tor�nak hat�-
konys�g�val.
16. (*1.5) �rjuk meg az itos(int) f�ggv�nyt, amely a param�terk�nt megadott int
�rt�k string �br�zol�s�t adja vissza.
20. Karakterl�ncok 809
Adatfolyamok
.Csak azt kapod, amit l�tsz.
(Brian Kernighan)
Kimenet �s bemenet . Kimeneti adatfolyamok . Be�p�tett t�pusok kimenete .
Felhaszn�-
l�i t�pusok kimenete . Virtu�lis kimeneti f�ggv�nyek . Bemeneti adatfolyamok .
Be�p�tett
t�pusok bemenete . Form�zatlan bemenet . Adatfolyamok �llapota . Felhaszn�l�i
t�pusok
bemenete . I/O kiv�telek . Adatfolyamok �sszek�t�se . Orszemek . Eg�sz �s lebego-
pontos kimenet form�z�sa . Mezok �s igaz�t�s . M�dos�t�k . Szabv�nyos m�dos�t�k .
Felhaszn
�l�i m�dos�t�k . F�jlfolyamok . Adatfolyamok lez�r�sa . Karakterl�nc-folyamok
. Adatfolyamok �s �tmeneti t�rol�k . Helyi saj�toss�gok . Adatfolyam-visszah�v�sok

. printf() . Tan�csok . Gyakorlatok


21.1. Bevezeto
Egy programoz�si nyelvben �ltal�nos be- �s kimeneti (input/output, I/O) rendszert
megval
�s�tani rendk�v�l neh�z. R�gebben az I/O lehetos�gek csak arra korl�toz�dtak, hogy
n�-
h�ny be�p�tett adatt�pust kezeljenek. A legegyszerubbek kiv�tel�vel azonban a C++
programok
sz�mos felhaszn�l�i t�pust is haszn�lnak, �gy e t�pusok ki- �s bemenet�t is meg
kell
oldani. Egy I/O rendszernek a rugalmass�g �s hat�konys�g mellett egyszerunek,
k�nyel-
21
mesnek, biztons�gosnak �s mindenekfelett �tfog�nak kell lennie. Eddig m�g senki
nem �llt
elo olyan megold�ssal, amellyel mindenki el�gedett lenne, ez�rt lehetov� kell
tenn�nk,
hogy a felhaszn�l� saj�t ki- �s bemeneti eszk�z�ket k�sz�thessen, illetve a
szabv�nyos lehet
os�geket egyedi felhaszn�l�si ter�letek kezel�s�vel bov�thesse ki.
A C++ olyan nyelv, melyben a felhaszn�l� �j t�pusokat adhat meg �s e t�pusok
haszn�lata
ugyanolyan hat�kony �s k�nyelmes lehet, mint a be�p�tett adatt�pusok�. Ez�rt
logikus elv�-
r�s a C++ nyelv I/O szolg�ltat�sait�l, hogy C++ nyelven k�sz�ljenek �s csak olyan
eszk�-
z�ket haszn�ljanak, melyek minden programoz� sz�m�ra el�rhetok. Az itt bemutatott,
adatfolyam-
bemenetet �s -kimenetet kezelo lehetos�gek az e k�vetelm�nyek kiel�g�t�s�re tett
erofesz�t�sek eredm�nyei:
�21.2 Kimenet: A kimenet alatt az alkalmaz�sprogramoz� azt �rti, hogy tetszoleges
t�pus� (int, char* vagy Employee_record) objektumokb�l karaktersorozatot
�ll�that elo. Ebben a pontban azokat a lehetos�geket ismertetj�k,
melyekkel a be�p�tett �s a felhaszn�l�i t�pusok kimenete megval�s�that�.
�21.3 Bemenet: Azok az eszk�z�k, melyekkel karaktereket, karakterl�ncokat
vagy m�s (ak�r be�p�tett, ak�r felhaszn�l�i) t�pusok �rt�keit beolvashatjuk.
�21.4 Form�z�s: A kimenet elrendez�s�vel kapcsolatban gyakran k�l�nleges
elv�r�saink vannak. Az int �rt�keket p�ld�ul �ltal�ban t�zes sz�mrendszerben
szeretj�k ki�rni, a mutat�k hagyom�nyos form�ja a hexadecim�-
lis (tizenhatos sz�mrendszeru) alak, a lebegopontos sz�mokat pedig
megadott pontoss�ggal kell megjelen�teni. Ez a r�sz a form�z�ssal �s az
azt seg�to programoz�si eszk�z�kkel foglalkozik.
�21.5 F�jlok �s adatfolyamok: Alap�rtelmez�s szerint minden C++ program
haszn�lhatja a szabv�nyos adatfolyamokat: a szabv�nyos kimenetet
(cout), a szabv�nyos bemenetet (cin) �s a hibakimenetet (cerr). Ha m�s
eszk�z�ket vagy f�jlokat akarunk haszn�lni, akkor adatfolyamokat kell
l�trehoznunk �s ezeket hozz� kell k�tn�nk a megfelelo eszk�zh�z, illetve
f�jlhoz. Ez a r�sz a f�jlok megnyit�s�nak �s bez�r�s�nak, illetve az
adatfolyamok f�jlokhoz �s karakterl�ncokhoz val� hozz�k�t�s�nek m�dszereivel
foglalkozik.
�21.6 �tmeneti t�rol�s: Hat�kony ki- �s bemenetet �gy lehet megval�s�tani, ha
�tmeneti t�rakat (.puffereket.) haszn�lunk. A m�dszer alkalmazhat�
mindk�t oldalon, �gy az �tmeneti t�rb�l kiolvashatjuk �s oda �rhatjuk is
az adatokat. Ebben a pontban az �tmeneti t�rol�s (.pufferel�s.) alapm�dszereit
mutatjuk be.
�21.7 Helyi saj�toss�gok: A locale objektum azt hat�rozza meg, hogy a sz�mokat
�ltal�ban milyen form�ban jelen�tj�k meg, milyen karaktereket tekint
�nk betunek �s �gy tov�bb. Teh�t az adott kult�r�ra jellemzo .specialit�-
812 A standard k�nyvt�r
sokat. foglalja �ssze. Az I/O rendszer automatikusan haszn�lja ezeket az
inform�ci�kat, �gy ez a r�sz csak nagy vonalakban foglalkozik a t�m�val.
�21.8 C st�lus� I/O: Itt a C <stdio.h> fej�llom�ny�nak printf() f�ggv�ny�t �s a C
k�nyvt�r�nak a C++ <iostream> k�nyvt�r�hoz fuzodo viszony�t
mutatjuk be.
Ahhoz, hogy az adatfolyam-k�nyvt�rat haszn�ljuk, nem kell �rten�nk a
megval�s�t�s�hoz
haszn�lt �sszes m�dszert, m�r csak az�rt sem, mert a k�l�nb�zo C++-v�ltozatokban
k�l�nb
�zo m�dszereket alkalmazhatnak. Egy sz�p I/O rendszer megval�s�t�sa azonban komoly

kih�v�st jelent. Meg�r�sa k�zben sz�mos olyan lehetos�ggel megismerkedhet�nk,


amelyet
m�s programoz�si �s tervez�si feladatok megold�s�ban is felhaszn�lhatunk. Ez�rt
nagyon
fontos, hogy megismerj�k azokat a m�dszereket, melyekkel egy ki- �s bemeneti
rendszer
elk�sz�theto.
Ebben a fejezetben csak addig a m�lys�gig mutatjuk be az adatfolyamok
bemeneti/kimeneti
rendszer�t, hogy pontosan meg�rts�k annak szerkezet�t, felhaszn�lhassuk a
leggyakoribb
I/O muveletek v�grehajt�s�hoz, �s ki tudjuk eg�sz�teni �gy, hogy az �ltalunk
l�trehozott
�j t�pusokat is k�pes legyen kezelni. Ha szabv�nyos vagy �j t�pus� adatfolyamokat
akarunk
haszn�lni, esetleg saj�t helyi saj�toss�gokat akarunk meghat�rozni, a k�nyvt�r
forr�sk
�dj�ra, j� rendszerle�r�sra, �s muk�do p�ldaprogramokra is sz�ks�g�nk lesz az itt
le�rt inform
�ci�kon k�v�l.
Az adatfolyam I/O rendszer �sszetevoit az al�bbi �br�val szeml�ltethetj�k:
21. Adatfolyamok 813
ios_base:
helyi saj�toss�gokt�l f�ggetlen
�llapot
basic_streambuf<>:
�tmeneti t�rol�s
locale:
form�z�si inform�ci�k
karakterek �tmeneti t�rol�sa
t�nyleges c�l/forr�s
basic_ios<>:
helyi saj�toss�gokt�l f�ggo
�llapot, adatfolyam-�llapot
basic_iostream<>:
form�z�s (<<, >> stb.),
l�trehoz�s/felsz�mol�s
A basic_iostream<> felol indul� pontozott ny�l azt jelzi, hogy a basic_ios<> egy
virtu�lis
b�zisoszt�ly, az egyszeru vonalak mutat�kat �br�zolnak. Azon oszt�lyok, melyek
neve ut�n
a <> jel szerepel, olyan sablonok, melyek param�tere egy karaktert�pus �s
tartalmaznak egy
locale objektumot is.
Az adatfolyamok (streams) �s az hozz�juk haszn�lt �ltal�nos jelrendszer sz�mos
kommunik
�ci�s probl�ma megold�s�t lehetov� teszik. Adatfolyamokat haszn�lhatunk objektumok

g�pek k�z�tti �tvitel�re (�25.4.1), �zenetfolyamok titkos�t�s�hoz (�21.10[22]),


adatt�m�r�-
t�shez, objektumok �lland� (perzisztens) t�rol�s�hoz �s �gy tov�bb. Ennek ellen�re
az al�bbiakban
csak az egyszeru, karakterk�zpont� ki- �s bemenetet mutatjuk be.
Az adatfolyam ki- �s bemenethez kapcsol�d� oszt�lyok �s sablonok deklar�ci�j�t
(melyek
el�g inform�ci�t adnak ahhoz, hogy hivatkozzunk r�juk, de ahhoz nem, hogy
muveleteket
hajtsunk v�gre rajtuk), valamint a szabv�nyos t�pus-meghat�roz�sokat (typedef-
eket) az
<iosfwd> fej�llom�nyban tal�lhatjuk meg. Erre a f�jlra n�ha sz�ks�g�nk lesz,
amikor m�s
I/O fej�llom�nyokat . de nem az �sszeset . haszn�lni akarunk.
21.2. Kimenet
A be�p�tett �s a felhaszn�l�i t�pusok egys�ges �s t�pusbiztos kezel�se egyszeruen
megval�-
s�that�, ha t�lterhelj�k a kimeneti f�ggv�nyeket:
put(cerr,"x = "); // cerr a hiba�zenetek kimeneti adatfolyama
put(cerr,x);
put(cerr,'\n');
A param�ter t�pusa hat�rozza meg, melyik put() f�ggv�ny ker�l megh�v�sra az adott
helyzetben.
Ezt a megold�st sok nyelv alkalmazza, b�r sok ism�tl�st k�v�n. Ha az .�rd ki. mu-
velet megval�s�t�s�hoz a << oper�tort terhelj�k t�l, szebb jel�l�st kapunk �s
lehetos�get
adunk a programoz�nak, hogy objektumok sorozat�t egyetlen utas�t�ssal �rja ki:
cerr << "x = " << x << '\n';
Ha x egy int t�pus� v�ltoz�, melynek �rt�ke 123, akkor az elozo parancs a
szabv�nyos hibakimeneti
adatfolyamra (cerr) az al�bbi sz�veget �rja ki (egy �jsor karakterrel lez�rva):
x = 123
814 A standard k�nyvt�r
Ugyanakkor, ha x t�pusa complex (�22.5), �rt�ke pedig (1,2.4), a ki�rt sz�veg az
al�bbi lesz:
x = (1,2.4)
Ez a st�lus mindaddig muk�dok�pes, am�g x t�pus�ra a << muvelet defini�lt,
m�rpedig a felhaszn
�l� k�nnyed�n k�sz�thet ilyen f�ggv�nyt saj�t t�pusaihoz.
Ha el akarjuk ker�lni a kimeneti f�ggv�ny haszn�lat�b�l eredo k�nyelmetlen
megfogalmaz
�st, mindenk�ppen sz�ks�g�nk van egy kimeneti oper�torra. De mi�rt pont a <<
oper�-
tort v�lasszuk? Arra nincs lehetos�g�nk, hogy �j nyelvi elemet vezess�nk be
(�11.2). Az �rt
�kad� oper�tor haszn�lhat� lenne a ki- �s a bemenet jel�l�s�re is, de �gy tunt, a
legt�bb
programoz� k�l�nb�zo oper�tort szeretne haszn�lni a kimenethez �s a bemenethez.
R�-
ad�sul az = rossz ir�nyba k�t: a cout=a=b jelent�se cout=(a=b), m�g nek�nk a
(cout=a)=b
�rtelmez�sre lenne sz�ks�g�nk (�6.2). Pr�b�lkoztam a < �s a > oper�tor
haszn�lat�val is, de
az emberek tudat�ban ez a k�t jel annyira a .kisebb, mint. �s .nagyobb, mint.
jelent�shez
kapcsol�dik, hogy az �j I/O utas�t�sok teljesen olvashatatlanok voltak.
A << �s a >> oper�tort nem haszn�ljuk olyan gyakran a be�p�tett t�pusokra, hogy ez
probl
�m�t okozzon programjaink olvashat�s�g�ban. El�g szimmetrikusak ahhoz, hogy jelk�-

pezz�k a .kimenet. �s a .bemenet. muveletet. Amikor ezeket az oper�torokat ki- �s


bemenetre
haszn�ljuk, a << jelenti a ki�r�st, a >> pedig a beolvas�st. Azok, akik jobban
szeretik
a muszaki kifejez�seket, nevezhetik ezt a k�t muveletet sorrendben output-nak �s
inputnak,
esetleg besz�r�snak �s kinyer�snek (inserter, extractor). A << oper�tornak a
precedencia
sorrendben elfoglalt helye el�g alacsony ahhoz, hogy z�r�jelez�s n�lk�l lehetov�
tegye
a param�terekben aritmetikai muveletek elv�gz�s�t:
cout << "a*b+c=" << a*b+c << '\n';
Ha azonban olyan muveletet akarunk haszn�lni, amely precedenci�ja alacsonyabban
helyezkedik el, mint a << oper�tor, akkor nem szabad elfelejten�nk a z�r�jeleket:
cout << "a^b|c=" << (a^b|c) << '\n';
A balra l�pteto oper�tor (�6.2.4) szint�n haszn�lhat� kimeneti utas�t�sban, de
term�szetesen
ezt is z�r�jelek k�z� kell �rnunk:
cout << "a<<b=" << (a<<b) << '\n';
21. Adatfolyamok 815
21.2.1. Kimeneti adatfolyamok
Az ostream arra val�, hogy tetszoleges t�pus� �rt�keket karakterek sorozat�v�
alak�tsunk.
Ezut�n ezeket a karaktereket �ltal�ban alacsonyszintu kimeneti muveletekkel �rjuk
ki. Sokf
�le karakter l�tezik (�20.2) �s ezeket egy-egy char_traits objektum jellemzi
(�20.2.1). Ebb
ol k�vetkezik, hogy az ostream egy bizonyos t�pus� karakterre .specializ�lt.
v�ltozata
a basic_ostream sablonnak:
template <class Ch, class Tr = char_traits<Ch> >
class std::basic_ostream : virtual public basic_ios<Ch,Tr> {
public:
virtual ~basic_ostream();
// ...
};
A sablon �s a hozz� tartoz� muveletek az std n�vt�rben szerepelnek �s az <ostream>
fej�llom
�nyb�l �rhetok el, amely az <iostream> fej�llom�ny kimenettel kapcsolatos r�szeit
tartalmazza.
A basic_ostream param�terei meghat�rozz�k, hogy a megval�s�t�s milyen t�pus�
karaktereket
haszn�l, de nem r�gz�tik a ki�rhat� objektumok t�pus�t. Az egyszeru char t�pust �s

a sz�les karaktereket haszn�l� adatfolyamokat viszont minden v�ltozat k�zvetlen�l


t�mogatja:
typedef basic_ostream<char> ostream;
typedef basic_ostream<wchar_t> wostream;
Sok rendszerben a sz�les karakterek (wide character) �r�sa olyan szinten
optimaliz�lhat�
a wostream oszt�ly seg�ts�g�vel, amelyhez a kimeneti egys�gk�nt b�jtot haszn�l�
adatfolyamok
nehezen �rhetnek fel.
Lehetos�g van olyan adatfolyamok meghat�roz�s�ra is, melyekben a fizikai ki- �s
bemenetet
nem karakterszinten val�s�tjuk meg, ezek az adatfolyamok azonban meghaladj�k a
standard
k�nyvt�r hat�k�r�t, �gy ebben a k�nyvben nem foglalkozunk vel�k (�21.10[15]).
A basic_ios b�zisoszt�ly az <ios> fej�llom�nyban tal�lhat�. Ez kezeli a form�z�st
(�21.4),
a helyi saj�toss�gokat (�21.7) �s az �tmeneti t�rak el�r�s�t (�21.6) is. Az
egys�ges jel�l�srendszer
�rdek�ben n�h�ny t�pust is meghat�roz:
816 A standard k�nyvt�r
template <class Ch, class Tr = char_traits<Ch> >
class std::basic_ios : public ios_base {
public:
typedef Ch char_type;
typedef Tr traits_type;
typedef typename Tr::int_type int_type; // a karakter eg�sz �rt�k�nek t�pusa
typedef typename Tr::pos_type pos_type; // poz�ci� az �tmeneti t�rban
typedef typename Tr::off_type off_type; // eltol�s az �tmeneti t�rban
// ... l�sd m�g �21.3.3, �21.3.7, �21.4.4, �21.6.3 �s �21.7.1. ...
};
A basic_ios oszt�ly letiltja a m�sol� konstruktort �s az �rt�kad� oper�tort. Ebbol
k�vetkezik,
hogy az ostream �s istream objektumok nem m�solhat�k. Ha egy adatfolyam c�lja
megv�ltozik, k�nytelenek vagyunk vagy az �tmeneti t�rat kicser�lni (�21.6.4) vagy
mutat�-
kat haszn�lni (�6.1.7).
Az ios_base b�zisoszt�ly olyan inform�ci�kat �s muveleteket tartalmaz, amelyek
f�ggetlenek
a haszn�lt karaktert�pust�l. (Ilyen p�ld�ul a lebegopontos sz�mok kimeneti
pontoss�-
ga.) Ez�rt ez az oszt�ly nem kell, hogy sablon legyen.
Az ios_base oszt�lyban szereplo t�pus-meghat�roz�sokon k�v�l az adatfolyam I/O
k�nyvt�r
egy elojeles eg�sz t�pust is haszn�l, melynek neve streamsize �s az egy I/O
muvelettel �tvitt
karakterek sz�m�t, illetve az �tmeneti t�r m�ret�t adhatjuk meg a seg�ts�g�vel.
Emellett
rendelkez�s�nkre �ll a streamoff is, amely az adatfolyamokban �s az �tmeneti
t�rakban val
� eltol�st (offset) �br�zolja.
Az <iostream> fej�llom�ny t�bb szabv�nyos adatfolyamot is megad:
ostream cout; // karakterek szabv�nyos kimeneti adatfolyama
ostream cerr; // hiba�zenetek szabv�nyos, nem pufferelt kimeneti adatfolyama
ostream clog; // hiba�zenetek szabv�nyos kimeneti adatfolyama
wostream wcout; // a cout-nak megfelelo "sz�les" adatfolyam
wostream wcerr; // a cerr-nek megfelelo "sz�les" adatfolyam
wostream wclog; // a clog-nak megfelelo "sz�les" adatfolyam
A cerr �s a clog adatfolyamok ugyanarra a kimeneti eszk�zre mutatnak, a k�l�nbs�g
k�zt
�k csak a haszn�lt �tmeneti t�r t�pusa. A cout ugyanarra az eszk�zre �r, mint a C
stdout
(�21.8), m�g a cerr �s a clog ugyanarra, mint a C stderr. Ha sz�ks�g van r�, a
programoz�
tov�bbi adatfolyamokat is l�trehozhat (�21.5).
21. Adatfolyamok 817
21.2.2. Be�p�tett t�pusok kimenete
Az ostream oszt�ly megadja a << (.kimenet.) oper�tort, amellyel a be�p�tett
t�pusok ki�r�-
s�t v�gezhetj�k el:
template <class Ch, class Tr = char_traits<Ch> >
class basic_ostream : virtual public basic_ios<Ch,Tr> {
public:
// ...
basic_ostream& operator<<(short n);
basic_ostream& operator<<(int n);
basic_ostream& operator<<(long n);
basic_ostream& operator<<(unsigned short n);
basic_ostream& operator<<(unsigned int n);
basic_ostream& operator<<(unsigned long n);
basic_ostream& operator<<(float f);
basic_ostream& operator<<(double f);
basic_ostream& operator<<(long double f);
basic_ostream& operator<<(bool n);
basic_ostream& operator<<(const void* p); // mutat��rt�k ki�r�sa
basic_ostream& put(Ch c); // c ki�r�sa
basic_ostream& write(const Ch* p, streamsize n); // p[0]..p[n-1]
// ...
};
A put() �s write() f�ggv�nyek egyszeruen karaktereket �rnak ki, �gy az erre a
muveletre
szolg�l� << oper�tornak nem kell tagnak lennie. A karakter-operandust v�r�
operator<<()
f�ggv�nyek a put() seg�ts�g�vel nem tagk�nt k�sz�thetok el:
template <class Ch, class Tr>
basic_ostream<Ch, Tr>& operator<<(basic_ostream<Ch, Tr>&, Ch);
template <class Ch, class Tr>
basic_ostream<Ch, Tr>& operator<<(basic_ostream<Ch, Tr>&, char);
template <class Tr>
basic_ostream<char, Tr>& operator<<(basic_ostream<char, Tr>&, char);
template <class Tr>
basic_ostream<char, Tr>& operator<<(basic_ostream<char, Tr>&, signed char);
template <class Tr>
basic_ostream<char, Tr>& operator<<(basic_ostream<char, Tr>&, unsigned char);
818 A standard k�nyvt�r
A << a null�val lez�rt karaktert�mb�k ki�r�s�hoz is rendelkez�sre �ll:
template <class Ch, class Tr>
basic_ostream<char, Tr>& operator<<(basic_ostream<Ch, Tr>&, const Ch*);
template <class Ch, class Tr>
basic_ostream<char, Tr>& operator<<(basic_ostream<Ch, Tr>&, const char*);
template <class Tr>
basic_ostream<char, Tr>& operator<<(basic_ostream<char, Tr>&, const char*);
template <class Tr>
basic_ostream<char, Tr>& operator<<(basic_ostream<char, Tr>&, const signed char*);

template <class Tr>


basic_ostream<char, Tr>& operator<<(basic_ostream<char, Tr>&, const unsigned
char*);
A string-ek kimeneti oper�torait a <string> tartalmazza (�20.3.15).
Az operator <<() muvelet egy referenci�t ad vissza ugyanarra az ostream
objektumra, amelyre
megh�vtuk, �gy azonnal alkalmazhatjuk r� a k�vetkezo operator <<() muveletet:
cerr << "x = " << x;
Itt x egy int, az utas�t�s jelent�se pedig a k�vetkezo:
(cerr.operator<<("x = ")).operator<<(x);
Fontos k�vetkezm�ny, hogy amikor t�bb elemet �ratunk ki egyetlen kimeneti
utas�t�ssal,
azok a megfelelo sorrendben, balr�l jobbra haladva jelennek meg:
void val(char c)
{
cout << "int('" << c << "') = " << int(c) << '\n';
}
int main()
{
val('A');
val('Z');
}
Egy ASCII karaktereket haszn�l� rendszerben a fenti programr�szlet eredm�nye a
k�vetkez
o lesz:
int('A') = 65
int('Z') = 90
21. Adatfolyamok 819
Megfigyelhetj�k, hogy a karakterliter�lok t�pusa char (�4.3.1), �gy a cout<<.Z. a
Z betut fogja
ki�rni, nem annak int �rt�k�t, a 90-et.
Ha logikai (bool) �rt�ket �ratunk ki, az alap�rtelmez�s szerint 0 vagy 1 form�ban
jelenik
meg. Ha ez nem megfelelo sz�munkra, be�ll�thatjuk az <iomanip> fej�llom�nyban
(�21.4.6.2) meghat�rozott boolalpha form�z�sjelzot, �gy a true vagy a false sz�veg
jelenik
meg:
int main()
{
cout << true << ' ' << false << '\n';
cout << boolalpha; // a true �s false szimbolikus �br�zol�sa
cout << true << ' ' << false << '\n';
}
A ki�rt sz�veg:
1 0
true false
Pontosabban fogalmazva a boolalpha tulajdons�g azt biztos�tja, hogy a bool
�rt�keknek
a helyi saj�toss�goknak (locale) megfelelo �rt�k�t kapjuk. Ha �n megfeleloen
be�ll�tom
a locale-t (�21.7), a k�vetkezo eredm�nyt kapom:
1 0
sandt falsk
A lebegopontos sz�mok form�z�s�r�l, az eg�szek sz�mrendszer�rol stb. a �21.4.
pontban
lesz sz�.
Az ostream::operator<<(const void*) f�ggv�ny egy mutat� �rt�k�t jelen�ti meg, az
�ppen
haszn�lt sz�m�t�g�p fel�p�t�s�nek megfelelo form�ban:
int main()
{
int i = 0;
int* p = new int;
cout << "local " << &i << ", free store " << p << '\n';
}
820 A standard k�nyvt�r
Az eredm�ny az �n g�pemen a k�vetkezo:
local 0x7fffead0, free store 0x500c
M�s rendszerek m�sk�ppen jelen�thetik meg a mutat� �rt�k�t.
21.2.3. Felhaszn�l�i t�pusok kimenete
K�pzelj�k el az al�bbi, felhaszn�l�i complex t�pust (�11.3):
class complex {
public:
double real() const { return re; }
double imag() const { return im; }
// ...
};
A << oper�tort a k�vetkezok�ppen defini�lhatjuk az �j complex sz�m�ra:
ostream& operator<<(ostream&s, const complex& z)
{
return s << '(' << z.real() << ',' << z.imag() << ')';
}
Ezut�n a << muveletet pontosan ugyan�gy haszn�lhatjuk saj�t t�pusunkra, mint a
be�p�tett
t�pusokra:
int main()
{
complex x(1,2);
cout << "x = " << x << '\n';
}
Az eredm�ny:
x = (1,2)
A felhaszn�l�i t�pusok kimeneti muveleteinek megval�s�t�s�hoz nem kell
megv�ltoztatnunk
az ostream oszt�ly deklar�ci�j�t. Ez az�rt szerencs�s, mert az ostream oszt�ly az
<iostream> fej�llom�nyban defini�lt, amit a felhaszn�l�k jobb ha nem v�ltoztatnak
meg (er-
21. Adatfolyamok 821
re nincs is lehetos�g�k). Az, hogy az ostream bov�t�s�t nem tett�k lehetov�,
v�delmet ny�jt
az adatszerkezet v�letlen m�dos�t�sa ellen is, �s lehetov� teszi, hogy an�lk�l
v�ltoztassuk
meg az ostream oszt�ly megval�s�t�s�t, hogy a felhaszn�l�i programokra hat�ssal
lenn�nk.
21.2.3.1. Virtu�lis kimeneti f�ggv�nyek
Az ostream tagf�ggv�nyei nem virtu�lisak. Azok a kimeneti muveletek, melyeket egy
programoz
� val�s�t meg, nem az oszt�ly r�szei, �gy ezek sem lehetnek virtu�lisak. Ennek
egyik
oka az, hogy az egyszeru muveletek eset�ben (p�ld�ul egyetlen karakter �tmeneti
t�rba
�r�sa) �gy k�zel optim�lis sebess�get �rhet�nk el. Ez olyan ter�let, ahol a fut�si
ideju hat�-
konys�g rendk�v�l fontos �s szinte k�telezo helyben kifejtett (inline) elj�r�sokat
k�sz�teni.
A virtu�lis f�ggv�nyek haszn�lata it arra vonatkozik, hogy a leheto legnagyobb
rugalmass
�got biztos�tsuk azon muveletek sz�m�ra, melyek kifejezetten a �tmeneti t�r
t�lcsordul�-
s�val, illetve alulcsordul�s�val foglalkoznak (�21.6.4).
Ennek ellen�re a programoz�k gyakran k�v�nnak megjelen�teni olyan objektumokat,
melyeknek
csak egy b�zisoszt�lya ismert. Mivel a pontos t�pust nem ismerj�k, a megfelelo
kimenetet
nem �ll�thatjuk elo �gy, hogy egyszeruen minden �j t�pushoz megadjuk a << mu-
veletet. Ehelyett k�sz�thet�nk egy virtu�lis kimeneti f�ggv�nyt az absztrakt
b�zisoszt�lyban:
class My_base {
public:
// ...
virtual ostream& put(ostream& s) const = 0; // *this ki�r�sa s-re
};
ostream& operator<<(ostream& s, const My_base& r)
{
return r.put(s); // a megfelelo put() haszn�lata
}
Teh�t a put() egy olyan virtu�lis f�ggv�ny, amely biztos�tja, hogy a megfelelo
kimeneti mu-
velet ker�lj�n v�grehajt�sra a << oper�torban.
Ennek felhaszn�l�s�val a k�vetkezo programr�szletet �rhatjuk.
class Sometype : public My_base {
public:
// ...
822 A standard k�nyvt�r
ostream& put(ostream& s) const; // az igazi kimeneti f�ggv�ny: My_base::put()
// fel�l�r�sa
};
void f(const My_base& r, Sometype& s) // haszn�ljuk a << oper�tort a
// megfelelo put() h�v�s�hoz
{
cout << r << s;
}
Ezzel a virtu�lis put() f�ggv�ny be�p�l az ostream oszt�ly �s a << muvelet �ltal
biztos�tott
keretbe. A m�dszer j�l alkalmazhat� minden olyan esetben, amikor egy virtu�lis
f�ggv�nyk
�nt muk�do muveletre van sz�ks�g�nk, de fut�si idoben a m�sodik param�ter alapj�n
akarunk v�lasztani.
21.3. Bemenet
A bemenetet a kimenethez nagyon hasonl�an kezelhetj�k. Az istream oszt�ly
biztos�tja
a >> bemeneti oper�tort n�h�ny �ltal�nos t�pushoz, a felhaszn�l�i t�pusokhoz pedig
k�sz�thet
�nk egy-egy operator>>() f�ggv�nyt.
21.3.1. Bemeneti adatfolyamok
A basic_ostream (�21.2.1) oszt�llyal p�rhuzamosan az <istream> fej�llom�nyban
megtal�lhatjuk
a basic_istream oszt�lyt, amely az <iostream> bemenettel kapcsolatos r�szeit
tartalmazza:
template <class Ch, class Tr = char_traits<Ch> >
class std::basic_istream : virtual public basic_ios<Ch,Tr> {
public:
virtual ~basic_istream();
// ...
};
A basic_ios b�zisoszt�lyt a �21.2.1. pontban mutattuk be.
21. Adatfolyamok 823
A cin �s a wcin k�t szabv�nyos bemeneti adatfolyam, melyeket az <iostream>
fej�llom�ny �r le:
typedef basic_istream<char> istream;
typedef basic_istream<wchar_t> wistream;
istream cin; // karakterek szabv�nyos bemeneti adatfolyama
wistream wcin; // szabv�nyos bemeneti adatfolyam wchar_t r�sz�re
A cin adatfolyam ugyanazt a forr�st haszn�lja, mint a C stdin adatfolyama (�21.8).

21.3.2. Be�p�tett t�pusok bemenete


A be�p�tett t�pusokhoz az istream biztos�tja a >> oper�tort:
template <class Ch, class Tr = char_traits<Ch> >
class basic_istream : virtual public basic_ios<Ch,Tr> {
public:
// ...
// form�zott bevitel:
basic_istream& operator>>(short& n); // olvas�s n-be
basic_istream& operator>>(int& n);
basic_istream& operator>>(long& n);
basic_istream& operator>>(unsigned short& u); // olvas�s u-ba
basic_istream& operator>>(unsigned int& u);
basic_istream& operator>>(unsigned long& u);
basic_istream& operator>>(float& f); // olvas�s f-be
basic_istream& operator>>(double& f);
basic_istream& operator>>(long double& f);
basic_istream& operator>>(bool& b); // olvas�s b-be
basic_istream& operator>>(void*& p); // mutat��rt�k olvas�sa p-be
// ...
};
Az operator>>() f�ggv�nyek a k�vetkezo st�lust k�vetik:
istream& istream::operator>>(T& tvar) // T egy t�pus, melyre az
istream::operator>>
// deklar�lt
{
// �reshely karaktereket �tl�pni,
824 A standard k�nyvt�r
// majd valahogyan beolvasni egy T t�pus� elemet `tvar'-ba
return *this;
}
Mivel a >> �tugorja az �reshely (whitespace) karaktereket, az ilyenekkel
elv�lasztott eg�-
szeket az al�bbi egyszeru ciklussal olvashatjuk be:
int read_ints(vector<int>& v) // felt�lti v-t , visszat�r a beolvasott eg�szek
sz�m�val
{
int i = 0;
while (i<v.size() && cin>>v[i]) i++;
return i;
}
Ha a bemeneten egy nem eg�sz �rt�k jelenik meg, a bemeneti muvelet hib�ba �tk�zik,
�gy
a ciklus is megszakad. P�ld�ul ezt a bemenetet felt�telezve:
1 2 3 4 5.6 7 8.
a read_ints() f�ggv�ny �t eg�sz sz�mot fog beolvasni:
1 2 3 4 5
A muvelet ut�n a bemeneten a k�vetkezo beolvashat� karakter a pont lesz. A nem
l�that�
�reshely (whitespace) karakterek meghat�roz�sa itt is ugyanaz, mint a szabv�nyos
C-ben
(sz�k�z, tabul�tor, �jsor, f�ggoleges tabul�torra illeszt�s, kocsivissza), �s a
<cctype> fej�llom
�nyban levo isspace() f�ggv�nnyel ellenorizhetok valamely karakterre (�20.4.2).
Az istream objektumok haszn�latakor a leggyakoribb hiba, hogy a bemenet nem
eg�szen
abban a form�tumban �rkezik, mint amire felk�sz�lt�nk, ez�rt a bemenet nem
t�rt�nik
meg. Ez�rt mielott haszn�lni kezden�nk azokat az �rt�keket, melyeket rem�nyeink
szerint
beolvastunk, ellenorizn�nk kell a bemeneti adatfolyam �llapot�t (�21.3.3), vagy
kiv�teleket
kell haszn�lnunk (�21.3.6).
A bemenethez haszn�lt form�tumot a helyi saj�toss�gok (locale) hat�rozz�k meg
(�21.7).
Alap�rtelmez�s szerint a logikai �rt�keket a 0 (hamis) �s az 1 (igaz) �rt�k jelzi,
az eg�szeket
t�zes sz�mrendszerben kell megadnunk, a lebegopontos sz�mok form�ja pedig olyan,
ahogy a C++ programokban �rhatjuk azokat. A basefield (�21.4.2) tulajdons�g
be�ll�t�s�val
lehetos�g van arra is, hogy a 0123 sz�mot a 83 t�zes sz�mrendszerbeli sz�m okt�lis
alakjak
�nt, a 0xff bemenetet pedig a 255 hexadecim�lis alakjak�nt �rtelmezz�k. A mutat�k
beolvas
�s�hoz haszn�lt form�tum teljesen az adott nyelvi v�ltozatt�l f�gg (n�zz�nk ut�na,
saj�t
fejlesztorendszer�nk hogyan muk�dik).
21. Adatfolyamok 825
Meglepo m�don nincs olyan >> tagf�ggv�ny, mellyel egy karaktert olvashatn�nk be.
Ennek
oka az, hogy a >> oper�tor a karakterekhez a get() karakter-beolvas� f�ggv�ny
(�21.3.4) seg
�ts�g�vel k�nnyen megval�s�that�, �gy nem kell tagf�ggv�nyk�nt szerepelnie. Az
adatfolyamokr
�l saj�t karaktert�pusaiknak megfelelo karaktereket olvashatunk be. Ha ez a
karaktert
�pus a char, akkor beolvashatunk signed char �s unsigned char t�pus� adatot is:
template<class Ch, class Tr>
basic_istream<Ch,Tr>& operator>>(basic_istream<Ch,Tr>&, Ch&);
template<class Tr>
basic_istream<char,Tr>& operator>>(basic_istream<char,Tr>&, unsigned char&);
template<class Tr>
basic_istream<char,Tr>& operator>>(basic_istream<char,Tr>&, signed char&);
A felhaszn�l� szempontj�b�l teljesen mindegy, hogy a >> tagf�ggv�ny vagy �n�ll�
elj�r�s-e.
A t�bbi >> oper�torhoz hasonl�an ezek a f�ggv�nyek is elosz�r �tugorj�k a bevezeto

�reshely karaktereket:
void f()
{
char c;
cin >> c;
// ...
}
Ez a k�dr�szlet az elso nem �reshely karaktert a cin adatfolyamb�l a c v�ltoz�ba
helyezi.
A beolvas�s c�lja lehet karaktert�mb is:
template<class Ch, class Tr>
basic_istream<Ch,Tr>& operator>>(basic_istream<Ch,Tr>&, Ch*);
template<class Tr>
basic_istream<char,Tr>& operator>>(basic_istream<char,Tr>&, unsigned char*);
template<class Tr>
basic_istream<char,Tr>& operator>>(basic_istream<char,Tr>&, signed char*);
Ezek a muveletek is eldobj�k a bevezeto �reshely karaktereket, majd addig
olvasnak, am�g
egy �reshely karakter vagy f�jlv�ge jel nem k�vetkezik, v�g�l a karaktert�mb
v�g�re egy 0
karaktert �rnak. Term�szetesen ez a megold�s alkalmat ad a t�lcsordul�sra, �gy
�rdemesebb
ink�bb egy string objektumba (�20.3.15) helyezni a beolvasott adatokat. Ha m�gis
az elobbi
826 A standard k�nyvt�r
megold�st v�lasztjuk, r�gz�ts�k, hogy legfeljebb h�ny karaktert akarunk beolvasni
a >> oper
�tor seg�ts�g�vel. Az is.width(n) f�ggv�nyh�v�ssal azt hat�rozzuk meg, hogy a
k�vetkezo,
is bemeneti adatfolyamon v�grehajtott >> muvelet legfeljebb n-1 karaktert olvashat
be:
void g()
{
char v[4];
cin.width(4);
cin >> v;
cout << "v = " << v << endl;
}
Ez a programr�szlet legfeljebb 3 karaktert olvas be a v v�ltoz�ba �s a v�g�n
elhelyezi a 0
karaktert.
Egy istream eset�ben a width() �ltal be�ll�tott �rt�k csak az ut�na k�vetkezo >>
muveletre
van hat�ssal, �s arra is csak akkor, ha a c�lt�pus egy t�mb.
21.3.3. Az adatfolyam �llapota
Minden adatfolyam (az istream �s az ostream is) rendelkezik valamilyen �llapottal
(state).
A hib�kat �s a szokatlan �llapotokat ezen �llapot�rt�k megfelelo be�ll�t�s�val �s
lek�rdez�-
s�vel kezelhetj�k.
Az adatfolyam-�llapot (stream state) fogalm�t a basic_istream b�zisoszt�lya, a
basic_ios �rja
le az <ios> fej�llom�nyban:
template <class Ch, class Tr = char_traits<Ch> >
class basic_ios : public ios_base {
public:
// ...
bool good() const; // a k�vetkezo muvelet siker�lhet
bool eof() const; // f�jlv�ge k�vetkezett be
bool fail() const; // a k�vetkezo muvelet sikertelen lesz
bool bad() const; // az adatfolyam s�r�lt
iostate rdstate() const; // io �llapotjelzo lek�rdez�se
void clear(iostate f = goodbit); // io �llapotjelzo be�ll�t�sa
void setstate(iostate f) { clear(rdstate()|f); } // az f io �llopotjelzo
be�ll�t�sa
21. Adatfolyamok 827
operator void*() const; // nemnulla, ha !fail()
bool operator!() const { return fail(); }
// ...
};
Ha az �llapot good(), a megelozo bemeneti muvelet sikeres volt. Ilyenkor a
k�vetkezo bemeneti
muvelet helyes v�grehajt�s�ra is van es�ly, ellenkezo esetben viszont az biztosan
nem lesz hib�tlan. Ha egy olyan adatfolyamon pr�b�lunk meg bemeneti muveletet
v�grehajtani,
amely nem good() �llapotban van, akkor semmi sem t�rt�nik. Ha megpr�b�lunk a v
v�ltoz�ba �rt�ket beolvasni, de a bemeneti muvelet sikertelen, v �rt�k�nek nem
szabad
megv�ltoznia. (Ha v olyan t�pus�, amit az istream �s az ostream tagf�ggv�nyei
kezelnek,
biztosan megmarad az �rt�ke.) A fail() �s a bad() �llapot k�z�tti k�l�nbs�g igen
kicsi. Ha
az �llapot fail(), de nem bad(), akkor az adatfolyam �rv�nytelenn� v�lt, de nem
vesztek el
karakterek. Ha bad() �llapotba ker�lt�nk, m�r nem rem�nykedhet�nk.
Az adatfolyam �llapot�t jelzok (jelzobitek, flag-ek) hat�rozz�k meg. Az
adatfolyamok �llapot
�t kifejezo legt�bb konstanshoz hasonl�an ezeket is a basic_ios b�zisoszt�lya, az
ios_base �rja le:
class ios_base {
public:
// ...
typedef implementation_defined2 iostate;
static const iostate badbit, // az adatfolyam s�r�lt
eofbit, // f�jlv�ge k�vetkezett be
failbit, // a k�vetkezo muvelet sikertelen lesz
goodbit; // goodbit==0
// ...
};
Az I/O �llapot jelzobitjeit k�zvetlen�l m�dos�thatjuk:
void f()
{
ios_base::iostate s = cin.rdstate(); // iostate bitek halmaz�val t�r vissza
if (s & ios_base::badbit) {
// cin karakterek elveszhettek
}
// ...
cin.setstate(ios_base::failbit);
// ...
}
828 A standard k�nyvt�r
Ha az adatfolyamot felt�telk�nt haszn�ljuk, annak �llapot�t az operator void*()
vagy az operator
!() f�ggv�nnyel vizsg�lhatjuk meg. A vizsg�lat csak akkor lesz sikeres, ha az
�llapot
!fail() (a void*() eset�ben), illetve fail() (a !() eset�ben). Egy �ltal�nos
m�sol� elj�r�st p�ld
�ul az al�bbi form�ban �rhatunk meg.
template<class T> void iocopy(istream& is, ostream& os)
{
T buf;
while (is>>buf) os << buf << '\n';
}
Az is>>buf muvelet egy referenci�t ad vissza, amely az is adatfolyamra hivatkozik,
a vizsg�-
latot pedig az is::operator void*() muvelet v�gzi:
void f(istream& i1, istream& i2, istream& i3, istream& i4)
{
iocopy<complex>(i1,cout); // komplex sz�mok m�sol�sa
iocopy<double>(i2,cout); // k�tszeres pontoss�g� lebegopontos sz�mok m�sol�sa
iocopy<char>(i3,cout); // karakterek m�sol�sa
iocopy<string>(i4,cout); // �reshelyekkel elv�lasztott szavak m�sol�sa
}
21.3.4. Karakterek beolvas�sa
A >> oper�tor form�zott bemenetre szolg�l, teh�t adott t�pus� �s adott form�tum�
objektumok
beolvas�s�ra. Ha erre nincs sz�ks�g�nk �s ink�bb val�ban karakterekk�nt akarjuk
beolvasni
a karaktereket, hogy k�sobb mi dolgozzuk fel azokat, haszn�ljuk a get()
f�ggv�nyeket:
template <class Ch, class Tr = char_traits<Ch> >
class basic_istream : virtual public basic_ios<Ch,Tr> {
public:
// ...
// form�zatlan bemenet
streamsize gcount() const; // a legut�bbi get() �ltal beolvasott karakterek sz�ma
int_type get(); // egy Ch (vagy Tr::eof()) beolvas�sa
basic_istream& get(Ch& c); // egy Ch olvas�sa c-be
basic_istream& get(Ch* p, streamsize n); // �jsor a lez�r�jel
basic_istream& get(Ch* p, streamsize n, Ch term);
21. Adatfolyamok 829
basic_istream& getline(Ch* p, streamsize n); // �jsor a lez�r�jel
basic_istream& getline(Ch* p, streamsize n, Ch term);
basic_istream& ignore(streamsize n = 1, int_type t = Tr::eof());
basic_istream& read(Ch* p, streamsize n); // legfeljebb n karakter beolvas�sa
// ...
};
Ezek mellett a <string> fej�llom�ny biztos�tja a getline() f�ggv�nyt is, amely a
szabv�nyos
string-ek (�20.3.15) beolvas�s�ra haszn�lhat�.
A get() �s a getline() f�ggv�nyek ugyan�gy kezelik az �reshely karaktereket, mint
b�rmely
m�s karaktert. Kifejezetten olyan adatok beolvas�s�ra szolg�lnak, ahol nem sz�m�t
a beolvasott
karakterek jelent�se.
Az istream::get(char&) f�ggv�ny egyetlen karaktert olvas be param�ter�be. Egy
karakterenk
�nt m�sol� programot p�ld�ul a k�vetkezok�ppen �rhatunk meg.
int main()
{
char c;
while(cin.get(c)) cout.put(c);
}
A h�romparam�teru s.get(p,n,term) legfeljebb n-1 karaktert olvas be a p[0],., p[n-
2] t�mbbe.
A get() az �tmeneti t�rban mindenk�ppen elhelyez egy 0 karaktert a beolvasott
karakterek
ut�n, �gy a p mutat�nak egy legal�bb n karakter m�retu t�mbre kell mutatnia. A
harmadik
param�ter (term) az olvas�st lez�r� karaktert hat�rozza meg. A h�romparam�teru
get() leggyakoribb felhaszn�l�si m�dja az, hogy beolvasunk egy .sort. egy
r�gz�tett m�retu
t�rba �s k�sobb innen haszn�ljuk fel karaktereit:
void f()
{
char buf[100];
cin >> buf; // gyan�s: t�lcsordulhat
cin.get(buf,100,'\n'); // biztons�gos
// ...
}
Ha a get() megtal�lja a lez�r� karaktert, az adatfolyamban hagyja, teh�t a
k�vetkezo bemeneti
muvelet ezt a karaktert kapja meg elsok�nt. Soha ne h�vjuk meg �jra a get()
f�ggv�nyt
a lez�r� karakter elt�vol�t�sa n�lk�l. Ha egy get() vagy getline() f�ggv�ny
egyetlen karaktert
sem olvas �s t�vol�t el az adatfolyamr�l megh�v�dik setstate(failbit), �gy a
k�vetkezo beolvas
�sok sikertelenek lesznek (vagy kiv�tel v�lt�dik ki, 21.3.6).
830 A standard k�nyvt�r
void subtle_error
{
char buf[256];
while (cin) {
cin.get(buf,256); // a sor beolvas�sa
cout << buf; // a sor ki�r�sa.
// Hopp�: elfelejtett�k elt�vol�tani cin-rol '\n'-t, a k�vetkezo get() sikertelen
lesz
}
}
Ez a p�lda j�l szeml�lteti, mi�rt �rdemes a get() helyett a getline() f�ggv�nyt
haszn�lnunk.
A getline() ugyanis pontosan �gy muk�dik, mint a megfelelo get(), de a lez�r�
karaktert is
elt�vol�tja az adatfolyamb�l:
void f()
{
char word[MAX_WORD][MAX_LINE]; // MAX_WORD darab t�mb,
// mindegyik MAX_LINE karaktert tartalmaz
int i = 0;
while(cin.getline(word[i++],MAX_LINE,'\n') && i<MAX_WORD);
// ...
}
Ha nem a hat�konys�g a legfontosabb, �rdemes string (�3.6, �20.3.15) objektumba
olvasnunk,
mert azzal elker�lhetj�k a leggyakoribb t�lcsordul�si, illetve helyfoglal�si
probl�m�-
kat. A get(), a getline() �s a read() f�ggv�nyre viszont az ilyen magas szintu
szolg�ltat�sok
megval�s�t�s�hoz sz�ks�g van. A nagyobb sebess�g �ra a viszonylag kusza fel�let,
de legal
�bb nem kell �jra megvizsg�lnunk a bemeneti adatfolyamot, ahhoz, hogy megtudjuk,
mi
szak�totta meg a beolvas�si muveletet; pontosan korl�tozhatjuk a beolvasand�
karakterek
sz�m�t �s �gy tov�bb.
A read(p,n) f�ggv�ny legfeljebb n karaktert olvas be a p[0], ., p[n-1] t�mbbe. A
read()
nem foglalkozik a bemeneten megjeleno lez�r� karakterekkel �s az eredm�nyt�mb
v�g�re
sem helyez 0 karaktert. Ez�rt k�pes t�nyleg n karaktert beolvasni (�s nem csak n-
1-t). Teh
�t a read() f�ggv�ny egyszeruen karaktereket olvas, �s nem pr�b�lja az eredm�nyt C
st�-
lus� karakterl�ncc� alak�tani.
Az ignore() f�ggv�ny ugyan�gy karaktereket olvas, mint a read(), de egy�ltal�n nem
t�rolja
azokat. Egy m�sik hasonl�s�g a read() f�ggv�nnyel, hogy t�nyleg k�pes n (�s nem n-
1)
darab karakter beolvas�s�ra. Az ignore() alap�rtelmez�s szerint egy karaktert
olvas be, teh
�t ha param�terek n�lk�l h�vjuk meg, akkor jelent�se .dobd el a k�vetkezo
karaktert..
21. Adatfolyamok 831
A getline() f�ggv�nyhez hasonl�an itt is megadhatunk egy lez�r� karaktert, amit
elt�vol�t
a bemeneti adatfolyamb�l, ha bele�tk�zik. Az ignore() alap�rtelmezett lez�r�
karaktere
a f�jlv�ge jel. Ezekn�l a f�ggv�nyekn�l nem vil�gos azonnal, hogy mi �ll�totta meg
az olvas
�st, �s n�ha m�g arra is neh�z eml�kezni, melyik olvas�si muveletn�l mi volt a
le�ll�si felt
�tel. Azt viszont mindig meg tudjuk k�rdezni, hogy el�rt�k-e m�r a f�jlv�ge jelet
(�21.3.3).
Hasonl� seg�ts�g, hogy a gcount() f�ggv�nnyel meg�llap�thatjuk, hogy a legut�bbi
form�-
zatlan bemeneti elj�r�s h�ny karaktert olvasott be az adatfolyamb�l:
void read_a_line(int max)
{
// ...
if (cin.fail()) { // Hopp�: hib�s bemeneti form�tum
cin.clear(); // a bemeneti jelzobitek t�rl�se (�21.3.3)
cin.ignore(max,';'); // ugr�s a pontosvesszore
if (!cin) {
// hopp�: el�rt�k az adatfolyam v�g�t
}
else if (cin.gcount()==max) {
// hopp�: max sz�m� karaktert beolvastunk
}
else {
// megtal�ltuk �s eldobtuk a pontosvesszot
}
}
}
Sajnos ha a megengedett legt�bb karaktert olvastuk be, nincs m�dunk annak
meg�llap�t�-
s�ra, hogy megtal�ltuk-e a lez�r� karaktert (utols� beolvasott karakterk�nt).
A param�ter n�lk�li get() a <cstdio> fej�llom�nyban szereplo getchar() f�ggv�ny
(�21.8)
<iostream> -beli megfeleloje. Egyszeruen beolvas egy karaktert �s visszaadja annak
sz�m-
�rt�k�t. Ezzel a megold�ssal semmit nem kell felt�teleznie az �ppen haszn�lt
karaktert�pusr
�l. Ha nincs beolvashat� karakter a get() adatfolyam�ban, akkor a megfelelo
f�jlv�ge jelet
(teh�t a traits_type::eof() karaktert) adja vissza, majd be�ll�tja az istream
objektum eof �llapot
�t (�21.3.3):
void f(unsigned char* p)
{
int i;
while((i = cin.get()) && i!=EOF) {
*p++ = i;
// ...
}
}
832 A standard k�nyvt�r
Az EOF az eof() f�ggv�ny �ltal visszaadott �rt�k a char t�pus szok�sos char_traits
oszt�ly�-
b�l. Az EOF �rt�ket az <iostream> fej�llom�ny hat�rozza meg. Teh�t e ciklus
helyett nyugodtan
�rhattuk volna a read(p, MAX_INT) utas�t�st, de tegy�k fel, hogy explicit ciklust
akartunk �rni, mert, mondjuk, minden beolvasott karaktert egyes�vel akartunk
l�tni. A C
nyelv egyik legnagyobb eross�g�nek tartj�k azt a lehetos�get, hogy karaktereket
olvashatunk
be, �s �gy d�nthet�nk, hogy semmit sem csin�lunk vel�k, r�ad�sul mindezt gyorsan
tehetj�k. Ez t�nyleg fontos �s al�becs�lt eross�g, �gy a C++ igyekszik ezt
megtartani.
A <cctype> szabv�nyos fej�llom�ny sok olyan f�ggv�nyt biztos�t, amelynek haszn�t
vehetj
�k a bemenet feldolgoz�s�ban (�20.4.2). Az eatwhite() f�ggv�ny p�ld�ul, amely az
�reshely karaktereket t�rli az adatfolyamb�l, a k�vetkezok�ppen defini�lhat�:
istream& eatwhite(istream& is)
{
char c;
while (is.get(c)) {
if (!isspace(c)) { // c �reshely karakter?
is.putback(c); // c visszarak�sa a bemenet �tmeneti t�r�ba
break;
}
}
return is;
}
Az is.putback(c) f�ggv�nyh�v�sra az�rt van sz�ks�g, hogy a c legyen a k�vetkezo
karakter,
amit az is adatfolyamb�l beolvasunk (�21.6.4).
21.3.5. Felhaszn�l�i t�pusok beolvas�sa
A felhaszn�l�i t�pusok beolvas�s�t pontosan ugyan�gy lehet megval�s�tani, mint
kimeneti
muveleteiket. Az egyetlen k�l�nbs�g, hogy a bemeneti muveletek eset�ben a m�sodik
param
�ternek nem-konstans referencia t�pus�nak kell lennie:
istream& operator>>(istream& s, complex& a)
/*
a complex t�pus lehets�ges bemeneti form�tumai ("f" lebegopontos sz�m)
f
( f )
( f , f )
*/
{
21. Adatfolyamok 833
double re = 0, im = 0;
char c = 0;
s >> c;
if (c == '(') {
s >> re >> c;
if (c == ',') s >> im >> c;
if (c != ')') s.clear(ios_base::failbit); // �llapot be�ll�t�sa
}
else {
s.putback(c);
s >> re;
}
if (s) a = complex(re,im);
return s;
}
A nagyon kev�s hibakezelo utas�t�s ellen�re ez a programr�szlet szinte minden
hibat�pust
k�pes kezelni. A lok�lis c v�ltoz�nak az�rt adunk kezdo�rt�ket, hogy ha az elso >>
muvelet
sikertelen, nehogy v�letlen�l pont a ( karakter legyen benne. Az adatfolyam
�llapot�nak
ellenorz�s�re a f�ggv�ny v�g�n az�rt van sz�ks�g, mert az a param�ter �rt�k�t csak
akkor
v�ltoztathatjuk meg, ha a kor�bbi muveleteket sikeresen v�grehajtottuk. Ha
form�z�si hiba
t�rt�nik az adatfolyam �llapota failbit lesz. Az�rt nem badbit, mert maga az
adatfolyam nem
s�r�lt meg. A felhaszn�l� a clear() f�ggv�nnyel alap�llapotba helyezheti az
adatfolyamot �s
tov�bbl�pve �rtelmes adatokat nyerhet onnan.
Az adatfolyam �llapot�nak be�ll�t�s�ra szolg�l� f�ggv�ny neve clear(), mert
�ltal�ban arra
haszn�ljuk, hogy az adatfolyam �llapot�t good() �rt�kre �ll�tsuk. Az
ios_base::clear()
(�21.3.3) param�ter�nek alap�rtelmezett �rt�ke ios_base::goodbit.
21.3.6. Kiv�telek
Nagyon k�nyelmetlen minden egyes I/O muvelet ut�n k�l�n ellenorizni, hogy sikeres
volte,
ez�rt nagyon gyakori hiba, hogy elfelejt�nk egy ellenorz�st ott, ahol felt�tlen�l
sz�ks�g
van r�. A kimeneti muveleteket �ltal�ban nem ellenorzik, annak ellen�re, hogy n�ha
ott is
elofordulhat hiba.
Egy adatfolyam �llapot�nak k�zvetlen megv�ltoztat�s�ra csak a clear() f�ggv�nyt
haszn�lhatjuk.
Ez�rt ha �rtes�lni akarunk az adatfolyam �llapot�nak megv�ltoz�s�r�l, el�g
nyilv�nval
� m�dszer, hogy a clear() f�ggv�nyt kiv�telek kiv�lt�s�ra k�rj�k. Az ios_base
oszt�ly
exceptions() tagf�ggv�nye pontosan ezt teszi:
834 A standard k�nyvt�r
template <class Ch, class Tr = char_traits<Ch> >
class basic_ios : public ios_base {
public:
// ...
class failure; // kiv�teloszt�ly (l�sd �14.10)
iostate exceptions() const; // kiv�tel-�llapot kiolvas�sa
void exceptions(iostate except); // kiv�tel-�llapot be�ll�t�sa
// ...
};
A k�vetkezo utas�t�ssal p�ld�ul el�rhetj�k, hogy a clear() egy ios_base::failure
kiv�telt v�ltson
ki, ha a cout adatfolyam bad, fail vagy eof �llapotba ker�l, vagyis ha valamelyik
muvelet
nem hib�tlanul fut le:
cout.exceptions(ios_base::badbit|ios_base::failbit|ios_base::eofbit);
Ha sz�ks�g van r�, a cout vizsg�lat�val pontosan meg�llap�thatjuk, milyen probl�ma
t�rt
�nt. Ehhez hasonl�an a k�vetkezo utas�t�ssal azokat a ritk�nak egy�ltal�n nem
nevezheto
eseteket dolgozhatjuk fel, amikor a beolvasni k�v�nt adatok form�tuma nem
megfelelo, �s
ennek k�vetkezt�ben a bemeneti muvelet nem ad vissza �rt�ket:
cin.exceptions(ios_base::badbit|ios_base::failbit);
Ha az exceptions() f�ggv�nyt param�terek n�lk�l h�vjuk meg, akkor azokat az I/O
�llapotjelz
oket adja meg, amelyek kiv�telt v�ltanak ki:
void print_exceptions(ios_base& ios)
{
ios_base::iostate s = ios.exceptions();
if (s&ios_base::badbit) cout << "bad kiv�telek";
if (s&ios_base::failbit) cout << "fail kiv�telek";
if (s&ios_base::eofbit) cout << "eof kiv�telek";
if (s == 0) cout << "nincs kiv�tel";
}
Az I/O kiv�telek leggyakoribb felhaszn�l�si ter�lete az, hogy a ritk�n elofordul�
(ez�rt k�nnyen
elfelejtheto) hib�kat kezelj�k. M�sik fontos feladatuk a ki- �s bemenet vez�rl�se
lehet:
21. Adatfolyamok 835
void readints(vector<int>& s) // nem a kedvenc st�lusom!
{
ios_base::iostate old_state = cin.exceptions(); // menti a kiv�tel-�llapotot
cin.exceptions(ios_base::eofbit); // eof kiv�telt v�lt ki
for (;;)
try {
int i;
cin>>i;
s.push_back(i);
}
catch(ios_base::failure) {
// rendben: el�rt�k a f�jl v�g�t
}
cin.exceptions(old_state); // kiv�tel-�llapot vissza�ll�t�sa
}
A kiv�telek ilyen form�ban val� felhaszn�l�sakor felmer�l a k�rd�s, nevezhetj�k-e
az adott
helyzetet hib�nak vagy t�nyleg kiv�teles helyzetnek. �ltal�ban mindk�t k�rd�sre
ink�bb
a nem v�laszt adjuk, ez�rt �gy gondolom, c�lszerubb az adatfolyam �llapot�t
k�zvetlen�l
vizsg�lni. Amit egy f�ggv�ny belsej�ben, lok�lis vez�rl�si szerkezetekkel
kezelhet�nk, azt
a kiv�telek sem kezelik jobban.
21.3.7. Adatfolyamok �sszek�t�se
A basic_ios oszt�ly tie() f�ggv�nye arra haszn�lhat�, hogy kapcsolatot l�tes�ts�nk
egy
istream �s egy ostream k�z�tt:
template <class Ch, class Tr = char_traits<Ch> >
class std::basic_ios : public ios_base {
// ...
basic_ostream<Ch,Tr>* tie() const; // mutat� �sszek�t�tt adatfolyamokra
basic_ostream<Ch,Tr>* tie(basic_ostream<Ch,Tr>* s); // *this hozz�k�t�se s-hez
// ...
};
836 A standard k�nyvt�r
Vegy�k p�ld�ul az al�bbi programr�szletet:
string get_passwd()
{
string s;
cout << "Jelsz�: ";
cin >> s;
// ...
}
Hogyan bizonyosodhatn�nk meg arr�l, hogy a Jelsz�: sz�veg megjelent-e a k�pernyon,
miel
ott a bemeneti muveletet v�grehajtjuk? A cout adatfolyamra k�ld�tt kimenet
�tmeneti t�rba
ker�l, �gy ha a cin �s a cout f�ggetlen egym�st�l, a Jelsz� esetleg mindaddig nem
jelenik
meg a k�pernyon, am�g a kimeneti t�r meg nem telik. A megold�st az jelenti, hogy
a cout adatfolyamot hozz�k�tj�k a cin adatfolyamhoz a cin.tie(&cout) utas�t�ssal.
Ha egy ostream objektumot �sszek�t�nk egy istream objektummal, az ostream mindig
ki-
�r�l, amikor egy bemeneti muvelet alulcsordul�st okoz az istream adatfolyamban,
azaz
amikor egy bemeneti feladat v�grehajt�s�hoz �j karakterekre van sz�ks�g a kijel�lt
bemeneti
eszk�zrol. Teh�t ilyenkor a
cout << "Jelsz�: ";
cin >> s;
utas�t�ssorozat egyen�rt�ku az al�bbival:
cout << "Jelsz�: ";
cout.flush();
cin >> s;
Adott idoben minden adatfolyamhoz legfeljebb egy ostream objektum k�theto. Az
s.tie(0)
utas�t�ssal lev�laszthatjuk az s objektumhoz k�t�tt adatfolyamot (ha volt ilyen).
A t�bbi
olyan adatfolyam-f�ggv�nyhez hasonl�an, melyek �rt�ket �ll�tanak be, a tie(s) is a
kor�bbi
�rt�ket adja vissza, teh�t a legut�bb ide k�t�tt adatfolyamot, vagy ha ilyen
nincs, akkor a 0
�rt�ket. Ha a tie() f�ggv�nyt param�terek n�lk�l h�vjuk meg, akkor egyszeruen
visszakapjuk
az aktu�lis �rt�ket, annak megv�ltoztat�sa n�lk�l.
A szabv�nyos adatfolyamok eset�ben a cout hozz� van k�tve a cin bemenethez, a
wcout
pedig a wcin adatfolyamhoz. A cerr adatfolyamot felesleges lenne b�rmihez is
hozz�k�tni,
mivel ehhez nincs �tmeneti t�r, a clog pedig nem v�r felhaszn�l�i k�zremuk�d�st.
21. Adatfolyamok 837
21.3.8. Orszemek
Amikor a << �s a >> oper�tort a complex t�pusra haszn�ltuk, egy�ltal�n nem
foglalkoztunk
az �sszek�t�tt adatfolyamok (�21.3.7) k�rd�s�vel, vagy azzal, hogy az adatfolyam
�llapot�-
nak megv�ltoz�sa kiv�teleket okoz-e (�21.3.6). Egyszeruen azt felt�telezt�k (�s
nem ok n�lk
�l), hogy a k�nyvt�r �ltal k�n�lt f�ggv�nyek figyelnek helyett�nk ezekre a
probl�m�kra.
De hogyan k�pesek erre? N�h�ny tucat ilyen f�ggv�nnyel kell megbirk�znunk, �gy ha
olyan
bonyolult elj�r�sokat kellene k�sz�ten�nk, amely az �sszek�t�tt adatfolyamokkal, a
helyi
saj�toss�gokkal (locale, �21.7, �D), a kiv�telekkel, �s egyebekkel is
foglalkoznak, akkor
igen kusza k�dot kapn�nk.
A megold�st a sentry (.orszem.) oszt�ly bevezet�se jelenti, amely a k�z�s
k�dr�szleteket
tartalmazza. Azok a r�szek, melyeknek elsok�nt kell lefutniuk (a .prefix k�d.,
p�ld�ul egy
lek�t�tt adatfolyam ki�r�t�se), a sentry konstruktor�ban kaptak helyet. Az
utols�k�nt fut�
sorokat (a .suffix k�dokat., p�ld�ul az �llapotv�ltoz�sok miatt elv�rt kiv�telek
kiv�lt�s�t)
a sentry destruktora hat�rozza meg:
template <class Ch, class Tr = char_traits<Ch> >
class basic_ostream : virtual public basic_ios<Ch,Tr> {
// ...
class sentry;
// ...
};
template <class Ch, class Tr = char_traits<Ch> >
class basic_ostream<Ch,Tr>::sentry {
public:
explicit sentry(basic_ostream<Ch,Tr>& s);
~sentry();
operator bool();
// ...
};
Teh�t egy �ltal�nos k�dot �rtunk, melynek seg�ts�g�vel az egyes f�ggv�nyek a
k�vetkezo
form�ba �rhat�k:
template <class Ch, class Tr = char_traits<Ch> >
basic_ostream<Ch,Tr>& basic_ostream<Ch,Tr>::operator<<(int i)
{
sentry s(*this);
if (!s) { // ellenorz�s, minden rendben van-e a ki�r�s megkezd�s�hez
setstate(failbit);
return *this;
}
838 A standard k�nyvt�r
// az int ki�r�sa
return *this;
}
A konstruktorok �s a destruktorok ilyen jellegu felhaszn�l�sa �ltal�nos az elotag
(prefix) �s ut�-
tag (suffix) k�dr�szletek beilleszt�s�hez, �s nagyon sok helyzetben alkalmazhat�
m�dszer.
Term�szetesen a basic_istream hasonl� sentry tagoszt�llyal rendelkezik.
21.4. Form�z�s
A �21.2. pontban bemutatott p�ld�k mind abba a kateg�ri�ba tartoztak, amit
�ltal�nosan
form�zatlan kimenetnek (unformatted output) nevez�nk. Ez azt jelenti, hogy az
objektumot
�gy alak�tottuk karaktersorozatt�, hogy csak alap�rtelmezett szab�lyokat
haszn�ltunk.
A programoz�knak gyakran enn�l r�szletesebb vez�rl�si lehetos�gekre van sz�ks�g�k.
N�-
ha p�ld�ul meg kell hat�roznunk, hogy a kimenet mekkora ter�letet haszn�ljon, vagy
hogy
a sz�mok milyen form�ban jelenjenek meg. Az ehhez hasonl� t�nyezok vez�rl�s�re a
bemenet
eset�ben is sz�ks�g lehet.
A ki- �s bemenet form�z�s�t vez�rlo eszk�z�k a basic_ios oszt�lyban, illetve annak

ios_base b�zisoszt�ly�ban kaptak helyet. A basic_ios p�ld�ul inform�ci�kat


tartalmaz
a sz�mrendszerrol (nyolcas, t�zes vagy tizenhatos), amit eg�sz sz�mok ki�r�sakor
�s beolvas
�sakor haszn�l a rendszer, vagy a lebegopontos sz�mok pontoss�g�r�l �s �gy tov�bb.

Az ezen adatfolyam-szintu (minden adatfolyamra k�l�n be�ll�that�) v�ltoz�k


lek�rdez�s�-
re �s be�ll�t�s�ra szolg�l� f�ggv�nyek szint�n ebben az oszt�lyban kaptak helyet.
A basic_ios b�zisoszt�lya a basic_istream �s a basic_ostream oszt�lynak, �gy a
form�z�s vez
�rl�se minden adatfolyamra k�l�n adhat� meg.
21. Adatfolyamok 839
21.4.1. Form�z�si �llapot
A ki- �s bemenet form�z�s�t n�h�ny jelzobit �s n�h�ny eg�sz �rt�k vez�rli, melyek
az adatfolyamok
ios_base b�zisoszt�ly�ban szerepelnek:
class ios_base {
public:
// ...
// form�z�sjelzok nevei:
typedef megval�s�t�s_f�ggo1 fmtflags;
static const fmtflags
skipws, // �reshelyek �tl�p�se a bemeneten
left, // mezoigaz�t�s: felt�lt�s az �rt�k ut�n
right, // felt�lt�s az �rt�k elott
internal, // felt�lt�s elojel �s �rt�k k�z�tt
boolalpha, // a true �s false szimbolikus megjelen�t�se
dec, // sz�mrendszer alapja eg�szekn�l: 10 (decim�lis)
hex, // 16 (hexadecim�lis)
oct, // 8 (okt�lis)
scientific, // lebegopontos jel�l�s: d.ddddddEdd
fixed, // dddd.dd
showbase, // ki�r�skor okt�lisak el� 0, hexadecim�lisok el� 0x elotag
showpoint, // a z�r� null�k ki�r�sa
showpos, // '+' a pozit�v eg�szek el�
uppercase, // 'E', 'X' alkalmaz�sa ('e', 'x' helyett)
adjustfield, // mezoigaz�t�ssal kapcsolatos jelzo (�21.4.5)
basefield, // eg�sz sz�mrendszer alapj�val kapcsolatos jelzo (�21.4.2)
floatfield; // lebegopontos kimenettel kapcsolatos jelzo (�21.4.3)
fmtflags unitbuf; // minden kimenet ut�n az �tmeneti t�r �r�t�se
fmtflags flags() const; // jelzobitek kiolvas�sa
fmtflags flags(fmtflags f); // jelzobitek be�ll�t�sa
fmtflags setf(fmtflags f) { return flags(flags()|f); } // jelzobit hozz�ad�sa
840 A standard k�nyvt�r
// a jelzobitek t�rl�se �s be�ll�t�sa a maszkban
fmtflags setf(fmtflags f, fmtflags mask) { return flags((flags()&~mask)|(f&mask));
}
void unsetf(fmtflags mask) { flags(flags()&~mask); } // jelzobitek t�rl�se
// ...
};
Az egyes jelzobitek (flag) �rt�ke az adott nyelvi v�ltozatt�l f�gg, �gy mindig a
szimbolikus
neveket haszn�ljuk a konkr�t sz�m�rt�kek helyett, m�g akkor is, ha az �ltalunk
haszn�lt �rt
�kek v�letlen�l �ppen megfeleloen muk�dnek.
Egy fel�letet jelzok sorozat�val, illetve azokat be�ll�t� �s lek�rdezo
f�ggv�nyekkel meghat
�rozni idotakar�kos, de kicsit r�gim�di m�dszer. Legfobb er�nye, hogy a
felhaszn�l� a lehet
os�geket �ssze�p�theti:
const ios_base::fmtflags my_opt = ios_base::left|ios_base::oct|ios_base::fixed;
Ez lehetov� teszi, hogy egy f�ggv�nynek be�ll�t�sokat adjunk �t, �s akkor
kapcsoljuk be
azokat, amikor sz�ks�g van r�juk:
void your_function(ios_base::fmtflags opt)
{
ios_base::fmtflags old_options = cout.flags(opt); // r�gi be�ll�t�sok ment�se,
�jak be�ll�t�sa
// ...
cout.flags(old_options); // vissza�ll�t�s
}
void my_function()
{
your_function(my_opt);
// ...
}
A flags() f�ggv�ny az eddig �rv�nyben levo be�ll�t�sokat adja vissza.
Ha k�pesek vagyunk az �sszes tulajdons�g egy�ttes �r�s�ra �s olvas�s�ra, egyes�vel
is be-
�ll�thatjuk azokat:
myostream.flags(myostream.flags()|ios_base::showpos);
Ezen utas�t�s hat�s�ra a myostream adatfolyam minden pozit�v sz�m elott egy +
jelet fog
megjelen�teni; m�s be�ll�t�sok nem v�ltoznak meg. Elosz�r beolvassuk a r�gi
be�ll�t�sokat,
21. Adatfolyamok 841
majd be�ll�tjuk a showpos tulajdons�got �gy, hogy az eredeti sz�mhoz a bitenk�nti
vagy
muvelettel hozz�kapcsoljuk ezt az �rt�ket. A setf() f�ggv�ny pontosan ugyanezt
teszi, teh�t
a fenti p�ld�val teljesen egyen�rt�ku az al�bbi sor:
myostream.setf(ios_base::showpos);
Egy jelzo mindaddig megtartja �rt�k�t, am�g azt meg nem v�ltoztatjuk.
A ki- �s bemeneti tulajdons�gok vez�rl�se a jelzobitek k�zvetlen be�ll�t�s�val
igen nyers
megold�s �s k�nnyen hib�khoz vezethet. Az egyszerubb esetekben a m�dos�t�k
(manipulator) (�21.4.6) tiszt�bb fel�letet adnak. A jelzobitek haszn�lata egy
adatfolyam �llapot
�nak vez�rl�s�re a megval�s�t�si m�dszerek tanulm�nyoz�s�hoz megfelel, a
fel�lettervez
�shez m�r kev�sb�.
21.4.1.1. Form�z�si �llapot lem�sol�sa
A copyfmt() f�ggv�ny seg�ts�g�vel egy adatfolyam teljes form�z�si �llapot�t
lem�solhatjuk:
template <class Ch, class Tr = char_traits<Ch> >
class basic_ios : public ios_base {
public:
// ...
basic_ios& copyfmt(const basic_ios& f);
// ...
};
Az adatfolyam �tmeneti t�r�n (�21.6) �s annak �llapot�n k�v�l a copyfmt() minden
�llapottulajdons
�got �tm�sol, teh�t a kiv�telkezel�si m�dot (�21.3.6) �s a felhaszn�l� �ltal
megadott
tov�bbi be�ll�t�sokat is (�21.7.1).
21.4.2. Eg�sz kimenet
A .bitenk�nti vagy. haszn�lata egy �j be�ll�t�s megad�s�hoz a flags() �s setf()
f�ggv�nyek
seg�ts�g�vel csak akkor haszn�lhat�, ha az adott tulajdons�got egy bit hat�rozza
meg. Nem
ez a helyzet azonban egy olyan jellemzon�l, mint p�ld�ul az eg�szek ki�r�s�hoz
haszn�lt
sz�mrendszer vagy a lebegopontos sz�mok kimeneti form�tuma. Az ilyen tulajdons�gok

eset�ben az �rt�k, amely egy adott st�lust �br�zol, nem fogalmazhat� meg egyetlen
bittel
vagy ak�r egym�st�l f�ggetlen bitek sorozat�val.
842 A standard k�nyvt�r
Az <iostream> fej�llom�nyban alkalmazott megold�s az, hogy a setf() f�ggv�ny olyan
v�ltozat
�t hat�rozza meg, amelynek egy m�sodik, .�lparam�tert. is meg kell adnunk. Ez a
param
�ter hat�rozza meg, milyen tulajdons�got akarunk be�ll�tani az �j �rt�kkel:
cout.setf(ios_base::oct,ios_base::basefield); // okt�lis
cout.setf(ios_base::dec,ios_base::basefield); // decim�lis
cout.setf(ios_base::hex,ios_base::basefield); // hexadecim�lis
Ezek az utas�t�sok az eg�szek sz�mrendszer-alapj�t �ll�tj�k be, an�lk�l, hogy az
adatfolyam
�llapot�nak b�rmely m�s r�sz�t megv�ltoztatn�k. Az alapsz�m mindaddig v�ltozatlan
marad,
am�g meg nem v�ltoztatjuk. P�ld�ul az al�bbi utas�t�ssorozat eredm�nye 1234 1234
2322 2322 4d2 4d2.
cout << 1234 << ' ' << 1234 << ' '; // alap�rtelmezett: decim�lis
cout.setf(ios_base::oct,ios_base::basefield); // okt�lis
cout << 1234 << ' ' << 1234 << ' ';
cout.setf(ios_base::hex,ios_base::basefield); // hexadecim�lis
cout << 1234 << ' ' << 1234 << ' ';
Ha az eredm�nyrol meg kell tudnunk �llap�tani, hogy melyik sz�m milyen
sz�mrendszerben
�rtendo, a showbase be�ll�t�st haszn�lhatjuk. Teh�t ha az elobbi utas�t�sok el�
besz�rjuk a
cout.setf(ios_base::showbase);
utas�t�st, akkor az 1234 1234 02322 02322 0x4d2 0x4d2 sz�msorozatot kapjuk. A
szabv�-
nyos m�dos�t�k (manipulator) (�21.4.6.2) eleg�nsabb megold�st k�n�lnak az eg�sz
sz�mok
ki�r�s�hoz haszn�lt sz�mrendszer be�ll�t�s�ra.
21.4.3. Lebegopontos sz�m kimenet
A lebegopontos sz�mok kimenet�t k�t t�nyezo befoly�solja: a form�tum (format) �s a
pontoss
�g (precision).
� Az �ltal�nos (general) form�tum lehetov� teszi a megval�s�t�s sz�m�ra, hogy
olyan
sz�mform�tumot haszn�ljon, amely a rendelkez�sre �ll� ter�leten a leheto legjobban

�br�zolja a lebegopontos �rt�ket. A pontoss�g a megjeleno sz�mjegyek maxim


�lis sz�m�t hat�rozza meg. Ez a jellemzo a printf() f�ggv�ny %g be�ll�t�s�nak
felel meg (�21.8).
21. Adatfolyamok 843
� A tudom�nyos (scientific) form�tumban egy sz�mjegy szerepel a tizedespont elott,

�s egy kitevo (exponens) hat�rozza meg a sz�m nagys�grendj�t. A pontoss�g ez


esetben a tizedespont ut�n �ll� sz�mjegyek maxim�lis sz�m�t jelenti. Ezt az esetet

a printf() f�ggv�ny %e be�ll�t�sa val�s�tja meg.


� A fixpontos (fixed) form�tum a sz�mot eg�szr�sz, tizedespont, t�rtr�sz form�ban
jelen
�ti meg. A pontoss�g most is a tizedespont ut�n �ll� sz�mjegyek sz�m�nak maximum
�t adja meg. A printf() f�ggv�ny %f be�ll�t�sa viselkedik �gy.
A lebegopontos sz�mok kimeneti form�tum�t az �llapotm�dos�t� f�ggv�nyek (state
manipulator function) seg�ts�g�vel szab�lyozhatjuk. Ezek felhaszn�l�s�val a
lebegopontos
�rt�kek megjelen�t�s�t �gy �ll�thatjuk be, hogy az adatfolyam �llapot�nak m�s
r�szeit nem
befoly�soljuk:
cout << "Alap�rtelmezett:\t" << 1234.56789 << '\n';
cout.setf(ios_base::scientific,ios_base::floatfield); // tudom�nyos form�tum
haszn�lata
cout << "Tudom�nyos:\t" << 1234.56789 << '\n';
cout.setf(ios_base::fixed,ios_base::floatfield); // fixpontos form�tum haszn�lata
cout << "Fixpontos:\t" << 1234.56789 << '\n';
cout.setf(0,ios_base::floatfield); // alap�rtelmez�s vissza�ll�t�sa
// (�ltal�nos form�tum)
cout << "Alap�rtelmezett:\t" << 1234.56789 << '\n';
Az eredm�ny a k�vetkezo lesz:
default: 1234.57
scientific: 1.234568e+03
fixed: 1234.567890
default: 1234.57
A pontoss�g alap�rtelmezett �rt�ke minden form�tum eset�ben 6, amit az ios_base
oszt�ly
k�l�n tagf�ggv�ny�vel m�dos�thatunk:
class ios_base {
public:
// ...
streamsize precision() const; // pontoss�g lek�rdez�se
streamsize precision(streamsize n); // pontoss�g be�ll�t�sa (�s a r�gi pontoss�g
lek�rdez�se)
// ...
};
844 A standard k�nyvt�r
A precision() f�ggv�ny megh�v�s�val minden lebegopontos I/O muvelet pontoss�g�t
megv
�ltoztatjuk az adatfolyamban a f�ggv�ny k�vetkezo megh�v�s�ig. Ez�rt a
cout.precision(8);
cout << 1234.56789 << ' ' << 1234.56789 << ' ' << 123456 << '\n';
cout.precision(4);
cout << 1234.56789 << ' ' << 1234.56789 << ' ' << 123456 << '\n';
utas�t�ssorozat eredm�nye a k�vetkezo lesz:
1234.5679 1234.5679 123456
1235 1235 123456
A p�ld�ban k�t dolgot figyelhet�nk meg: az egyik, hogy a lebegopontos �rt�kek
kerek�tve
jelennek meg, nem egyszeruen lev�gva, a m�sik, hogy a precision() az eg�sz �rt�kek
megjelen
�t�s�re nincs hat�ssal.
Az uppercase jelzobit (�21.4.1) azt hat�rozza meg, hogy a tudom�nyos form�tumban e
vagy
E betu jel�lje a kitevot.
A m�dos�t�k (manipulator) eleg�nsabb megold�st k�n�lnak a lebegopontos sz�mok
kimeneti
form�tum�nak be�ll�t�s�ra (�21.4.6.2).
21.4.4. Kimeneti mezok
Gyakran arra van sz�ks�g�nk, hogy egy kimeneti sor adott ter�let�t t�lts�k fel
sz�veggel.
Ilyenkor pontosan n karaktert akarunk haszn�lni, kevesebbet semmik�pp (t�bbet
pedig
csak akkor, ha a sz�veg nem f�r el a meghat�rozott ter�leten). Ehhez meg kell
adnunk a ter
�let sz�less�g�t �s a kit�lto karaktert:
class ios_base {
public:
// ...
streamsize width() const; // mezosz�less�g lek�rdez�se
streamsize width(streamsize wide); // mezosz�less�g be�ll�t�sa
// ...
};
template <class Ch, class Tr = char_traits<Ch> >
class basic_ios : public ios_base {
public:
// ...
21. Adatfolyamok 845
Ch fill() const; // kit�lto karakter lek�rdez�se
Ch fill(Ch ch); // kit�lto karakter be�ll�t�sa
// ...
};
A width() f�ggv�ny a kimeno karakterek legkisebb sz�m�t hat�rozza meg a standard
k�nyvt�r k�vetkezo olyan << muvelet�ben, amellyel sz�m�rt�ket, logikai �rt�ket, C
st�lus�
karakterl�ncot, karaktert, mutat�t (�21.2.1), string objektumot (�20.3.15) vagy
bitfield v�ltoz
�t (�17.5.3.3) �runk ki:
cout.width(4);
cout << 12;
Ez az utas�t�s a 12 sz�mot k�t sz�k�z karakter ut�n �rja ki.
A kit�lto karaktert a fill() f�ggv�ny seg�ts�g�vel adhatjuk meg:
cout.width(4);
cout.fill('#');
cout << "ab";
Az eredm�ny ##ab lesz.
Az alap�rtelmezett kit�lto karakter a sz�k�z, az alap�rtelmezett pontoss�g pedig
0, ami
annyi karaktert jelent, amennyire sz�ks�g van. A kimeneti mezo m�ret�t teh�t a
k�vetkezo
utas�t�ssal �ll�thatjuk vissza alap�rtelmezett �rt�k�re:
cout.width(0); // "annyi karakter, amennyi csak kell"
A width(n) utas�t�ssal a ki�rhat� karakterek legkisebb sz�m�t n-re �ll�tjuk. Ha
enn�l t�bb
karaktert adunk meg, akkor azok mind megjelennek:
cout.width(4);
cout << "abcdef";
Az eredm�ny abcdef lesz, nem pedig csak abcd. Ez az�rt van �gy, mert �ltal�ban
jobb
a megfelelo �rt�ket cs�nya form�ban megkapni, mint a rossz �rt�ket sz�pen igaz�tva
(l�sd
m�g �21.10[21]).
846 A standard k�nyvt�r
A width(n) f�ggv�nyh�v�s csak a k�zvetlen�l ut�na k�vetkezo << kimeneti muveletre
vonatkozik:
cout.width(4);
cout.fill('#');
cout << 12 << ':' << 13;
Az eredm�ny csak ##12:13 lesz �s nem ##12###:##13, ami akkor jelenne meg, ha
a width(4) minden k�sobbi muveletre vonatkozna. Ha a width() f�ggv�nyt t�bb,
egym�s
ut�ni kimeneti muveletre is alkalmazni szeretn�nk, k�nytelenek lesz�nk minden
egyes �rt
�khez k�l�n-k�l�n megadni.
A szabv�nyos m�dos�t�k (modifier) (�21.4.6.2) eleg�nsabb megold�st k�n�lnak a
kimeneti
mezok m�ret�nek szab�lyoz�s�ra is.
21.4.5. Mezok igaz�t�sa
A karakterek mezon bel�li igaz�t�s�t (adjustment) a setf() f�ggv�ny megh�v�s�val
�ll�thatjuk
be:
cout.setf(ios_base::left,ios_base::adjustfield); // bal
cout.setf(ios_base::right,ios_base::adjustfield); // jobb
cout.setf(ios_base::internal,ios_base::adjustfield); // belso
Ezek az utas�t�sok az ios_base::width() f�ggv�nnyel meghat�rozott kimeneti mezon
bel�l
adj�k meg az igaz�t�st, az adatfolyam egy�b be�ll�t�saira nincsenek hat�ssal.
Az igaz�t�st a k�vetkezok�ppen haszn�lhatjuk.
cout.fill('#');
cout << '(';
cout.width(4);
cout << -12 << "),(";
cout.width(4);
cout.setf(ios_base::left,ios_base::adjustfield);
cout << -12 << "),(";
cout.width(4);
cout.setf(ios_base::internal,ios_base::adjustfield);
cout << -12 << ")";
21. Adatfolyamok 847
Az eredm�ny: (#-12), (-12#), (-#12). Az internal be�ll�t�s a kit�lto karaktereket
az elojel �s az
�rt�k k�z� helyezi. A p�ld�b�l l�thatjuk, hogy az alap�rtelmezett be�ll�t�s a
jobbra igaz�t�s.
21.4.6. M�dos�t�k
A standard k�nyvt�r szeretn� megk�m�lni a programoz�t att�l, hogy az adatfolyamok
�llapot
�t jelzobiteken kereszt�l �ll�tsa be, ez�rt k�l�n f�ggv�nyeket k�n�l ezen feladat
megold
�s�hoz. Az alap�tlet az, hogy a ki�rt vagy beolvasott objektumok k�z�tt adjuk meg
azokat
a muveleteket is, melyek az adatfolyam �llapot�t megv�ltoztatj�k. Az al�bbi
utas�t�ssal p�ld
�ul a kimenet �tmeneti t�r�nak azonnali ki�r�t�s�re sz�l�thatjuk fel az
adatfolyamot:
cout << x << flush << y << flush;
A megfelelo helyeken a cout.flush() f�ggv�ny fut le. Ezt az �tletet �gy
val�s�thatjuk meg,
hogy egy olyan << v�ltozatot k�sz�t�nk, amely egy f�ggv�nyre hivatkoz� mutat�t v�r
param
�terk�nt �s t�rzs�ben lefuttatja a hivatkozott f�ggv�nyt:
template <class Ch, class Tr = char_traits<Ch> >
class basic_ostream : virtual public basic_ios<Ch,Tr> {
public:
// ...
basic_ostream& operator<<(basic_ostream& (*f)(basic_ostream&)) { return
f(*this); }
basic_ostream& operator<<(ios_base& (*f)(ios_base&));
basic_ostream& operator<<(basic_ios<Ch,Tr>& (*f)(basic_ios<Ch,Tr>&));
// ...
};
Ahhoz, hogy ez a megold�s muk�dj�n, a (mutat�k�nt �tadott) f�ggv�nynek nem szabad
tagf�ggv�nynek lennie (legfeljebb statikus tagf�ggv�nynek), �s a megfelelo
t�pussal kell
rendelkeznie. Ez�rt a flush() f�ggv�nyt p�ld�ul a k�vetkezok�ppen kell
meghat�roznunk:
template <class Ch, class Tr = char_traits<Ch> >
basic_ostream<Ch,Tr>& flush(basic_ostream<Ch,Tr>& s)
{
return s.flush(); // az ostream oszt�ly flush() tagf�ggv�ny�nek megh�v�sa
}
Ezen deklar�ci�k ut�n a
cout << flush;
848 A standard k�nyvt�r
utas�t�s egyen�rt�ku lesz a
cout.operator<<(flush);
utas�t�ssal, ami pedig megh�vja a
flush(cout);
f�ggv�nyt, �gy v�g�l a
cout.flush();
ker�l v�grehajt�sra.
A teljes elj�r�s ford�t�si idoben t�rt�nik, �gy lehetov� teszi, hogy a
basic_ostream::flush()
f�ggv�nyt cout<<flush form�ban h�vjuk meg. Nagyon sok olyan muvelet van, amelyet
k�zvetlen
�l egy ki- vagy bemeneti muvelet elott vagy ut�n akarunk v�grehajtani:
cout << x;
cout.flush();
cout << y;
unset(ios_base::skipws); // ne ugorjuk �t az �reshelyeket
cin >> x;
Ha ezeket a muveleteket k�l�n utas�t�sokk�nt kell megfogalmaznunk, a muveletek
k�z�tti
kapcsolatok kev�sb� fognak l�tsz�dni, m�rpedig az ilyen logikai kapcsolatok
elveszt�se
erosen rontja a program olvashat�s�g�t. A m�dos�t�k (manipulator) lehetov� teszik,
hogy
az olyan muveleteket, mint a flush() �s a noskipws(), k�zvetlen�l a ki- vagy
bemeneti mu-
veletek list�j�ban helyezz�k el:
cout << x << flush << y << flush;
cin >> noskipws >> x;
Megjegyzendo, hogy a m�dos�t�k az std n�vt�rhez tartoznak, ez�rt minos�ten�nk kell
azokat,
amennyiben az std nem r�sze az adott hat�k�rnek:
std::cout << endl; // hiba: endl nincs a hat�k�rben
std::cout << std::endl; // rendben
21. Adatfolyamok 849
Term�szetesen a basic_istream a m�dos�t�k sz�m�ra is ugyan�gy biztos�tja a >>
oper�torokat,
mint a basic_ostream:
template <class Ch, class Tr = char_traits<Ch> >
class basic_istream : virtual public basic_ios<Ch,Tr> {
public:
// ...
basic_istream& operator>>(basic_istream& (*pf)(basic_istream&));
basic_istream& operator>>(basic_ios<Ch,Tr>& (*pf)(basic_ios<Ch,Tr>&));
basic_istream& operator>>(ios_base& (*pf)(ios_base&));
// ...
};
21.4.6.1. M�dos�t�k, melyek param�tereket v�rnak
Nagyon hasznosak lenn�nek az olyan m�dos�t�k is, melyeknek param�tereket is �t
tudunk
adni. P�ld�ul j� lenne, ha le�rhatn�nk az al�bbi sort, �s vele az angle
lebegopontos v�ltoz�
megjelen�t�s�t 4 jegy pontoss�g�ra �ll�thatn�nk:
cout << setprecision(4) << angle;
Ennek el�r�s�hez a setprecision-nek egy objektumot kell visszaadnia, amelynek a 4
kezdo-
�rt�ket adjuk, �s amely megh�vja a cout::setprecision(4) f�ggv�nyt. Az ilyen
m�dos�t�k f�ggv
�nyobjektumok, amelyeket a () helyett a << oper�tor h�v meg. A f�ggv�nyobjektum
pontos
t�pusa az adott megval�s�t�st�l f�gg; egy lehets�ges defin�ci�ja p�ld�ul a
k�vetkezo:
struct smanip {
ios_base& (*f)(ios_base&,int); // megh�vand� f�ggv�ny
int i;
smanip(ios_base& (*ff)(ios_base&,int), int ii) : f(ff), i(ii) { }
};
template<class Ch, class Tr>
ostream<Ch,Tr>& operator<<(ostream<Ch,Tr>& os, const smanip& m)
{
return m.f(os,m.i);
}
Az smanip konstruktor param�tereit az f-ben �s az i-ben t�rolja, majd az
operator<< egy f(i)
f�ggv�nyh�v�st hajt v�gre. Ennek felhaszn�l�s�val a fenti setprecision() m�dos�t�
a k�vetkez
ok�ppen defini�lhat�:
850 A standard k�nyvt�r
ios_base& set_precision(ios_base& s, int n) // seg�d
{
return s.precision(n); // a tagf�ggv�ny h�v�sa
}
inline smanip setprecision(int n)
{
return smanip(set_precision,n); // f�ggv�nyobjektum l�trehoz�sa
}
�gy m�r le�rhatjuk az utas�t�st:
cout << setprecision(4) << angle ;
A programoz�k saj�t m�dos�t�kat is megadhatnak az smanip st�lus�ban, ha m�s
lehetos�-
gekre is sz�ks�g�k van (�21.10[22]). Ehhez nem kell megv�ltoztatniuk a standard
k�nyvt�r
oszt�lyait �s sablonjait (p�ld�ul basic_istream, basic_ostream, basic_ios vagy
ios_base).
21.4.6.2. Szabv�nyos ki- �s bemeneti m�dos�t�k
A standard k�nyvt�rban sok m�dos�t� (manipulator) szerepel a k�l�nb�zo form�z�si
�llapotok
kezel�s�hez. A szabv�nyos m�dos�t�k az std n�vt�rben tal�lhat�k. Az ios_base
oszt�lyhoz
kapcsol�d� m�dos�t�k az <ios> fej�llom�nyon kereszt�l �rhetok el, m�g az istream
vagy az
ostream felhaszn�l�s�val muk�do m�dos�t�k az <istream> �s az <ostream> (illetve
n�ha az
<iostream>) fej�llom�nyb�l. A t�bbi szabv�nyos m�dos�t�t az <iomanip> fej�llom�ny
adja
meg.
ios_base& boolalpha(ios_base&); // true �s false szimbolikus jelz�se (bemenet �s
// kimenet)
ios_base& noboolalpha(ios_base& s); // s.unsetf(ios_base::boolalpha)
ios_base& showbase(ios_base&); // kimenetn�l okt�lishoz 0, hexadecim�lishoz 0x
// elotag
ios_base& noshowbase(ios_base& s); // s.unsetf(ios_base::showbase)
ios_base& showpoint(ios_base&);
ios_base& noshowpoint(ios_base& s); // s.unsetf(ios_base::showpoint)
ios_base& showpos(ios_base&);
ios_base& noshowpos(ios_base& s); // s.unsetf(ios_base::showpos)
ios_base& skipws(ios_base&); // �reshelyek �tugr�sa
ios_base& noskipws(ios_base& s); // s.unsetf(ios_base::skipws)
21. Adatfolyamok 851
ios_base& uppercase(ios_base&); // X �s E (x �s e helyett)
ios_base& nouppercase(ios_base&); // x �s e (X �s E helyett)
ios_base& internal(ios_base&); // igaz�t�s (�21.4.5)
ios_base& left(ios_base&); // felt�lt�s �rt�k ut�n
ios_base& right(ios_base&); // felt�lt�s �rt�k elott
ios_base& dec(ios_base&); // eg�sz sz�mrendszer alapja: 10 (�21.4.2)
ios_base& hex(ios_base&); // eg�sz sz�mrendszer alapja: 16
ios_base& oct(ios_base&); // eg�sz sz�mrendszer alapja: 8
ios_base& fixed(ios_base&); // lebegopontos, fixpontos: dddd.dd (�21.4.3)
ios_base& scientific(ios_base&); // tudom�nyos form�tum: d.ddddEdd
template <class Ch, class Tr>
basic_ostream<Ch,Tr>& endl(basic_ostream<Ch,Tr>&); // '\n' ki�r�sa �s az
// adatfolyam �r�t�se
template <class Ch, class Tr>
basic_ostream<Ch,Tr>& ends(basic_ostream<Ch,Tr>&); // '\0' ki�r�sa �s az
// adatfolyam �r�t�se
template <class Ch, class Tr>
basic_ostream<Ch,Tr>& flush(basic_ostream<Ch,Tr>&); // az adatfolyam �r�t�se
template <class Ch, class Tr>
basic_istream<Ch,Tr>& ws(basic_istream<Ch,Tr>&); // �reshely "lenyel�se"
smanip resetiosflags(ios_base::fmtflags f); // jelzobitek t�rl�se (�21.4)
smanip setiosflags(ios_base::fmtflags f); // jelzobitek be�ll�t�sa (�21.4)
smanip setbase(int b); // eg�szek ki�r�sa b alap� sz�mrend
// szerben (�21.4.2)
smanip setfill(int c); // legyen c a kit�lto karakter (�21.4.4)
smanip setprecision(int n); // n sz�mjegy (�21.4.3, �21.4.6)
smanip setw(int n); // a k�vetkezo mezosz�less�g n karakter
// (�21.4.4)
P�ld�ul a
cout << 1234 << ',' << hex << 1234 << ',' << oct << 1234 << endl;
utas�t�s eredm�nye 1234, 4d2, 2322, m�g a
cout << '(' << setw(4) << setfill('#') << 12 << ") (" << 12 << ")\n";
eredm�nye (##12) (12).
852 A standard k�nyvt�r
Figyelj�nk r�, hogy ha olyan m�dos�t�kat haszn�lunk, melyek nem vesznek �t
param�tereket,
akkor nem szabad kitenn�nk a z�r�jeleket. A param�tereket is fogad� m�dos�t�k
haszn
�lat�hoz az <iomanip> fej�llom�nyt be kell �p�ten�nk (#include):
#include <iostream>
using namespace std;
int main()
{
cout << setprecision(4) // hiba: setprecision nem meghat�rozott (<iomanip>
kimaradt)
<< scientific() // hiba: ostream<<ostream& ("hamis" z�r�jelek)
<< 3.141421 << endl;
}
21.4.6.3. Felhaszn�l�i m�dos�t�k
A szabv�nyos m�dos�t�k st�lus�ban a programoz� is k�sz�thet �j m�dos�t�kat. Az
al�bbiakban
egy olyan eszk�zt mutatunk be, melynek a lebegopontos sz�mok form�z�sakor vehetj
�k haszn�t.
A pontoss�g minden tov�bbi kimeneti muveletre vonatkozik, m�g a sz�less�g-
be�ll�t�s csak
a k�vetkezo numerikus kimeneti utas�t�sra. C�lunk most az lesz, hogy egy
lebegopontos
sz�mot az �ltalunk megk�v�nt form�ban jelen�ts�nk meg, an�lk�l, hogy a k�sobbi
kimeneti
muveletek form�z�s�ra hat�ssal lenn�nk. Az alap�tlet az, hogy egy olyan oszt�lyt
k�sz�-
t�nk, amely form�tumokat �br�zol, �s egy olyat, amely a form�z�son k�v�l a
form�zni k�-
v�nt �rt�ket is t�rolja. Ennek felhaszn�l�s�val k�sz�thet�nk egy olyan <<
oper�tort, amely
a kimeneti adatfolyamon az adott form�ban jelen�ti meg az �rt�ket:
Form gen4(4); // �ltal�nos form�tum, pontoss�g 4
void f(double d)
{
Form sci8 = gen4;
sci8.scientific().precision(8); // tudom�nyos form�tum, pontoss�g 8
cout << d << ' ' << gen4(d) << ' ' << sci8(d) << ' ' << d << '\n';
}
Az f(1234.56789) f�ggv�nyh�v�s eredm�nye a k�vetkezo lesz:
1234.57 1235 1.23456789e+03 1234.57
Figyelj�k meg, hogy egy Form haszn�lata nem befoly�solja az adatfolyam �llapot�t,
hiszen
21. Adatfolyamok 853
a d utols� ki�rat�sakor ugyanazt a form�t kapjuk, mint az elsoben.
�me, egy leegyszerus�tett v�ltozat:
class Bound_form; // forma �s �rt�k
class Form {
friend ostream& operator<<(ostream&, const Bound_form&);
int prc; // pontoss�g
int wdt; // sz�less�g, 0 jelent�se: a sz�ks�ges sz�less�g
int fmt; // �ltal�nos, tudom�nyos, vagy fix (�21.4.3)
// ...
public:
explicit Form(int p = 6) : prc(p) // alap�rtelmezett pontoss�g 6
{
fmt = 0; // �ltal�nos form�tum (�21.4.3)
wdt = 0; // sz�ks�ges sz�less�g
}
Bound_form operator()(double d) const; // Bound_form objektum l�trehoz�sa *this
// �s d alapj�n
Form& scientific() { fmt = ios_base::scientific; return *this; }
Form& fixed() { fmt = ios_base::fixed; return *this; }
Form& general() { fmt = 0; return *this; }
Form& uppercase();
Form& lowercase();
Form& precision(int p) { prc = p; return *this; }
Form& width(int w) { wdt = w; return *this; } // minden t�pusra
Form& fill(char);
Form& plus(bool b = true); // explicit pozit�v elojel
Form& trailing_zeros(bool b = true); // z�r� null�k ki�r�sa
// ...
};
Az �tlet az, hogy a Form minden olyan inform�ci�t t�rol, ami egy adatelem
form�z�s�hoz
sz�ks�ges. Az alap�rtelmezett �rt�keket �gy v�lasztottuk meg, hogy azok a legt�bb
esetben
megfelelok legyenek; az egyes form�z�si be�ll�t�sokat a tagf�ggv�nyek seg�ts�g�vel
k�l�nk
�l�n adhatjuk meg. A ki�rand� �rt�khez a meghat�rozott form�z�st a ( ) oper�tor
seg�ts�-
g�vel k�tj�k hozz�. A Bound_form objektum ezek ut�n a megfelelo << oper�tor
seg�ts�g�-
vel tetszoleges kimeneti adatfolyamon megjelen�theto:
854 A standard k�nyvt�r
struct Bound_form {
const Form& f;
double val;
Bound_form(const Form& ff, double v) : f(ff), val(v) { }
};
Bound_form Form::operator()(double d) { return Bound_form(*this,d); }
ostream& operator<<(ostream& os, const Bound_form& bf)
{
ostringstream s; // karakterl�nc-folyamok le�r�sa: �21.5.3
s.precision(bf.f.prc);
s.setf(bf.f.fmt,ios_base::floatfield);
s << bf.val; // s �ssze�ll�t�sa
return os << s.str(); // s ki�r�sa os-re
}
A << oper�tor egy kev�sb� egyszeru v�ltozat�nak elk�sz�t�s�t feladatnak hagyjuk
(�21.10[21]). A Form �s a Bound_form oszt�lyt k�nnyen kibov�thetj�k, hogy eg�szek,
karakterl
�ncok stb. form�z�s�ra is haszn�lhat� legyen (l�sd �21.10[20]).
Megfigyelhetj�k, hogy ezen deklar�ci�k a << �s a ( ) p�ros�t�s�val egy h�rmas
oper�tort
hoznak l�tre. A cout<<sci4(d) utas�t�ssal egyetlen f�ggv�nyben kapcsolunk �ssze
egy
ostream objektumot, egy form�tumot �s egy �rt�ket, mielott a t�nyleges muveletet
v�grehajtan
�nk.
21.5. F�jl- �s karakterl�nc-folyamok
Amikor egy C++ programot elind�tunk, a cout, a cerr, a clog, �s a cin, illetve
sz�leskarakteres megfeleloik (�21.2.1) azonnal el�rhetok. Ezeket az adatfolyamokat
a rendszer
automatikusan hozza l�tre �s k�ti hozz� a megfelelo I/O eszk�zh�z vagy f�jlhoz.
Ezeken
k�v�l azonban saj�t adatfolyamokat is l�trehozhatunk, �s ezek eset�ben nek�nk kell

megmondanunk, hogy mihez akarjuk azokat k�tni. Az adatfolyamoknak f�jlokhoz,


illetve
karakterl�ncokhoz val� k�t�se el�g �ltal�nos feladat ahhoz, hogy a standard
k�nyvt�r k�zvetlen
�l t�mogassa. Az al�bbi �bra a szabv�nyos adatfolyam-oszt�lyok viszonyrendszer�t
mutatja be:
21. Adatfolyamok 855
Azok az oszt�lyok, melyek neve ut�n a <> jel szerepel, olyan sablonok, melyeknek
param
�tere egy karaktert�pus. Ezek teljes neve a basic_ elotaggal kezdodik. A pontozott
vonal
virtu�lis b�zisoszt�lyt jel�l (�15.2.4).
A f�jlok �s a karakterl�ncok azon t�rol�k k�z� tartoznak, melyeket �r�sra �s
olvas�sra is felhaszn
�lhatunk. Ez�rt ezekhez olyan adatfolyamokat hat�rozhatunk meg, melyek a << �s
a >> muveleteket egyar�nt t�mogatj�k. Az ilyen adatfolyamok b�zisoszt�lya az
iostream,
amely az std n�vt�rhez tartozik �s az <iostream> fej�llom�ny �rja le:
template <class Ch, class Tr = char_traits<Ch> >
class basic_iostream : public basic_istream<Ch,Tr>, public basic_ostream<Ch,Tr> {
public:
explicit basic_iostream(basic_streambuf<Ch,Tr>* sb);
virtual ~basic_iostream();
};
typedef basic_iostream<char> iostream;
typedef basic_iostream<wchar_t> wiostream;
Egy iostream �r�s�t �s olvas�s�t a streambuf objektum�n (�21.6.4) v�gzett ki- �s
bemeneti
t�rmuveletekkel vez�relhetj�k.
21.5.1. F�jlfolyamok
A k�vetkezo p�ld�ban bemutatunk egy teljes programot, amely egy f�jlt egy m�sikba
m�-
sol. A f�jlneveket parancssori param�terekk�nt lehet megadni:
856 A standard k�nyvt�r
ios_base
ios<>
istream<> ostream<>
istrigstream<> ifstream<> iostream<> ofstream<> ostringstream<>
fstream<> stringstream<>
#include <fstream>
#include <cstdlib>
void error(const char* p, const char* p2 = "")
{
cerr << p << ' ' << p2 << '\n';
std::exit(1);
}
int main(int argc, char* argv[ ])
{
if (argc != 3) error("Hib�s param�tersz�m");
std::ifstream from(argv[1]); // bemeneti f�jlfolyam megnyit�sa
if (!from) error("A bemeneti f�jl nem nyithat� meg",argv[1]);
std::ofstream to(argv[2]); // kimeneti f�jlfolyam megnyit�sa
if (!to) error("A kimeneti f�jl nem nyithat� meg",argv[2]);
char ch;
while (from.get(ch)) to.put(ch);
if (!from.eof() || !to) error("V�ratlan esem�ny t�rt�nt");
}
Egy f�jlt olvas�sra az ifstream oszt�ly egy objektum�nak l�trehoz�s�val nyithatunk
meg, param
�terk�nt a f�jl nev�t megadva. Ugyan�gy az ofstream oszt�ly felhaszn�l�s�val a
f�jlt �r�sra
k�sz�thetj�k fel. Mindk�t esetben a l�trehozott objektum �llapot�nak vizsg�lat�val
ellen-
orizz�k, hogy siker�lt-e a f�jl megnyit�sa. A basic_ofstream az <fstream>
fej�llom�nyban
a k�vetkezok�ppen szerepel:
template <class Ch, class Tr = char_traits<Ch> >
class basic_ofstream : public basic_ostream<Ch,Tr> {
public:
basic_ofstream();
explicit basic_ofstream(const char* p, openmode m = out);
basic_filebuf<Ch,Tr>* rdbuf() const; // mutat� az aktu�lis �tmeneti t�rra
(�21.6.4)
bool is_open() const;
void open(const char* p, openmode m = out);
void close();
};
21. Adatfolyamok 857
A basic_ifstream nagyon hasonl�t a basic_ofstream oszt�lyra, azzal a k�l�nbs�ggel,
hogy
a basic_istream oszt�lyb�l sz�rmazik, �s alap�rtelmez�s szerint olvas�sra
nyithatjuk meg.
Ezeken k�v�l a standard k�nyvt�r biztos�tja a basic_fstream oszt�lyt is, amely
szint�n hasonl
�t a basic_ofstream-re, csak itt a b�zisoszt�ly a basic_iostream, �s
alap�rtelmez�s szerint �rhat
� �s olvashat� is.
Szok�s szerint a leggyakrabban haszn�lt t�pusokhoz �n�ll� t�pusnevek (typedef-ek)
tartoznak:
typedef basic_ifstream<char> ifstream;
typedef basic_ofstream<char> ofstream;
typedef basic_fstream<char> fstream;
typedef basic_ifstream<wchar_t> wifstream;
typedef basic_ofstream<wchar_t> wofstream;
typedef basic_fstream<wchar_t> wfstream;
A f�jlfolyamok konstruktorainak m�sodik param�ter�ben m�s megnyit�si m�dokat is
megadhatunk:
class ios_base {
public:
// ...
typedef megval�s�t�s_f�ggo3 openmode;
static openmode app, // hozz�fuz�s
ate, // megnyit�s �s poz�cion�l�s a f�jl v�g�re
// (kiejt�se: "at end")
binary, // bin�ris I/O (a sz�veges (text) m�d
// ellent�te)
in, // megnyit�s olvas�sra
out, // megnyit�s �r�sra
trunc; // f�jl csonkol�sa 0 hossz�s�g�ra
// ...
};
Az openmode konstansok konkr�t �rt�ke �s jelent�se a megval�s�t�st�l f�gg, ez�rt
ha r�szleteket
szeretn�nk megtudni, akkor saj�t fejlesztorendszer�nk �s standard k�nyvt�runk le-
�r�s�t kell elolvasnunk, vagy k�s�rletezn�nk kell. A megjegyz�sekbol
k�vetkeztethet�nk,
hogy az egyes m�dokt�l k�r�lbel�l mit v�rhatunk. P�ld�ul egy f�jlt megnyithatunk
�gy,
hogy minden, amit bele�runk, a v�g�re ker�lj�n:
ofstream mystream(name.c_str(),ios_base::app);
858 A standard k�nyvt�r
De megnyithatunk egy f�jlt egyszerre �r�sra �s olvas�sra is:
fstream dictionary("concordance",ios_base::in|ios_base::out);
21.5.2. Adatfolyamok lez�r�sa
A f�jlokat k�zvetlen�l az adatfolyam close() tagf�ggv�ny�nek megh�v�s�val
z�rhatjuk be:
void f(ostream& mystream)
{
// ...
mystream.close();
}
Ennek ellen�re az adatfolyam destruktora is elv�gzi ezt a feladatot, �gy a close()
f�ggv�ny
megh�v�s�ra akkor van csak sz�ks�g, ha a f�jlt m�r azelott be kell z�rnunk,
mielott az adatfolyam
hat�k�r�bol kiker�ln�nk.
Ez felveti a k�rd�st, hogy az adott fejlesztok�rnyezet hogyan biztos�thatja, hogy
a cout, cin,
cerr �s clog adatfolyamok m�r elso haszn�latuk elott l�trej�jjenek �s csak utols�
haszn�latuk
ut�n z�r�djanak le. Term�szetesen az <iostream> adatfolyam-k�nyvt�r k�l�nb�zo
v�ltozatai
k�l�nb�zo m�dszereket alkalmazhatnak e c�l el�r�s�hez. V�geredm�nyben az,
hogy hogyan oldjuk meg ezt a probl�m�t, r�szletk�rd�s, amelyet nem kell �s nem is
szabad
a felhaszn�l� �ltal l�that�v� tenni. Az al�bbiakban csak egy lehets�ges megold�st
mutatunk
be, amely el�g �ltal�nos arra, hogy k�l�nb�zo t�pus� glob�lis objektumok
konstruktorainak �s destruktorainak lefut�si sorrendj�t r�gz�ts�k. Egy konkr�t
megval�s�t�s
enn�l hat�konyabb megold�st is k�n�lhat a ford�t� �s az �sszeszerkeszto (linker)
egyedi lehet
os�geinek felhaszn�l�s�val.
Az alap�tlet az, hogy egy olyan seg�doszt�lyt hozunk l�tre, amely sz�mon tartja,
h�nyszor
�p�tett�k be az <iostream> fej�llom�nyt egy k�l�n ford�tott forr�sf�jlba:
class ios_base::Init {
static int count;
public:
Init();
~Init();
};
21. Adatfolyamok 859
namespace { // az <iostream> �llom�nyban, egy m�solat minden f�jlban,
ios_base::Init __ioinit; // ahov� <iostream>-et be�p�tik
}
int ios_base::Init::count = 0; // valamelyik .c �llom�nyban
Minden ford�t�si egys�g (�9.1) deklar�l egy-egy saj�t __ioinit nevu objektumot. Az
__ioinit
objektumok konstruktora az ios_base::Init::count felhaszn�l�s�val biztos�tja, hogy
az I/O
k�nyvt�r glob�lis objektumainak kezdeti �rt�kad�sa csak egyszer t�rt�njen meg:
ios_base::Init::Init()
{
if (count++ == 0) { /* kezdo�rt�k cout, cerr, cin stb. sz�m�ra */ }
}
Ugyan�gy az __ioinit objektumok destruktora az ios_base::Init::count seg�ts�g�vel
biztos�tja
az adatfolyamok lez�r�s�t:
ios_base::Init::~Init()
{
if (--count == 0) { /* felsz�molja cout-ot (flush stb.), illetve a cerr-t, cin-t
stb. */ }
}
Ez a m�dszer �ltal�nosan haszn�lhat� olyan k�nyvt�rak eset�ben, melyekben glob�lis
objektumoknak
kell kezdo�rt�ket adni, illetve meg kell azokat semmis�teni. Az olyan
rendszerekben,
ahol a teljes program az elsodleges mem�ri�ban kap helyet fut�s k�zben, ez a
m�dszer
nem jelent teljes�tm�nyroml�st. Ha azonban nem ez a helyzet, akkor jelentos
vesztes�get
jelenthet, hogy a kezdeti �rt�kad�sok miatt k�nytelenek vagyunk a t�rgyk�dokat
(object f�jlokat)
sorban beolvasni az elsodleges mem�ri�ba. Ha lehets�ges, ker�lj�k el a glob�lis
objektumok
haszn�lat�t. Egy olyan oszt�lyban, ahol minden muvelet jelentos, �rdemes lehet
minden
f�ggv�nyben elv�gezni egy olyan ellenorz�st, mint amit az ios_base::Init::count
v�gez,
ezzel biztos�thatjuk a kezdeti �rt�kad�sokat. Ez a megold�s azonban az
adatfolyamok eset�-
ben rendk�v�l k�lts�ges lenne. Egy olyan f�ggv�ny sz�m�ra, amely egyetlen
karaktert �r ki
vagy olvas be, egy ilyen ellenorz�s komoly t�bbletterhel�st jelentene.
21.5.3. Karakterl�nc-folyamok
Az adatfolyamokat hozz�k�thetj�k karakterl�ncokhoz is. Ez azt jelenti, hogy az
adatfolyamok
�ltal k�n�lt form�z�si lehetos�gek felhaszn�l�s�val karakterl�ncokat is �rhatunk
�s olvashatunk.
Az ilyen adatfolyamok neve stringstream, le�r�sukat az <sstream> fej�llom�ny
tartalmazza:
860 A standard k�nyvt�r
template <class Ch, class Tr=char_traits<Ch> >
class basic_stringstream : public basic_iostream<Ch,Tr> {
public:
explicit basic_stringstream(ios_base::openmode m = out|in);
explicit basic_stringstream(const basic_string<Ch>& s, openmode m = out|in);
basic_string<Ch> str() const; // a karakterl�nc m�solat�t veszi
void str(const basic_string<Ch>& s); // az �rt�ket s m�solat�ra �ll�tja
basic_stringbuf<Ch,Tr>* rdbuf() const; // mutat� az aktu�lis �tmeneti t�rra
};
A basic_istringstream a basic_stringstream oszt�lyra hasonl�t, azzal a
k�l�nbs�ggel, hogy
a basic_istream oszt�lyb�l sz�rmazik, �s alap�rtelmez�s szerint olvas�sra
nyithatjuk meg.
A basic_ostringstream is a basic_stringstream .testv�re., csak itt a b�zisoszt�ly
a basic_ostream, �s alap�rtelmez�s szerint �r�sra nyitjuk meg.
Szok�s szerint a leggyakrabban haszn�lt egyedi c�l� v�ltozatokhoz �n�ll�
t�pusnevek
(typedef-ek) tartoznak:
typedef basic_istringstream<char> istringstream;
typedef basic_ostringstream<char> ostringstream;
typedef basic_stringstream<char> stringstream;
typedef basic_istringstream<wchar_t> wistringstream;
typedef basic_ostringstream<wchar_t> wostringstream;
typedef basic_stringstream<wchar_t> wstringstream;
Az ostringstream objektumokat p�ld�ul �zenet-karakterl�ncok form�z�s�ra
haszn�lhatjuk:
string compose(int n, const string& cs)
{
extern const char* std_message[ ];
ostringstream ost;
ost << "error(" << n << ") " << std_message[n] << " (user comment: " << cs << ')';

return ost.str();
}
A t�lcsordul�st ez esetben nem kell ellenorizn�nk, mert az ost m�rete az ig�nyek
szerint no.
Ez a lehetos�g k�l�n�sen hasznos olyan esetekben, amikor a megk�v�nt form�z�si
feladatok
bonyolultabbak ann�l, amit az �ltal�nos, sorokat elo�ll�t� kimeneti eszk�z�k
kezelni
tudnak.
A karakterl�nc-folyamok kezdo�rt�k�t ugyan�gy �rtelmezi a rendszer, mint a
f�jlfolyamok
eset�ben:
21. Adatfolyamok 861
string compose2(int n, const string& cs) // egyen�rt�ku a compose()-zal
{
extern const char* std_message[ ];
ostringstream ost("hiba(",ios_base::ate); // a kezdeti karakterl�nc v�g�tol kezd
�rni
ost << n << ") " << std_message[n] << " (felhaszn�l�i megjegyz�s: " << cs << ')';
return ost.str();
}
Az istringstream egy olyan bemeneti adatfolyam, amely az adatokat a konstruktorban
megadott
karakterl�ncb�l olvassa (ugyan�gy, ahogy az ifilestream a megadott f�jlb�l olvas):

#include <sstream>
void word_per_line(const string& s) // soronk�nt egy sz�t �r ki
{
istringstream ist(s);
string w;
while (ist>>w) cout << w << '\n';
}
int main()
{
word_per_line("Ha azt hiszed, a C++ neh�z, tanulj angolul");
}
A kezdo�rt�ket ad� string bem�sol�dik az istringstream objektumba. A karakterl�nc
v�ge
a bemenet v�g�t is jelenti.
Lehetos�g van olyan adatfolyamok meghat�roz�s�ra is, melyek k�zvetlen�l
karaktert�mb
�kbol olvasnak, illetve oda �rnak (�21.10[26]). Ez igen hasznos seg�ts�g, foleg,
ha r�gebbi
programokkal kell foglalkoznunk. Az ezen szolg�ltat�st megval�s�t� ostrstream �s
istrstream oszt�ly m�r r�gebben beker�lt a szabv�nyos adatfolyam-k�nyvt�rba.
21.6. Ki- �s bemeneti �tmeneti t�rak
A kimeneti adatfolyamok vez�relve, hogy egy �tmeneti t�rba (pufferbe) �rj�k a
karaktereket,
�s azok egy kis ido m�lva innen ker�lnek �t oda, ahova val�j�ban �rni akartuk
azokat.
Az �tmeneti t�rak oszt�ly�nak neve streambuf (�21.6.4), melynek defin�ci�ja a
<streambuf>
fej�llom�nyban szerepel. A k�l�nb�zo t�pus� streambuf oszt�lyok k�l�nb�zo t�rol�si
m�d-
862 A standard k�nyvt�r
szereket alkalmaznak. A leg�ltal�nosabb megold�s az, hogy a streambuf egy t�mbben
t�-
rolja a karaktereket mindaddig, am�g t�lcsordul�s nem k�vetkezik be, �s csak
ilyenkor �rja
ki a teljes t�mb�t a megfelelo helyre. Teh�t egy ostream objektumot az al�bbi
form�ban
�br�zolhatunk:
Az ostream-nek �s a hozz� tartoz� streambuf objektumnak ugyanazokat a
sablonparam�-
tereket kell haszn�lnia, �s ezek hat�rozz�k meg a karakterek �tmeneti t�r�ban
haszn�lt
karaktert�pust.
Az istream oszt�lyok nagyon hasonl�ak, csak ott a karakterek az ellenkezo ir�nyba
folynak.
Az �tmenetileg nem t�rolt (unbuffered) I/O olyan egyszeru ki- �s bemenet, ahol az
adatfolyam
�tmeneti t�ra azonnal tov�bb�t minden karaktert, �s nem v�rakozik addig, am�g
megfelel
o sz�m� karakter gyulik �ssze a hat�kony tov�bb�t�shoz.
21.6.1. Kimeneti adatfolyamok �s �tmeneti t�rol�k
Az ostream oszt�ly sz�mtalan k�l�nb�zo t�pus� �rt�k karakterr� �talak�t�s�t teszi
lehetov�
az alap�rtelmez�seknek (�21.2.1) �s a megadott form�z�si utas�t�soknak (�21.4)
megfelelo-
en. Az ostream ezenk�v�l ny�jt n�h�ny olyan f�ggv�nyt is, melyek k�zvetlen�l a
streambuf
kezel�s�vel foglalkoznak:
template <class Ch, class Tr = char_traits<Ch> >
class basic_ostream : virtual public basic_ios<Ch,Tr> {
public:
// ...
explicit basic_ostream(basic_streambuf<Ch,Tr>* b);
21. Adatfolyamok 863
tellp()
begin
current
end
val�di c�l
ostream:
karakter �tmeneti t�r
streambuf:
pos_type tellp(); // aktu�lis poz�ci� lek�r�se
basic_ostream& seekp(pos_type); // aktu�lis poz�ci� be�ll�t�sa
basic_ostream& seekp(off_type, ios_base::seekdir); // aktu�lis poz�ci� be�ll�t�sa
basic_ostream& flush(); // �tmeneti t�r �r�t�se (a t�nyleges c�l fel�)
basic_ostream& operator<<(basic_streambuf<Ch,Tr>* b); // �r�s b-bol
};
Az ostream konstruktor�ban megadott strembuf param�ter hat�rozza meg, hogy a ki�rt
karaktereket
hogyan kezelj�k �s mikor legyenek t�nylegesen ki�rva a meghat�rozott eszk�zre.
P�ld�ul egy ostringcstream (�21.5.3) vagy egy ofstream (�21.5.1) l�trej�ttekor az
ostream
objektumnak a megfelelo streambuf (�21.6.4) megad�s�val adunk kezdo�rt�ket.
A seekp() f�ggv�nyek azt �ll�tj�k be, hogy az ostream milyen poz�ci�ra �rjon. A p
ut�tag azt
jelzi, hogy ez a poz�ci� az adatfolyamban a karakterek ki�r�s�ra (put) szolg�l.
Ezek a f�ggv
�nyek csak akkor muk�dnek, ha az adatfolyam olyasvalamihez van k�tve, amin a
pozicion
�l�s �rtelmes muvelet (teh�t p�ld�ul egy f�jlhoz). A pos_type t�pus egy
karakterhelyet �br
�zol a f�jlban, m�g az off_type az ios_base::seekdir v�ltoz� �ltal kijel�lt
helytol val� elt�r�st
jel�li:
class ios_base {
// ...
typedef implementation_defined seekdir;
static const seekdir beg, // keres�s a f�jl elej�tol
cur, // keres�s az aktu�lis poz�ci�t�l
end; // keres�s a f�jl v�g�tol
// ...
};
Az adatfolyamok kezdopoz�ci�ja a 0, �gy a f�jlokat nyugodtan k�pzelhetj�k n
karakterbol
�ll� t�mb�knek:
int f(ofstream& fout) // fout valamilyen f�jlra hivatkozik
{
fout.seekp(10);
fout << '#'; // karakter ki�r�sa �s poz�ci� mozgat�sa (+1)
fout.seekp(-2,ios_base::cur);
fout << '*';
}
864 A standard k�nyvt�r
A fenti programr�szlet egy # karaktert helyez a file[10] poz�ci�ra �s egy *
szimb�lumot
a file[9] helyre. Az egyszeru istream �s ostream oszt�ly eset�ben ilyen k�zvetlen
hozz�f�-
r�sre nincs lehetos�g�nk (l�sd �21.10[13]). Ha megpr�b�lunk a f�jl eleje el� vagy
v�ge ut�n
�rni, az adatfolyam bad() �llapotba ker�l (�21.3.3).
A flush() muvelet lehetov� teszi a programoz� sz�m�ra, hogy a t�lcsordul�s
megv�r�sa n�lk
�l �r�tse ki az �tmeneti t�rat.
Lehetos�g van arra is, hogy a << oper�tor seg�ts�g�vel egy streambuf objektumot
k�zvetlen
�l a kimeneti adatfolyamba �rjunk. Ez elsosorban az I/O rendszerek k�sz�toinek
hasznos
seg�ts�g.
21.6.2. Bemeneti adatfolyamok �s �tmeneti t�rol�k
Az istream elsosorban olyan muveleteket k�n�l, melyek seg�ts�g�vel karaktereket
olvashatunk
be �s alak�thatunk �t k�l�nb�zo t�pus� �rt�kekre (�21.3.1). Ezenk�v�l azonban
ny�jt
n�h�ny olyan szolg�ltat�st is, melyekkel k�zvetlen�l a streambuf objektumot
�rhetj�k el:
template <class Ch, class Tr = char_traits<Ch> >
class basic_istream : virtual public basic_ios<Ch,Tr> {
public:
// ...
explicit basic_istream(basic_streambuf<Ch,Tr>* b);
pos_type tellg(); // aktu�lis poz�ci� lek�rdez�se
basic_istream& seekg(pos_type); // aktu�lis poz�ci� be�ll�t�sa
basic_istream& seekg(off_type, ios_base::seekdir); // aktu�lis poz�ci� be�ll�t�sa
basic_istream& putback(Ch c); // c visszarak�sa az �tmeneti t�rba
basic_istream& unget(); // putback alkalmaz�sa a legut�bb beolvasott
// karakterre
int_type peek(); // a k�vetkezo beolvasand� karakter
int sync(); // �tmeneti t�r �r�t�se (flush)
basic_istream& operator>>(basic_streambuf<Ch,Tr>* b); // olvas�s b-be
basic_istream& get(basic_streambuf<Ch,Tr>& b, Ch t = Tr::newline());
streamsize readsome(Ch* p, streamsize n); // legfeljebb n karakter beolvas�sa
};
21. Adatfolyamok 865
A pozicion�l� f�ggv�nyek ugyan�gy muk�dnek, mint az ostream oszt�lybeli
megfeleloik
(�21.6.1). A g ut�tag azt jelzi, hogy ez a poz�ci� a karakterek beolvas�s�nak
(get) helye. A p
�s a g ut�tagokra az�rt van sz�ks�g, mert k�sz�thet�nk olyan iostream oszt�lyt is,
melynek
b�zisoszt�lya az istream �s az ostream is, �s ilyenkor is meg kell tudnunk
k�l�nb�ztetni az
�r�si �s az olvas�si poz�ci�t.
A putback() f�ggv�nyek azt teszik lehetov�, hogy a program visszategye az
adatfolyamba
azokat a karaktereket, amelyekre egyelore nincs sz�ks�ge, de k�sobb m�g fel
szeretn�nk
dolgozni. Erre a �21.3.5 pontban mutattunk p�ld�t. Az unget() f�ggv�ny a
legutolj�ra beolvasott
karaktert teszi vissza az adatfolyamba. Sajnos a bemeneti adatfolyamok ilyen
.visszag
�rget�se. nem mindig lehets�ges. P�ld�ul ha megpr�b�ljuk vissza�rni az utols�
elotti beolvasott
karaktert is, az ios_base::failbit hibajelzo bekapcsol�dik. Csak abban lehet�nk
biztosak, hogy egyetlen, sikeresen beolvasott karaktert vissza tudunk �rni. A
peek() beolvassa
a k�vetkezo karaktert, de azt az �tmeneti t�rban hagyja, �gy �jra beolvashatjuk.
Teh�t
a c=peek() utas�t�s egyen�rt�ku a (c=get(),unget(),c) �s a (putback(c=get()),c)
parancs-sorozatokkal.
Figyelj�nk r�, hogy a failbit bekapcsol�sa kiv�telt v�lthat ki (�21.3.6).
Az istream-ek �tmeneti t�r�nak azonnali ki�r�t�s�t (flushing) a sync() paranccsal
k�nyszer
�thetj�k ki, de ezt a muveletet sem mindig haszn�lhatjuk biztons�gosan. Bizonyos
t�pus�
adatfolyamokban ehhez �jra kellene olvasnunk a karaktereket az eredeti forr�sb�l,
ami
nem mindig lehets�ges vagy hib�s bemenetet eredm�nyezhet. Ez�rt a sync() 0 �rt�ket
ad
vissza, ha sikeresen lefutott, �s .1-t, ha nem. Ha a muvelet sikertelen volt, erre
az
ios_base::badbit (�21.3.3) is felh�vja a figyelm�nket. A badbit �rt�k�nek
megv�ltoz�sa is kiv
�telt v�lthat ki (�21.3.6). Ha a sync() f�ggv�nyt olyan �tmeneti t�rra haszn�ljuk,
amely egy
ostream objektumhoz kapcsol�dik, akkor az �tmeneti t�r tartalma a kimenetre ker�l.

A >> �s a get() muveletnek is van olyan v�ltozata, mely k�zvetlen�l az �tmeneti


t�rba �r, de
ezek is elsosorban az I/O szolg�ltat�sok k�sz�toinek jelentenek hasznos
seg�ts�get, hiszen
az adatfolyamok �tmeneti t�rainak k�zvetlen el�r�s�re csak nekik van sz�ks�g�k.
A readsome() f�ggv�ny egy alacsonyszintu muvelet, mellyel a programoz�
meg�llap�thatja,
hogy van-e az adatfolyamban beolvas�sra v�r� karakter. Ez a szolg�ltat�s akkor
nagyon
hasznos, ha nem akarunk a bemenet meg�rkez�s�re v�rni (p�ld�ul a billentyuzetrol).
L�sd
m�g: in_avail() (�21.6.4).
21.6.3. Az adatfolyamok �s az �tmeneti t�rak kapcsolata
Az adatfolyam �s a hozz� tartoz� �tmeneti t�r k�z�tti kapcsolatot az adatfolyamok
basic_ios
oszt�lya tartja fenn:
866 A standard k�nyvt�r
template <class Ch, class Tr = char_traits<Ch> >
class basic_ios : public ios_base {
public:
// ...
basic_streambuf<Ch,Tr>* rdbuf() const; // mutat� az �tmeneti t�rra
// az �tmeneti t�r be�ll�t�sa, clear(), �s mutat� visszaad�sa a r�gi t�rra
basic_streambuf<Ch,Tr>* rdbuf(basic_streambuf<Ch,Tr>* b);
locale imbue(const locale& loc); // helyi saj�toss�gok be�ll�t�sa (�s
// a r�gi �rt�k kiolvas�sa)
char narrow(char_type c, char d) const; // char �rt�k char_type t�pus� c-bol
char_type widen(char c) const; // char_type �rt�k a c char-b�l
// ...
protected:
basic_ios();
void init(basic_streambuf<Ch,Tr>* b); // a kezdeti �tmeneti t�r be�ll�t�sa
};
Azon k�v�l, hogy lek�rdezhetj�k �s be�ll�thatjuk az adatfolyam streambuf
objektum�t
(�21.6.4), a basic_ios oszt�lyban szerepel az imbue() f�ggv�ny is, mellyel
beolvashatjuk �s
�t�ll�thatjuk az adatfolyam helyi saj�toss�gokat le�r� locale objektum�t (�21.7).
Az imbue()
f�ggv�nyt az ios_base (�21.7.1) objektumra, a pubimbue() f�ggv�nyt az �tmeneti
t�rra
(�21.6.4) kell megh�vnunk.
A narrow() �s a widen() f�ggv�ny seg�ts�g�vel az �tmeneti t�r karaktert�pus�t
konvert�lhatjuk
char t�pus�ra, vagy ford�tva. A narrow(c,d) f�ggv�nyh�v�s m�sodik param�tere az
a char, amelyet akkor szeretn�nk visszakapni, ha a c-ben megadott char_type
�rt�knek
nincs char megfeleloje.
21.6.4. Adatfolyamok �tmeneti t�rol�sa
Az I/O muveletek meghat�roz�sa f�jlt�pus eml�t�se n�lk�l t�rt�nt, de nem
kezelhet�nk minden
eszk�zt ugyan�gy az �tmeneti t�rol�sn�l. Egy karakterl�nchoz k�t�tt ostream
objektumnak
(�21.5.3) p�ld�ul m�sf�le t�rol�sra van sz�ks�ge, mint egy f�jlhoz k�t�tt
(�21.5.1)
kimeneti adatfolyamnak. Ezeket a probl�m�kat �gy oldhatjuk meg, hogy a k�l�nb�zo
adatfolyamokhoz
a kezdeti �rt�kad�skor k�l�nb�zo t�pus� �tmeneti t�rakat rendel�nk. Mivel
a k�l�nb�zo t�pus� t�rak ugyanazokat a muveleteket biztos�tj�k, az ostream
oszt�lynak
nem kell k�l�nb�zonek lennie hozz�juk. Minden �tmeneti t�r a streambuf oszt�lyb�l
sz�r-
21. Adatfolyamok 867
mazik. A streambuf virtu�lis f�ggv�nyeket ny�jt azokhoz a muveletekhez, melyek a
k�l�nb
�zo t�rol�si m�dszerekn�l elt�roek lehetnek. Ilyenek p�ld�ul a t�lcsordul�st �s az
alulcsordul
�st kezelo elj�r�sok.
A basic_streambuf oszt�ly k�t fel�letet tesz el�rhetov�. A nyilv�nos (public)
fel�let elsosorban
azoknak hasznos, akik olyan adatfolyam-oszt�lyokat akarnak elk�sz�teni, mint az
istream, az ostream, az fstream vagy a stringstream. A v�dett (protected) fel�let
c�lja azon
programoz�k ig�nyeinek kiszolg�l�sa, akik �j t�rol�si m�dszert akarnak bevezetni,
vagy �j
bemeneti forr�sokat �s kimeneti c�lokat akarnak kezelni.
A streambuf oszt�ly meg�rt�s�hez �rdemes elosz�r megismerkedn�nk az alapj�t k�pezo
�tmeneti
t�rter�let modellel, amelyet a v�dett fel�let biztos�t. K�pzelj�k el, hogy a
streambuf
objektumnak van egy kimeneti ter�lete, amelybe a << oper�tor seg�ts�g�vel
�rhatunk, �s
van egy bemeneti ter�lete, amelybol a >> oper�tor olvas. Mindk�t ter�letet h�rom
mutat� �r
le: egy a kezdopontra, egy az aktu�lis poz�ci�ra, egy pedig az utols� ut�ni elemre
mutat.
Ezeket a mutat�kat f�ggv�nyeken kereszt�l �rhetj�k el:
template <class Ch, class Tr = char_traits<Ch> >
class basic_streambuf {
protected:
Ch* eback() const; // a bemeneti t�r kezdete
Ch* gptr() const; // k�vetkezo karakter (a k�vetkezo olvas�s innen t�rt�nik)
Ch* egptr() const; // a bemeneti t�r utols� eleme ut�nra mutat
void gbump(int n); // n hozz�ad�sa gptr()-hez
void setg(Ch* begin, Ch* next, Ch* end); // eback(), gptr(), �s egptr() be�ll�t�sa

Ch* pbase() const; // a kimeneti t�r kezdete


Ch* pptr() const; // a k�vetkezo �res karakter (a k�vetkezo ki�r�s ide t�rt�nik)
Ch* epptr() const; // a kimeneti t�r utols� eleme ut�nra mutat
void pbump(int n); // n hozz�ad�sa pptr()-hez
void setp(Ch* begin, Ch* end); // pbase() �s pptr() begin-re, epptr() end-re
�ll�t�sa
// ...
};
Egy karaktert�mbre a setg() �s a setp() f�ggv�ny seg�ts�g�vel megfeleloen
be�ll�thatjuk
a mutat�kat. A programoz� a bemeneti ter�letet a k�vetkezo form�ban �rheti el:
template <class Ch, class Tr = char_traits<Ch> >
basic_streambuf<Ch,Tr>::int_type basic_streambuf<Ch,Tr>::snextc()
// az aktu�lis karakter �tl�p�se, a k�vetkezo beolvas�sa
{
868 A standard k�nyvt�r
if (1<egptr()-gptr()) { // ha legal�bb k�t karakter van az �tmeneti t�rban
gbump(1); // az aktu�lis karakter �tl�p�se
return Tr::to_int_type(*gptr()); // az �j aktu�lis karakter visszaad�sa
}
if ( 1==egptr()-gptr()) { // ha pontosan egy karakter van az �tmeneti t�rban
gbump(1); // az aktu�lis karakter �tl�p�se
return underflow();
}
// az �tmeneti t�r �res (vagy nem haszn�lt), pr�b�ljuk felt�lteni
if (Tr::eq_int_type(uflow(), Tr::eof()) return Tr::eof();
if (0<eptr()-gptr()) return Tr::to_int_type(*gptr()); // az �j aktu�lis karakter
visszaad�sa
return underflow;
}
Az �tmeneti t�rat a gptr()-en kereszt�l �rj�k el, az egptr() a bemeneti ter�let
hat�r�t jelzi.
A karaktereket a val�di forr�sb�l az uflow() �s az underflow() olvass�k ki.
A traits_type::to_int_type() megh�v�sa biztos�tja, hogy a k�d f�ggetlen lesz az
�ppen haszn
�lt karaktert�pust�l. A k�d t�bbf�le t�pus� adatfolyam-t�rral haszn�lhat� �s
figyelembe veszi
azt is, hogy az uflow() �s az underflow() virtu�lis f�ggv�nyek (a setg()
seg�ts�g�vel) �j
bemeneti ter�letet is meghat�rozhatnak.
A streambuf nyilv�nos fel�lete a k�vetkezo:
template <class Ch, class Tr = char_traits<Ch> >
class basic_streambuf {
public:
// szok�sos t�pus-meghat�roz�sok (�21.2.1)
virtual ~basic_streambuf();
locale pubimbue(const locale &loc); // locale be�ll�t�sa (�s r�gi kiolvas�sa)
locale getloc() const; // locale kiolvas�sa
basic_streambuf* pubsetbuf(Ch* p, streamsize n); // �tmeneti t�rter�let be�ll�t�sa

pos_type pubseekoff(off_type off, ios_base::seekdir way, // poz�ci� (�21.6.1)


ios_base::openmode m = ios_base::in|ios_base::out);
pos_type pubseekpos(pos_type p, ios_base::openmode m = ios_base::in|
ios_base::out);
int pubsync(); // sync(), l�sd �21.6.2
int_type snextc(); // aktu�lis karakter �tl�p�se, a k�vetkezo kiolvas�sa
int_type sbumpc(); // gptr() l�ptet�se 1-el
int_type sgetc(); // az aktu�lis karakter beolvas�sa
21. Adatfolyamok 869
streamsize sgetn(Ch* p, streamsize n); // beolvas�s p[0]..p[n-1]-be
int_type sputbackc(Ch c); // c visszahelyez�se az �tmeneti t�rba (�21.6.2)
int_type sungetc(); // az utols� karakter visszahelyez�se
int_type sputc(Ch c); // c ki�r�sa
streamsize sputn(const Ch* p, streamsize n); // p[0]..p[n-1] ki�r�sa
streamsize in_avail(); // bemenet rendben?
// ...
};
A nyilv�nos fel�let olyan f�ggv�nyeket tartalmaz, melyekkel karaktereket
helyezhet�nk az
�tmeneti t�rba, illetve karaktereket vehet�nk ki onnan. Ezek a f�ggv�nyek
�ltal�ban nagyon
egyszeruek �s helyben kifejtve (inline) is ford�that�k, ami a hat�konys�g
szempontj�-
b�l kulcsfontoss�g�.
Azok a f�ggv�nyek, melyek tev�kenys�ge f�gg a haszn�lt t�rol�si m�dt�l, a v�dett
fel�let
megfelelo elj�r�s�t h�vj�k meg. A pubsetbuf() p�ld�ul a setbuf() f�ggv�nyt h�vja
meg, amelyet
a lesz�rmazott oszt�ly fel�l�r az �tmenetileg t�rolt karakterek sz�m�ra val�
mem�riafoglal
�shoz. Teh�t az olyan muveletek megval�s�t�s�ra, mint a setbuf(), k�t f�ggv�ny
szolg�l,
ami az�rt praktikus, mert �gy egy iostream is v�gezhet .rendfenntart�.
muveleteket, mik�zben
a felhaszn�l� f�ggv�ny�t megh�vja. A virtu�lis f�ggv�ny megh�v�s�t egy try blokkba

helyezhetj�k, �s elkaphatjuk a felhaszn�l�i k�d �ltal kiv�ltott kiv�teleket is.


Alap�rtelmez�s szerint a setbuf(0,0) az �tmeneti t�rol�s hi�ny�t jelenti, m�g a
setbuf(p,n)
a p[0],., p[n-1] tartom�ny haszn�lat�t �rja elo a karakterek �tmeneti t�rol�s�ra.
Az in_avail() f�ggv�ny megh�v�s�val azt �llap�thatjuk meg, h�ny karakter �ll
rendelkez�-
s�nkre az �tmeneti t�rban. Ennek vizsg�lat�val elker�lhetj�k a bemenetre val�
v�rakoz�st.
Amikor olyan adatfolyamb�l olvasunk, amely a billentyuzethez kapcsol�dik, a
cin.get(c)
ak�r addig v�rakozik, am�g a felhaszn�l� vissza nem t�r az eb�dj�rol. Egyes
rendszerekben
�s alkalmaz�sokban �rdemes felk�sz�ln�nk erre a lehetos�gre:
if (cin.rdbuf()->in_avail()) { // get() nem fog lefagyni
cin.get(c);
// csin�lunk valamit
}
else { // get() lefagyhat
// valami m�st csin�lunk
}
870 A standard k�nyvt�r
Vigy�zzunk e lehetos�g haszn�latakor, mert n�ha nem k�nnyu annak meg�llap�t�sa,
hogy
van-e beolvashat� bemenet. Az in_avail() adott v�ltozata esetleg 0 �rt�ket ad
vissza, ha egy
bemeneti muveletet sikeresen v�grehajthatunk.
A nyilv�nos fel�let mellett . amelyet a basic_istream �s a basic_ostream haszn�l .

a basic_streambuf egy v�dett fel�letet is k�n�l, mellyel az adatfolyamok �tmeneti


t�rainak
elk�sz�t�s�t seg�ti, �s azokat a virtu�lis f�ggv�nyeket vezeti be, amelyek
meghat�rozz�k az
�tmeneti t�rol�s ir�nyelveit:
template <class Ch, class Tr = char_traits<Ch> >
class basic_streambuf {
protected:
// ...
basic_streambuf();
virtual void imbue(const locale &loc); // locale be�ll�t�sa
virtual basic_streambuf* setbuf(Ch* p, streamsize n);
virtual pos_type seekoff(off_type off, ios_base::seekdir way,
ios_base::openmode m = ios_base::in|ios_base::out);
virtual pos_type seekpos(pos_type p,
ios_base::openmode m = ios_base::in|ios_base::out);
virtual int sync(); // sync(), l�sd �21.6.2
virtual int showmanyc();
virtual streamsize xsgetn(Ch* p, streamsize n); // n karakter beolvas�sa
virtual int_type underflow(); // az olvas�si ter�let �res, eof vagy
// karakter visszaad�sa
virtual int_type uflow(); //az olvas�si ter�let �res, eof vagy
// karakter visszaad�sa, gptr() n�vel�se
virtual int_type pbackfail(int_type c = Tr::eof()); // a putback nem j�rt sikerrel

virtual streamsize xsputn(const Ch* p, streamsize n); // n karakter ki�r�sa


virtual int_type overflow(int_type c = Tr::eof()); // ki�r� ter�let megtelt
};
Az underflow() �s az uflow() f�ggv�ny szolg�l arra, hogy a k�vetkezo karaktereket
beolvassuk
a t�nyleges bemeneti forr�sr�l, ha az �tmeneti t�r �res. Ha az adott forr�son
nincs beolvashat
� bemenet, az adatfolyam eof �llapotba (�21.3.3) ker�l. Ha ez nem v�lt ki
kiv�telt,
a traits_type::eof() �rt�ket kapjuk vissza. A gptr()-t a visszaadott karakter ut�n
az uflow() n�-
21. Adatfolyamok 871
veli, az underflow() viszont nem. A rendszerben �ltal�ban nem csak azok az
�tmeneti t�rak
vannak, amelyeket az iostream k�nyvt�r hoz l�tre, �gy akkor is elofordulhatnak
�tmeneti t�-
rol�s miatti k�sleked�sek, amikor �tmenetileg nem t�rolt adatfolyamot haszn�lunk.
Az overflow() f�ggv�ny akkor fut le, amikor az �tmeneti t�r megtelik, �s ez
tov�bb�tja a karaktereket
a kimenet val�di c�l�llom�s�ra. Az overflow(c) utas�t�s az �tmeneti t�r tartalm�t
�s a c karaktert is ki�rja. Ha a c�l�llom�sra nem lehet t�bb karaktert �rni, az
adatfolyam eof
�llapotba ker�l (�21.3.3). Ha ez nem okoz kiv�telt, a traits_type::eof() �rt�ket
kapjuk.
A showmanyc() . .show how many characters., .mondd meg, h�ny karakter. . egy igen
�rdekes
f�ggv�ny. C�lja az, hogy a felhaszn�l� lek�rdezhesse, h�ny karaktert tudunk
.gyorsan
. beolvasni, azaz az oper�ci�s rendszer �tmeneti t�rainak ki�r�t�s�vel, de a
lemezrol val
� olvas�s megv�r�sa n�lk�l. A showmanyc() f�ggv�ny .1 �rt�ket ad vissza, ha nem
tudja
garant�lni, hogy ak�r egy karaktert is be tudn�nk olvasni a f�jlv�ge jel
meg�rkez�se elott.
Ez az elj�r�s (sz�ks�gszeruen) el�g alacsony szintu, �s nagym�rt�kben f�gg az
adott megval
�s�t�st�l. Soha ne haszn�ljuk a showmanyc() f�ggv�nyt fejlesztorendszer�nk
dokument
�ci�j�nak alapos tanulm�nyoz�sa �s egy kis k�s�rletez�s n�lk�l.
Alap�rtelmez�s szerint minden adatfolyam a glob�lis helyi saj�toss�goknak (global
local)
megfeleloen (�21.7) muk�dik. A pubimbue(loc) vagy az imbue(loc) f�ggv�ny
megh�v�s�-
val az adatfolyamot a loc objektumban megfogalmazott helyi saj�toss�gok
haszn�lat�ra utas
�thatjuk.
Az adott adatfolyamhoz haszn�lt streambuf oszt�lyt a basic_streambuf oszt�lyb�l
kell sz�rmaztatnunk.
Ebben kell szerepelnie azoknak a konstruktoroknak �s kezdo�rt�k-ad� f�ggv�-
nyeknek, melyek a streambuf objektumot a karakterek val�di forr�s�hoz vagy
c�lj�hoz k�tik,
�s ez �rja fel�l a virtu�lis f�ggv�nyeket az �tmeneti t�rol�s m�dj�nak
megval�s�t�s�hoz:
template <class Ch, class Tr = char_traits<Ch> >
class basic_filebuf : public basic_streambuf<Ch,Tr> {
public:
basic_filebuf();
virtual ~basic_filebuf();
bool is_open() const;
basic_filebuf* open(const char* p, ios_base::openmode mode);
basic_filebuf* close();
protected:
virtual int showmanyc();
virtual int_type underflow();
virtual int_type uflow();
virtual int_type pbackfail(int_type c = Tr::eof());
872 A standard k�nyvt�r
virtual int_type overflow(int_type c = Tr::eof());
virtual basic_streambuf<Ch,Tr>* setbuf(Ch* p, streamsize n);
virtual pos_type seekoff(off_type off, ios_base::seekdir way,
ios_base::openmode m = ios_base::in|ios_base::out);
virtual pos_type seekpos(pos_type p,
ios_base::openmode m = ios_base::in|ios_base::out);
virtual int sync();
virtual void imbue(const locale& loc);
};
Az �tmeneti t�rak kezel�s�re haszn�lt f�ggv�nyek v�ltozatlan form�ban a
basic_streambuf
oszt�lyb�l sz�rmaznak. Csak a kezdeti �rt�kad�sra �s a t�rol�si m�dszerre hat�
f�ggv�nyeket
kell k�l�n megadnunk.
Szok�s szerint a leggyakoribb oszt�lyokat �s .sz�les. megfeleloiket k�l�n typedef-
ek teszik
k�nnyen el�rhetov�:
typedef basic_streambuf<char> streambuf;
typedef basic_stringbuf<char> stringbuf;
typedef basic_filebuf<char> filebuf;
typedef basic_streambuf<wchar_t> wstreambuf;
typedef basic_stringbuf<wchar_t> wstringbuf;
typedef basic_filebuf<wchar_t> wfilebuf;
21.7. Helyi saj�toss�gok
A locale egy olyan objektum, amely a karakterek betuk, sz�mok stb. szerinti
oszt�lyoz�s�-
nak m�dj�t adja meg, illetve a karakterl�ncok rendez�si sorrendj�t �s a sz�mok
megjelen�-
si form�j�t ki�r�skor �s beolvas�skor. Az iostream k�nyvt�r �ltal�ban
automatikusan haszn
�l egy �ltal�nos locale objektumot, amely biztos�tja n�h�ny nyelv �s kult�ra
szok�sainak
betart�s�t. Ha ez megfelel c�ljainknak, nem is kell foglalkoznunk locale
objektumokkal. Ha
azonban m�s szok�sokat akarunk k�vetni, akkor az adatfolyam viselked�s�t �gy
v�ltoztathatjuk
meg, hogy lecser�lj�k a hozz� k�t�tt locale objektumot.
21. Adatfolyamok 873
Az std n�vt�rhez tartoz� locale oszt�lyt a <locale> fej�llom�ny �rja le:
class locale { //a teljes deklar�ci�t l�sd �D.2
public:
// ...
locale() throw(); // az aktu�lis glob�lis locale m�solata
explicit locale(const char* name); // locale l�trehoz�sa C st�lus� locale n�v
alapj�n
basic_string<char> name() const; // a haszn�lt locale neve
locale(const locale&) throw(); // locale m�sol�sa
const locale& operator=(const locale& ) throw(); // locale m�sol�sa
static locale global(const locale&); // a glob�lis locale be�ll�t�sa
// (az elozo �rt�k kiolvas�sa)
static const locale& classic(); // a C �ltal meghat�rozott locale
};
A helyi saj�toss�gok legk�z�ns�gesebb haszn�lata, amikor egy locale objektumot egy
m�-
sikra kell cser�ln�nk:
void f()
{
std::locale loc("POSIX"); // szabv�nyos POSIX locale
cin.imbue(loc); // cin haszn�lja loc-ot
// ...
cin.imbue(std::locale()); // cin vissza�ll�t�sa az alap�rtelmezett (glob�lis)
// locale haszn�lat�ra
}
Az imbue() f�ggv�ny a basic_ios (�21.7.1) oszt�ly tagja.
L�thatjuk, hogy n�h�ny, viszonylag szabv�nyos locale objektum saj�t karakterl�nc-
neveket
haszn�l. Ezeket az elnevez�seket a C nyelv is haszn�lja.
El�rhetj�k azt is, hogy a C++ minden �jonnan k�sz�tett adatfolyamhoz automatikusan
az �ltalunk
megadott locale objektumot haszn�lja:
void g(const locale& loc = locale()) // alap�rtelmez�s szerint az aktu�lis
// glob�lis locale haszn�lata
{
locale old_global = locale::global(loc); // legyen loc az alap�rtelmez�s
// ...
}
874 A standard k�nyvt�r
A glob�lis locale objektum �t�ll�t�sa nincs hat�ssal a m�r l�tezo adatfolyamokra,
mert azok
tov�bbra is a glob�lis locale r�gi �rt�k�t haszn�lj�k. Ez vonatkozik p�ld�ul a
cin, cout stb.
adatfolyamra is. Ha ezeket is meg akarjuk v�ltoztatni, k�zvetlen�l az imbue()
f�ggv�nyt kell
haszn�lnunk.
Azzal, hogy egy adatfolyamhoz �j locale objektumot rendel�nk, t�bb helyen is
megv�ltoztatjuk
arculat�t, viselked�s�t. A locale oszt�ly tagjait k�zvetlen�l is haszn�lhatjuk, �j
helyi saj
�toss�gok meghat�roz�s�ra vagy a r�giek bov�t�s�re. A locale arra is haszn�lhat�,
hogy be-
�ll�tsuk a p�nzegys�gek, d�tumok stb. megjelen�si form�j�t ki- �s bemenetkor
(�21.10[25]),
vagy a k�l�nb�zo k�dk�szletek k�z�tti �talak�t�st. A helyi saj�toss�gok
haszn�lat�nak elv�t,
illetve a locale �s facet (arculat, viselked�s) oszt�lyokat a .D. f�ggel�k �rja
le. A C st�lus�
locale meghat�roz�sa a <clocale> �s a <locale.h> fej�llom�nyokban tal�lhat�.
21.7.1. Adatfolyam-visszah�v�sok
N�ha a programoz�k az adatfolyamok �llapotle�r�s�t bov�teni akarj�k. P�ld�ul
elv�rhatjuk
egy adatfolyamt�l, hogy .tudja., milyen form�ban kell egy komplex sz�mot
megjelen�teni:
pol�r- vagy Descartes-koordin�tarendszerben. Az ios_base oszt�lyban szerepel az
xalloc()
f�ggv�ny, mellyel az ilyen egyszeru �llapotinform�ci�k sz�m�ra foglalhatunk
mem�ri�t.
Az xalloc() �ltal visszaadott �rt�k azt a k�t mem�riater�letet adja meg, amelyet
az iword()
�s a pword() f�ggv�nnyel el�rhet�nk:
class ios_base {
public:
// ...
~ios_base();
locale imbue(const locale& loc); // locale kiolvas�sa �s be�ll�t�sa, l�sd �D.2.3
locale getloc() const; // locale kiolvas�sa
static int xalloc(); // egy eg�sz �s egy mutat� lefoglal�sa (mindketto 0
// kezdo�rt�kkel)
long& iword(int i); // az iword(i) eg�sz el�r�se
void*& pword(int i); // a pword(i) mutat� el�r�se
// visszah�v�sok
enum event { erase_event, imbue_event, copyfmt_event }; // esem�nyt�pusok
typedef void (*event_callback)(event, ios_base&, int i);
void register_callback(event_callback f, int i); // f hozz�rendel�se word(i)-hez
};
21. Adatfolyamok 875
A felhaszn�l�knak �s a k�nyvt�rak k�sz�toinek n�ha sz�ks�g�k van arra, hogy
�rtes�t�st
kapjanak az adatfolyam �llapot�nak megv�ltoz�s�r�l. A register_callback() elj�r�s
seg�ts�-
g�vel a f�ggv�nyeket .bejegyezhetj�k., �s azok akkor futnak le, amikor a nekik
kijel�lt
.esem�ny. bek�vetkezik. Teh�t p�ld�ul az imbue(), a copyfmt() vagy a ~ios_base()
f�ggv
�ny megh�v�sa maga ut�n vonhatja egy bejegyzett f�ggv�ny lefut�s�t, amely
sorrendben
az imbue_event, a copyfmt_event, illetve az erase_event esem�nyt figyeli. Amikor
az �llapot
megv�ltozik, a bejegyzett f�ggv�ny a register_callback() f�ggv�nyben megadott i
param�-
tert kapja meg.
Ez a t�rol�si �s visszah�v�si elj�r�s meglehetosen bonyolult, teh�t csak akkor
haszn�ljuk, ha
felt�tlen�l sz�ks�g�nk van az alacsonyszintu form�z�si szolg�ltat�sok
kibov�t�s�re.
21.8. C st�lus� ki- �s bemenet
Mivel a C �s a C++ k�dokat gyakran keverik, a C++ adatfolyamon alapul� ki- �s
bemeneti
elj�r�sait sokszor egy�tt haszn�ljuk a C nyelv printf() f�ggv�nycsal�dj�t haszn�l�
I/O rendszerrel.
A C st�lus� I/O f�ggv�nyek a <cstdio> �s az <stdio.h> fej�llom�nyban tal�lhat�k.
Mivel a C f�ggv�nyek szabadon megh�vhat�k a C++ programokb�l, sok programoz�
sz�vesebben
haszn�lja a megszokott C ki- �s bemeneti szolg�ltat�sokat, de m�g ha az
adatfolyamokon
alapul� I/O elj�r�sokat r�szes�tj�k is elonyben, n�ha akkor is tal�lkozni fogunk C

st�lus� megold�sokkal.
A C �s a C++ st�lus� be- �s kimenet karakterszinten keverheto. Ha a
sync_with_stdio() f�ggv
�nyt megh�vjuk a legelso adatfolyam alap� I/O muvelet elott, akkor a C �s a C++
st�lus�
elj�r�sok ugyanazokat az �tmeneti t�rakat fogj�k haszn�lni. Ha az elso adatfolyam
muvelet
elott a sync_with_stdio(false) parancsot adjuk ki, az �tmeneti t�rakat a rendszer
biztosan
nem fogja megosztani, �gy egyes esetekben n�velhetj�k a teljes�tm�nyt:
class ios_base {
// ...
static bool sync_with_stdio(bool sync = true); // kiolvas�s �s be�ll�t�s
};
Az adatfolyam elvu kimeneti f�ggv�nyek legfobb elonye a C standard k�nyvt�r�nak
printf() f�ggv�ny�vel szemben, hogy az adatfolyam-f�ggv�nyek t�pusbiztosak �s
egys�ges
st�lust biztos�tanak a k�l�nb�zo objektumok megad�s�ra, legyen azok t�pusa ak�r
be�p�tett,
ak�r felhaszn�l�i.
876 A standard k�nyvt�r
A C �ltal�nos kimeneti f�ggv�nyei form�zott kimenetet �ll�tanak elo, melyben a
megadott
param�terek sorozat�nak megjelen�s�t a format form�z�si karakterl�nc hat�rozza
meg:
int printf(const char* format ...); // �r�s az stdout-ra
int fprintf(FILE*, const char* format ...); // �r�s "file"-ba (stdout, stderr)
int sprintf(char* p, const char* format ...); // �r�s p[0] ... stb.-re
A form�z�si karakterl�nc k�tfajta elemet tartalmazhat: sima karaktereket,
amelyeket a rendszer
egyszeruen a kimeneti adatfolyamba m�sol, illetve �talak�t�s-meghat�roz�sokat
(conversion-specification), melyek mindegyike egy param�ter �talak�t�s�t �s
ki�r�s�t vez�rli.
Az �talak�t�s-meghat�roz�sokat a % karakterrel kell kezdeni:
printf("Jelen volt %d szem�ly.",no_of_members);
Itt a %d azt hat�rozza meg, hogy a no_of_members v�ltoz�t int �rt�kk�nt kell
kezelni �s
a megfelelo decim�lis sz�mjegyek ki�r�s�val kell megjelen�teni.
Ha a no_of_members==127, akkor a megjeleno eredm�ny a k�vetkezo lesz:
Jelen volt 127 szem�ly.
Az �talak�t�s-meghat�roz�sokat igen sokf�lek�ppen megadhatjuk �s nagyfok�
rugalmass�-
got biztos�tanak. A % karaktert k�vetoen az al�bbi jelek �llhatnak:
- A nem k�telezo m�nuszjel azt �rja elo, hogy a rendszer a megadott mezoben az
�talak
�tott �rt�ket balra igaz�tsa.
+ A nem k�telezo pluszjel haszn�lata azt eredm�nyezi, hogy az elojeles t�pus�
�rt�-
kek mindig + vagy - elojellel fognak megjelenni.
0 A nem k�telezo nulla jelent�se: a mezosz�less�g felt�lt�s�re numerikus �rt�kek
eset�n 0 karakterekkel t�rt�nik. Ha a - vagy a pontoss�g megadott, akkor a 0
elo�r�st figyelmen k�v�l hagyjuk.
# A szint�n nem k�telezo # azt jelenti, hogy a lebegopontos �rt�kek mindenk�ppen
tizedesponttal egy�tt jelennek meg, f�ggetlen�l att�l, hogy ut�na esetleg csak 0
sz�mjegyek �llnak; hogy a lez�r� null�k is megjelennek; illetve hogy az okt�lis
sz�-
mok elott egy 0 karakter, hexadecim�lis sz�mok elott pedig a 0x vagy a 0X
karakterp�r jelenik meg.
d A nem k�telezo sz�mjegysorozat a mezo sz�less�g�t hat�rozza meg. Ha az �talak�-
tott �rt�k kevesebb karaktert tartalmaz, mint a mezo sz�less�ge, akkor annak bal
oldal�n (illetve balra igaz�t�s eset�n a jobb oldal�n) �res karakterek jelennek
meg
a megfelelo sz�less�g el�r�se �rdek�ben. Ha a mezosz�less�g megad�s�t 0
karakterrel
kezdj�k, a sz�less�gn�velo karakterek sz�k�z helyett null�k lesznek.
21. Adatfolyamok 877
. A nem k�telezo pont ki�r�s�val v�laszthatjuk el a mezosz�less�get megad� �rt�ket

a k�vetkezo sz�mjegy-sorozatt�l.
d �jabb, nem k�telezo sz�mjegy-sorozat. A pontoss�got hat�rozza meg, azaz e �s f-
�talak�t�s eset�n a tizedes pont ut�n megjeleno sz�mjegyek sz�m�t, karakterl�ncok
eset�ben pedig a megjelen�tendo karakterek legnagyobb sz�m�t.
* A mezosz�less�g vagy a pontoss�g konkr�t megad�sa helyett haszn�lhatjuk a *
karaktert,
melynek hat�s�ra a k�vetkezo param�terben szereplo eg�sz �rt�k adja meg
a k�v�nt �rt�ket.
h A nem k�telezo h karakter azt jelzi, hogy a k�vetkezo d, o, x vagy u egy short
int
param�terre vonatkozik.
l A nem k�telezo l karakter azt jelzi, hogy a k�vetkezo d, o, x vagy u egy long
int
param�terre vonatkozik.
% Azt jelzi, hogy a % karakter ki�rand�. Param�tert nem haszn�l fel.
c Az �talak�t�s t�pus�t jelzo karakter. Az �talak�t� karakterek �s jelent�seik
a k�vetkezok:
d Eg�sz �rt�k, amit t�zes sz�mrendszerben kell megjelen�teni.
i Eg�sz �rt�k, amit t�zes sz�mrendszerben kell megjelen�teni.
o Eg�sz �rt�k, amit nyolcas sz�mrendszerben kell megjelen�teni.
x Eg�sz �rt�k, amit tizenhatos sz�mrendszerben kell megjelen�teni, 0x kezdettel
X Eg�sz �rt�k, amit tizenhatos sz�mrendszerben kell megjelen�teni, 0X kezdettel.
f Egy float vagy egy double param�tert kell t�zes sz�mrendszerbeli �rt�kk�
alak�tani a [-]ddd.ddd form�tummal. A tizedespont ut�n �ll� sz�mjegyek sz�-
m�t a megadott param�ter pontoss�ga hat�rozza meg. Ha sz�ks�g van r�, az
�rt�ket a rendszer kerek�ti. Ha pontoss�g nincs megadva, 6 sz�mjegy jelenik
meg; ha pontoss�gk�nt 0 �rt�ket adunk meg �s a # jelet nem haszn�ljuk,
a tizedesjegyek nem �r�dnak ki.
e Egy float vagy double param�tert alak�t t�zes sz�mrendszerbeli alakj�ra a tudom
�nyos [-]d.ddde+dd vagy a [-]d.ddde-dd alakra, ahol a tizedespont elott
pontosan egy jegy szerepel, m�g a tizedespont ut�n �ll� sz�mjegyek sz�m�t
az adott param�ter pontoss�g-meghat�roz�sa adja meg. Ha sz�ks�ges, az �rt
�ket a rendszer kerek�ti. Ha pontoss�g nincs megadva, az alap�rtelmezett
�rt�k 6 lesz; ha a pontoss�g nulla �s a # jelet nem haszn�ltuk, sem a tizedespont,

sem az ut�na �ll� sz�mjegyek nem jelennek meg.


E Nagyon hasonl�t az e-re, de a kitevo jel�l�s�re ez a forma nagy E betut haszn�l.

g A float vagy double t�pus� param�tert d, f, vagy e st�lusban �rja ki, aszerint,
hogy melyik biztos�tja a legnagyobb pontoss�got a leheto legkisebb ter�leten.
G Ugyanaz, mint a g, de a kitevo jel�l�s�re a nagy E betut haszn�lja.
c Karakter param�tert jelen�t meg. A nullkaraktereket figyelmen k�v�l hagyja.
s Az �gy �tvett param�ter egy karakterl�nc (karakterre hivatkoz� mutat�).
878 A standard k�nyvt�r
A karaktereket addig m�solja a kimenetre, am�g a nullkaraktert, vagy a pontoss
�g-meghat�roz�sban meghat�rozott karaktersz�mot el nem �ri. Ha
a pontoss�g 0 vagy nincs megadva, akkor csak a nullkarakter jelenti a karakterl
�nc ki�r�s�nak v�g�t.
p A param�ter egy mutat�. A megjelen�t�shez haszn�lt form�tum a megval�s�-
t�st�l f�gg.
u Elojel n�lk�li eg�sz param�tert alak�t t�zes sz�mrendszerbeli alakra.
n A printf(), az fprintf() vagy az sprintf() megh�v�s�val eddig ki�rt karakterek
sz�m�t a mutatott int-be �rja.
Az nem fordulhat elo, hogy nulla vagy kicsi mezosz�less�g miatt csonkol�s
t�rt�njen, mert
a rendszer csak akkor foglalkozik a sz�less�g kezel�s�vel, ha a mezo sz�less�ge
meghaladja
a benne szereplo �rt�k sz�less�g�t.
�me egy kicsivel bonyolultabb p�lda:
char* line_format = "#sor sz�ma %d \"%s\"\n";
int line = 13;
char* file_name = "C++/main.c";
printf("int a;\n");
printf(line_format,line,file_name);
printf("int b;\n");
Az eredm�ny a k�vetkezo lesz:
int a;
#sor sz�ma 13 "C++/main.c"
int b;
A printf() f�ggv�ny haszn�lata nem biztons�gos, mert a param�terek beolvas�sakor
nem
t�rt�nik t�pusellenorz�s. Az al�bbi hiba p�ld�ul �ltal�ban megj�solhatatlan
kimenetet eredm
�nyez vagy m�g nagyobb hib�t:
char x;
// ...
printf("rossz bemeneti karakter: %s",x); // %s helyett %c kell
A printf() ennek ellen�re nagyfok� rugalmass�got biztos�t, olyan form�ban, amelyet
a C
programoz�k m�r j�l ismernek.
21. Adatfolyamok 879
A getchar() f�ggv�ny hasonl�an j�l ismert m�dszert ad karakterek beolvas�s�ra:
int i;
while ((i=getchar())!=EOF) { /* i haszn�lata */ }
Figyelj�nk r�, hogy a f�jlv�ge jelet csak akkor tudjuk felismerni az int t�pus�
EOF konstans
seg�ts�g�vel, ha a getchar() �ltal visszaadott �rt�ket is int t�pus� v�ltoz�ban
t�roljuk �s nem
char t�pus� adatk�nt.
A C bemeneti/kimeneti rendszer�nek alaposabb megismer�s�hez olvassunk el egy C
k�zik
�nyvet vagy Kernighan �s Ritchie A C programoz�si nyelv c�mu k�nyv�t (Muszaki
K�nyvkiad
�, 1994) [Kernighan, 1988].
21.9. Tan�csok
[1] Az olyan felhaszn�l�i t�pusokhoz, melyekhez �rtelmes sz�veges forma
rendelheto,
�rdemes megadnunk a >> �s a << oper�tort. �21.2.3, �21.3.5.
[2] Ha alacsony precedenci�j� oper�torokat tartalmaz� kifejez�sek eredm�ny�t
akarjuk
megjelen�teni, z�r�jeleket kell haszn�lnunk. �21.2.
[3] �j >> �s << oper�torok l�trehoz�s�hoz nem kell m�dos�tanunk az istream �s az
ostream oszt�lyt. �21.2.3.
[4] Olyan f�ggv�nyeket is k�sz�thet�nk, amelyek a m�sodik (vagy az ut�ni)
param�ter
alapj�n virtu�lisk�nt muk�dnek. �21.2.3.1.
[5] Ne feledj�k, hogy a >> alap�rtelmez�s szerint �tugorja az �reshely
karaktereket.
�21.3.2.
[6] Alacsonyszintu bemeneti f�ggv�nyeket (p�ld�ul get() �s read()) �ltal�ban csak
magasabb
szintu elj�r�sok megval�s�t�s�hoz kell haszn�lnunk. �21.3.4.
[7] Mindig k�r�ltekintoen fogalmazzuk meg a befejez�si felt�telt, ha a get(), a
getline()
vagy a read() f�ggv�nyt haszn�ljuk. �21.3.4.
[8] Az �llapotjelzo bitek k�zvetlen �t�ll�t�sa helyett haszn�ljunk m�dos�t�kat
(manipulator) az I/O vez�rl�s�hez. �21.3.3, �21.4, �21.4.6.
[9] Kiv�teleket csak a ritk�n elofordul� I/O hib�k kezel�s�re haszn�ljunk.
�21.3.6.
[10] A lek�t�tt adatfolyamok az interakt�v (felhaszn�l�i k�zremuk�d�st v�r�) ki-
�s
bemenethez ny�jtanak seg�ts�get. �21.3.7.
[11] Ha t�bb f�ggv�ny be- �s kil�p�si muveleteit egy helyen akarjuk megfogalmazni,

haszn�ljunk orszemeket. �21.3.8.


880 A standard k�nyvt�r
[12] Param�ter n�lk�li m�dos�t� ut�n ne tegy�nk z�r�jeleket. �21.4.6.2.
[13] Ha szabv�nyos m�dos�t�kat haszn�lunk, ne felejts�k ki programunkb�l az
#include <iomanip> sort. �21.4.6.2.
[14] Egy egyszeru f�ggv�nyobjektum l�trehoz�s�val ak�r egy h�romparam�teru oper�-
tor hat�s�t (�s hat�konys�g�t) is megval�s�thatjuk. �21.4.6.3.
[15] A width meghat�roz�sok csak a k�vetkezo I/O muveletre vonatkoznak. �21.4.4.
[16] A precision be�ll�t�sai minden k�sobbi lebegopontos kimeneti muveletre
hat�ssal
vannak. �21.4.3.
[17] A mem�ri�ban val� form�z�shoz haszn�ljunk karakterl�nc-folyamokat. �21.5.3.
[18] A f�jlfolyamok kezel�si m�dj�t meghat�rozhatjuk. �21.5.1.
[19] Az I/O rendszer bov�t�sekor k�l�n�ts�k el a form�z�st (iostream) �s az
�tmeneti t�-
rol�st (streambuf). �21.1, �21.6.
[20] Az �rt�kek nem szabv�nyos tov�bb�t�s�t �tmeneti t�rral oldjuk meg. �21.6.4.
[21] Az �rt�kek nem szabv�nyos form�z�s�t adatfolyam-muveletekkel oldjuk meg.
�21.2.3, �21.3.5.
[22] A felhaszn�l�i k�dr�szleteket elk�l�n�thetj�k �s �n�ll� egys�gk�nt
kezelhetj�k, ha
f�ggv�nyp�rokat haszn�lunk. �21.6.4.
[23] Az in_avail() f�ggv�ny seg�ts�g�vel meg�llap�thatjuk, hogy a k�vetkezo
bemeneti
muveletnek v�rakoznia kell-e majd a bemenetre. �21.6.4.
[24] V�lasszuk sz�t a biztons�gi k�rd�sekkel foglalkoz� elj�r�sokat azon egyszeru
mu-
veletektol, melyek legfontosabb tulajdons�ga a hat�konys�g. (Az elobbieket
a virtual, az ut�bbiakat az inline kulcssz�val adjuk meg.) �21.6.4.
[25] Haszn�ljuk a locale oszt�lyt a .kultur�lis k�l�nbs�gek. megfogalmaz�s�ra.
�21.7.
[26] A sync_with_stdio(x) f�ggv�nnyel a C st�lus� ki- �s bemenetet
�sszeegyeztethetj�k
a C++ I/O rendszer�vel, de teljesen sz�t is v�laszthatjuk azokat. �21.8.
[27] A C st�lus� I/O haszn�latakor mindig nagyon figyelj�nk a t�pushib�k
elker�l�s�re.
�21.8.
21.10. Feladatok
1. (*1.5) Olvassunk be egy lebegopontos sz�mokat tartalmaz� f�jlt, a beolvasott
sz�mp�rokb�l k�sz�ts�nk komplex �rt�keket, majd ezeket �rjuk ki.
2. (*1.5) Hat�rozzuk meg a Name_and_address (N�v �s c�m) t�pust. Adjuk meg hozz�
a << �s a >> oper�tort. M�soljunk le egy Name_and_address objektumokat tartalmaz
� adatfolyamot.
3. (*2.5) Pr�b�ljunk meg lem�solni olyan Name_and_address objektumokb�l �ll�
adatfolyamot, melyben a leheto legt�bb hiba szerepel (p�ld�ul form�z�si hib�k,
21. Adatfolyamok 881
karakterl�ncok t�l korai v�gzod�se stb.). Pr�b�ljuk meg �gy kezelni ezeket a hib�-

kat, hogy a m�sol� f�ggv�ny a helyesen form�zott Name_and_address objektumok


t�bbs�g�t be tudja olvasni m�g akkor is, ha a bemenet kor�bban teljesen
�sszekeveredett.
4. (*2.5) �rjuk �jra a Name_and_address t�pus kimeneti form�j�t �gy, hogy az
kev�sb
� legyen �rz�keny a form�z�si hib�kra.
5. (*2.5) K�sz�ts�nk n�h�ny f�ggv�nyt k�l�nb�zo t�pus� inform�ci�k bek�r�s�hez
�s beolvas�s�hoz (p�ld�ul eg�szekhez, lebegopontos sz�mokhoz, f�jlnevekhez,
e-mail c�mekhez, d�tumokhoz, szem�lyi adatokhoz stb.). Pr�b�ljunk min�l
�zembiztosabb
f�ggv�nyeket k�sz�teni.
6. (*1.5) �rjunk programot, amely ki�rja (a) az �sszes kisbetut, (b) az �sszes
betut, (c)
az �sszes betut �s sz�mjegyet, (d) minden karaktert, amely rendszer�nkben C++
azonos�t�ban szerepelhet, (e) az �sszes �r�sjelet, (f) a vez�rlokarakterek
k�djait, (g)
az �sszes �reshely karaktert, (h) az �reshely karakterek k�djait, �s v�g�l (i)
minden
l�that� karaktert.
7. (*2) Olvassunk be sz�vegsorokat egy r�gz�tett m�retu karakteres �tmeneti t�rba.

T�r�lj�nk minden �reshely karaktert �s az alfanumerikus karaktereket helyettes�ts


�k az �b�c� k�vetkezo karakter�vel (a z betut a-ra, a 9-et 0-ra cser�lj�k). �rjuk
ki
az �gy keletkezo sorokat.
8. (*3) K�sz�ts�nk egy miniatur adatfolyam I/O rendszert, melyben defini�ljuk az
istream, az ostream, az ifstream, �s az ofstream oszt�lyt, melyek biztos�tj�k az
operator<<( ) �s az operator>>( ) f�ggv�nyt eg�sz �rt�kekhez, illetve az olyan
elj�-
r�sokat, mint az open() �s a close() a f�jlok kezel�s�hez.
9. (*4) �rjuk meg a C szabv�nyos ki- �s bemeneti k�nyvt�r�t (<stdio.h>) a C++
szabv
�nyos I/O k�nyvt�r�nak (<iostream>) felhaszn�l�s�val.
10. (*4) �rjuk meg a C++ szabv�nyos I/O k�nyvt�r�t (<iostream>) a C szabv�nyos I/O

k�nyvt�r�nak (<stdio.h>) felhaszn�l�s�val.


11. (*4) �rjuk meg a C �s a C++ k�nyvt�rat �gy, hogy azokat egyszerre
haszn�lhassuk.
12. (*2) K�sz�ts�nk egy oszt�lyt, amelyben a [ ] oper�tor seg�ts�g�vel k�zvetlen�l
olvashatjuk
be egy f�jl karaktereit.
13. (*3) Ism�telj�k meg a �21.10[12] feladatot �gy, hogy a [ ] oper�tort �r�sra �s
olvas�sra
is haszn�lhassuk. �tlet: a [ ] adjon vissza egy olyan objektumot, amely egy
f�jlpoz
�ci�t azonos�t. Az ezen objektumra vonatkoz� �rt�kad�s �rja a f�jlba a megfelelo
adatokat, m�g az objektumnak char t�pusra val� automatikus konverzi�ja jelentse
a megfelelo karakter beolvas�s�t az �llom�nyb�l.
14. (*2) Ism�telj�k meg a �21.10[13] feladatot �gy, hogy a [ ] oper�tor
tetszoleges t�pus
� objektum beolvas�s�hoz haszn�lhat� legyen, ne csak karakterekhez.
15. (*3.5) �rjuk meg az istream �s az ostream olyan v�ltozat�t, amely a sz�mokat
bin�-
ris form�ban �rja ki, �s olvassa be ahelyett, hogy sz�veges alakra alak�tan�
azokat.
Vizsg�ljuk meg ezen megk�zel�t�s elonyeit �s h�tr�nyait a karakteralap� megk�zel
�t�ssel szemben.
882 A standard k�nyvt�r
16. (*3.5) Tervezz�nk �s �rjunk meg egy mintailleszto bemeneti muveletet.
Haszn�ljunk
printf st�lus� form�zott karakterl�ncokat a minta meghat�roz�s�hoz. Azt is tegy
�k lehetov�, hogy t�bbf�le mint�t .r�pr�b�lhassunk. a bemenetre a form�tum
megtal�l�s�hoz. A mintailleszto bemeneti oszt�lyt sz�rmaztassuk az istream oszt
�lyb�l.
17. (*4) Tal�ljunk ki (�s �rjunk meg) egy sokkal jobb mintailleszt�si elj�r�st.
Hat�rozzuk
meg pontosan, miben jobb a mi megold�sunk.
18. (*2) Hat�rozzunk meg egy kimeneti m�dos�t�t (neve legyen based), amely k�t
param
�tert kap: egy alapsz�mot �s egy int �rt�ket, �s az eg�sznek az alapsz�m szerinti
sz�mrendszerbeli alakj�t �rja a kimenetre. A based(2,9) hat�s�ra p�ld�ul az
1001 jelenjen meg a kimeneten.
19. (*2) K�sz�ts�nk m�dos�t�kat, melyek ki- �s bekapcsolj�k a karakterek
vissza�r�s�t
(echoing).
20. (*2) �rjuk meg a �21.4.6.3 r�sz Bound_form oszt�ly�t a szok�sos be�p�tett
t�pusokra.
21. (*2) �rjuk meg a �21.4.6.3 r�sz Bound_form oszt�ly�t �gy, hogy egy kimeneti
mu-
velet soha ne csordulhasson t�l a sz�m�ra megadott width() �rt�ken. Azt is
biztos�-
tanunk kell a programoz� sz�m�ra, hogy a kimenet soha ne csonkuljon a megadott
pontoss�gi �rt�k miatt.
22. (*3) K�sz�ts�nk egy encrypt(k) m�dos�t�t, melynek hat�s�ra az ostream
objektumon
minden kimenet a k �rt�kkel titkos�tva jelenik meg. �rjuk meg a m�dos�t�
decrypt(k) p�rj�t is az istream oszt�lyra. Adjunk lehetos�get a titkos�t�s
kikapcsol�-
s�ra is, teh�t tudjunk �jra .olvashat�. sz�veget �rni a kimenetre.
23. (*2) K�vess�k v�gig egy karakter �tj�t rendszer�nkben a billentyuzettol a
k�perny
oig az al�bbi egyszeru utas�t�ssorozat eset�ben:
char c;
cin >> c;
cout << c << endl;
24. (*2) M�dos�tsuk a �21.3.6 pont readints() f�ggv�ny�t �gy, hogy minden kiv�telt

kezelni tudjon. �tlet: .kezdeti �rt�kad�s az eroforr�s megszerz�s�vel..


25. (*2.5) Minden rendszerben lehetos�g van arra, hogy d�tumokat �rjunk, olvassunk

�s �br�zoljunk egy locale objektum le�r�sa szerint. Tal�ljuk meg saj�t rendszer�nk

dokument�ci�j�ban, hogyan val�s�thatjuk ezt meg, �s k�sz�ts�nk egy r�vid


programot,
amely e m�dszer felhaszn�l�s�val �r �s olvas karaktereket. �tlet: struct tm.
26. (*2.5) Hozzuk l�tre az ostrstream oszt�lyt az ostream oszt�lyb�l val�
sz�rmaztat�ssal
�gy, hogy egy karaktert�mbh�z (C st�lus� karakterl�nchoz) k�thess�k hozz�,
ugyan�gy, ahogy az ostringstream k�theto egy string objektumhoz. Ne m�soljuk
be a t�mb�t az ostrstream objektumba, sem ki onnan. Az ostrstream oszt�lynak
21. Adatfolyamok 883
egyszeru lehetos�get kell adnia a t�mbbe val� �r�sra. Az oszt�lyt olyan mem�ri�-
ban v�gzett form�z�sokra szeretn�nk felhaszn�lni, mint az al�bbi:
char buf[message_size];
ostrstream ost(buf,message_size);
do_something(arguments,ost); // ki�r�s buf-ra ost-on kereszt�l
cout << buf; // ost hozz�adja a lez�r� 0-t
A do_something()-hoz hasonl� muveletek az ost adatfolyamra �rnak, esetleg tov
�bbadj�k azt saj�t r�sz-muveleteiknek, �s a szabv�nyos kimeneti f�ggv�nyeket
haszn�lj�k. A t�lcsordul�s ellenorz�s�re nincs sz�ks�g, mert az ost ismeri a saj�t

m�ret�t �s fail() �llapotba ker�l, amikor megtelik. V�g�l a display() muvelet megh
�v�s�val az �zenetet egy .val�di. kimeneti adatfolyamba �rhatjuk. Ez a m�dszer
nagyon hasznos lehet akkor, ha a v�gso kimeneti eszk�z bonyolultabban tudja
megval�s�tani a kimenetet, mint a szok�sos sorki�r�son alapul� kimeneti eszk�z�k.
Az ost objektumban t�rolt sz�veget p�ld�ul megjelen�thetj�k a k�pernyo egy r�gz�-
tett m�retu ter�let�n. Ugyan�gy hozzuk l�tre az istrstream oszt�lyt, amely egy
bemeneti
karakterl�nc-folyam, ami nullkarakterrel lez�rt karakterl�ncb�l olvas. A lez
�r� nullkaraktert haszn�ljuk f�jlv�ge jelk�nt. Ezek az strstream oszt�lyok az
eredeti
adatfolyam-k�nyvt�r r�sz�t k�pezt�k �s gyakran szerepelnek a <strstream.h> fej-
�llom�nyban.
27. (*2.5) K�sz�ts�k el a general() m�dos�t�t, amely vissza�ll�tja az adatfolyamot
az
eredeti form�tum�ra, hasonl�an ahhoz, ahogy a scientific() (�21.4.6.2) az
adatfolyamot
tudom�nyos form�tumra �ll�tja.
884 A standard k�nyvt�r
Sz�mok
.A sz�m�t�s c�lja nem a sz�m,
hanem a tiszt�nl�t�s..
(R.W. Hamming)
.. de a tanul�nak gyakran
sz�mokon kereszt�l
vezet az �t a tiszt�nl�t�shoz..
(A. Ralston)
Bevezet�s . A sz�mt�pusok korl�tai . Matematikai f�ggv�nyek . valarray .
Vektormuveletek
. Szeletek . slice_array . Az ideiglenes v�ltoz�k kik�sz�b�l�se . gslice_array
. mask_array . indirect_array . complex . �ltal�nos�tott algoritmusok . V�letlen
sz�mok
. Tan�csok . Gyakorlatok
22
22.1. Bevezet�s
A gyakorlatban ritk�n akadunk olyan programoz�si feladatra, ahol nincs sz�ks�g
valamilyen
sz�mokkal v�gzett muveletre. Programjainkban �ltal�ban . az alapveto aritmetikai
mu-
veleteken k�v�l . sz�ks�g�nk van egy kis igazi matematik�ra is. Ez a fejezet a
standard
k�nyvt�r ehhez kapcsol�d� szolg�ltat�sait mutatja be.
Sem a C, sem a C++ nyelvet nem elsodlegesen sz�mmuveletek elv�gz�s�re tervezt�k.
Azok
viszont jellemzoen m�s k�rnyezetbe be�gyazva fordulnak elo . megeml�theto itt az
adatb�-
zis- illetve h�l�zatkezel�s, a muszerek vez�rl�se, a grafika, a p�nz�gyi
sz�m�t�sok, valamint
a szimul�ci� k�l�nb�zo ter�letei ., �gy a C++ remek lehetos�geket ny�jthat a
n�mileg bonyolultabb
matematikai feladatok elv�gz�s�re is, amelyekkel az elobb eml�tett ter�letek
megfeleloen kiszolg�lhat�k. A sz�mmuveletek sk�l�ja igen sz�les, az egyszeru
ciklusokt�l
a lebegopontos sz�mokb�l alkotott vektorokig terjed. A C++ ereje az ilyen
�sszetettebb
adatszerkezeteken v�gzett muveletekn�l mutatkozik meg igaz�n, ez�rt egyre
gyakrabban
alkalmazz�k m�rn�ki �s tudom�nyos sz�m�t�sok elv�gz�s�re. A fejezetben a standard
k�nyvt�r azon szolg�ltat�saival �s elj�r�saival ismerkedhet�nk meg, melyek
kifejezetten
a sz�mmuveletek elv�gz�s�t t�mogatj�k a C++ k�rnyezetben. A matematikai alapok
tiszt�-
z�s�ra k�s�rletet sem tesz�nk, ezeket ismertnek t�telezz�k fel. Az esetleges
hi�nyoss�gok
matematikai (�s nem sz�m�t�stechnik�val foglalkoz�) szakk�nyvekbol p�tolhat�k.
22.2. A sz�mt�pusok korl�toz�sai
Ha egy programban nem csup�n alapszinten v�gz�nk sz�mmuveleteket, mindenk�ppen
sz�ks�g van arra, hogy ismerj�k a be�p�tett t�pusok alapveto tulajdons�gait. Ezek
sokkal ink
�bb az adott fejlesztok�rnyezettol f�ggnek, mintsem a nyelv szab�lyait�l (�4.6).
P�ld�ul
melyik a legnagyobb �br�zolhat� int? Mekkora a legkisebb float? Mi t�rt�nik egy
double t�-
pus� sz�mmal, ha float t�pus�v� alak�tjuk? Kerek�ti vagy csonk�tja a rendszer?
H�ny bitet tartalmaz
a char t�pus?
Az ilyen, �s ehhez hasonl� k�rd�sekre a <limits> fej�llom�nyban le�rt
numeric_limits sablon
(template) specializ�ci�i szolg�lhatnak v�lasszal. L�ssunk egy p�ld�t:
886 A standard k�nyvt�r
void f(double d, int i)
{
if (numeric_limits<unsigned char>::digits != 8) {
// szokatlan b�jt (a bitek sz�ma nem 8)
}
if (i<numeric_limits<short>::min() || numeric_limits<short>::max()<i) {
// i nem t�rolhat� short t�pusban �rt�kveszt�s n�lk�l
}
if (0<d && d<numeric_limits<double>::epsilon()) d = 0;
if (numeric_limits<Quad>::is_specialized) {
// a Quad t�pushoz rendelkez�sre �llnak korl�t-adatok
}
}
Minden specializ�ci� biztos�tja a saj�t param�tert�pus�nak legfontosabb
inform�ci�kat. K�-
vetkez�sk�ppen az �ltal�nos numeric_limits sablon egyszeruen arra szolg�l, hogy
szabv�-
nyos nevet adjon n�h�ny konstansnak �s helyben kifejtett (inline) f�ggv�nynek:
template<class T> class numeric_limits {
public:
static const bool is_specialized = false; // �ll rendelkez�sre inform�ci�
// a numeric_limits<T>-rol?
// �rdektelen alap�rtelmez�sek
};
A t�nyleges inform�ci� az egyedi c�l� v�ltozatokban (specializ�ci�kban) szerepel.
A standard
k�nyvt�r minden v�ltozata az �sszes alapt�pushoz (karakterekhez, eg�szekhez, val�s

sz�mokhoz, valamint a logikai t�pushoz) szolg�ltat egy-egy specializ�ci�t a


numeric_limitsb
ol. Nem szerepel viszont ilyen a t�bbi t�pushoz: a void mutat�hoz, a felsorol�
t�pusokhoz,
vagy a k�nyvt�ri t�pusokhoz (p�ld�ul a complex<double> szerkezethez).
A be�p�tett t�pusok (p�ld�ul a char) eset�ben csup�n n�h�ny adat eml�t�sre m�lt�.
L�ssunk
egy numeric_limits<char>-t olyan megval�s�t�sban, ahol a char 8 bites �s elojeles:

class numeric_limits<char> {
public:
static const bool is_specialized = true; // igen, van adat
static const int digits = 7; // bitek sz�ma ("bin�ris sz�mjegyek") elojel n�lk�l
22. Sz�mok 887
static const bool is_signed = true; // ebben a megval�s�t�sban a char t�pus
// elojeles (signed)
static const bool is_integer = true; // a char eg�sz jellegu t�pus
static char min() throw() { return -128; } // legkisebb �rt�k
static char max() throw() { return 127; } // legnagyobb �rt�k
// deklar�ci�k, amelyek k�z�mb�sek a char t�pus sz�m�ra
};
Jegyezz�k meg, hogy egy elojeles eg�sz t�pus t�nylegesen sz�m�br�zol�sra haszn�lt
bitjeinek
sz�ma (digits) eggyel kevesebb a t�pushoz rendelt bitsz�mn�l, hiszen egy bitet az
elo-
jel foglal le.
A numeric_limits tagjainak t�bbs�ge a lebegopontos sz�mok le�r�s�ra szolg�l. A
k�vetkez
o p�lda egy lehets�ges float-v�ltozatot mutat:
class numeric_limits<float> {
public:
static const bool is_specialized = true;
static const int radix = 2; // a kitevo t�pusa (ebben az esetben 2-es alap�)
static const int digits = 24; // radix sz�mjegyek a mantissz�ban
static const int digits10 = 6; // 10-es alap� sz�mjegyek a mantissz�ban
static const bool is_signed = true;
static const bool is_integer = false;
static const bool is_exact = false;
static float min() throw() { return 1.17549435E-38F; }
static float max() throw() { return 3.40282347E+38F; }
static float epsilon() throw() { return 1.19209290E-07F; }
static float round_error() throw() { return 0.5F; }
static float infinity() throw() { return /* valamilyen �rt�k */; }
static float quiet_NaN() throw() { return /* valamilyen �rt�k */; }
static float signaling_NaN() throw() { return /* valamilyen �rt�k */; }
static float denorm_min() throw() { return min(); }
static const int min_exponent = -125;
static const int min_exponent10 = -37;
static const int max_exponent = +128;
static const int max_exponent10 = +38;
888 A standard k�nyvt�r
static const bool has_infinity = true;
static const bool has_quiet_NaN = true;
static const bool has_signaling_NaN = true;
static const float_denorm_style has_denorm = denorm_absent; // enum a <limits>-bol

static const bool has_denorm_loss = false;


static const bool is_iec559 = true; // megfelel IEC-559-nek
static const bool is_bounded = true;
static const bool is_modulo = false;
static const bool traps = true;
static const bool tinyness_before = true;
static const float_round_style round_style = round_to_nearest; // enum a <limits>-
bol
};
Ne feledj�k, hogy a min() a legkisebb pozit�v norm�lt sz�m, az epsilon pedig a
legkisebb
pozit�v lebegopontos sz�m, amelyre az 1+epsilon-1 �br�zolhat�.
Amikor egy skal�r t�pust egy be�p�tett t�pus seg�ts�g�vel defini�lunk, �rdemes
egy�ttal
a numeric_limits megfelelo specializ�ci�j�t is megadnunk. Ha p�ld�ul egy
n�gyszeres pontoss
�g� Quad, vagy egy k�l�nlegesen pontos eg�sz, long long t�pust k�sz�t�nk, a
felhaszn
�l�k jogos elv�r�sa, hogy l�tezzenek a numeric_limits<Quad> �s a
numeric_limits<long
long> specializ�ci�k.
A numeric_limits-nek elk�pzelheto olyan v�ltozata, mely egy olyan felhaszn�l�i
t�pus tulajdons
�gait �rja le, melynek nem sok k�ze van lebegopontos sz�mokhoz. Az ilyen esetekben

rendszerint aj�nlatosabb a t�pustulajdons�gok le�r�s�ra haszn�lt �ltal�nos elj�r�s


alkalmaz�-
sa, mint egy �j numeric_limits meghat�roz�sa olyan tulajdons�gokkal, melyek a
szabv�nyban
nem szerepelnek.
A lebegopontos sz�mokat helyben kifejtett (inline) f�ggv�nyek �br�zolj�k. A
numeric_limits
oszt�lyban szereplo eg�sz �rt�keket viszont olyan form�ban kell �br�zolnunk, amely
megengedi,
hogy konstans kifejez�sekben felhaszn�ljuk azokat, ez�rt ezek az elemek oszt�lyon
bel�li kezdeti �rt�kad�ssal rendelkeznek (�10.4.6.2). Ha ilyen c�lokra static
const tagokat
haszn�lunk felsorol� t�pusok helyett, ne felejts�k el defini�lni a static
elemeket.
22. Sz�mok 889
22.2.1. Korl�toz�si makr�k
A C++ �r�k�lte a C-tol azokat a makr�kat, melyek le�rj�k az eg�sz t�pusok
tulajdons�gait.
Ezek a <climits>, illetve a <limits.h> fej�llom�nyban szerepelnek. Ilyen makr�
p�ld�ul
a CHAR_BIT vagy az INT_MAX. Ugyan�gy a <cfloat> �s a <float.h> fej�llom�ny azokat
a makr�kat tartalmazza, amelyek a lebegopontos sz�mok tulajdons�gait �rj�k le.
Ezekre p�lda
a DBL_MIN_EXP, a FLT_RADIX vagy a LDBL_MAX.
Mint mindig, a makr�kat most is �rdemes elker�ln�nk.
22.3. Szabv�nyos matematikai f�ggv�nyek
A <cmath> �s a <math.h> fej�llom�ny szolg�ltatja azokat a f�ggv�nyeket, amelyeket
�ltal
�ban .szok�sos matematikai f�ggv�nyeknek. nevez�nk:
double abs(double); // abszol�t�rt�k, ugyanaz mint fabs(); ilyen nincs a C-ben
double fabs(double); // abszol�t�rt�k
double ceil(double d); // a d-n�l nem kisebb legkisebb eg�sz
double floor(double d); // a d-n�l nem nagyobb legnagyobb eg�sz
double sqrt(double d); // d n�gyzetgy�ke, d nem negat�v kell legyen
double pow(double d, double e); // d e-edik hatv�nya,
// hiba, ha d==0 �s e<=0, vagy ha d<0 �s e nem eg�sz
double pow(double d, int i); // d i-edik hatv�nya; ilyen nincs a C-ben
double cos(double); // koszinusz
double sin(double); // szinusz
double tan(double); // tangens
double acos(double); // arkusz koszinusz
double asin(double); // arkusz szinusz
double atan(double); // arkusz tangens
double atan2(double x, double y); // atan(x/y)
double sinh(double); // szinusz hiperbolikusz
double cosh(double); // koszinusz hiperbolikusz
double tanh(double); // tangens hiperbolikusz
890 A standard k�nyvt�r
double exp(double); // e alap� exponenci�lis
double log(double d); // term�szetes (e alap�) logaritmus,
// d nagyobb kell legyen 0-n�l
double log10(double d); // 10-es alap� logaritmus, d nagyobb kell legyen 0-n�l
double modf(double d, double* p); // d t�rt r�sz�vel t�r vissza,
// az eg�sz r�szt *p-be helyezi
double frexp(double d, int* p); // x eleme [.5,1) �s y �gy, hogy d = x*pow(2,y)
legyen;
// visszat�ro �rt�k x, y *p-be helyez�se
double fmod(double d, double m); // lebegopontos marad�k, elojele megfelel d
elojel�nek
double ldexp(double d, int i); // d*pow(2,i)
A <cmath> �s a <math.h> fej�llom�ny ugyanezeket a f�ggv�nyeket float �s long
double param
�terekkel is el�rhetov� teszi.
Ha egy muveletnek t�bb lehets�ges eredm�nye is van (mint p�ld�ul az asin()
eset�ben),
a f�ggv�nyek a null�hoz legk�zelebbi �rt�ket adj�k vissza. Az acos() eredm�nye
mindig
nemnegat�v.
Ezek a f�ggv�nyek a hib�kat az <errno> fej�llom�nyban szereplo errno v�ltoz�
be�ll�t�s�-
val jelzik. Ennek �rt�ke EDOM, ha egy f�ggv�ny nem �rtelmezheto a megadott
param�terre,
�s ERANGE ha az eredm�ny nem �br�zolhat� az adott t�pussal:
void f()
{
errno = 0; // t�rli az elozo hibak�dot
sqrt(-1);
if (errno==EDOM) cerr << "A sqrt() nem defini�lt negat�v param�ter eset�n";
pow(numeric_limits<double>::max(),2);
if (errno == ERANGE) cerr << "A pow() eredm�nye t�l nagy ahhoz,"
<< "hogy double-k�nt �br�zoljuk";
}
A C++ elozm�nyeire visszavezetheto okokb�l n�h�ny matematikai f�ggv�ny a <cstdlib>
fej-
�llom�nyban szerepel a <cmath> helyett:
int abs(int); // abszol�t�rt�k
long abs(long); // abszol�t�rt�k ; ilyen nincs a C-ben
long labs(long); // abszol�t�rt�k
struct div_t { megval�s�t�s_f�ggo quot, rem; };
struct ldiv_t { megval�s�t�s_f�ggo quot, rem; };
22. Sz�mok 891
div_t div(int n, int d); // n oszt�sa d-vel, visszat�r�s (kv�ciens,marad�k)
ldiv_t div(long int n, long int d); // n oszt�sa d-vel, visszat�r�s
(kv�ciens,marad�k);
// ilyen nincs a C-ben
ldiv_t ldiv(long int n, long int d); // n oszt�sa d-vel, visszat�r�s
(kv�ciens,marad�k)
22.4. Vektormuveletek
A legt�bb sz�m�t�si feladat viszonylag egyszeru, egydimenzi�s vektorokra
vonatkozik,
amelyek lebegopontos sz�mokat t�rolnak. Ez�rt a nagyteljes�tm�nyu sz�m�t�g�pek
k�l�n
t�mogatj�k az ilyen vektorok kezel�s�t, a vel�k foglalkoz� k�nyvt�rak sz�les
k�rben haszn
�latosak, �s nagyon sok ter�leten l�tfontoss�g� az ilyen vektorokat kezelo
f�ggv�nyek lehet
o legoptim�lisabb kialak�t�sa. A standard k�nyvt�r tartalmaz egy olyan vektort
(valarray), amelyet kifejezetten a szok�sos matematikai vektormuveletek gyors
v�grehajt�-
s�ra dolgoztak ki.
Mik�zben �ttekintj�k a valarray lehetos�geit, mindig gondoljunk arra, hogy ez egy
viszonylag
alacsony szintu programelem, amely nagy hat�konys�g� sz�m�t�sok elv�gz�s�hez
k�sz�lt. Teh�t az oszt�ly tervez�sekor a legfontosabb c�lkituz�s nem a k�nyelmes
haszn�-
lat volt, hanem a nagyteljes�tm�nyu sz�m�t�g�pek lehetos�geinek min�l jobb
kihaszn�l�sa,
a legerosebb optimaliz�l�si m�dszerek alkalmaz�sa. Ha saj�t programunkban a
rugalmass
�g �s az �ltal�noss�g fontosabb, mint a hat�konys�g, val�sz�nuleg �rdemesebb a
szabv�-
nyos t�rol�k k�z�l v�lasztanunk (melyeket a 16. �s a 17. fejezet mutat be), ne is
pr�b�ljunk
a valarray egyszeru, hat�kony �s sz�nd�kosan hagyom�nyos kereteihez igazodni.
Felmer�lhet benn�nk a k�rd�s, hogy mi�rt nem a valarray neve lett vector, hiszen
ez a hagyom
�nyos, matematikai vektor val�di megfeleloje, �s a �16.3 pont vector oszt�ly�t
k�ne ink
�bb array t�pusnak nevezni. A terminol�gia m�gsem ezt az elnevez�si rendet k�veti.

A valarray numerikus sz�m�t�sokra optimaliz�lt vektor, m�g a vector egy rugalmas


t�rol�,
amely a legk�l�nb�zobb t�pus� objektumok t�rol�s�ra �s kezel�s�re szolg�l. Az
.array.
(t�mb) fogalma erosen k�todik a be�p�tett t�mbt�pushoz.
A valarray t�pust n�gy kiseg�to t�pus eg�sz�ti ki, melyek a valarray egy-egy
r�szhalmaz�t
k�pezik:
� A slice_array �s a gslice_array a szeletek (slice) fogalm�t �br�zolj�k (�22.4.6,

�22.4.8).
� A mask_array egy r�szhalmazt hat�roz meg, �gy, hogy minden elemrol megmondja,
hogy az benne van-e a r�szhalmazban vagy sem (�22.4.9).
892 A standard k�nyvt�r
� Az indirect_array a r�szhalmazba tartoz� elemek index�rt�keinek (sorsz�mainak)
list�j�t tartalmazza (�22.4.10).
22.4.1. Valarray l�trehoz�sa
A valarray t�pus �s a hozz� tartoz� szolg�ltat�sok definici�ja az std n�vt�rben
szerepel �s
a <valarray> fej�llom�ny seg�ts�g�vel �rheto el:
template<class T> class std::valarray {
// �br�zol�s
public:
typedef T value_type;
valarray(); // valarray size()==0 m�rettel
explicit valarray(size_t n); // n elem, �rt�k�k: T()
valarray(const T& val, size_t n); // n elem, �rt�k�k: val
valarray(const T* p, size_t n); // n elem, �rt�k�k: p[0], p[1], ...
valarray(const valarray& v); // v m�solata
valarray(const slice_array<T>&); // l�sd �22.4.6
valarray(const gslice_array<T>&); // l�sd �22.4.8
valarray(const mask_array<T>&); // l�sd �22.4.9
valarray(const indirect_array<T>&); // l�sd �22.4.10
~valarray();
// ...
};
Ezek a konstruktorok lehetov� teszik, hogy egy valarray objektumnak a kiseg�to
numerikus
t�mbt�pusok vagy �n�ll� �rt�kek seg�ts�g�vel adjunk kezdo�rt�ket:
valarray<double> v0; // helyfoglal�s, v0-nak k�sobb adunk �rt�ket
valarray<float> v1(1000); // 1000 elem, mindegyik �rt�ke float()==0.0F
valarray<int> v2(-1,2000); // 2000 elem, mindegyik �rt�ke -1
valarray<double> v3(100,9.8064); // hiba: lebegopontos valarray m�ret
valarray<double> v4 = v3; // v4 elemsz�ma v3.size()
A k�tparam�teru konstruktorokban az �rt�ket az elemsz�m elott kell megadnunk. Ez
elt�r
a szabv�nyos t�rol�kban haszn�lt megold�st�l (�16.3.4).
22. Sz�mok 893
A m�sol� konstruktornak �tadott valarray param�ter elemeinek sz�ma hat�rozza meg a
l�trej
�vo valarray m�ret�t.
A legt�bb program t�bl�kb�l vagy valamilyen bemeneti muvelet seg�ts�g�vel jut
hozz� az adatokhoz.
Ezt t�mogatja az a konstruktor, amely egy be�p�tett t�mbbol m�solja ki az
elemeket:
const double vd[ ] = { 0, 1, 2, 3, 4 };
const int vi[ ] = { 0, 1, 2, 3, 4 };
valarray<double> v3(vd,4); // 4 elem: 0,1,2,3
valarray<double> v4(vi,4); // t�pushiba: vi nem double-ra mutat
valarray<double> v5(vd,8); // nem meghat�rozott: t�l kev�s elem a kezdo�rt�k-
ad�ban
Ez a kezdo�rt�k-ad� forma nagyon fontos, mert a legt�bb numerikus program nagy
t�mb
�k form�j�ban adja meg az adatokat.
A valarray t�pust �s kiseg�to szolg�ltat�sait nagy sebess�gu sz�m�t�sokhoz
tervezt�k. Ez n�-
h�ny, a felhaszn�l�kra vonatkoz� korl�toz�sban, �s n�h�ny, a megval�s�t�kra
vonatkoz�
engedm�nyben nyilv�nul meg. A valarray k�sz�toje szinte b�rmilyen optimaliz�l�si
m�dszert
haszn�lhat, amit csak el tud k�pzelni. A muveletek p�ld�ul lehetnek helyben
kifejtettek,
a valarray muveleteit pedig mell�khat�sok n�lk�linek tekinthetj�k (persze saj�t
param
�tereikre ez nem vonatkozik). Egy valarray objektumr�l felt�telezhetj�k, hogy nem
rendelkezik �ln�vvel (alias), kiseg�to t�pusokat b�rmikor bevezethet�nk, �s az
ideiglenes
v�ltoz�kat is szabadon kik�sz�b�lhetj�k, ha az alapveto jelent�st �gy is meg
tudjuk tartani.
Ez�rt a <valarray> fej�llom�nyban szereplo deklar�ci�k jelentosen el is t�rhetnek
az itt bemutatott
(�s a szabv�nyban szereplo) form�t�l, de azon programok sz�m�ra, melyek nem
s�rtik meg a szab�lyokat, mindenk�ppen ugyanazokat a muveleteket kell
biztos�taniuk,
ugyanazzal a jelent�ssel. A valarray elemeinek m�sol�sa p�ld�ul a szok�sos m�don
kell,
hogy muk�dj�n (�17.1.4).
22.4.2. A valarray indexel�se �s az �rt�kad�s
A valarray oszt�ly eset�ben az indexel�s egyar�nt haszn�lhat� �n�ll� elemek
el�r�s�hez �s
r�szt�mb�k kijel�l�s�hez:
template<class T> class valarray {
public:
// ...
valarray& operator=(const valarray& v); // v m�sol�sa
valarray& operator=(const T& val); // minden elem val-t kapja �rt�k�l
894 A standard k�nyvt�r
T operator[ ](size_t) const;
T& operator[ ](size_t);
valarray operator[ ](slice) const; // l�sd �22.4.6
slice_array<T> operator[ ](slice);
valarray operator[ ](const gslice&) const; // l�sd �22.4.8
gslice_array<T> operator[ ](const gslice&);
valarray operator[ ](const valarray<bool>&) const; // l�sd �22.4.9
mask_array<T> operator[ ](const valarray<bool>&);
valarray operator[ ](const valarray<size_t>&) const; // l�sd �22.4.10
indirect_array<T> operator[ ](const valarray<size_t>&);
valarray& operator=(const slice_array<T>&); // l�sd �22.4.6
valarray& operator=(const gslice_array<T>&); // l�sd �22.4.8
valarray& operator=(const mask_array<T>&); // l�sd �22.4.9
valarray& operator=(const indirect_array<T>&); // l�sd �22.4.10
// ...
};
Egy valarray objektumot �rt�k�l adhatunk egy m�sik, ugyanolyan m�retu valarray-
nek.
Elv�r�sainknak megfeleloen a v1=v2 utas�t�s a v2 minden elem�t a v1 megfelelo
elem�be
m�solja. Ha a t�mb�k k�l�nb�zo m�retuek, az eredm�ny nem meghat�rozott lesz, mert
a sebess�gre optimaliz�lt valarray oszt�lyt�l nem k�vetelhetj�k meg, hogy nem
megfelelo
m�retu objektum �rt�k�l ad�sakor k�nnyen �rtheto hibajelz�st (p�ld�ul kiv�telt)
kapjunk,
vagy m�s, logikus viselked�st tapasztaljunk.
Ezen hagyom�nyos �rt�kad�s mellett lehetos�g van arra is, hogy egy valarray
objektumhoz
egy skal�r �rt�ket rendelj�nk. A v=7 utas�t�s p�ld�ul a v valarray minden egyes
elem�be
a 7 �rt�ket �rja. Ez elso r�n�z�sre el�g meglepo, �s szerep�t �gy �rthetj�k meg
legink�bb,
ha �gy gondolunk r�, mint az �rt�kad� muveleteknek egy, n�h�ny esetben hasznos,
.elfajzott
. v�ltozat�ra (�22.4.3).
Az eg�szekkel val� sorsz�moz�s a szok�sos m�don muk�dik, tartom�nyellenorz�s
n�lk�l.
Az �n�ll� elemek kiv�laszt�sa mellett a valarray indexel�se lehetos�get ad
r�szt�mb�k
n�gyf�le kijel�l�s�re is (�22.4.6). Megford�tva, az �rt�kad� utas�t�sok (�s a
konstruktorok,
�22.4.1) ilyen r�szt�mb�ket is elfogadnak param�terk�nt. A valarray t�pusra
megval�s�tott
�rt�kad� utas�t�sok biztos�tj�k, hogy a kiseg�to t�mb t�pusokat (mint a
slice_array) ne kelljen
�talak�tanunk valarray t�pusra, mielott �rt�k�l adjuk azokat. A hat�konys�g
biztos�t�sa
22. Sz�mok 895
�rdek�ben egy alapos fejlesztok�rnyezetnek illik a vektor m�s muveleteihez
(p�ld�ul a +
�s a *) is biztos�tani az ilyen v�ltozatokat. Ezenk�v�l a vektormuveletek
sz�mtalan m�don
optimaliz�lhat�k, szeletek (slice) vagy m�s kiseg�to vektort�pusok haszn�lat�val.
22.4.3. Muveletek tagf�ggv�nyk�nt
A nyilv�nval� �s a kev�sb� nyilv�nval� tagf�ggv�nyek list�ja k�vetkezo:
template<class T> class valarray {
public:
// ...
valarray& operator*=(const T& arg); // v[i]*=arg minden elemre
// hasonl�an: /=, %=, +=, -=, ^=, &=, |=, <<=, �s >>=
T sum() const; // elemek �sszege, += haszn�lat�val
T min() const; // legkisebb �rt�k, < haszn�lat�val
T max() const; // legnagyobb �rt�k, < haszn�lat�val
valarray shift(int i) const; // logikai l�ptet�s (balra, ha 0<i; jobbra, ha i<0)
valarray cshift(int i) const; // ciklikus l�ptet�s (balra, ha 0<i; jobbra, ha i<0)

valarray apply(T f(T)) const; // eredm�ny[i] = f(v[i]) minden elemre


valarray apply(T f(const T&)) const;
valarray operator-() const; // eredm�ny[i] = -v[i] minden elemre
// hasonl�an: +, ~, !
size_t size() const; // elemek sz�ma
void resize(size_t n, const T& val = T()); // n elem, �rt�k�k val
};
Ha size()=0, akkor sum(), min() �s max() �rt�ke nem meghat�rozott.
P�ld�ul, ha v egy valarray, akkor a v*=.2 vagy a v/=1.3 utas�t�sok alkalmazhat�ak
r�. Ha
skal�rmuveleteket hajtunk v�gre egy vektoron, akkor az azt jelenti, hogy a vektor
minden
elem�re elv�gezz�k azt. Szok�s szerint, egyszerubb a *= muveletet optimaliz�lni,
mint a *
�s az = p�ros�t�s�t (�11.3.1).
896 A standard k�nyvt�r
Figyelj�k meg, hogy a nem �rt�kad� muveletek mindig �j valarray objektumot hoznak
l�tre:
double incr(double d) { return d+1; }
void f(valarray<double>& v)
{
valarray<double> v2 = v.apply(incr); // �j, megn�velt valarray-t hoz l�tre,
megn�velt �rt�kkel
}
Ezen programr�szlet hat�s�ra a v �rt�ke nem v�ltozik. Sajnos az apply() nem k�pes
f�ggv
�nyobjektumokat (�18.4) haszn�lni param�terk�nt (�22.9.[1]).
A logikai �s a ciklikus l�pteto f�ggv�nyek (a shift() �s a cshift()) olyan �j
valarray objektumokat
adnak vissza, amelyben az elemek megfeleloen el vannak l�ptetve. Az eredeti vektor

itt is v�ltozatlan marad. A v2=v.cshift(n) ciklikus l�ptet�s p�ld�ul egy olyan


valarray objektumot
eredm�nyez, melynek elemeire v2[i]==v[(i+n)%v.size()].. A v3=v.shift(n) logikai
l�pteto muvelet hat�s�ra a v3[i] a v[i+n] �rt�ket veszi fel, ha az i+n l�tezo
indexe a v vektornak.
Ellenkezo esetben az adott elembe a vektor alap�rtelmezett �rt�ke ker�l. Ebbol
k�vetkezik,
hogy a shift() �s a cshift() is balra tolja az elemeket, ha pozit�v param�tert
adunk
meg, �s jobbra, ha negat�v �rt�ket:
void f()
{
int alpha[ ] = { 1, 2, 3, 4, 5 ,6, 7, 8 };
valarray<int> v(alpha,8); // 1, 2, 3, 4, 5, 6, 7, 8
valarray<int> v2 = v.shift(2); // 3, 4, 5, 6, 7, 8, 0, 0
valarray<int> v3 = v<<2; // 4, 8, 12, 16, 20, 24, 28, 32
valarray<int> v4 = v.shift(-2); // 0, 0, 1, 2, 3, 4, 5, 6
valarray<int> v5 = v>>2; // 0, 0, 0, 1, 1, 1, 1, 2
valarray<int> v6 = v.cshift(2); // 3, 4, 5, 6, 7, 8, 1, 2
valarray<int> v7 = v.cshift(-2); // 7, 8, 1, 2, 3, 4, 5, 6
}
A valarray t�pus eset�ben a << �s a >> oper�tor bitenk�nti l�ptet�st v�gez, teh�t
nem elemeket
tolnak el �s nem is I/O muveletek (�22.4). Ennek megfeleloen a <<= �s a >>=
muveletekkel
elemeken bel�li eltol�st v�gezhet�nk eg�sz t�pus� elemek eset�ben:
void f(valarray<int> vi, valarray<double> vd)
{
vi <<= 2; // vi[i]<<=2, vi minden elem�re
vd <<= 2; // hiba: a l�ptet�s nem meghat�rozott lebegopontos �rt�kekre
}
22. Sz�mok 897
A valarray m�ret�t m�dos�thatjuk is. A resize() itt nem arra szolg�l, hogy a
valarray oszt
�lyt egy dinamikusan n�vekedni k�pes adatszerkezett� tegye . mint ahogy a vector
�s
a string eset�ben t�rt�nik ., hanem �j kezdo�rt�ket ad� muvelet, amely a l�tezo
elemeket
is lecser�li a valarray alap�rtelmezett �rt�k�re, �gy a r�gi elemeket v�glegesen
elvesz�tj�k.
Az �tm�retez�sre sz�nt valarray objektumokat gyakran �res vektork�nt hozzuk l�tre.
Gondoljuk
v�gig p�ld�ul, hogyan adhatunk kezdo�rt�ket egy valarray objektumnak bemenet
alapj�n:
void f()
{
int n = 0;
cin >> n; // a t�mb m�ret�nek beolvas�sa
if (n<=0) error("hib�s t�mbm�ret");
valarray<double> v(n); // t�mb l�trehoz�sa a sz�ks�ges m�rettel
int i = 0;
while (i<n && cin>>v[i++]) ; // a t�mb felt�lt�se
if (i!=n) error("t�l kev�s bemeneti elem");
// ...
}
Ha a bemenetet k�l�n f�ggv�nyben szeretn�nk kezelni, a k�vetkezot tehetj�k:
void initialize_from_input(valarray<double>& v)
{
int n = 0;
cin >> n; // a t�mb m�ret�nek beolvas�sa
if (n<=0) error("hib�s t�mbm�ret");
v.resize(n); // v �tm�retez�se a sz�ks�ges m�retre
int i = 0;
while (i<n && cin>>v[i++]) ; // a t�mb felt�lt�se
if (i!=n) error("t�l kev�s bemeneti elem");
}
void g()
{
valarray<double> v; // alap�rtelmezett t�mb l�trehoz�sa
initialize_from_input(v); // v m�retez�se �s felt�lt�se
// ...
}
Ezzel a megold�ssal elker�lhetj�k nagy m�retu adatter�letek m�sol�s�t.
898 A standard k�nyvt�r
Ha azt szeretn�nk, hogy egy valarray megorizze az �rt�kes adatokat, mik�zben
dinamikusan
n�vekszik, ideiglenes v�ltoz�t kell haszn�lnunk:
void grow(valarray<int>& v, size_t n)
{
if (n<=v.size()) return;
valarray<int> tmp(n); // n alap�rtelmezett elem
copy(&v[0],&v[v.size()],&tmp[0]); // m�sol� algoritmus �18.6.1-bol
v.resize(n);
copy(&tmp[0],&tmp[v.size()],&v[0]);
}
A valarray t�pust nem az ilyen felhaszn�l�si ter�letekre tervezt�k. Egy valarray
objektumnak
nem illik megv�ltoztatnia m�ret�t, miut�n a kezdeti helyfoglal�s megt�rt�nt.
A valarray elemei egyetlen sorozatot alkotnak, teh�t a v[0],.,v[n-1] elemek egym�s
ut�n
tal�lhat�k a mem�ri�ban. Ebbol k�vetkezik, hogy a T* egy k�zvetlen el�r�su
(randomaccess)
bej�r� (iter�tor, �19.2.1) a valarray<T> vektorhoz, �gy a szabv�nyos algoritmusok,

p�ld�ul a copy(), alkalmazhat�k r�. Ennek ellen�re jobban illik a valarray


szellemis�g�hez,
ha a m�sol�st �rt�kad�sok �s r�szt�mb�k form�j�ban fejezz�k ki:
void grow2(valarray<int>& v, size_t n)
{
if (n<=v.size()) return;
valarray<int> tmp = v;
slice s(0,v.size(),1); // v.size() elemsz�m� r�szt�mb (l�sd �22.4.5)
v.resize(n); // az �tm�retez�s nem orzi meg az elemek �rt�k�t
v[s] = tmp; // elemek visszam�sol�sa v elso r�sz�be
}
Ha valamilyen okb�l a bemeneti adatok olyan elrendez�suek, hogy be kell azokat
olvasnunk,
mielott megtudn�nk a t�rol�sukhoz sz�ks�ges vektor m�ret�t, �ltal�ban �rdemes elo-

sz�r egy vector (�16.3.5) objektumba olvasni az elemeket �s onnan m�solni azokat
egy
valarray v�ltoz�ba.
22. Sz�mok 899
22.4.4. Nem tagf�ggv�nyk�nt megval�s�tott muveletek
A szok�sos bin�ris (k�toperandus�) oper�torok �s matematikai f�ggv�nyek �gy
szerepelnek
a k�nyvt�rban:
template<class T> valarray<T> operator*(const valarray<T>&, const valarray<T>&);
template<class T> valarray<T> operator*(const valarray<T>&, const T&);
template<class T> valarray<T> operator*(const T&, const valarray<T>&);
// hasonl�an: /, %, +, -, ^, &, |, <<, >>, &&, ||, ==, !=, <, >, <=, >=, atan2, �s
pow
template<class T> valarray<T> abs(const valarray<T>&);
// hasonl�an: acos, asin, atan, cos, cosh, exp, log, log10, sin, sinh, sqrt, tan,
�s tanh
A bin�ris muveleteket k�t valarray objektumra, vagy egy valarray objektum �s a
megfelel
o t�pus� skal�r �rt�k egy�ttes�re alkalmazhatjuk:
void f(valarray<double>& v, valarray<double>& v2, double d)
{
valarray<double> v3 = v*v2; // v3[i] = v[i]*v2[i] minden i-re
valarray<double> v4 = v*d; // v4[i] = v[i]*d minden i-re
valarray<double> v5 = d*v2; // v5[i] = d*v2[i] minden i-re
valarray<double> v6 = cos(v); // v6[i] = cos(v[i]) minden i-re
}
Ezek a vektormuveletek valarray operandusuk (operandusaik) minden elem�re
v�grehajtj
�k a megfelelo muveletet, �gy, ahogy a * �s a cos() p�ld�kon kereszt�l bemutattuk.
Term
�szetesen minden muvelet csak akkor alkalmazhat�, ha a megfelelo f�ggv�ny
defini�lt
a sablonparam�terk�nt megadott t�pusra. Ellenkezo esetben a ford�t� hiba�zenetet
ad, amikor
megpr�b�lja p�ld�nyos�tani a sablont (�13.5).
Ha az eredm�ny egy valarray, akkor annak hossza megegyezik a param�ter(ek)ben
haszn
�lt valarray m�ret�vel. Ha k�t valarray param�ter m�rete nem egyezik meg (bin�ris
mu-
veletn�l), az eredm�ny nem meghat�rozott lesz.
�rdekes m�don I/O muveletek nem �llnak rendelkez�s�nkre a valarray t�pushoz
(�22.4.3);
a << �s a >> oper�tor csak l�ptet�sre szolg�l. Ha m�gis sz�ks�g�nk van a k�t
oper�tor ki-
�s bemenetet kezelo v�ltozat�ra, minden gond n�lk�l defini�lhatjuk azokat
(�22.9[5]).
900 A standard k�nyvt�r
Jegyezz�k meg, hogy ezek a valarray muveletek �j valarray objektumokat adnak
vissza,
�s nem operandusaikat m�dos�tj�k. Ez egy kicsit .k�lts�gesebb�. teheti a
f�ggv�nyeket, de
ha kelloen hat�kony optimaliz�ci�s m�dszereket alkalmazunk, ez a vesztes�g nem
jelentkezik
(l�sd p�ld�ul �22.4.7).
A valarray objektumokra alkalmazhat� oper�torok �s matematikai f�ggv�nyek ugyan�gy

haszn�lhat�k slice_array (�22.4.6), gslice_array (�22.4.8), mask_array (�22.4.9)


�s
indirect_array (�22.4.10) objektumokra is, egyes nyelvi v�ltozatok azonban lehet,
hogy
a nem valarray t�pus� operandusokat elosz�r valarray t�pusra alak�tj�k, majd ezen
v�gzik
el a kijel�lt muveletet.
22.4.5. Szeletek
A slice (szelet) olyan elvont t�pus, amely lehetov� teszi, hogy vektorokat
ak�rh�ny dimenzi
�s m�trixk�nt hat�konyan kezelj�nk. Ez a t�pus a Fortran vektorok alapeleme �s
kulcsszerepet
j�tszik a BLAS (Basic Linear Algebra Subprograms) k�nyvt�rban, amely viszont a
legt
�bb sz�mmuvelet kiindul�pontja. A szelet alapj�ban v�ve nem m�s, mint egy valarray
egy
r�szlet�nek minden n-ik eleme:
class std::slice {
// kezdoindex, hossz, �s l�p�sk�z
public:
slice();
slice(size_t start, size_t size, size_t stride);
size_t start() const; // az elso elem index�rt�ke
size_t size() const; // elemek sz�ma
size_t stride() const; // az n-ik elem helye: start()+n*stride()
};
A stride a l�p�sk�z, vagyis a t�vols�g (az elemek sz�m�ban kifejezve) a slice k�t,
egym�st
k�veto eleme k�z�tt. Teh�t a slice eg�szek egy sorozat�t �rja le:
size_t slice_index(const slice& s, size_t i) // i lek�pez�se a megfelelo
index�rt�kre
{
return s.start()+i*s.stride();
}
void print_seq(const slice& s) // s elemeinek ki�r�sa
{
for (size_t i = 0; i<s.size(); i++) cout << slice_index(s,i) << " ";
}
22. Sz�mok 901
void f()
{
print_seq(slice(0,3,4)); // 0. sor
cout << ", ";
print_seq(slice(1,3,4)); // 1. sor
cout << ", ";
print_seq(slice(0,4,1)); // 0. oszlop
cout << ", ";
print_seq(slice(4,4,1)); // 1. oszlop
}
A megjeleno sz�veg a k�vetkezo lesz: 0 4 8 , 1 5 9 , 0 1 2 3 , 4 5 6 7
Teh�t egy slice nem tesz m�st, mint hogy nemnegat�v eg�sz �rt�keket sorsz�mokra
k�pez
le. Az elemek sz�ma (size()) nincs hat�ssal a lek�pez�sre (a c�mz�sre), de
lehetos�get ad
sz�munkra a sorozat v�g�nek megtal�l�s�ra. Ez a lek�pez�s egy egyszeru, hat�kony,
�ltal
�nos �s viszonylag k�nyelmes lehetos�get ad egy k�tdimenzi�s t�mb ut�nz�s�ra egy
egydimenzi
�s t�mbben (p�ld�ul egy valarray objektumban). P�ld�ul l�ssunk egy 3-szor 4-es
m�trixot abban a form�ban, ahogy megszoktuk (�C.7):
A Fortran szok�sainak megfeleloen ezt a k�vetkezo form�ban helyezhetn�nk el a
mem�ri�ban:
A C++ nem ezt a megold�st haszn�lja (l�sd �C.7), ugyanakkor biztos�tanunk kell egy

rendszert, amely tiszta �s logikus kezelofel�letet ad, �s ehhez olyan �br�zol�st


kell v�lasztanunk,
amely megfelel a probl�ma k�t�tts�geinek. Itt most a Fortran elrendez�s�t
v�lasztottam,
hogy k�nnyen megval�s�that� legyen az egy�ttmuk�d�s az olyan numerikus prog-
902 A standard k�nyvt�r
00 01 02
10 11 12
20 21 22
30 31 32
00
0 1 2 3
0 4 8
10 20 30 01 11 21 31 02 12 22 32
ramokkal, melyek ezt az elvet k�vetik. Annyira az�rt nem voltam hajland�
v�ltoztatni, hogy
az indexel�st 0 helyett 1-rol ind�tsam . ha ilyen c�ljaink vannak, oldjuk meg a
�22.9[9] feladatot.
A legt�bb sz�mmuveletet tov�bbra is sz�mos nyelv �s m�g t�bb k�nyvt�r egy�ttes
haszn�lat�val kell megoldanunk. A k�l�nb�zo nyelvek �s k�nyvt�rak elt�ro form�tum�

adatainak kezel�se gyakran l�tsz�ks�glet.


Egy x sort a slice(x,3,4) kifejez�ssel �rhatunk le. Teh�t az x sor elso eleme a
vektor x -ik eleme,
a sor k�vetkezo eleme az (x+4)-ik �s �gy tov�bb. A fenti p�ld�ban minden sor h�rom

elemet tartalmaz. Az �br�k szerint a slice(0,3,4) a 00, a 01 �s a 02 elemet


jel�li.
Egy y oszlopot a slice(4*y,4,1) hat�roz meg. Az y oszlop elso eleme a vektornak
4*y-ik eleme,
a k�vetkezo oszlopelem a (4*y+1)-ik vektorelem stb. Minden oszlopban 4 elem
szerepel.
A slice(0,4,1) kifejez�s teh�t az �br�k szerint a 00, a 10, a 20 �s a 30 elemet
jel�li. Azon
k�v�l, hogy k�nnyen ut�nozhatunk k�tdimenzi�s t�mb�ket, a slice seg�ts�g�vel
sz�mtalan
m�s sorozatot is le�rhatunk; az egyszeru sorozatok megad�s�ra �gy kelloen
�ltal�nos m�dszert
biztos�t. Ezzel a �22.4.8 pont foglalkozik r�szletesen.
Egy szeletet elk�pzelhet�nk �gy is, mint egy k�l�nleges bej�r�t (iterator): a
slice lehetov�
teszi, hogy le�rjunk egy indexsorozatot egy valarray objektumban. Ez alapj�n egy
val�di
bej�r�t is fel�p�thet�nk:
template<class T> class Slice_iter {
valarray<T>* v;
slice s;
size_t curr; // az aktu�lis elem indexe
T& ref(size_t i) const { return (*v)[s.start()+i*s.stride()]; }
public:
Slice_iter(valarray<T>* vv, slice ss) :v(vv), s(ss), curr(0) { }
Slice_iter end()
{
Slice_iter t = *this;
t.curr = s.size(); // az utols� ut�ni elem index�rt�ke
return t;
}
Slice_iter& operator++() { curr++; return *this; }
Slice_iter operator++(int) { Slice_iter t = *this; curr++; return t; }
T& operator[ ](size_t i) { return ref(curr=i); } // C st�lus� index
T& operator()(size_t i) { return ref(curr=i); } // Fortran st�lus� index
T& operator*() { return ref(curr); } // az aktu�lis elem
// ...
};
22. Sz�mok 903
Mivel a slice r�gz�tett m�retu, tartom�nyellenorz�st is v�gezhet�nk. A fenti
p�ld�ban
a slice::size() kihaszn�l�s�val val�s�tottuk meg az end() muveletet, hogy a
valarray utols�
ut�ni elem�re �ll�thassuk a bej�r�t.
A slice le�rhat egy sort �s egy oszlopot is, �gy a Slice_iter is lehetov� teszi,
hogy ak�r egy
sort, ak�r egy oszlopot j�rjunk be a valarray objektumban.
Ahhoz, hogy a Slice_iter igaz�n j�l haszn�lhat� legyen, meg kell hat�roznunk az
==, a != �s
a < oper�tort is:
template<class T> bool operator==(const Slice_iter<T>& p, const Slice_iter<T>& q)
{
return p.curr==q.curr && p.s.stride()==q.s.stride() && p.s.start()==q.s.start();
}
template<class T> bool operator!=(const Slice_iter<T>& p, const Slice_iter<T>& q)
{
return !(p==q);
}
template<class T> bool operator<(const Slice_iter<T>& p, const Slice_iter<T>& q)
{
return p.curr<q.curr && p.s.stride()==q.s.stride() && p.s.start()==q.s.start();
}
22.4.6. A slice_array
A valarray �s a slice felhaszn�l�s�val olyan szerkezetet �p�thet�nk, amely �gy n�z
ki �s �gy
is viselkedik, mint egy valarray, pedig val�j�ban csak a szelet �ltal kijel�lt
ter�letre hivatkozik.
Ezt a slice_array t�pust a k�vetkezok�ppen defini�lhatjuk:
template <class T> class std::slice_array {
public:
typedef T value_type;
void operator=(const valarray<T>&);
void operator=(const T& val); // minden elem val-t kapja �rt�k�l
void operator*=(const T& val); // v[i]*=val minden elemre
// hasonl�an: /=, %=, +=, -=, ^=, &=, |=, <<=, >>=
904 A standard k�nyvt�r
~slice_array();
private:
slice_array(); // l�trehoz�s megakad�lyoz�sa
slice_array(const slice_array&); // m�sol�s megakad�lyoz�sa
slice_array& operator=(const slice_array&); // m�sol�s megakad�lyoz�sa
valarray<T>* p; // megval�s�t�st�l f�ggo �br�zol�s
slice s;
};
A felhaszn�l�k nem hozhatnak l�tre k�zvetlen�l egy slice_array objektumot, csak
egy
valarray .indexel�s�vel. az adott szeletre. Miut�n a slice_array objektumnak
kezdo�rt�ket
adtunk, minden r� t�rt�no hivatkoz�s k�zvetve arra a valarray objektumra hat majd,
amelyhez
l�trehoztuk. Az al�bbi form�ban p�ld�ul egy olyan szerkezetet hozhatunk l�tre,
amely
egy t�mb minden m�sodik elem�t v�lasztja ki:
void f(valarray<double>& d)
{
slice_array<double>& v_even = d[slice(0,d.size()/2+d.size()%2,2)];
slice_array<double>& v_odd = d[slice(1,d.size()/2,2)];
v_even*= v_odd; // az elemp�rok szorzat�t t�roljuk a p�ros elemekben
v_odd = 0; // 0 �rt�k�l ad�sa a p�ratlan elemeknek
}
A slice_array objektumok m�sol�s�t nem engedhetj�k meg, mert csak �gy tehetj�k
leheto-
v� olyan optimaliz�ci�s m�dszerek alkalmaz�s�t, melyek kihaszn�lj�k, hogy egy
objektumra
csak egyf�lek�ppen, �lnevek n�lk�l hivatkozhatunk. Ez a korl�toz�s n�ha nagyon
kellemetlen:
slice_array<double> row(valarray<double>& d, int i)
{
slice_array<double> v = d[slice(0,2,d.size()/2)]; // hiba: m�sol�s k�s�rlete
return d[slice(i%2,i,d.size()/2)]; // hiba: m�sol�s k�s�rlete
}
Egy slice_array m�sol�sa gyakran helyettes�theto a megfelelo slice m�sol�s�val.
A szeletek alkalmasak a t�mb�k bizonyos t�pus� r�szhalmazainak kifejez�s�re. A
k�vetkez
o p�ld�ban p�ld�ul szeleteket haszn�lunk egy folytonos r�sztartom�ny kezel�s�hez:
22. Sz�mok 905
inline slice sub_array(size_t first, size_t count) // [first:first+count[
{
return slice(first,count,1);
}
void f(valarray<double>& v)
{
size_t sz = v.size();
if (sz<2) return;
size_t n = sz/2;
size_t n2 = sz-n;
valarray<double> half1(n);
valarray<double> half2(n2);
half1 = v[sub_array(0,n)]; // v elso fel�nek m�sol�sa
half2 = v[sub_array(n,n2)]; // v m�sodik fel�nek m�sol�sa
// ...
}
A standard k�nyvt�rban nem szerepel m�trix oszt�ly. Ehelyett a valarray �s a slice
egy�ttesen
igyekszik biztos�tani azokat az eszk�z�ket, melyekkel k�l�nb�zo ig�nyekhez
igaz�tott
m�trixokat �p�thet�nk fel. N�zz�k meg, hogyan k�sz�thet�nk egy egyszeru,
k�tdimenzi�s
m�trixot a valarray �s a slice_array felhaszn�l�s�val:
class Matrix {
valarray<double>* v;
size_t d1, d2;
public:
Matrix(size_t x, size_t y); // megjegyz�s: nincs alap�rtelmezett konstruktor
Matrix(const Matrix&);
Matrix& operator=(const Matrix&);
~Matrix();
size_t size() const { return d1*d2; }
size_t dim1() const { return d1; }
size_t dim2() const { return d2; }
Slice_iter<double> row(size_t i);
Cslice_iter<double> row(size_t i) const;
Slice_iter<double> column(size_t i);
Cslice_iter<double> column(size_t i) const;
double& operator()(size_t x, size_t y); // Fortran st�lus� index
double operator()(size_t x, size_t y) const;
906 A standard k�nyvt�r
Slice_iter<double> operator()(size_t i) { return row(i); }
Cslice_iter<double> operator()(size_t i) const { return row(i); }
Slice_iter<double> operator[ ](size_t i) { return row(i); } // C st�lus� index
Cslice_iter<double> operator[ ](size_t i) const { return row(i); }
Matrix& operator*=(double);
valarray<double>& array() { return *v; }
};
A Matrix-ot egy valarray �br�zolja. Erre a t�mbre a k�tdimenzi�s jelleget a
szeletel�s seg�ts
�g�vel .h�zhatjuk r�.. Ezt az �br�zol�st tekinthetj�k egy-, k�t-, h�rom- stb.
dimenzi�s
t�mbnek is, ugyan�gy, ahogy az alap�rtelmezett k�tdimenzi�s n�zetet biztos�tjuk a
row()
�s a column() f�ggv�ny megval�s�t�s�val. A Slice_iter objektumok seg�ts�g�vel
megker�lhetj
�k a slice_array objektumok m�sol�s�nak tilalm�t. Egy slice_array t�pus�
objektumot
nem adhatunk vissza:
slice_array<double> row(size_t i) { return (*v)(slice(i,d1,d2)); } // hiba
Ez�rt a slice_array helyett egy bej�r�t (iterator) adunk meg, amely egy mutat�t
tartalmaz
a valarray objektumra, illetve mag�t a slice objektumot.
Meg kell hat�roznunk egy tov�bbi oszt�lyt is, a .bej�r�t a konstans szeletekhez..
Ez
a Cslice_iter, amely egy const Matrix �s egy nem konstans Matrix szeletei k�z�tti
k�l�nbs
�get fejezi ki.
inline Slice_iter<double> Matrix::row(size_t i)
{
return Slice_iter<double>(v,slice(i,d1,d2));
}
inline Cslice_iter<double> Matrix::row(size_t i) const
{
return Cslice_iter<double>(v,slice(i,d1,d2));
}
inline Slice_iter<double> Matrix::column(size_t i)
{
return Slice_iter<double>(v,slice(i*d2,d2,1));
}
inline Cslice_iter<double> Matrix::column(size_t i) const
{
return Cslice_iter<double>(v,slice(i*d2,d2,1));
}
22. Sz�mok 907
A Cslice_iter definici�ja megegyezik a Slice_iter-�vel, a k�l�nbs�g mind�ssze
annyi, hogy
itt a szelet elemeire const referenci�k fognak mutatni.
A t�bbi tagf�ggv�ny meglehetosen egyszeru:
Matrix::Matrix(size_t x, size_t y)
{
// ellenorz�s: x �s y �rtelmes-e
d1 = x;
d2 = y;
v = new valarray<double>(x*y);
}
double& Matrix::operator()(size_t x, size_t y)
{
return row(x)[y];
}
double mul(Cslice_iter<double>& v1, const valarray<double>& v2)
{
double res = 0;
for (size_t i = 0; i<v1.size(); i++) res+= v1[i]*v2[i];
return res;
}
valarray<double> operator*(const Matrix& m, const valarray<double>& v)
{
valarray<double> res(m.dim1());
for (size_t i = 0; i<m.dim1(); i++) res[i] = mul(m.row(i),v);
return res;
}
Matrix& Matrix::operator*=(double d)
{
(*v) *= d;
return *this;
}
A Matrix indexel�s�hez az (i,j) jel�l�st haszn�ltam, mert a ( ) egy el�g egyszeru
oper�tor,
�s ez a jel�l�s a .matematikus t�rsadalomban. el�gg� elfogadott. A sor fogalma
ennek ellen
�re lehetov� teszi a C �s C++ vil�gban megszokottabb [i][j] jel�l�st is:
void f(Matrix& m)
{
m(1,2) = 5; // Fortran st�lus� index
m.row(1)(2) = 6;
908 A standard k�nyvt�r
m.row(1)[2] = 7;
m[1](2) = 8; // zavaros, kevert st�lus (de muk�dik)
m[1][2] = 9; // C++ st�lus� index
}
Ha a slice_array oszt�lyt haszn�ljuk az indexel�shez, eros optimaliz�l�sra van
sz�ks�g�nk.
Ennek a szerkezetnek az �ltal�nos�t�sa n-dimenzi�s m�trixra �s tetszoleges
elemt�pusra
a megfelelo muvelethalmaz biztos�t�s�val a �22.9[7] feladat t�m�ja.
Elk�pzelheto, hogy elso �tlet�nk a k�tdimenzi�s vektor megval�s�t�s�ra a k�vetkezo
volt:
class Matrix {
valarray< valarray<double> > v;
public:
// ...
};
Ez a megold�s is muk�dok�pes (�22.9[10]), de �gy igen neh�z an�lk�l
�sszeegyeztetni a hat�-
konys�got a nagyteljes�tm�nyu sz�m�t�sok �ltal megk�v�nt k�vetelm�nyekkel, hogy
a valarray �s a slice oszt�ly �ltal �br�zolt alacsonyabb �s hagyom�nyosabb szintre
t�rn�nk �t.
22.4.7. Ideiglenes v�ltoz�k, m�sol�s, ciklusok
Ha megpr�b�lunk k�sz�teni egy vektor vagy egy m�trix oszt�lyt, r�vid idon bel�l
r�j�het
�nk, hogy h�rom, egym�ssal �sszef�ggo probl�m�t kell figyelembe venn�nk a
teljes�tm
�nyt hangs�lyoz� felhaszn�l�k ig�nyeinek kiel�g�t�s�hez:
1. Az ideiglenes v�ltoz�k sz�m�t a leheto legkisebbre kell cs�kkenten�nk.
2. A m�trixok m�sol�s�nak sz�m�t a leheto legkisebbre kell cs�kkenten�nk.
3. Az �sszetettebb muveletekben az ugyanazon adatokon v�gighalad� ciklusok
sz�m�t a leheto legkisebbre kell cs�kkenten�nk.
A standard k�nyvt�r nem k�zvetlen�l ezekkel a c�lokkal foglalkozik. Ennek ellen�re
l�tezik
olyan elj�r�s, melynek seg�ts�g�vel optim�lis megold�st biztos�thatunk.
Vegy�k p�ld�ul az U=M*V+W muveletet, ahol U, V �s W vektor, M pedig m�trix. A
legegyszer
ubb megold�sban k�l�n-k�l�n ideiglenes v�ltoz�ra van sz�ks�g�nk az M*V �s az
M*V+W sz�m�ra, �s m�solnunk kell az M*V �s az M*V+W eredm�ny�t is. Egy .okosabb.
22. Sz�mok 909
v�ltozatban elk�sz�thetj�k a mul_add_and_assign(&U, &M, &V, &W) f�ggv�nyt,
amelynek
nincs sz�ks�ge ideiglenes v�ltoz�kra, sem a vektorok m�sol�s�ra, �s r�ad�sul
minden
m�trix minden elem�t a leheto legkevesebbszer �rinti.
Ilyen m�rvu optimaliz�l�sra egy-k�t kifejez�sn�l t�bbsz�r ritk�n van sz�ks�g�nk.
�gy a hat
�konys�gi probl�m�k megold�s�ra a mul_add_and_assign() jellegu f�ggv�nyek �r�sa,
az
egyik legegyszerubb m�dszer melyeket a felhaszn�l� sz�ks�g eset�n megh�vhat.
Ugyanakkor
lehetos�g van olyan Matrix kifejleszt�s�re is, amely automatikusan alkalmaz ilyen
optimaliz�ci�t, ha a kifejez�seket megfelelo form�ban fogalmazzuk meg. A l�nyeg
az, hogy
az U=M*V+W kifejez�st tekinthetj�k egyetlen, n�gy operandussal rendelkezo oper�tor
alkalmaz
�s�nak. Az elj�r�st m�r bemutattuk az ostream m�dos�t�kn�l (�21.4.6.3). Az ott
bemutatott
m�dszer �ltal�nosan haszn�lhat� arra, hogy n darab k�toperandus� oper�tor
egy�ttes�t egy (n+1) param�teru oper�tork�nt kezelj�k. Az U=M*V+W kifejez�s
kezel�s�-
hez be kell vezetn�nk k�t seg�doszt�lyt. Ennek ellen�re bizonyos rendszerekben ez
a elj�-
r�s igen jelentos (ak�r 30-szoros) sebess�gn�veked�st is el�rhet azzal, hogy
tov�bbi optimaliz
�l�st tesz lehetov�.
Elosz�r is meg kell hat�roznunk egy Matrix �s egy Vector szorz�sakor k�pzodo
eredm�ny
t�pus�t:
struct MVmul {
const Matrix& m;
const Vector& v;
MVmul(const Matrix& mm, const Vector &vv) :m(mm), v(vv) { }
operator Vector(); // az eredm�ny kisz�m�t�sa �s visszaad�sa
};
inline MVmul operator*(const Matrix& mm, const Vector& vv)
{
return MVmul(mm,vv);
}
A .szorz�s. semmi m�st nem tesz, mint hogy referenci�kat t�rol az operandusair�l;
az M*V
t�nyleges kisz�m�t�s�t k�sobbre halasztjuk. Az objektum, amelyet a * muvelet
eredm�nyez,
igen k�zel �ll ahhoz, amit gyakran lez�r�s (closure; ink�bb .befoglal� objektum.)
n�ven
emlegetnek. Ugyan�gy kezelhetj�k egy Vector hozz�ad�s�t az eddigi eredm�nyhez:
struct MVmulVadd {
const Matrix& m;
const Vector& v;
const Vector& v2;
910 A standard k�nyvt�r
MVmulVadd(const MVmul& mv, const Vector& vv) :m(mv.m), v(mv.v), v2(vv) { }
operator Vector(); // az eredm�ny kisz�m�t�sa �s visszaad�sa
};
inline MVmulVadd operator+(const MVmul& mv, const Vector& vv)
{
return MVmulVadd(mv,vv);
}
Ezzel az M*V+W kifejez�s kisz�m�t�s�t is elhalasztjuk. Most m�r csak azt kell
biztos�tanunk,
hogy hat�kony algoritmussal sz�moljuk ki a t�nyleges eredm�nyt, amikor a kifejez�s
eredm
�ny�t �rt�k�l adjuk egy Matrix objektumnak:
class Vector {
// ...
public:
Vector(const MVmulVadd& m) // kezdeti �rt�kad�s m eredm�ny�vel
{
// elemek lefoglal�sa, stb.
mul_add_and_assign(this,&m.m,&m.v,&m.v2);
}
Vector& operator=(const MVmulVadd& m) // m eredm�ny�nek �rt�k�l ad�sa *this-nek
{
mul_add_and_assign(this,&m.m,&m.v,&m.v2);
return *this;
}
// ...
};
�gy teh�t az U=M*V+W kifejez�s automatikusan a k�vetkezo kifejez�sre v�ltozik:
U.operator=(MVmulVadd(MVmul(M,V),W))
Ezt pedig a helyben kifejt�s alkalmaz�sa az eredeti, megk�v�nt f�ggv�nyh�v�sra
alak�tja:
mul_add_and_assign(&U,&M,&V,&W)
Ezzel a megold�ssal kik�sz�b�lt�k a m�sol�sokat �s az ideiglenes v�ltoz�kat,
r�ad�sul
a mul_add_and-assign() f�ggv�nyen tov�bbi optimaliz�l�st is v�grehajthatunk. Sot,
ha
a mul_add_and_assign() f�ggv�nyt a leheto legegyszerubb m�don k�sz�tj�k el, akkor
is
olyan form�t alak�tottunk ki, amely az automatikus optimaliz�l� eszk�z�k sz�m�ra
sokkal
kedvezobb.
22. Sz�mok 911
A fenti p�ld�ban egy �j Vector t�pust haszn�ltunk (nem az egyszeru valarray
oszt�lyt), mert
�j �rt�kad� oper�torokat kellett meghat�roznunk �s az �rt�kad�soknak mindenk�ppen
tagf
�ggv�nyeknek kell lenni�k (�11.2.2). Nagy val�sz�nus�ggel azonban a valarray
oszt�lyt
haszn�ljuk a Vector megval�s�t�s�hoz. Ennek a m�dszernek abban �ll a jelentos�ge,
hogy
a legink�bb idoig�nyes vektor- �s m�trixmuveletek elv�gz�s�t n�h�ny egyszeru
nyelvi elemmel
fogalmazzuk meg. Annak igaz�n soha sincs �rtelme, hogy �gy optimaliz�ljunk egy
f�ltucat
oper�tort haszn�l� kifejez�st, ezekre a hagyom�nyosabb elj�r�sok (�11.6) is
megfeleloek.
Az �tlet l�nyege, hogy ford�t�si ideju vizsg�latokat v�gz�nk �s befoglal�
objektumokat
(closure) haszn�lunk, azzal a c�llal, hogy a r�szkifejez�sek kisz�m�t�s�t a teljes
muveletet
�br�zol� objektumra b�zzuk. Az elv sz�mos ter�leten haszn�lhat�; l�nyege, hogy
t�bb �n�ll
� inform�ci�elemet egyetlen f�ggv�nybe gyujt�nk �ssze, mielott a t�nyleges
muveleteket
elkezden�nk. A k�sleltetett kisz�m�t�s �rdek�ben l�trehozott objektumokat
kompoz�ci�s lez
�rt (befoglal�) objektumoknak (composition closure object) vagy egyszeruen
kompozitoroknak
(compositor) nevezz�k.
22.4.8. �ltal�nos�tott szeletek
A �22.4.6 pontban szereplo Matrix p�lda megmutatta, hogyan haszn�lhatunk k�t slice
objektumot
egy k�tdimenzi�s t�mb sorainak �s oszlopainak le�r�s�ra. �ltal�nosan az igaz,
hogy egy slice alkalmas egy n-dimenzi�s t�mb b�rmely sor�nak vagy oszlop�nak
kijel�l�-
s�re (�22.9[7]), de n�ha sz�ks�g�nk lehet olyan r�szt�mb kijel�l�s�re is, amely
nem egyetlen
sora, vagy egyetlen oszlopa az n-dimenzi�s t�mbnek. Tegy�k fel, hogy egy 3-szor 4-
es
m�trix bal felso sark�ban elhelyezkedo 2-szer 3-as r�szm�trixot akarunk kijel�lni:

Sajnos ezek az elemek nem �gy helyezkednek el a mem�ri�ban, hogy egy slice
seg�ts�g�-
vel le�rhatn�nk azokat:
912 A standard k�nyvt�r
00 01 02
10 11 12
20 21 22
30 31 32
00
4 5 6
0 1 2
10 20 30 01 11 21 31 02 12 22 32
A gslice egy olyan �ltal�nos�tott slice, amely (majdnem) n darab szelet
inform�ci�it tartalmazza:
class std::gslice {
// ahelyett, hogy a slice-hoz hasonl�an 1 l�p�sk�z �s 1 m�ret lenne,
// a gslice-ban n l�p�sk�z �s n m�ret van
public:
gslice();
gslice(size_t s, const valarray<size_t>& l, const valarray<size_t>& d);
size_t start() const; // az elso elem index�rt�ke
valarray<size_t> size() const; // elemek sz�ma a dimenzi�ban
valarray<size_t> stride() const; // l�p�sk�z index[0], index[1], ... k�z�tt
};
Az �j �rt�kek lehetov� teszik, hogy a gslice lek�pez�st hat�rozzon meg n darab
eg�sz �s
egy index k�z�tt, amit a t�mb elemeinek el�r�s�hez haszn�lhatunk fel. Egy 2-szer
3-as m�trix
elhelyezked�s�t p�ld�ul k�t (hossz�s�g, l�p�sk�z) elemp�rral �rhatjuk le. A
�22.4.5 pontban
bemutattuk, hogy a 2 hossz�s�g �s a 4 l�p�sk�z a 3-szor 4-es m�trix egy sor�nak
k�t
elem�t �rja le, ha a Fortran elrendez�s�t haszn�ljuk. Ugyan�gy, a 3 hossz�s�g �s
az 1 l�p�sk
�z egy oszlop 3 elem�t jel�li ki. A ketto egy�tt k�pes le�rni egy 2-szer 3-as
r�szm�trix
�sszes elem�t. Az elemek felsorol�s�hoz az al�bbi elj�r�sra lesz sz�ks�g�nk:
size_t gslice_index(const gslice& s, size_t i, size_t j)
{
return s.start()+i*s.stride()[0]+j*s.stride()[1];
}
size_t len[ ] = { 2, 3 }; // (len[0],str[0]) egy sort �r le
size_t str[ ] = { 4, 1 }; // (len[1],str[1]) egy oszlopot �r le
valarray<size_t> lengths(len,2);
valarray<size_t> strides(str,2);
void f()
{
gslice s(0,lengths,strides);
for (int i = 0 ; i<s.size()[0]; i++) cout << gslice_index(s,i,0) << " "; // sor
cout << ", ";
for (int j = 0 ; j<s.size()[1]; j++) cout << gslice_index(s,0,j) << " "; // oszlop

}
Az eredm�ny 0 4 , 0 1 2 lesz.
22. Sz�mok 913
Ezzel a m�dszerrel egy gslide k�t (hossz�s�g, l�p�sk�z) p�r seg�ts�g�vel k�pes
megadni
egy k�tdimenzi�s t�mb tetszoleges r�szm�trix�t. H�rom (hossz�s�g, l�p�sk�z) p�rral
le�rhatjuk
egy h�romdimenzi�s t�mb r�szt�mbjeit �s �gy tov�bb. Ha egy gslice objektumot
haszn�lunk egy valarray indexel�s�hez, akkor egy gslice_array t�pus� objektumot
kapunk,
ami a gslice �ltal kijel�lt elemeket tartalmazza. P�ld�ul:
void f(valarray<float>& v)
{
gslice m(0,lengths,strides);
v[m] = 0; // �rt�k�l adja 0-t v[0],v[1],v[2],v[4],v[5],v[6] elemeknek
}
A gslice_array ugyanazokat a tagf�ggv�nyeket biztos�tja, mint a slice_array, �gy
egy
gslice_array objektumot sem hozhat l�tre k�zvetlen�l a felhaszn�l�, �s nem is
m�solhatja
(�22.4.6), viszont gslice_array objektumot kapunk eredm�nyk�nt, ha egy valarray
(�22.4.2)
objektumot egy gslice objektummal indexel�nk.
22.4.9. Maszkok
A mask_array t�pus a valarray t�mb valamely r�sze kijel�l�s�nek m�sik m�dja.
R�ad�sul
az eredm�nyt is egy valarray-szeru form�ban kapjuk meg. A valarray oszt�ly
szempontj�-
b�l a maszk egyszeruen egy valarray<bool> objektum. Amikor maszkot haszn�lunk egy
valarray indexel�s�hez, a true bitek jelzik, hogy a valarray megfelelo elem�t az
eredm�nyben
is meg szeretn�nk kapni. Ez a megold�s lehetov� teszi, hogy egy valarray
objektumnak
olyan r�szhalmaz�t dolgozzuk fel, amely nem valamilyen egyszeru elrendez�sben
(p�ld
�ul egy szeletben) helyezkedik el:
void f(valarray<double>& v)
{
bool b[ ] = { true , false, false, true, false, true };
valarray<bool> mask(b,6); // a 0, 3, �s 5 elem
valarray<double> vv = cos(v[mask]); // vv[0]==cos(v[0]), vv[1]==cos(v[3]),
// vv[2]==cos(v[5])
}
A mask_array oszt�ly ugyanazokat a muveleteket biztos�tja, mint a slice_array. Egy

mask_array objektumot sem hozhatunk l�tre k�zvetlen�l, �s nem is m�solhatjuk


(�22.4.6).
Egy mask_array meghat�roz�s�hoz egy valarray (�22.4.2) objektumot kell indexeln�nk

valarray<bool> objektummal. A maszkol�shoz haszn�lt valarray m�rete nem lehet


nagyobb,
mint azon valarray elemeinek sz�ma, amelyben ezt indexel�sre akarjuk haszn�lni.
914 A standard k�nyvt�r
22.4.10. Indirekt t�mb�k
Az indirect_array (indirekt vagyis k�zvetett t�mb) lehetos�get ad arra, hogy egy
valarray
objektumot tetszolegesen indexelj�nk �s �trendezz�nk:
void f(valarray<double>& v)
{
size_t i[ ] = { 3, 2, 1, 0 }; // az elso 4 elem ford�tott sorrendben
valarray<size_t> index(i,4); // a 3, 2, 1, 0 elemek (ebben a sorrendben)
valarray<double> vv = log(v[index]); // vv[0]==log(v[3]), vv[1]==log(v[2]),
// vv[2]==log(v[1]), vv[3]==log(v[0])
}
Ha egy sorsz�m k�tszer szerepel, akkor a valarray objektum valamely elem�re
k�tszer hivatkozunk
egy muveleten bel�l. Ez pontosan az a t�pus� t�bbsz�r�s hivatkoz�s (�ln�v),
amit a valarray nem enged meg. �gy az indirect_array muk�d�se nem meghat�rozott,
ha
t�bbsz�r haszn�ljuk ugyanazt az index�rt�ket.
Az indirect_array oszt�ly ugyanazokat a muveleteket biztos�tja, mint a
slice_array, teh�t
nem hozhatunk l�tre k�zvetlen�l indirect_array objektumokat, �s nem is m�solhatjuk
azokat
(�22.4.6); erre a c�lra egy valarray (�22.4.2) objektum valarray<size_t>
objektummal
val� indexel�se szolg�l.
22.5. Komplex aritmetika
A standard k�nyvt�r tartalmaz egy complex sablont, k�r�lbel�l azokkal a
tulajdons�gokkal,
amelyekkel a �11.3 pontban szereplo complex oszt�lyt meghat�roztuk. A k�nyvt�rban
szerepl
o complex oszt�lynak az�rt kell sablonk�nt (template) szerepelnie, hogy k�l�nb�zo
skal�r t�pusokra �p�lo komplex sz�mokat is kezelni tudjunk. A k�nyvt�rban k�l�n-
k�l�n
v�ltozat szerepel a float, a double �s a long double skal�rt�pushoz.
A complex oszt�ly az std n�vt�rhez tartozik �s a <complex> fej�llom�ny
seg�ts�g�vel �rheto el:
template<class T> class std::complex {
T re, im;
public:
typedef T value_type;
22. Sz�mok 915
complex(const T& r = T(), const T& i = T()) : re(r), im(i) { }
template<class X> complex(const complex<X>& a) : re(a.real()), im(a.imag()) { }
T real() const { return re; }
T imag() const { return im; }
complex<T>& operator=(const T& z); // complex(z,0) �rt�k�l ad�sa
template<class X> complex<T>& operator=(const complex<X>&);
// hasonl�an: +=, -=, *=, /=
};
Az itt bemutatott megval�s�t�s �s a helyben kifejtett (inline) f�ggv�nyek csak
illusztr�ci�-
k�nt szerepelnek. Ha nagyon akarunk, el tudunk k�pzelni m�s megval�s�t�st is a
standard
k�nyvt�r complex oszt�ly�hoz. Figyelj�k meg a sablon tagf�ggv�nyeket, amelyek
lehetov�
teszik, hogy b�rmilyen t�pus� complex objektumnak egy m�sikkal adjunk
kezdo�rt�ket,
vagy azt egyszeru �rt�kad�ssal rendelj�k hozz� (�13.6.2).
A k�nyv folyam�n a complex oszt�lyt nem sablonk�nt haszn�ltuk, csak .egyszeru.
oszt�lyk
�nt. Erre az�rt volt lehetos�g, mert a n�vterekkel �gyeskedve a double �rt�kek
complex
oszt�ly�t tett�k .alap�rtelmezett�.:
typedef std::complex<double> complex;
Rendelkez�s�nkre �llnak a szok�sos egyoperandus� (un�ris) �s k�toperandus�
(bin�ris)
oper�torok is:
template<class T> complex<T> operator+(const complex<T>&, const complex<T>&);
template<class T> complex<T> operator+(const complex<T>&, const T&);
template<class T> complex<T> operator+(const T&, const complex<T>&);
// hasonl�an: -, *, /, ==, �s !=
template<class T> complex<T> operator+(const complex<T>&);
template<class T> complex<T> operator-(const complex<T>&);
A koordin�ta-f�ggv�nyek a k�vetkezok:
template<class T> T real(const complex<T>&);
template<class T> T imag(const complex<T>&);
template<class T> complex<T> conj(const complex<T>&);
// pol�r koordin�tarendszer szerinti l�trehoz�s (abs(),arg()):
916 A standard k�nyvt�r
template<class T> complex<T> polar(const T& rho, const T& theta);
template<class T> T abs(const complex<T>&); // n�ha rho a neve
template<class T> T arg(const complex<T>&); // n�ha theta a neve
template<class T> T norm(const complex<T>&); // az abs() n�gyzetgy�ke
A szok�sos matematikai f�ggv�nyeket is haszn�lhatjuk:
template<class T> complex<T> sin(const complex<T>&);
// hasonl�an: sinh, sqrt, tan, tanh, cos, cosh, exp, log, �s log10
template<class T> complex<T> pow(const complex<T>&,int);
template<class T> complex<T> pow(const complex<T>&, const T&);
template<class T> complex<T> pow(const complex<T>&, const complex<T>&);
template<class T> complex<T> pow(const T&, const complex<T>&);
A ki- �s bemeneti adatfolyamok kezel�s�re pedig a k�vetkezok szolg�lnak:
template<class T, class Ch, class Tr>
basic_istream<Ch,Tr>& operator>>(basic_istream<Ch,Tr>&, complex<T>&);
template<class T, class Ch, class Tr>
basic_ostream<Ch,Tr>& operator<<(basic_ostream<Ch,Tr>&, const complex<T>&);
A komplex sz�mok ki�r�si form�ja (x,y), m�g beolvas�sra haszn�lhatjuk az x, az (x)
�s az
(x,y) form�tumot is (�21.2.3, �21.3.5). A complex<float>, a complex<double> �s
a complex<long double> specializ�ci�k az�rt szerepelnek, hogy korl�tozzuk a
konverzi�kat
(�13.6.2) �s lehetos�get adjunk az optimaliz�l�sra is:
template<> class complex<double> {
double re, im;
public:
typedef double value_type;
complex(double r = 0.0, double i = 0.0) : re(r), im(i) { }
complex(const complex<float>& a) : re(a.real()), im(a.imag()) { }
explicit complex(const complex<long double>& a) : re(a.real()), im(a.imag()) { }
// ...
};
22. Sz�mok 917
Ezek ut�n egy complex<float> �rt�k gond n�lk�l complex<double> sz�mra
konvert�lhat�,
de egy complex<long double> m�r nem. Ugyanilyen specializ�ci�k biztos�tj�k, hogy
egy
complex<float> vagy egy complex<double> automatikusan konvert�lhat� complex<long
double> �rt�kre, de egy complex<long double> nem alak�that� .titokban.
complex<float>
vagy complex<double> sz�mm�. �rdekes m�don az �rt�kad�sok nem ugyanazt a v�delmet
biztos�tj�k, mint a konstruktorok:
void f(complex<float> cf, complex<double> cd, complex<long double> cld,
complex<int> ci)
{
complex<double> c1 = cf; // j�
complex<double> c2 = cd; // j�
complex<double> c3 = cld; // hiba: esetleg csonkol
complex<double> c4(cld); // rendben: explicit konverzi�
complex<double> c5 = ci; // hiba: nincs konverzi�
c1 = cld; // rendben, de vigy�zat: esetleg csonkol
c1 = cf; // rendben
c1 = ci; // rendben
}
22.6. �ltal�nos�tott numerikus algoritmusok
A <numeric> fej�llom�nyban a standard k�nyvt�r biztos�t n�h�ny �ltal�nos�tott
numerikus
algoritmust is, az <algorithm> fej�llom�ny (18. fejezet) nem numerikus
algoritmusainak
st�lus�ban:
918 A standard k�nyvt�r
�ltal�nos�tott numerikus algoritmusok <numeric>
accumulate() Egy sorozat elemein v�gez el egy muveletet.
inner_product() K�t sorozat elemein v�gez el egy muveletet.
partial_sum() Egy sorozatot �ll�t elo egy m�sik sorozatra alkalmazott
muvelettel.
adjacent_difference() Egy sorozatot �ll�t elo egy m�sik sorozatra alkalmazott
muvelettel.
Ezek az algoritmusok egy-egy jellegzetes, gyakran haszn�lt muveletet
�ltal�nos�tanak.
Az egyik p�ld�ul kisz�m�tja egy sorozat elemeinek �sszeg�t, de �gy, hogy b�rmilyen
t�pus
� sorozatra haszn�lhassuk az elj�r�st, a muveletet pedig, amit a sorozat elemeire
el kell v�-
gezni, param�terk�nt adjuk meg. Mindegyik algoritmus eset�ben az �ltal�nos
muveletet kieg
�sz�ti egy olyan v�ltozat, amely k�zvetlen�l a leggyakoribb oper�tort haszn�lja az
adott
algoritmushoz.
22.6.1. Az accumulate()
Az accumulate() algoritmust felfoghatjuk �gy, mint egy vektor elemeit �sszegzo
elj�r�s �ltal
�nos�t�s�t. Az accumulate() algoritmus az std n�vt�rhez tartozik �s a <numeric>
fej�llom
�nyb�l �rhetj�k el:
template <class In, class T> T accumulate(In first, In last, T init)
{
while (first != last) init = init + *first++; // �sszead�s
return init;
}
template <class In, class T, class BinOp> T accumulate(In first, In last, T init,
BinOp op)
{
while (first != last) init = op(init,*first++); // �ltal�nos muvelet
return init;
}
Az accumulate() legegyszerubb v�ltozata egy sorozat elemeit adja �ssze, az
elemekre �rtelmezett
+ oper�tor seg�ts�g�vel:
void f(vector<int>& price, list<float>& incr)
{
int i = accumulate(price.begin(),price.end(),0); // int-be �sszegz�s
double d = 0;
d = accumulate(incr.begin(),incr.end(),d); // double-ba �sszegz�s
// ...
}
A visszat�r�si �rt�k t�pus�t az �tadott kezdo�rt�k t�pusa hat�rozza meg.
22. Sz�mok 919
Gyakran azok az �rt�kek, melyeket �sszegezni szeretn�nk, nem egy sorozat
elemeik�nt �llnak
rendelkez�s�nkre. Ha ilyen helyzetbe ker�l�nk, akkor az accumulate() sz�m�ra
megadhat
� muveletet felhaszn�lhatjuk arra is, hogy az �rt�keket elo�ll�tsuk. A
legegyszerubb
ilyen elj�r�s csak annyit tesz, hogy a sorozatban t�rolt adatszerkezetbol
kiv�lasztja a k�v�nt
�rt�ket:
struct Record {
// ...
int unit_price;
int number_of_units;
};
long price(long val, const Record& r)
{
return val + r.unit_price * r.number_of_units;
}
void f(const vector<Record>& v)
{
cout << "�sszeg: " << accumulate(v.begin(),v.end(),0,price) << '\n';
}
Az accumulate() szerep�nek megfelelo muveletet egyes fejlesztok reduce vagy
reduction
n�ven val�s�tj�k meg.
22.6.2. Az inner_product
Egyetlen sorozat elemeinek �sszegz�se, illetve az ilyen jellegu muveletek nagyon
gyakoriak,
ugyanakkor a sorozatp�rokon ilyen muveletet v�gzo elj�r�sok viszonylag ritk�k.
Az inner_product() algoritmus meghat�roz�sa az std n�vt�rben szerepel,
deklar�ci�j�t pedig
a <numeric> fej�llom�nyban tal�lhatjuk meg:
template <class In, class In2, class T>
T inner_product(In first, In last, In2 first2, T init)
{
while (first != last) init = init + *first++ * *first2++;
return init;
}
template <class In, class In2, class T, class BinOp, class BinOp2>
T inner_product(In first, In last, In2 first2, T init, BinOp op, BinOp2 op2)
{
while (first != last) init = op(init,op2(*first++,*first2++));
return init;
}
920 A standard k�nyvt�r
Szok�s szerint, a m�sodik sorozatnak csak az elej�t kell megadnunk param�terk�nt.
A m�-
sodik bemeneti sorozatr�l azt felt�telezz�k, hogy legal�bb olyan hossz�, mint az
elso.
Amikor egy Matrix objektumot egy valarray objektummal akarunk �sszeszorozni, akkor

a legfontosabb muvelet az inner_product:


valarray<double> operator*(const Matrix& m, valarray<double>& v)
{
valarray<double> res(m.dim2());
for (size_t i=0; i<m.dim1(); i++) {
const Cslice_iter<double>& ri = m.row(i);
res[i] = inner_product(ri,ri.end(),&v[0], double(0));
}
return res;
}
valarray<double> operator*(valarray<double>& v, const Matrix& m)
{
valarray<double> res(m.dim1());
for (size_t i=0; i<m.dim2(); i++) {
const Cslice_iter<double>& ci = m.column(i);
res[i] = inner_product(ci, ci.end(), &v[0], double(0));
}
return res;
}
Az inner_product (belso szorzat) bizonyos form�it gyakran emlegetj�k .pont-
szorz�s. (dot
product) n�ven is.
22.6.3. N�vekm�nyes v�ltoz�s
A partial_sum() �s az adjacent_difference() algoritmus egym�s ford�tottj�nak
(inverz�nek)
tekintheto, de mindketto az inkrement�lis vagy n�vekm�nyes v�ltoz�s (incremental
change) fogalm�val foglalkozik. Le�r�suk az std n�vt�rben �s a <numeric>
fej�llom�nyban
szerepel:
template <class In, class Out> Out adjacent_difference(In first, In last, Out
res);
template <class In, class Out, class BinOp>
Out adjacent_difference(In first, In last, Out res, BinOp op);
22. Sz�mok 921
Az a, b, c, d, . sorozatb�l p�ld�ul az adjacent_difference() a k�vetkezo sorozatot
�ll�tja
elo: a, b-a, c-b, d-c, .
K�pzelj�nk el egy sorozatot, amely hom�rs�klet-�rt�keket tartalmaz. Ebbol k�nnyen
k�sz�thet
�nk egy olyan vektort, amely a hom�rs�klet-v�ltoz�sokat tartalmazza:
vector<double> temps;
void f()
{
adjacent_difference(temps.begin(),temps.end(),temps.begin());
}
A 17, 19, 20, 20, 17 sorozatb�l p�ld�ul a 17, 2, 1, 0, -3 eredm�nyt kapjuk.
Megford�tva, a partial_sum() azt teszi lehetov�, hogy t�bb n�vekm�nyes v�ltoz�s
v�geredm
�ny�t kisz�m�tsuk:
template <class In, class Out, class BinOp>
Out partial_sum(In first, In last, Out res, BinOp op)
{
if (first==last) return res;
*res = *first;
T val = *first;
while (++first != last) {
val = op(val,*first);
*++res = val;
}
return ++res;
}
template <class In, class Out> Out partial_sum(In first, In last, Out res)
{
return partial_sum(first,last,res,plus); // �18.4.3
}
Az a, b, c, d, . sorozatb�l a partial_sum() a k�vetkezo eredm�nyt �ll�tja elo: a,
a+b,
a+b+c, a+b+c+d, . P�ld�ul:
void f()
{
partial_sum(temps.begin(),temps.end(),temps.begin());
}
922 A standard k�nyvt�r
Figyelj�k meg, hogy a partial_sum() n�veli a res �rt�k�t, mielott �j �rt�ket adna
a hivatkozott
ter�letnek. Ez lehetov� teszi, hogy a res ugyanaz a sorozat legyen, mint a
bemeneti.
Ugyan�gy muk�dik az adjacent_difference() is. Teh�t a k�vetkezo utas�t�s az a, b,
c, d sorozatot
az a, a+b, a+b+c, a+b+c+d sorozatra k�pezi le:
partial_sum(v.begin(),v.end(),v.begin());
Az al�bbi utas�t�ssal pedig vissza�ll�thatjuk az eredeti sorozatot:
adjacent_difference(v.begin(),v.end(),v.begin());
Egy m�sik p�lda: a partial_sum() a 17, 2, 1, 0, -3 sorozatb�l a 17, 19, 20, 20, 17
sorozatot
�ll�tja vissza.
Akik szerint a hom�rs�klet-v�ltoz�sok figyel�se csup�n rendk�v�l unalmas
r�szletk�rd�se
a meteorol�gi�nak vagy a tudom�nyos, laborat�riumi k�s�rleteknek, azok sz�m�ra
megjegyezz
�k, hogy a k�szlettartal�kok v�ltoz�sainak vizsg�lata pontosan ugyanezen a k�t mu-

veleten alapul.
22.7. V�letlensz�mok
A v�letlensz�mok fontos szerepet t�ltenek be igen sok szimul�ci�s �s
j�t�kprogramban.
A <cstdlib> �s az <stdlib.h> fej�llom�nyban a standard k�nyvt�r egyszeru alapot
biztos�t
a v�letlensz�mok elo�ll�t�s�hoz:
#define RAND_MAX megval�s�t�s_f�ggo /* nagy pozit�v eg�sz */
int rand(); // �l-v�letlensz�m 0 �s RAND_MAX k�z�tt
int srand(int i); // a v�letlensz�m-elo�ll�t� be�ll�t�sa i-vel
J� v�letlensz�m-elo�ll�t� (gener�tor) k�sz�t�se nagyon neh�z feladat, ez�rt sajnos
nem minden
rendszerben �ll rendelkez�s�nkre j� rand() f�ggv�ny. K�l�n�sen igaz ez
a v�letlensz�mok als� bitjeire, aminek k�vetkezt�ben a rand()%n kifejez�s
egy�ltal�n nem
tekintheto �ltal�nos (m�s rendszerre �tviheto) m�dszernek arra, hogy 0 �s n-1 k�z�
eso
v�letlensz�mokat �ll�tsunk elo. A (double(rand())/RAND_MAX)*n �ltal�ban sokkal
elfogadhat
�bb eredm�nyt ad.
22. Sz�mok 923
Az srand() f�ggv�ny megh�v�s�val egy �j v�letlensz�m-sorozatot kezdhet�nk a
param�terk
�nt megadott alap�rt�ktol. A programok tesztel�sekor gyakran nagyon hasznos, hogy
egy
adott alap�rt�kbol sz�rmaz� v�letlensz�m-sorozatot meg tudjunk ism�telni. Ennek
ellen�-
re �ltal�ban a program minden futtat�sakor m�s alap�rt�krol akarunk indulni. Ahhoz
hogy
j�t�kainkat t�nyleg megj�solhatatlann� tegy�k, gyakran sz�ks�g van arra, hogy az
alap�rt
�ket a program k�rnyezet�bol szerezz�k be. Az ilyen programokban a sz�m�t�g�p
�r�ja �ltal
jelzett ido n�h�ny bitje �ltal�ban j� alap�rt�k.
Ha saj�t v�letlensz�m-elo�ll�t�t kell k�sz�ten�nk, elengedhetetlen az alapos
tesztel�s
(�22.9[14]).
Egy v�letlensz�m-elo�ll�t� gyakran haszn�lhat�bb, ha oszt�ly form�j�ban �ll
rendelkez�-
s�nkre. �gy k�nnyen k�sz�thet�nk v�letlensz�m-elo�ll�t�kat a k�l�nb�zo
�rt�ktartom�-
nyokhoz:
class Randint { // egyenletes eloszl�s 32 bites long-ot felt�telezve
unsigned long randx;
public:
Randint(long s = 0) { randx=s; }
void seed(long s) { randx=s; }
// buv�s sz�mok: 31 bitet haszn�lunk egy 32 bites long-b�l:
long abs(long x) { return x&0x7fffffff; }
static double max() { return 2147483648.0; } // figyelem: double
long draw() { return randx = randx*1103515245 + 12345; }
double fdraw(){ return abs(draw())/max(); } //a [0,1] tartom�nyban
long operator()() { return abs(draw()); } //a [0,pow(2,31)] tartom�nyban
};
class Urand : public Randint { // egyenletes eloszl�s [0:n[ intervallumban
long n;
public:
Urand(long nn) { n = nn; }
long operator()() { long r = n*fdraw(); return (r==n) ? n-1 : r; }
};
class Erand : public Randint { // exponenci�lis eloszl�s� v�letlensz�m-elo�ll�t�
long mean;
public:
Erand(long m) { mean=m; }
long operator()() { return -mean * log( (max()-draw())/max() + .5); }
};
924 A standard k�nyvt�r
�me egy r�vid pr�baprogram:
int main()
{
Urand draw(10);
map<int,int> bucket;
for (int i = 0; i< 1000000; i++) bucket[draw()]++;
for(int j = 0; j<10; j++) cout << bucket[j] << '\n';
}
Ha nem minden bucket �rt�ke van a 100 000 k�zel�ben, valahol valamilyen hib�t
v�tett�nk.
Ezek a v�letlensz�m-elo�ll�t�k annak a megold�snak kiss� �talak�tott v�ltozatai,
amit a C++
k�nyvt�r legelso megval�s�t�s�ban (pontosabban az elso .oszt�lyokkal bov�tett C.
k�nyvt
�rban, �1.4) alkalmaztam.
22.8. Tan�csok
[1] A numerikus probl�m�k gyakran nagyon �rnyaltak. Ha nem vagyunk 100 sz�zal
�kig biztosak valamely probl�ma matematikai vonatkoz�saiban, mindenk�ppen
k�rj�k szakember seg�ts�g�t vagy k�s�rletezz�nk sokat. �22.1.
[2] A be�p�tett adatt�pusok tulajdons�gainak meg�llap�t�s�hoz haszn�ljuk
a numeric_limits oszt�lyt. �22.2.
[3] A felhaszn�l�i skal�rt�pusokhoz adjunk meg k�l�n numeric_limits oszt�lyt.
�22.2.
[4] Ha a fut�si ideju hat�konys�g fontosabb, mint a rugalmass�g az elemt�pusokra
�s a muveletekre n�zve, a sz�mmuveletekhez haszn�ljuk a valarray oszt�lyt.
�22.4.
[5] Ha egy muveletet egy t�mb r�sz�re kell alkalmaznunk, ciklusok helyett
haszn�ljunk
szeleteket. �22.4.6.
[6] Haszn�ljunk kompozitorokat, ha egyedi algoritmusokkal �s ideiglenes v�ltoz�k
kik�sz�b�l�s�vel akarjuk n�velni rendszer�nk hat�konys�g�t. �22.4.7.
[7] Ha komplex sz�mokkal kell sz�molnunk, haszn�ljuk az std::complex oszt�lyt.
�22.5.
[8] Ha egy �rt�ket egy lista elemeinek v�gign�z�s�vel kell kisz�m�tanunk, akkor
mielott saj�t ciklus megval�s�t�s�ba kezden�nk, vizsg�ljuk meg, nem felel-e
meg c�ljainknak az accumulate(), az inner_product() vagy az
adjacent_difference() algoritmus. �22.6.
22. Sz�mok 925
[9] Az adott eloszl�sokhoz k�sz�tett v�letlensz�m-elo�ll�t� oszt�lyok
hasznosabbak,
mint a rand() k�zvetlen haszn�lata. �22.7.
[10] Figyelj�nk r�, hogy v�letlensz�maink val�ban v�letlenek legyenek. �22.7.
22.9. Gyakorlatok
1. (*1.5) K�sz�ts�nk egy f�ggv�nyt, amely �gy viselkedik, mint az apply(), azzal
a k�l�nbs�ggel, hogy nem tagf�ggv�ny �s f�ggv�nyobjektumokat is elfogad.
2. (*1.5) K�sz�ts�nk f�ggv�nyt, amely csak abban t�r el az apply() f�ggv�nytol,
hogy nem tagf�ggv�nyk�nt szerepel, elfogad f�ggv�nyobjektumokat, �s a saj�t
valarray param�ter�t m�dos�tja.
3. (*2) Fejezz�k be a Slice_iter-t (�22.4.5). K�l�n�sen figyelj�nk a destruktor
l�trehoz
�sakor.
4. (*1.5) �rjuk meg �jb�l a �17.4.1.3 pontban szereplo programot az accumulate()
felhaszn�l�s�val.
5. (*2) K�sz�ts�k el a << �s a >> ki-, illetve bemeneti oper�tort a valarray
oszt�lyhoz.
K�sz�ts�nk egy get_array() f�ggv�nyt, amely �gy hoz l�tre egy valarray
objektumot, hogy annak m�ret�t is maga a bemenet adja meg.
6. (*2.5) Hat�rozzunk meg �s k�sz�ts�nk el egy h�romdimenzi�s t�mb�t a megfelel
o muveletek l�trehoz�s�val.
7. (*2.5) Hat�rozzunk meg �s k�sz�ts�nk el egy n-dimenzi�s m�trixot a megfelelo
muveletek l�trehoz�s�val.
8. (*2.5) K�sz�ts�nk egy valarray-szeru oszt�lyt, �s adjuk meg hozz� a + �s a *
muveletet. Hasonl�tsuk �ssze ennek hat�konys�g�t a saj�t C++-v�ltozatunk
valarray oszt�ly�nak hat�konys�g�val. �tlet: pr�b�ljuk ki t�bbek k�z�tt az
x=0.5*(x+y)-z kifejez�s ki�rt�kel�s�t k�l�nb�zo m�retu x, y �s z vektor felhaszn
�l�s�val.
9. (*3) K�sz�ts�nk egy Fortran st�lus� t�mb�t (p�ld�ul Fort_array n�ven), ahol az
indexek nem 0-t�l, hanem 1-tol indulnak.
10. (*3) K�sz�ts�k el a Matrix oszt�lyt �gy, hogy az egy saj�t valarray objektumot

haszn�ljon az elemek �br�zol�s�hoz (nem pedig egy mutat�t vagy referenci�t


a valarray objektumra).
11. (*2.5) Kompozitorok (�22.4.7) seg�ts�g�vel k�sz�ts�nk egy hat�kony t�bbdimenzi
�s indexel�si rendszert a [ ] jel�l�ssel. A k�vetkezo kifejez�sek mindegyike
a megfelelo elemeket, illetve r�szt�mb�ket jel�lje ki, m�ghozz� egyszeru indexm
uveletek seg�ts�g�vel: v1[x], v2[x][y], v2[x], v3[x][y][z], v3[x][y], v3[x] stb.
926 A standard k�nyvt�r
12. (*2) A �22.7 pontban szereplo program �tlet�nek �ltal�nos�t�s�val �rjunk olyan

f�ggv�nyt, amely param�terk�nt egy v�letlensz�m-elo�ll�t�t fogad �s egyszeru


grafikus form�ban szeml�lteti annak eloszl�s�t, �gy, hogy seg�ts�g�vel szeml�-
letesen is ellenorizhess�k a v�letlensz�m-elo�ll�t� helyess�g�t.
13. (*1) Ha n egy int �rt�k, akkor milyen a (double(rand())/RAND_MAX)*n kifejez
�s eloszl�sa?
14. (*2.5) Rajzoljunk pontokat egy n�gyzet alak� ter�leten. Az egyes pontok
koordin�ta-p�rjait az Urand(N) oszt�ly seg�ts�g�vel �ll�tsuk elo, ahol N a
megjelen
�t�si ter�let oldal�nak k�ppontban m�rt hossza. Milyen k�vetkeztet�st vonhatunk
le az eredm�ny alapj�n az Urand �ltal l�trehozott v�letlensz�mok
eloszl�s�r�l?
15. (*2) K�sz�ts�nk egy Normal eloszl�s� v�letlensz�m-elo�ll�t�t Nrand n�ven.
22. Sz�mok 927
Negyedik r�sz
Tervez�s a C++ seg�ts�g�vel
Ez a r�sz a programfejleszt�s �tfog�bb szemsz�g�bol mutatja be a C++-t �s az
�ltala t�mogatott
elj�r�sokat. A hangs�lyt a tervez�sre �s a nyelv lehetos�gein alapul� hat�kony
megval
�s�t�sra fektetj�k.
Fejezetek
23. Fejleszt�s �s tervez�s
24. Tervez�s �s programoz�s
25. Az oszt�lyok szerepe
..Csak most kezdem felfedezni, milyen neh�z a gondolatainkat pap�rra vetni. Am�g
csup
�n le�r�sb�l �ll, el�g k�nnyen megy, de amint �rvelni kell, a gondolatok k�z�tt
megfelelo
kapcsolatokat kell teremteni, vil�gosan �s g�rd�l�kenyen kell fogalmazni, s ez,
mint mondottam,
sz�momra oly neh�zs�get jelent, amire nem is gondoltam..
(Charles Darwin)
Fejleszt�s �s tervez�s
.Nincs ez�stgoly�..
(F. Brooks)
Program�p�t�s . C�lok �s eszk�z�k . A fejleszt�si folyamat . fejleszt�s ciklus .
Tervez�si
c�lok . Tervez�si l�p�sek . Oszt�lyok keres�se . Muveletek meghat�roz�sa .
F�gg�sek
meghat�roz�sa . Fel�letek meghat�roz�sa . Oszt�lyhierarchi�k �jraszervez�se .
Modellek
. K�s�rletez�s �s elemz�s . Tesztel�s . A programok karbantart�sa . Hat�konys�g .
Vezet
�s . �jrahasznos�t�s . M�ret �s egyens�ly . Az egy�nek fontoss�ga . Hibrid
tervez�s .
Bibliogr�fia . Tan�csok
23.1. �ttekint�s
Ez az elso a h�rom fejezetbol, melyek r�szletesebben bemutatj�k a szoftverterm�k
k�sz�-
t�s�t, a viszonylag magas szintu tervez�si szeml�letm�dt�l azokig a programoz�si
fogalmakig
�s elj�r�sokig, amelyekkel a C++ a tervez�st k�zvetlen�l t�mogatja. Ez a fejezet
a bevezeton �s a szoftverfejleszt�s c�ljait �s eszk�zeit r�viden t�rgyal� �23.3
ponton k�v�l
k�t fo r�szbol �ll:
23
�23.4 A szoftverfejleszt�s folyamat�nak �ttekint�se.
�23.5 Gyakorlati tan�csok a szoftverfejlesztoi munka megszervez�s�hez.
A 24. fejezet a tervez�s �s a programoz�si nyelv k�zti kapcsolatot t�rgyalja, a
25. pedig az oszt
�lyoknak a tervez�sben j�tszott szerep�vel foglalkozik. Eg�sz�ben v�ve a 4. r�sz
c�lja, hogy
�thidalja a szakad�kot a nyelvf�ggetlens�gre t�rekvo tervez�s �s a r�vidl�t�an a
r�szletekre
�sszpontos�t� programoz�s k�z�tt. Egy nagyobb program elk�sz�t�si folyamat�ban
mindkett
onek megvan a helye, de a tervez�si szempontok �s a haszn�lt elj�r�sok k�z�tt
megfelelo
�sszhangot kell teremteni, hogy elker�lj�k a katasztr�f�kat �s a felesleges
kiad�sokat.
23.2. Bevezet�s
A legegyszerubbek kiv�tel�vel minden program elk�sz�t�se �sszetett �s gyakran
cs�ggeszt
o feladat. A programutas�t�sok meg�r�sa m�g az �n�ll�an dolgoz� programoz� sz�m�ra
is
csup�n egy r�sze a folyamatnak. A probl�ma elemz�se, az �tfog� programtervez�s, a
dokument
�l�s, a tesztel�s �s a program fenntart�s�nak, m�dos�t�s�nak k�rd�sei, valamint
mindennek az �sszefog�sa mellett elt�rp�l az egyes k�dr�szek meg�r�s�nak �s
kijav�t�s�-
nak feladata. Term�szetesen nevezhetn�nk e tev�kenys�gek �sszess�g�t
.programoz�snak
., majd logikus m�don kijelenthetn�nk: .�n nem tervezek, csak programozok..
Ak�rminek
nevezz�k is azonban a tev�kenys�get, n�ha az a fontos, hogy a r�szletekre
�sszpontos
�tsunk, n�ha pedig az, hogy az eg�sz folyamatot tekints�k. Sem a r�szleteket, sem
a v�gc�lt
nem szabad szem elol t�veszten�nk . b�r n�ha pontosan ez t�rt�nik ., csak �gy
k�sz�thet
�nk teljes �rt�ku programokat.
Ez a fejezet a programfejleszt�s azon r�szeivel foglalkozik, melyek nem vonj�k
magukkal
egyes k�dr�szek �r�s�t �s jav�t�s�t. A t�rgyal�s kev�sb� pontos �s r�szletes, mint
a kor�bban
bemutatott nyelvi tulajdons�gok �s programoz�si elj�r�sok t�rgyal�sa, de nem is
lehet
olyan t�k�letes .szak�csk�nyvet. �rni, amely le�rn�, hogyan kell j� programot
k�sz�teni. L�-
tezhetnek r�szletes .hogyan kell. le�r�sok egyes programfajt�khoz, de az
�ltal�nosabb
alkalmaz�si ter�letekhez nem. Semmi sem p�tolja az intelligenci�t, a
tapasztalatot, �s
a programoz�si �rz�ket. K�vetkez�sk�ppen ez a fejezet csak �ltal�nos tan�csokat
ad, illetve
megk�zel�t�si m�dokat mutat be �s tanuls�gos megfigyel�seket k�n�l.
A probl�m�k megk�zel�t�s�t bonyol�tja a programok eleve elvont term�szete �s az a
t�ny,
hogy azok a m�dszerek, melyek kisebb projektekn�l (p�ld�ul amikor egy vagy k�t
ember
�r 10 000 sornyi k�dot) muk�dnek, nem sz�ks�gszeruen alkalmazhat�k k�zepes vagy
nagy
932 Tervez�s a C++ seg�ts�g�vel
projektekben. Ez�rt sz�mos k�rd�st ink�bb a kev�sb� elvont m�rn�ki tudom�nyokb�l
�tvett
hasonlatokon kereszt�l k�zel�t�nk meg, k�dp�ld�k haszn�lata helyett. A
programtervez
�s t�rgyal�sa a C++ fogalmaival, illetve a kapcsol�d� p�ld�k a 24. �s 25.
fejezetben tal
�lhat�k, de az itt bemutatott elvek t�kr�zodnek mind mag�ban a C++ nyelvben, mind
a k�nyv egyes p�ld�iban.
Arra is eml�keztetn�m az olvas�t, hogy az alkalmaz�si ter�letek, emberek �s
programfejleszt
o k�rnyezetek rendk�v�l sokf�l�k, ez�rt nem v�rhat� el, hogy minden itteni
javaslatnak
k�zvetlen�l haszn�t vehess�k egy adott probl�ma megold�s�ban. A megfigyel�sek
val�s
helyzetekben sz�lettek �s sz�mos ter�leten felhaszn�lhat�k, de nem tekinthetok
�ltal�nos
�rv�nyunek, ez�rt nem �rt n�mi eg�szs�ges szkepticizmus.
A C++ �gy is tekintheto, mint egy .jobb C.. De ha �gy tesz�nk, kihaszn�latlanul
maradnak
a C++ igazi eross�gei, �gy a nyelv elonyeinek csak t�red�ke �rv�nyes�l. Ez a
fejezet kimondottan
azokra a tervez�si megk�zel�t�sekre �sszpontos�t, melyek lehetov� teszik a C++
elvont
adat�br�zol�si �s objektumk�zpont� programoz�si lehetos�geinek hat�kony haszn�-
lat�t. Az ilyen m�dszereket gyakran nevezz�k objektumorient�lt (object-oriented)
tervez�snek.
A fejezet fo t�m�i a k�vetkezok:
� A szoftverfejleszt�s legfontosabb szempontja, hogy tiszt�ban legy�nk vele, mit
is k�sz�t�nk.
� A sikeres szoftverfejleszt�s sok�ig tart.
� Az �ltalunk �p�tett rendszerek �sszetetts�g�nek hat�rait saj�t tud�sunk �s
eszk�-
zeink k�pess�gei szabj�k meg.
� Semmif�le tank�nyvi m�dszer nem helyettes�theti az intelligenci�t, a
tapasztalatot,
a j� tervez�si �s programoz�si �rz�ket.
� A k�s�rletez�s minden bonyolultabb program elk�sz�t�s�n�l l�nyeges.
� A programk�sz�t�s k�l�nb�zo szakaszai . a tervez�s, a programoz�s �s a tesztel
�s . nem v�laszthat�k el szigor�an egym�st�l.
� A programoz�s �s a tervez�s nem v�laszthat�k el e tev�kenys�gek megszervez
�s�nek k�rd�s�tol.
K�nnyen abba a hib�ba eshet�nk . �s persze megfizetj�k az �r�t ., hogy ezeket a
szempontokat
al�becs�lj�k, pedig az elvont �tleteket neh�z a gyakorlatba �ttenni. Tudom�sul
kell venn�nk a tapasztalat sz�ks�gess�g�t: �pp�gy, mint a cs�nak�p�t�s, a
ker�kp�roz�s,
vagy �ppen a programoz�s, a tervez�s sem olyan k�pess�g, amely puszt�n elm�leti
tanulm
�nyokkal elsaj�t�that�.
23. Fejleszt�s �s tervez�s 933
Gyakran elfeledkez�nk a rendszer�p�t�s emberi t�nyezoirol, �s a programfejleszt�s
folyamat
�t egyszeruen meghat�rozott l�p�sek sorozat�nak tekintj�k, mely .a bemenetbol
adott
muveletek v�grehajt�s�val elo�ll�tja a k�v�nt kimenetet, a lefektetett
szab�lyoknak megfelel
oen.. A programoz�si nyelv, amelyet haszn�lunk, elfedi az emberi t�nyezo
jelenl�t�t, m�rpedig
a tervez�s �s a programoz�s emberi tev�kenys�gek . ha errol megfeledkez�nk, nem
j�rhatunk sikerrel.
Ez a fejezet olyan rendszerek tervez�s�vel foglalkozik, melyek a rendszert �p�to
emberek
tapasztalat�hoz �s eroforr�saihoz k�pest ig�nyesek. �gy tunik, a fejlesztok
szeretik feszegetni
lehetos�geik hat�rait. Az olyan munk�kn�l, melyek nem jelentenek ilyen kih�v�st,
nincs sz�ks�g a tervez�s megvitat�s�ra, hiszen ezeknek kidolgozott kereteik
vannak,
amelyeket nem kell sz�tt�rni. Csak akkor van sz�ks�g �j, jobb eszk�z�k �s
elj�r�sok elsaj
�t�t�s�ra, amikor valami ig�nyes dologra v�llalkozunk. Arra is hajlamosak vagyunk,
hogy
hozz�nk k�pest �joncokra olyan feladatokat b�zzunk, melyekrol .mi tudjuk, hogyan
kell elv
�gezni., de ok nem.
Nem l�tezik .egyetlen helyes m�dszer. minden rendszer tervez�s�re �s �p�t�s�re. A
hitet az
.egyetlen helyes m�dszerben. gyermekbetegs�gnek tekinten�m, ha nem fordulna elo
oly
gyakran, hogy tapasztalt programoz�k �s tervezok engednek neki. Eml�keztetek arra,
hogy
az�rt, mert egy elj�r�s a m�lt �vben egy adott munk�n�l j�l muk�d�tt, m�g nem
biztos,
hogy ugyanaz m�dos�t�s n�lk�l muk�dni fog valaki m�sn�l vagy egy m�sik munka sor�n

is. A legfontosabb, hogy mentesek legy�nk az ilyesfajta felt�telez�sektol.


Az itt le�rtak term�szetesen a nagyobb m�retu programok fejleszt�s�re vonatkoznak.
Azok,
akik nem muk�dnek k�zre ilyen fejleszt�sben, vissza�lhetnek �s �r�lhetnek, l�tv�n,
milyen
r�ms�gektol menek�ltek meg, illetve n�zegethetik az egy�ni munk�val foglalkoz� r�-

szeket. A programok m�ret�nek nincs als� hat�ra, ahol a k�dol�s elotti tervez�s
m�g
�sszeru, de l�tezik ilyen hat�r, amennyiben a tervez�s �s dokument�l�s
megk�zel�t�si
m�dj�r�l van sz�. A c�lok �s a m�ret k�z�tti egyens�ly fenntart�s�nak k�rd�seivel
a �23.5.2 pont foglalkozik.
A programfejleszt�s k�zponti probl�m�ja a bonyolults�g. A bonyolults�ggal pedig
egyetlen
m�don lehet elb�nni, az .oszd meg �s uralkodj!. elvet k�vetve. Ha egy probl�m�t
k�t �nmag
�ban kezelheto r�szprobl�m�ra v�laszthatunk sz�t, f�lig m�ris megoldottuk azt. Ez
az
egyszeru elv b�mulatosan v�ltozatos m�dokon alkalmazhat�. Nevezetesen, egy modul
vagy egy oszt�ly haszn�lata a rendszer megtervez�s�n�l k�t r�szre osztja a
programot
. a t�nyleges megval�s�t�sra �s a felhaszn�l�i k�dra . amelyeket ide�lis esetben
csak
egy j�l defini�lt fel�let (interface) kapcsol �ssze: ez a programmal j�r�
bonyolults�g kezel
�s�nek alapveto megk�zel�t�se. Ugyan�gy a programtervez�si folyamat is k�l�n
tev�keny-
934 Tervez�s a C++ seg�ts�g�vel
s�gekre bonthat�, s �gy a k�zremuk�do �s egym�ssal kapcsolatban �ll� fejlesztok
k�z�tt
feladatokra bontva sz�toszthat�: ez pedig a fejleszt�si folyamat �s a r�sztvevo
programoz�k
k�z�tti bonyolult kapcsolatok kezel�s�nek alapveto megk�zel�t�se.
Mindk�t esetben a feloszt�s �s a kapcsolatot megteremto fel�letek meghat�roz�sa
az, ahol
a legnagyobb tapasztalatra �s �rz�kre van sz�ks�g. Ez nem egyszeru, mechanikusan
megoldhat
� feladat; jellemzoen �lesl�t�st ig�nyel, melyre csak egy rendszer alapos
tanulm�nyoz
�sa �s az elvonatkoztat�si szintek megfelelo meg�rt�se �ltal tehet�nk szert (l�sd:
�23.4.2,
�24.3.1 �s �25.3). Ha egy programot vagy fejleszt�si folyamatot csak bizonyos
szemsz�gbol
vizsg�lunk, s�lyos hib�kat v�thet�nk. Azt is vegy�k �szre, hogy k�l�nv�lasztani
mind az
emberek feladatait, mind a programokat k�nnyu. A feladat neh�z r�sze a hat�kony
kapcsolattart
�s biztos�t�sa a v�laszfal k�t oldal�n levo felek k�z�tt an�lk�l, hogy
leromboln�nk
a v�laszfalat vagy elnyomn�nk az egy�ttmuk�d�shez sz�ks�ges kommunik�ci�t.
Ez a fejezet egy tervez�si megk�zel�t�st mutat be, nem egy teljes tervez�si
m�dszert; annak
bemutat�sa t�lmutatna e k�nyv keretein. Az itt bemutatott megk�zel�t�s az
�ltal�nos�-
t�s . vagyis a form�lis megfogalmaz�s . k�l�nb�zo fokozataival �s a m�g�tt�k
megb�v�
alapveto elvekkel ismertet meg. Nem szakirodalmi �ttekint�s �s nem sz�nd�kszik
�rinteni
minden, a szoftverfejleszt�sre vonatkoz� t�m�t, vagy bemutatni minden szempontot.
Ez ism
�t csak meghaladn� e k�nyv lehetos�geit. Ilyen �ttekint�st tal�lhatunk
[Booch,1994]-ben.
Feltunhet, hogy a kifejez�seket itt el�g �ltal�nos �s hagyom�nyos m�don haszn�lom.

A .leg�rdekesebbeknek. . tervez�s, protot�pus, programoz� . a szakirodalomban


sz�mos
k�l�nb�zo �s gyakran egym�ssal ellent�tes defin�ci�ja tal�lhat�. Legy�nk �vatosak,
nehogy
olyan nem sz�nd�kolt jelent�st olvassunk ki az itt elmondottakb�l, melyek az egyes
kifejez
�sek �nmag�ban vett vagy csup�n .helyileg. pontos meghat�roz�sain alapulnak.
23.3. C�lok �s eszk�z�k
A professzion�lis programoz�s c�lja olyan term�ket l�trehozni, mellyel
felhaszn�l�i el�gedettek
lesznek. Ennek elsodleges m�dja olyan programot alkotni, melynek belso fel�p�t�se
tiszta, �s csapatot kov�csolni olyan tervezokbol �s programoz�kb�l, akik el�g
�gyesek �s
lelkesek ahhoz, hogy gyorsan �s hat�konyan reag�ljanak a v�ltoz�sokra �s �lni
tudjanak lehet
os�geikkel.
23. Fejleszt�s �s tervez�s 935
Mi�rt? A program belso szerkezete �s keletkez�s�nek folyamata ide�lis esetben nem
�rinti
a v�gfelhaszn�l�t. Ny�ltabban fogalmazva: ha a v�gfelhaszn�l�nak agg�lya van,
hogyan �rt
�k meg a programot, akkor azzal a programmal valami baj van. Ezt figyelembe v�ve
feltehetj
�k a k�rd�st: miben �ll a program szerkezet�nek �s a programot megalkot�
embereknek
a fontoss�ga?
Elosz�r is, egy programnak tiszta belso fel�p�t�ssel kell rendelkeznie, hogy
megk�nny�tse
� a tesztel�st,
� a m�s rendszerekre val� �t�ltet�st,
� a program karbantart�s�t �s m�dos�t�s�t,
� a bov�t�st,
� az �jraszervez�st �s
� a k�d meg�rt�s�t.
A l�nyeg, hogy egyetlen sikeres nagy program t�rt�nete sem �r v�get a piacra
ker�l�ssel;
�jabb �s �jabb programoz�k �s tervezok dolgoznak rajta, �j hardverre viszik �t,
elore nem
l�tott c�lokra haszn�lj�k fel �s t�bbsz�r is �talak�tj�k szerkezet�t. A program
�lete folyam�n
�j v�ltozatokat kell k�sz�teni, elfogadhat� mennyis�gu hib�val, elfogadhat� ido
alatt. Ha ezzel
nem sz�molunk, kudarcra vagyunk �t�lve.
Vegy�k �szre, hogy b�r a v�gfelhaszn�l�k ide�lis esetben nem kell, hogy ismerj�k
egy rendszer
belso fel�p�t�s�t, elofordulhat, hogy k�v�ncsiak r�, p�ld�ul az�rt, hogy fel
tudj�k becs
�lni megb�zhat�s�g�t, lehets�ges fel�lvizsg�lat�t �s bov�t�s�t. Ha a k�rd�ses
program
nem egy teljes rendszer, csak m�s programok �p�t�s�t seg�to k�nyvt�rak k�szlete, a
felhaszn
�l�k m�g t�bb r�szletet akarnak tudni, hogy k�pesek legyenek jobban kihaszn�lni
a k�nyvt�rakat �s �tleteket mer�thessenek belol�k.
Egyens�lyt kell teremteni a program �tfog� tervez�s�nek melloz�se �s a szerkezetre
fektetett
t�lzott hangs�ly k�z�tt. Az elobbi v�g n�lk�li jav�tgat�sokhoz vezet (.ezt most
lesz�ll�tjuk,
a probl�m�t meg majd kijav�tjuk a k�vetkezo kiad�sban.), az ut�bbi t�lbonyol�tja
a tervez�st �s a l�nyeg elv�sz a formai t�k�letess�gre val� t�rekv�s k�zben, ami
azt eredm
�nyezi, hogy a t�nyleges megval�s�t�s k�sedelmet szenved a program szerkezet�nek
folytonos alak�tgat�sa miatt (.de ez az �j fel�p�t�s sokkal jobb, mint a r�gi; az
emberek
hajland�ak v�rni r�.). A forma tartalom f�l� rendel�se gyakran eredm�nyez olyan
eroforr
�s-ig�nyu rendszereket is, melyeket a leendo felhaszn�l�k t�bbs�ge nem engedhet
meg
mag�nak. Az egyens�ly megtart�sa a tervez�s legnehezebb r�sze �s ez az a ter�let,
ahol
a tehets�g �s a tapasztalat megmutatkozik. A v�laszt�s az �n�ll� programoz�
sz�m�ra is neh
�z, de m�g nehezebb a nagyobb programokn�l, melyek t�bb, k�l�nb�zo k�pess�gu ember

munk�j�t ig�nylik.
936 Tervez�s a C++ seg�ts�g�vel
A programot egy olyan szervezett k�z�ss�gnek kell megalkotnia �s fenntartania,
mely
a szem�lyi �s vezet�si v�ltoz�sok ellen�re k�pes a feladatot megoldani. N�pszeru
megk�-
zel�t�s a programfejleszt�st n�h�ny viszonylag alacsony szintu feladatra
szuk�teni, melyek
egy merev v�zba illeszkednek. Az elgondol�s egy k�nnyen betan�that� (olcs�) �s
.cser�lhet
o., alacsony szintu programoz�kb�l (.k�dol�kb�l.) �ll� oszt�ly �s egy valamivel
kev�sb
� olcs�, de ugyan�gy cser�lheto (�s ugyan�gy mellozheto) tervezokbol �ll� oszt�ly
l�trehoz�sa. A k�dol�kr�l nem t�telezz�k fel, hogy tervez�si d�nt�seket hoznak,
m�g a tervez
okrol nem t�telezz�k fel, hogy a k�dol�s .piszkos. r�szleteivel t�rodnek. Ez a
megk�-
zel�t�s gyakran csod�t mond; ahol pedig muk�dik, nagy m�retu, de gyenge
teljes�tm�nyu
programokat eredm�nyez.
E megold�s buktat�i a k�vetkezok:
� El�gtelen kapcsolattart�s a megval�s�t�st v�gzok �s a tervezok k�z�tt, ami
alkalmak
elmulaszt�s�t, k�s�st, rossz hat�konys�got, �s a tapasztalatb�l val� tanul�s
k�ptelens�ge miatt ism�tlodo probl�m�kat eredm�nyez.
� A programoz�k kezdem�nyez�si hat�sk�r�nek el�gtelens�ge, ami a szakmai fejl
od�s hi�ny�hoz, fel�letess�ghez �s k�oszhoz vezet.
E rendszer alapveto gondja a visszajelz�s hi�nya, mely lehetov� tenn�, hogy a
k�zremuk�-
dok egym�s tapasztalataib�l tanuljanak. Ez a szuk�s emberi tehets�g
elveszteget�se.
Az olyan keretek biztos�t�sa, melyen bel�l mindenki megcsillanthatja tehets�g�t,
�j k�pess
�geket fejleszthet ki, �tletekkel j�rulhat hozz� a sikerhez �s j�l �rezheti mag�t,
nemcsak az
egyed�li tisztess�ges megold�s, hanem gyakorlati �s gazdas�gi �rtelme is van.
M�sr�szt egy rendszert nem lehet fel�p�teni, dokument�lni �s a v�gtelens�gig
fenntartani
valamilyen �ttekintheto szerkezet n�lk�l. Egy �j�t�sokat is ig�nylo munka elej�n
gyakran az
a legjobb, ha egyszeruen megkeress�k a legjobb szakembereket �s hagyjuk oket, hogy
�gy
k�zel�ts�k meg a probl�m�t, ahogy a legjobbnak tartj�k. A munka elorehaladt�val
azonban
egyre ink�bb �gyelni kell a helyes �temez�sre, a r�szfeladatok kioszt�s�ra, a
bevont szem
�lyek k�z�tti kapcsolattart�sra �s bizonyos . a jel�l�sre, elnevez�sekre,
dokument�ci�ra,
tesztel�sre stb. vonatkoz� . ir�nyelvek betart�s�ra. Ism�t csak egyens�lyra �s a
hely�nval�
ir�nti �rz�kre van sz�ks�g. Egy t�l merev rendszer akad�lyozhatja a fejlod�st �s
elfojthatja
az innov�ci�t. Ebben az esetben a vezeto tehets�ge �s tapasztalts�ga m�rettetik
meg, de az
�n�ll� programoz� sz�m�ra is ugyanilyen dilemma kiv�lasztani, hol pr�b�ljon
�gyeskedni
�s hol csin�lja .a k�nyv szerint..
Az adott munk�n�l aj�nlatos nem csak a k�vetkezo kiad�sra, hanem hossz� t�vra
tervezni.
Az elorel�t�s hi�nya mindig megbosszulja mag�t. A szervezeti fel�p�t�st �s a
programfejleszt
�si strat�gi�t �gy kell megv�lasztani, hogy t�bb program t�bb kiad�s�nak
megalkot�-
s�t c�lozzuk meg . vagyis sikerek sorozat�t kell megtervezn�nk.
23. Fejleszt�s �s tervez�s 937
A .tervez�s. c�lja a program sz�m�ra tiszta �s viszonylag egyszeru belso szerkezet
. architekt
�ra . l�trehoz�sa. M�s sz�val, olyan v�zat akarunk alkotni, melybe beilleszthetok
az
egyes k�dr�szek �s ez�ltal ir�nyelvk�nt szolg�l e k�dr�szek meg�r�s�hoz.
A terv a tervez�si folyamat v�gterm�ke (amennyiben egy k�rk�r�s folyamatnak
v�gterm�-
ke lehet). Ez �ll a tervezo �s a programoz�, illetve az egyes programoz�k k�zti
kapcsolattart
�s k�z�ppontj�ban. Fontos, hogy itt kello ar�ny�rz�k�nk legyen. Ha �n . mint
�n�ll�
programoz� . egy kis programot tervezek, melyet holnap fogok elk�sz�teni,
megfelelo pontoss
�g� �s r�szletess�gu lehet egy bor�t�k h�t�ra firk�lt p�r sor. A m�sik v�glet: egy
tervez
ok �s programoz�k sz�zait foglalkoztat� rendszer fejleszt�se k�nyveket kitevo,
gondosan
meg�rt .szabv�nyokat. k�v�nhat, valamilyen szab�lyhoz r�szben vagy teljes
eg�sz�ben igazod
� jel�l�sek haszn�lat�val. Egy terv megfelelo r�szletess�gi, pontoss�gi �s
formalit�si
szintj�nek meghat�roz�sa �nmag�ban v�ve is kih�v� szakmai �s vezet�si feladat.
Ebben �s a k�vetkezo fejezetekben felt�telezem, hogy egy program terve
oszt�lydeklar�ci-
�k egy halmaz�val (a priv�t deklar�ci�ikat, mint zavar� r�szleteket, �ltal�ban
elhagyom) �s
a k�zt�k levo kapcsolatokkal van kifejezve. Ez persze egyszerus�t�s: egy konkr�t
tervben
sok m�s k�rd�s is felmer�l; p�ld�ul a p�rhuzamos folyamatok, a n�vterek kezel�se,
a nem
tag f�ggv�nyek �s adatok haszn�lata, az oszt�lyok �s f�ggv�nyek param�terez�se, az
�jraford
�t�s sz�ks�gess�g�t a leheto legalacsonyabb szintre visszaszor�t� k�dszervez�s, a
perzisztencia �s a t�bb-sz�m�t�g�pes haszn�lat. A t�rgyal�snak ezen a szintj�n
mindenk�ppen
sz�ks�g van egyszerus�t�sre �s a C++-ban a tervez�shez az oszt�lyok megfelelo
kiindul
�pontot jelenthetnek. A fent eml�tett t�mak�r�k k�z�l n�h�nyat fut�lag ez a
fejezet is
�rint, de a C++-ban val� tervez�sre k�zvetlen�l hat�st gyakorl�kat a 24. �s 25.
fejezet t�rgyalja.
Ha egy bizonyos objektumorient�lt tervez�si modellre r�szleteiben vagyunk
k�v�ncsiak,
[Booch, 1994] lehet seg�ts�g�nkre.
Az elemz�s (anal�zis, analysis) �s a tervez�s (design) k�z�tti k�l�nbs�gre nem
t�rek ki k�-
l�n�sebben, egyr�szt mert nem t�m�ja e k�nyvnek, m�sr�szt az egyes tervez�si
m�dszerek
eset�ben e k�l�nbs�get m�s-m�s m�don hat�rozhatn�nk meg. R�viden annyit
mondhatunk,
hogy az elemz�si m�dszert mindig az adott tervez�si megk�zel�t�shez kell
igaz�tani,
azt pedig a haszn�lt programoz�si nyelv �s st�lus alapj�n kell megv�lasztani.
938 Tervez�s a C++ seg�ts�g�vel
23.4. A fejleszt�si folyamat
A szoftverfejleszt�s ism�tl�st �s gyarapod�st jelent: a folyamat minden szakasza a
fejleszt�s
alatt �jra �s �jra fel�lvizsg�latra ker�l �s minden egyes fel�lvizsg�lat finom�tja
az adott szakasz
v�gterm�k�t. A fejleszt�si folyamatnak �ltal�ban nincs kezdete �s nincs v�ge.
Amikor
egy programrendszert megtervez�nk �s elk�sz�t�nk, m�s emberek terveit, k�nyvt�rait
�s
programjait vessz�k alapul. Amikor befejezz�k, a terv �s a k�d t�rzs�t m�sokra
hagyjuk,
hogy finom�ts�k, fel�lvizsg�lj�k, bov�ts�k �s m�s g�pekre �ttegy�k azt.
Term�szetesen egy
adott munk�nak lehet meghat�rozott kezdete �s v�ge, �s fontos is (b�r gyakran
meglepo-
en neh�z), hogy azt idoben �s t�rben tiszt�n �s pontosan behat�roljuk. Ha azonban
�gy tesz
�nk, mintha tiszta lappal induln�nk, komoly probl�m�kat okozhatunk. �gy tenni,
mintha
a vil�g a program .v�gso �tad�s�n�l. v�gzodne, egyar�nt fejf�j�st okozhat ut�daink
�s
gyakran saj�t magunk sz�m�ra.
Ebbol k�vetkezik, hogy a k�vetkezo fejezetek b�rmilyen sorrendben olvashat�k,
mivel egy
val�s munka sor�n a tervez�si �s megval�s�t�si szempontok majdnem tetsz�s szerint
�tfedhetik
egym�st. Ez azt jelenti, hogy a .tervez�s. majdnem mindig �jratervez�s, amely egy
elozo tervez�sen �s n�mi fejleszt�si tapasztalaton alapul. Tov�bb�, a tervez�st
korl�tozz�k
az �temtervek, a r�sztvevo emberek k�pess�gei, a kompatibilit�si k�rd�sek �s �gy
tov�bb.
A tervezo, vezeto vagy programoz� sz�m�ra nagy kih�v�st jelent rendet teremteni e
folyamatban
an�lk�l, hogy elfojtan�nk az �j�t�si t�rekv�seket �s t�nkretenn�nk a visszajelz�s
rendszer�t, melyek a sikeres fejleszt�shez sz�ks�gesek.
A fejleszt�si folyamat h�rom szakaszb�l �ll:
� Elemz�s: a megoldand� probl�ma kiterjed�s�nek meghat�roz�sa
� Tervez�s: a rendszer �tfog� fel�p�t�s�nek megalkot�sa
� Megval�s�t�s: a k�d meg�r�sa �s ellenorz�se
M�g egyszer eml�keztetn�k e folyamat ism�tlodo term�szet�re . nem v�letlen, hogy a
szakaszok
k�z�tt nem �ll�tottam fel sorrendet. Vegy�k �szre azt is, hogy a programfejleszt�s

n�h�ny fo szempontja nem k�l�n szakaszk�nt jelentkezik, mivel ezeknek a folyamat


sor�n
mindv�gig �rv�nyes�lni�k kell:
� K�s�rletez�s
� Ellenorz�s
� A tervek �s a megval�s�t�s elemz�se
� Dokument�l�s
� Vezet�s
23. Fejleszt�s �s tervez�s 939
A program fenntart�sa vagy .karbantart�sa. egyszeruen e fejleszt�si folyamat
t�bbsz�ri ism
�tl�s�t jelenti (�23.4.6).
A legfontosabb, hogy az elemz�s, a tervez�s �s a megval�s�t�s ne v�ljon el
t�lzottan egym�st
�l, �s hogy a bevont emberek k�z�s szellemis�g, kult�ra �s nyelv r�v�n hat�konyan
tudjanak
egym�ssal kommunik�lni. Nagyobb programok fejleszt�s�n�l ez sajnos ritk�n van �gy.

Ide�lis esetben az egy�nek a munka sor�n t�bb szakaszban is r�szt vesznek; ez az


ismeretek
�s tapasztalatok �tad�s�nak legjobb m�dja. Sajnos a programfejleszto c�gek gyakran
akad�-
lyozz�k az ilyen mozg�st, p�ld�ul az�ltal, hogy a tervezoknek magasabb beoszt�st
�s/vagy
magasabb fizet�st adnak, mint a .csak programoz�knak.. Ha gyakorlati szempontb�l
nem
c�lszeru, hogy a munkat�rsak v�ndorolva tanuljanak �s tan�tsanak, legal�bb arra
biztassuk
oket, hogy rendszeresen besz�lgessenek a fejleszt�s .m�s szakaszaiba. bevontakkal.

Kisebb �s k�zepes projektekn�l gyakran nem k�l�nb�ztetik meg az elemz�st �s a


tervez�st;
e k�t szakasz egyes�l. A kis programok k�sz�t�s�n�l �ltal�ban ugyan�gy nem v�lik
sz�t a tervez
�s �s a programoz�s, ami persze megoldja a kommunik�ci�s probl�m�kat. Fontos, hogy

a formalit�sok �s a szakaszok elk�l�n�t�se mindig az adott munk�hoz igazodjanak


(�23.5.2); nem l�tezik egyetlen, �r�k �rv�nyu �t.
Az itt le�rt programfejleszt�si modell gy�keresen k�l�nb�zik a hagyom�nyos
.v�zes�s. modellt
ol, amelyben a fejleszt�s szab�lyosan �s egyenes ir�nyban halad a fejleszt�si
szakaszokon
�t, az elemz�stol a tesztel�sig. A v�zes�s modell alapveto baja, hogy az
inform�ci�
foly�sa egyir�ny�. Ha a .foly�s ir�ny�ban haladva. probl�m�kba �tk�z�nk, a
szervezeti fel-
�p�t�s �s a munkam�dszerek arra k�nyszer�tenek, hogy helyben oldjuk meg azokat, az
elo-
zo szakaszokra val� hat�s n�lk�l. A visszacsatol�s ezen hi�nya gyenge tervekhez
vezet,
a helyi jav�t�sok pedig torz megval�s�t�st eredm�nyeznek. Vannak elker�lhetetlen
esetek,
amikor az inform�ci� mindenk�ppen visszafel� �ramlik �s megv�ltoztatja az eredeti
terveket.
A gerjesztett .hull�m. csak lassan �s neh�zkesen jut el c�lj�hoz, hiszen a
rendszert �gy
alkott�k meg, hogy ne legyen sz�ks�g v�ltoztat�sokra �s a rendszer emiatt lassan
�s kelletlen
�l reag�l. A .semmi v�ltoztat�s. vagy a .helyi jav�t�s. elve teh�t olyan elvv�
v�ltozik,
mely szerint egy r�szleg nem adhat t�bbletmunk�t m�s r�szlegeknek .a saj�t
k�nyelme �rdek
�ben.. Lehets�ges, hogy mire egy nagyobb hib�t �szlelnek, m�r olyan sok
pap�rmunk�t
v�geztek, hogy a k�d jav�t�s�hoz sz�ks�ges erofesz�t�s elt�rp�l ahhoz k�pest, ami
a dokument
�ci� m�dos�t�s�hoz kell. Ilyenkor a pap�rmunka v�lik a programfejleszt�s fo
ker�kk�-
toj�v�. Term�szetesen ilyen probl�m�k elofordulhatnak �s elo is fordulnak,
j�llehet a nagy
rendszerek fejleszt�s�t alaposan megszervezik. Mindenk�ppen elengedhetetlen n�mi
pap
�rmunka. Az egyenes vonal� (v�zes�s) fejleszt�si modell alkalmaz�sa azonban
nagyban
n�veli a val�sz�nus�g�t, hogy a probl�ma kezelhetetlenn� v�lik.
940 Tervez�s a C++ seg�ts�g�vel
A v�zes�ses modellel az a probl�ma, hogy nincs benne megfelelo visszacsatol�s �s
k�ptelen
a v�ltoz�sokra reag�lni. Az itt v�zolt ciklikus megk�zel�t�s vesz�lye viszont a
k�s�rt�s,
hogy a val�di gondolkod�s �s halad�s helyett nem azonos c�l �rdek�ben v�grehajtott
m�-
dos�t�sok sor�t v�gezz�k el. Mindk�t probl�m�t k�nnyebb felismerni, mint
megoldani, �s
b�rmilyen j�l is szervezz�k meg a feladat v�grehajt�s�t, k�nnyen
�sszet�veszthetj�k a puszta
munk�t a halad�ssal. Term�szetesen a munka elorehaladt�val a fejleszt�si folyamat
k�-
l�nb�zo szakaszainak jelentos�ge v�ltozik. Kezdetben a hangs�ly az elemz�sen �s a
tervez
�sen van, �s kevesebb figyelmet ford�tunk a programoz�si k�rd�sekre. Ahogy m�lik
az
ido, az eroforr�sok a tervez�s �s a programoz�s fel� tol�dnak, majd ink�bb a
programoz�s
�s a tesztel�s fel�. Kulcsfontoss�g� azonban, hogy soha ne �sszpontos�tsunk csup�n
az
elemz�s/tervez�s/megval�s�t�s egyik�re, kiz�rva l�t�k�r�nkbol a t�bbit.
Ne felejts�k el, hogy nem seg�thet rajtunk semmilyen, .a r�szletekre is kiterjedo.
figyelem,
vezet�si m�dszer vagy fejlett technol�gia, ha nincs tiszta elk�pzel�s�nk arr�l,
mit is akarunk
el�rni. T�bb terv hi�sul meg amiatt, hogy nincsenek j�l meghat�rozott �s val�szeru

c�ljai, mint b�rmilyen m�s okb�l. B�rmit tesz�nk is �s b�rhogyan fogunk is hozz�,
tuzz�nk
ki k�zzelfoghat� c�lokat, jel�lj�k ki a hozz� vezeto �t �llom�sait, �s haszn�ljunk
fel minden
megfelelo technol�gi�t, ami csak el�rheto . m�g akkor is, ha az beruh�z�st ig�nyel
., mert
az emberek jobban dolgoznak megfelelo eszk�z�kkel �s megfelelo k�rnyezetben. Ne
higgy�k persze, hogy k�nnyu ezt a tan�csot megfogadni.
23.4.1. A fejleszt�s k�rforg�sa
Egy program fejleszt�se sor�n �lland� fel�lvizsg�latra van sz�ks�g. A fo ciklus a
k�vetkezo
l�p�sek ism�telt v�grehajt�s�b�l �ll:
1. Vizsg�ljuk meg a probl�m�t.
2. Alkossunk �tfog� tervet.
3. Keress�nk szabv�nyos �sszetevoket.
� Igaz�tsuk ezeket a tervhez.
4. K�sz�ts�nk �j szabv�nyos �sszetevoket.
� Igaz�tsuk ezeket is a tervhez.
5. �ll�tsuk �ssze a konkr�t tervet.
Hasonlatk�nt vegy�nk egy aut�gy�rat. A projekt beind�t�s�hoz kell, hogy legyen egy
�tfog
� terv az �j aut�t�pusr�l. Az elozetes tervnek valamilyen elemz�sen kell alapulnia
�s �ltal
�noss�gban kell le�rnia az aut�t, ink�bb annak sz�nd�kolt haszn�lat�t, mintsem a
k�v�nt
tulajdons�gok kialak�t�s�nak r�szleteit szem elott tartva. Eld�nteni, mik is a
k�v�nt tulajdons
�gok . vagy m�g ink�bb, a d�nt�shez viszonylag egyszeru ir�nyelveket adni .
gyakran
23. Fejleszt�s �s tervez�s 941
a munka legnehezebb r�sze. Ezt sikeresen �ltal�ban egyetlen, nagy �ttekint�ssel
rendelkez
o egy�n tudja elv�gezni, �s ez az, amit gyakran l�tom�snak (vision) nevez�nk. Igen
gyakori,
hogy hi�nyoznak az ilyen tiszta c�lok . m�rpedig a terv ezek n�lk�l meginoghat
vagy
meg is hi�sulhat.
Tegy�k fel, hogy egy k�zepes nagys�g� aut�t akarunk �p�teni, n�gy ajt�val �s eros
motorral.
A tervez�s elso szakasza a leghat�rozottabban nem az aut� (�s az alkatr�szek)
megtervez
�se a .semmibol.. Egy meggondolatlan programtervezo vagy programoz� hasonl� k�-
r�lm�nyek k�z�tt (ostob�n) pontosan ezt pr�b�ln� tenni.
Az elso l�p�s annak sz�mbav�tele, milyen alkatr�szek szerezhetok be a gy�r saj�t
k�szleteib
ol �s megb�zhat� sz�ll�t�kt�l. Az �gy tal�lt alkatr�szek nem kell, hogy pontosan
illeszkedjenek
az �j aut�ba. Lesz m�d az alkatr�szek hozz�igaz�t�s�ra. Azt is megtehetj�k, hogy
az
ilyen alkatr�szek .k�vetkezo kiad�s�hoz. ir�nyelveket adunk, hogy saj�t
elk�pzel�seinkhez
jobban illeszkedjenek. P�ld�ul l�tezhet egy motor, melynek megfeleloek a
tulajdons�-
gai, azzal a kiv�tellel, hogy kicsit gyeng�bb a leadott teljes�tm�nye. A c�g vagy
a motor sz�ll
�t�ja r�szerelhet egy turb�felt�ltot, hogy ezt helyrehozza, an�lk�l, hogy
befoly�soln� az
alapveto terveket. Vegy�k �szre, hogy az ilyen, .az alaptervet nem befoly�sol�.
v�ltoztat�s
val�sz�nus�ge kicsi, hacsak az eredeti terv nem elolegezi meg valamilyen form�ban
az igaz
�that�s�got. Az ilyen igaz�that�s�g �ltal�ban egy�ttmuk�d�st k�v�n k�zt�nk �s a
motor
sz�ll�t�ja k�z�tt. A programoz� hasonl� lehetos�gekkel rendelkezik: a t�bbalak�
(polimorf)
oszt�lyok �s sablonok (template) p�ld�ul hat�konyan felhaszn�lhat�k egyedi
v�ltozatok
k�sz�t�s�re. Nem szabad azonban elv�rnunk, hogy az oszt�ly k�sz�toje a mi sz�junk
�ze szerint bov�tse alkot�s�t; ehhez a k�sz�to elorel�t�s�ra vagy a vel�nk val�
egy�ttmuk�-
d�sre van sz�ks�g.
Ha kimer�lt a megfelelo szabv�nyos alkatr�szek v�laszt�ka, az aut�tervezo nem
rohan,
hogy megtervezze az �j aut�hoz az optim�lis �j alkatr�szeket. Ez egyszeruen t�l
k�lts�ges
lenne. Tegy�k fel, hogy nem kaphat� megfelelo l�gkondicion�l� egys�g �s hogy egy
megfelel
o L alak� t�r �ll rendelkez�sre a motort�ren bel�l. Az egyik megold�s egy L alak�
l�gkondicion
�l� egys�g megtervez�se lenne, de annak val�sz�nus�ge, hogy ez a k�l�nleges
forma m�s aut�t�pusokn�l is haszn�lhat�, m�g alapos igaz�t�s eset�n is csek�ly.
Ebbol k�-
vetkezik, hogy aut�tervezonk nem lesz k�pes az ilyen egys�gek termel�si k�lts�geit
m�s
aut�t�pusok tervezoivel megosztani, �gy az egys�g kihaszn�lhat� �lettartama r�vid
lesz. �rdemes
teh�t olyan egys�get tervezni, mely sz�lesebb k�rben sz�m�that �rdeklod�sre;
vagyis
egy tiszt�bb vonal� egys�get kell tervezni, mely jobban az ig�nyekhez igaz�that�,
mint a mi
elm�letben elk�sz�tett L alak� furcsas�gunk. Ez val�sz�nuleg t�bb munk�val j�r,
mint az L
alak� egys�g �s mag�val vonhatja az aut� �tfog� terveinek m�dos�t�s�t is, hogy
illeszkedjen
az �ltal�nosabb c�l� egys�ghez. Mivel az �j egys�g sz�lesebb k�rben haszn�lhat�,
mint
a mi L alak� csod�nk, felt�telezheto, hogy sz�ks�g lesz egy kis igaz�t�sra, hogy
t�k�letesen
942 Tervez�s a C++ seg�ts�g�vel
illeszkedjen a mi fel�lvizsg�lt ig�nyeinkhez. A programoz� ism�t hasonl�
lehetos�gek k�-
z�l v�laszthat: ahelyett, hogy az adott programra n�zve egyedi k�dot �rna, �j,
�ltal�nosabb
�sszetevot tervezhet, amely rem�lhetoleg valamilyen szabv�nny� v�lik.
Amikor v�gk�pp kifogytunk a lehets�ges szabv�nyos �sszetevokbol, �ssze�ll�tjuk
a .v�gleges
. tervet. A leheto legkevesebb egyedi tervez�su alkatr�szt haszn�ljuk, mert j�vore
. kiss
� m�s form�ban . ism�t v�gig kell csin�lnunk ugyanezt a munk�t a k�vetkezo �j
modellhez,
�s az egyedi alkatr�szek lesznek azok, amelyeket a legval�sz�nubb, hogy �jra kell
�p�ten�nk vagy el kell dobnunk. Sajnos a hagyom�nyosan tervezett programokkal
kapcsolatban
az a tapasztalat, hogy kev�s benn�k az olyan r�sz, amelyet egy�ltal�n �n�ll�
�sszetev
onek lehetne tekinteni �s az adott programon k�v�l m�shol is fel lehetne
haszn�lni.
Nem �ll�tom, hogy minden aut�tervezo olyan �sszeruen gondolkodik, mint ahogy a
hasonlatban
felv�zoltam vagy hogy minden programtervezo elk�veti az eml�tett hib�kat. �ppen
ellenkezoleg, a bemutatott modell a programtervez�sben is haszn�lhat�. Ez a
fejezet �s
a k�vetkezok olyan elj�r�sokat ismertetnek, melyek a C++-ban muk�dnek. A programok

nem k�zzelfoghat� term�szete miatt viszont a hib�kat k�ts�gtelen�l nehezebb


elker�lni
(�24.3.1, 24.3.4), �s r�mutatok majd arra is (�23.5.3.1), hogy a c�gek muk�d�si
elve gyakran
elveszi az emberek b�tors�g�t, hogy az itt v�zolt modellt haszn�lj�k. Ez a
fejleszt�si modell
val�j�ban csak akkor muk�dik j�l, ha hosszabb t�vra tervez�nk. Ha l�t�k�r�nk csak
a k�-
vetkezo kiad�sig terjed, a szabv�nyos �sszetevok megalkot�sa �s fenntart�sa
�rtelmetlen,
egyszeruen felesleges t�lmunk�nak fogjuk l�tni. E modell k�vet�se olyan
fejlesztok�z�ss�-
gek sz�m�ra javasolt, melyek �lete sz�mos projektet fog �t �s melyek m�rete miatt
�rdemes
p�nzt fektetni a sz�ks�ges eszk�z�kbe (a tervez�shez, programoz�shoz �s
projektvezet�shez)
�s oktat�sba (a tervezok, programoz�k �s vezetok r�sz�re). Modell�nk val�j�ban
egyfajta
.szoftvergy�r. v�zlata, amely furcsa m�don csak m�reteiben k�l�nb�zik a legjobb
�n�ll� programoz�k gyakorlat�t�l, akik az �vek sor�n m�dszerek, tervek, eszk�z�k
�s
k�nyvt�rak k�szlet�t �p�tett�k fel, hogy fokozz�k szem�lyes hat�konys�gukat.
Sajnos �gy
tunik, a legt�bb c�g elmulasztotta kihaszn�lni a legjobbak gyakorlati tud�s�t,
mert hi�nyzott
belole az elorel�t�s �s a k�pess�g, hogy az �ltaluk haszn�lt megk�zel�t�st nagyobb

programokra is alkalmazza.
Vegy�k �szre, hogy nincs �rtelme minden .szabv�nyos �sszetevotol. elv�rni, hogy
�ltal�-
nos �rv�nyu szabv�ny legyen. Nemzetk�zileg szabv�nyos k�nyvt�rb�l csak n�h�ny
maradhat
fenn. A legt�bb �sszetevo vagy alkatr�sz (csak) egy orsz�gon, egy ipar�gon, egy
gy�rt�soron, egy oszt�lyon, egy alkalmaz�si ter�leten stb. bel�l lesz szabv�ny. A
vil�g egyszer
uen t�l nagy ahhoz, hogy val�s�gos vagy igaz�n k�v�natos c�l legyen minden
eszk�zre
egyetemes szabv�nyt alkotni.
23. Fejleszt�s �s tervez�s 943
Ha m�r az elej�n az egyetemess�get tuzz�k ki c�lul, a tervet arra �t�lj�k, hogy
soha ne legyen
befejezve. Ennek egyik oka, hogy a fejleszt�s k�rk�r�s folyamat, �s
elengedhetetlen,
hogy legyen egy muk�do rendszere, amelybol tapasztalatokat mer�thet�nk
(�23.4.3.6).
23.4.2. Tervez�si c�lok
Melyek a tervez�s �tfog� c�ljai? Az egyik term�szetesen az egyszerus�g, de milyen
szempontok
szerint? Felt�telezz�k, hogy a tervnek fejlodnie kell, vagyis a programot majd
bov�-
teni, m�s rendszerre �tvinni, finomhangolni �s t�bbf�le, elore nem l�that� m�don
m�dos�-
tani lesz sz�ks�ges. K�vetkez�sk�ppen olyan tervet �s rendszert kell megc�loznunk,
amely
egyszeru, de k�nnyen �s sokf�le m�don m�dos�that�. A val�s�gban a rendszerrel
szemben
t�masztott k�vetelm�nyek m�r a kezdeti terv �s a program elso kibocs�t�sa k�z�tt
t�bbsz�r
megv�ltoznak.
Ez mag�val vonja, hogy a programot �gy kell megtervezni, hogy a m�dos�t�sok
sorozata
alatt a leheto legegyszerubb maradjon. A m�dos�that�s�got figyelembe v�ve a
k�vetkezo-
ket kell c�lul kituzn�nk:
� Rugalmass�g
� Bov�thetos�g
� Hordozhat�s�g (m�s rendszerekre val� �t�ltethetos�g)
A legjobb, ha megpr�b�ljuk elszigetelni a program azon ter�leteit, melyek
val�sz�nuleg v�ltozni
fognak, a felhaszn�l�k sz�m�ra pedig lehetov� tessz�k, hogy m�dos�t�saikat e
r�szek
�rint�se n�lk�l v�gezhess�k el.
Ezt a program kulcsfogalmainak azonos�t�s�val �s azzal �rhetj�k el, hogy minden
egyes
oszt�lyra kiz�r�lagos feleloss�ggel r�b�zzuk egy fogalommal kapcsolatos minden
inform�-
ci� kezel�s�t. Ez esetben mindennemu v�ltoztat�s csup�n az adott oszt�ly
m�dos�t�s�val
�rheto el. Ide�lis esetben egy fogalom m�dos�t�s�hoz el�g egy �j oszt�ly
sz�rmaztat�sa
(�23.4.3.5) vagy egy sablon elt�ro param�terez�se. Term�szetesen az elvet a
gyakorlatban
sokkal nehezebb k�vetni.
Vegy�nk egy p�ld�t: egy meteorol�giai jelens�geket ut�nz� programban egy esofelhot

akarunk megjelen�teni. Hogyan csin�ljuk? Nem lehet �ltal�nos elj�r�sunk a felho


megjelen
�t�s�re, mivel a felho kin�zete f�gg a felho belso �llapot�t�l �s ez az �llapot a
felho kiz�-
r�lagos .feleloss�ge. al� kell, hogy tartozzon.
944 Tervez�s a C++ seg�ts�g�vel
A probl�ma elso megold�sa, hogy hagyjuk a felhore a saj�t megjelen�t�s�t. Ez
bizonyos k�-
r�lm�nyek k�z�tt elfogadhat�, de nem �ltal�nos megold�s, mert egy felhot sokf�le
m�don
lehet megjelen�teni: r�szletes k�ppel, elnagyolt v�zlatk�nt, vagy mint egy jelet
egy t�rk�pen.
M�s sz�val az, hogy egy felho mire hasonl�t, f�gg mind a felhotol, mind a
k�rnyezet�tol.
A m�sik megold�s, hogy a felhot .t�j�koztatjuk. k�rnyezet�rol, majd hagyjuk, hogy
megjelen
�tse mag�t. Ez m�g t�bb esetben elfogadhat�, de m�g mindig nem �ltal�nos m�dszer.
Ha
tudatjuk a felhovel k�rnyezet�nek r�szleteit, megs�rtj�k azt a szab�lyt, hogy egy
oszt�ly
csak egy dolog�rt lehet felelos �s hogy minden .dolog. valamelyik oszt�ly
feleloss�ge. Nem
biztos, hogy eljuthatunk .a felho k�rnyezet�nek. egy k�vetkezetes jel�l�s�hez,
mert �ltal�-
ban az, hogy egy felho mihez hasonl�t, f�gg mind a felhotol, mind a n�zotol. Az,
hogy sz�-
momra mihez hasonl�t egy felho, m�g a val�s �letben is meglehetosen f�gg att�l,
hogyan
n�zem: puszta szemmel, pol�rszuron kereszt�l vagy meteorol�giai radarral. A n�zon
�s
a felhon k�v�l lehet, hogy valamilyen .�ltal�nos h�tteret. is figyelembe kell
venni, p�ld�ul
a nap viszonylagos helyzet�t. Tov�bb bonyol�tja a dolgot, ha egy�b objektumokat is
. m�s
felhoket, rep�log�peket . sz�m�t�sba vesz�nk. Hogy a tervezo �let�t igaz�n
megnehez�ts
�k, adjuk hozz� azt a lehetos�get is, hogy egyszerre t�bb n�zonk van.
A harmadik megold�s, hogy hagyjuk a felhot �s a t�bbi objektumot (a rep�log�peket
�s
a napot), hogy le�rj�k magukat a n�zoknek. E megold�s el�g �ltal�nos ahhoz, hogy a
legt
�bb c�lnak megfeleljen, de jelentos �rat fizethet�nk �rte, mert a program
t�ls�gosan bonyolult
�s lass� lehet. Hogyan �rtetj�k meg p�ld�ul a n�zovel a felhok �s m�s objektumok
�ltal k�sz�tett le�r�sokat?
A programokban nem surun fordulnak elo esofelhok (b�r a p�lda kedv��rt l�sd
�15.2), de
a k�l�nb�zo I/O muveletekbe sz�ks�gszeruen bevont objektumok is hasonl�an
viselkednek.
Ez teszi a felho p�ld�t tal�l�v� a programok �s k�l�n�sen a k�nyvt�rak tervez�s�re

n�zve. Logikailag hasonl� p�lda C++ k�dj�t mutattam be az adatfolyamok be- �s


kimeneti
rendszer�nek t�rgyal�sakor, a form�zott kimenetre haszn�lt m�dos�t�kn�l
(manipulator,
�21.4.6, �21.4.6.3). Le kell azonban sz�gezn�nk, hogy a harmadik megold�s nem .a
helyes.,
csup�n a leg�ltal�nosabb megold�s. A tervezonek m�rlegelnie kell a rendszer
k�l�nb�zo
sz�ks�gleteit, hogy megv�lassza az adott probl�m�hoz az adott rendszerben
megfelelo
m�rt�ku �ltal�noss�got �s elvont �br�zol�sm�dot. Alapszab�ly, hogy egy hossz�
�letunek
tervezett programban az elvonatkoztat�si szintnek a m�g meg�rtheto �s megengedheto
leg-
�ltal�nosabbnak, nem az abszol�t leg�ltal�nosabbnak kell lennie. Ha az
�ltal�nos�t�s t�lhaladja
az adott program kereteit �s a k�sz�tok tapasztalat�t, k�ros lehet, mert
k�sedelmet, elfogadhatatlanul
rossz hat�konys�got, kezelhetetlen terveket �s nyilv�nval� kudarcot von
maga ut�n.
23. Fejleszt�s �s tervez�s 945
Az ilyen m�dszerek kezelhetov� �s gazdas�goss� t�tel�hez az �jrahasznos�t�s
mik�ntj�t is
meg kell tervezn�nk (�23.5.1) �s nem szabad teljesen elfeledkezni a hat�konys�gr�l

(�23.4.7).
23.4.3. Tervez�si l�p�sek
Vegy�k azt az esetet, amikor egyetlen oszt�lyt tervez�nk. Ez �ltal�ban nem j�
�tlet. Fogalmak
nem l�teznek elszigetelten; m�s fogalmakkal val� �sszef�gg�seik hat�rozz�k meg
azokat.
Ugyanez �rv�nyes az oszt�lyokra is; meghat�roz�suk logikailag kapcsol�d� oszt�lyok

meghat�roz�s�val egy�tt t�rt�nik. Jellemzoen egym�ssal kapcsolatban l�vo oszt�lyok


egy
halmaz�n dolgozunk. Az ilyen halmazt gyakran oszt�lyk�nyvt�rnak (class library)
vagy
�sszetevonek (komponens, component) nevezz�k. N�ha az adott �sszetevoben l�vo
�sszes
oszt�ly egyetlen oszt�lyhierarchi�t alkot, n�ha egyetlen n�vt�r tagjai, n�ha
viszont csup�n
deklar�ci�k ad hoc gyujtem�ny�t k�pezik (�24.4).
Az egy �sszetevoben l�vo oszt�lyok halmaz�t logikai k�tel�kek egyes�tik; k�z�s
st�lusuk
van vagy azonos szolg�ltat�sokra t�maszkodnak. Az �sszetevo teh�t a tervez�s, a
dokument
�ci�, a tulajdonl�s �s az �jrafelhaszn�l�s egys�ge. Ez nem jelenti azt, hogy ha
valakinek
egy �sszetevobol csak egy oszt�lyra van sz�ks�ge, �rtenie �s haszn�lnia kell az
�sszetev
o minden oszt�ly�t vagy be kell t�ltenie a programj�ba az �sszes oszt�ly k�dj�t.
�ppen
ellenkezoleg, �ltal�ban arra t�reksz�nk, hogy az oszt�lyoknak a leheto legkevesebb
g�pi �s
emberi eroforr�sra legyen sz�ks�g�k. Ahhoz azonban, hogy egy �sszetevo b�rmely
r�sz�t
haszn�lhassuk, �rten�nk kell az �sszetevot �sszetart� �s meghat�roz� logikai
kapcsolatokat,
(a dokument�ci�ban ezek rem�lhetoleg el�gg� vil�gosak), a fel�p�t�s�ben �s
dokument
�ci�j�ban megtestes�lt elveket �s st�lust, illetve a k�z�s szolg�ltat�sokat (ha
vannak).
L�ssuk teh�t, hogyan tervezhet�nk meg egy �sszetevot. Mivel ez �ltal�ban komoly
kih�v�st
jelent, meg�ri l�p�sekre bontani, hogy k�nnyebb legyen a k�l�nb�zo r�szfeladatokra
�sszpontos
�tani. Szokott m�don, az �sszetevok megtervez�s�nek sincs egyetlen helyes �tja.
Itt
csup�n egy olyan l�p�ssorozatot mutatok be, amely egyesek sz�m�ra m�r bev�lt:
1. Keress�k meg a fogalmakat/oszt�lyokat �s legalapvetobb kapcsolataikat.
2. Finom�tsuk az oszt�lyokat a rajtuk v�gezheto muveletek meghat�roz�s�val.
� Oszt�lyozzuk a muveleteket. K�l�n�sen figyelj�nk a l�trehoz�s, a m�sol�s
�s a megsemmis�t�s sz�ks�gess�g�re.
� T�rekedj�nk a min�l kisebb m�retre, a teljess�gre �s a k�nyelemre.
3. Finom�tsuk az oszt�lyokat az �sszef�gg�sek meghat�roz�s�val.
� �gyelj�nk a param�terez�sre �s az �r�kl�sre, �s haszn�ljuk ki
a f�ggos�geket.
946 Tervez�s a C++ seg�ts�g�vel
4. Hat�rozzuk meg a fel�leteket.
� V�lasszuk sz�t a f�ggv�nyeket priv�t �s v�dett muveletekre.
� A muveleteket hat�rozzuk meg pontosan az adott oszt�lyokra.
�szrevehetj�k, hogy ezek is egy ism�tlodo folyamat l�p�sei. �ltal�ban t�bbsz�r
kell rajtuk
v�gigmenni, hogy k�nyelmesen haszn�lhat� tervet kapjunk, melyet felhaszn�lhatunk
egy
elso vagy egy �jabb megval�s�t�sn�l. Ha az itt le�rtak szerinti elemezz�k a
tennival�kat �s
k�sz�tj�k el az elvont adat�br�zol�st, az azzal az elonnyel j�r, hogy viszonylag
k�nnyu lesz
az oszt�lykapcsolatok �trendez�se a k�d meg�r�sa ut�n is. (B�r ez sohasem t�l
egyszeru.)
Ha v�gezt�nk, elk�sz�tj�k az oszt�lyokat �s visszat�r�nk fel�lvizsg�lni a tervet
annak alapj
�n, amit a megval�s�t�s sor�n megtudtunk. A k�vetkezokben ezeket a l�p�seket
egyenk�nt
vessz�k sorra.
23.4.3.1. Elso l�p�s: keress�nk oszt�lyokat
Keress�k meg a fogalmakat/oszt�lyokat �s legalapvetobb kapcsolataikat. A j�
tervez�s kulcsa
a .val�s�g. valamely r�sz�nek k�zvetlen modellez�se . vagyis a program fogalmainak

oszt�lyokra val� lek�pez�se, az oszt�lyok k�zti kapcsolatok �br�zol�sa


meghat�rozott m�-
don (p�ld�ul �r�kl�ssel), �s mindezek ism�telt v�grehajt�sa k�l�nb�zo
elvonatkoztat�si
szinteken. De hogyan fogjunk hozz� a fogalmak megkeres�s�hez? Milyen megk�zel�t�st

c�lszeru k�vetni, hogy eld�nthess�k, mely oszt�lyokra van sz�ks�g?


A legjobb, ha elosz�r mag�ban a programban n�z�nk sz�t, ahelyett, hogy a
sz�m�t�g�ptud
�s .fogalomzs�kj�ban. keresg�ln�nk. Hallgassunk valakire, aki a rendszer
elk�sz�lte ut�n
annak szak�rto felhaszn�l�ja lesz, �s valakire, aki a kiv�ltand� rendszer kiss�
el�gedetlen
felhaszn�l�ja. Figyelj�k meg, milyen szavakat haszn�lnak.
Gyakran mondj�k, hogy a fonevek fognak megfelelni a programhoz sz�ks�ges
oszt�lyoknak
�s objektumoknak; �s ez t�bbnyire �gy is van. Ezzel azonban semmik�ppen sincs v�ge

a t�rt�netnek. Az ig�k jelenthetik az objektumokon v�gzett muveleteket, a


hagyom�nyos
(glob�lis) f�ggv�nyeket, melyek param�tereik �rt�kei vagy oszt�lyok alapj�n �j
�rt�keket
�ll�tanak elo. Az ut�bbira p�ld�k a f�ggv�nyobjektumok (function object, �18.4) �s
a m�-
dos�t�k (manipulator, �21.4.6). Az olyan ig�k, mint a .bej�r. vagy a .v�gleges�t.
�br�zolhat
�k egy bej�r� (iter�tor) objektummal, illetve egy adatb�zis commit muvelet�t
v�grehajt�
objektummal. M�g a mell�knevek is gyakran haszn�lhat� m�don �br�zolhat�k
oszt�lyokkal.
Vegy�k a .t�rolhat�., .p�rhuzamosan fut�., .bejegyzett. �s .lek�t�tt.
mell�kneveket.
Ezek is lehetnek oszt�lyok, melyek lehetov� teszik a tervezonek vagy a
programoz�nak,
hogy virtu�lis b�zisoszt�lyok meghat�roz�sa �ltal kiv�lassza a k�sobb
megtervezendo oszt
�lyok k�v�nt jellemzoit (�15.2.4).
23. Fejleszt�s �s tervez�s 947
Nem minden oszt�ly felel meg programszintu fogalmaknak. Vannak p�ld�ul rendszer-
ero-
forr�sokat vagy a megval�s�t�s fogalmait �br�zol� oszt�lyok (�24.3.1) is. Az is
fontos, hogy
elker�lj�k a r�gi rendszer t�l k�zeli modellez�s�t. P�ld�ul biztosan nem akarunk
olyan
rendszert k�sz�teni, mely egy adatb�zis k�r� �p�lve egy .k�zi rendszer.
lehetos�geit ut�-
nozza �s az egy�nnek csak pap�rok fizikai tologat�s�nak ir�ny�t�s�t engedi meg.
Az �r�kl�s (inheritance) fogalmak k�z�s tulajdons�gainak �br�zol�s�ra szolg�l.
Legfontosabb
felhaszn�l�sa a hierarchikus fel�p�t�s �br�zol�sa az egyes fogalmakat k�pviselo
oszt�-
lyok viselked�se alapj�n (�1.7, �12.2.6, �24.3.2). Erre n�ha �gy hivatkoznak, mint
oszt�lyoz
�s (classification), sot rendszertan (taxonomy). A k�z�s tulajdons�gokat akt�van
keresni
kell. Az �ltal�nos�t�s �s az oszt�lyoz�s magas szintu tev�kenys�gek, melyek
�lesl�t�st ig�-
nyelnek, hogy hasznos �s tart�s eredm�nyt adjanak. Egy k�z�s alapnak egy
�ltal�nosabb
fogalmat kell �br�zolnia, nem pedig egy hasonl�, az �br�zol�shoz esetleg kevesebb
adatot
ig�nylot.
Vegy�k �szre, hogy az oszt�lyoz�st a rendszerben modellezett fogalmak alapj�n kell
v�gezni,
nem m�s ter�leteken �rv�nyes szemsz�gbol. A matematik�ban p�ld�ul a k�r az
ellipszis
egy fajt�ja, de a legt�bb programban a k�rt nem az ellipszisbol �s az ellipszist
sem a k�rbol
sz�rmaztatj�k. Azok a gyakran hallhat� �rvek, hogy .az�rt, mert a matematik�ban ez
a m�dja
. �s .az�rt, mert a k�r az ellipszis r�szhalmaza., nem meggyozoek �s �ltal�ban
rosszak.
Ennek az az oka, hogy a legt�bb programban a k�r fo tulajdons�ga az, hogy
k�z�ppontja
van �s t�vols�ga a ker�let�ig r�gz�tett. A k�r minden viselked�se (minden
muvelete) meg
kell, hogy tartsa ezt a tulajdons�got (invari�ns; �24.3.7.1). M�sr�szt az
ellipszist k�t f�kuszpont
jellemzi, melyeket sok programban egym�st�l f�ggetlen�l lehet m�dos�tani. Ha ezek
a f�kuszpontok egybeesnek, az ellipszis olyan lesz, mint egy k�r, de nem k�r,
mivel a mu-
veletei nem tartj�k k�rnek. A legt�bb rendszerben ez a k�l�nbs�g �gy t�kr�zodik,
hogy
van egy k�r �s egy ellipszis, amelyeknek vannak muvelethalmazaik, de azok nem
egym�s
r�szhalmazai.
Nem az t�rt�nik, hogy kiagyalunk egy oszt�lyhalmazt az oszt�lyok k�z�tti
kapcsolatokkal
�s felhaszn�ljuk azokat a v�gso rendszerben. Ink�bb oszt�lyok �s kapcsolatok
kezdeti halmaz
�t alkotjuk meg, majd ezeket ism�telten finom�tjuk (�23.4.3.5), hogy eljussunk egy

olyan oszt�lykapcsolat-halmazig, mely el�gg� �ltal�nos, rugalmas �s stabil ahhoz,


hogy val
�di seg�ts�get ny�jtson a rendszer k�sobbi megalkot�s�hoz.
A kezdeti fo fogalmak/oszt�lyok felv�zol�s�ra a legjobb eszk�z egy t�bla,
finom�t�sukra pedig
az alkalmaz�si ter�let szak�rtoivel �s n�h�ny bar�tunkkal folytatott vita, melynek
sor�n
kialak�thatunk egy haszn�lhat� kezdeti sz�t�rat �s fogalmi v�zlatot. Kev�s ember
tudja ezt
egyed�l elv�gezni. A kiindul� oszt�lyhalmazb�l val�ban haszn�lhat� oszt�lyhalmaz
kialak
�t�s�nak egyik m�dja a rendszer ut�nz�sa, ahol a tervezok veszik �t az oszt�lyok
szerep�t.
948 Tervez�s a C++ seg�ts�g�vel
A nyilv�nos vita felt�rja a kezdeti �tletek hib�it, m�s megold�sok keres�s�re
�szt�n�z �s
eloseg�ti a kialakul� terv k�z�s meg�rt�s�t. A tev�kenys�g lapokra �rott
feljegyz�sekkel
t�mogathat�, amelyek k�sobb visszakereshetok. Az ilyen k�rty�kat rendszerint CRC
k�rty
�knak nevezik (.Class, Responsibility, Collaborators., vagyis .Oszt�lyok,
Feleloss�g,
Egy�ttmuk�dok., [Wirfs-Brock, 1990]) a r�juk feljegyzett inform�ci�k miatt.
A haszn�lati eset (use case) a rendszer egy konkr�t felhaszn�l�s�nak le�r�sa. �me
a haszn�-
lati eset egyszeru p�ld�ja egy telefonrendszerre: felvessz�k a kagyl�t, t�rcs�zunk
egy
sz�mot, a telefon a m�sik oldalon csenget, a m�sik oldalon felveszik a kagyl�t.
Ilyen haszn
�lati esetek halmaz�nak meghat�roz�sa hatalmas �rt�ku lehet a fejleszt�s minden
szakasz
�ban, a tervez�s elej�n pedig a haszn�lati esetek megkeres�se seg�t, hogy
meg�rts�k, mit
is pr�b�lunk �p�teni. A tervez�s alatt nyomon k�vethetj�k vel�k a rendszer
muk�d�si �tj�t
(p�ld�ul CRC k�rty�k haszn�lat�val), hogy ellenorizz�k, van-e �rtelme a
felhaszn�l� szempontj
�b�l a rendszer oszt�lyokkal �s objektumokkal val� viszonylag statikus le�r�s�nak;

a programoz�s �s tesztel�s alatt pedig lehets�ges helyzeteket modellezhet�nk


vel�k. Ily
m�don a haszn�lati eseteket a rendszer val�szerus�g�nek ellenorz�s�re
haszn�lhatjuk.
A haszn�lati esetek a rendszert (dinamikusan) muk�do egys�gk�nt tekintik. Ez�rt a
tervez
ot abba a csapd�ba ejthetik, hogy a rendszer rendeltet�s�t tartsa szem elott, ami
elvonja
a figyelm�t az oszt�lyokkal �br�zolhat�, haszn�lhat� fogalmak keres�s�nek
elengedhetetlen
feladat�t�l. K�l�n�sen azok, akiknek a rendszerezett elemz�s eross�g�k, de az
objektumorient
�lt programoz�sban �s tervez�sben kev�s tapasztalattal rendelkeznek, a haszn�-
lati esetek hangs�lyoz�s�val hajlamosak az eszk�z�ket a c�lnak al�rendelni. A
haszn�lati
esetek halmaza m�g nem tekintheto tervnek. Nem el�g a rendszer haszn�lat�t szem
elott
tartani, gondolni kell annak fel�p�t�s�re is.
A tervezok csapata eredendoen hi�baval� . �s k�lts�ges . k�s�rlet csapd�j�ba
eshet, ha az
�sszes haszn�lati esetet meg akarja keresni �s le akarja �rni. Amikor a
rendszerhez oszt�lyokat
keres�nk, ugyan�gy elj�n az ido, amikor ki kell mondani: .Ami sok, az sok. Itt az
ido,
hogy kipr�b�ljuk, amink van �s l�ssuk, mi t�rt�nik.. A tov�bbi fejleszt�s sor�n
csak egy elfogadhat
� oszt�lyhalmaz �s egy elfogadhat� haszn�latieset-halmaz haszn�lat�val kaphatjuk
meg a j� rendszer el�r�s�hez elengedhetetlen visszajelz�st. Persze neh�z
felismerni, mikor
�lljunk meg egy hasznos tev�kenys�gben, k�l�n�sen akkor, ha tudjuk, hogy k�sobb
vissza
kell t�rn�nk a feladatot befejezni.
Mennyi eset elegendo? Erre a k�rd�sre �ltal�ban nem lehet v�laszt adni. Az adott
munka sor
�n azonban elj�n az ido, amikor a rendszer fo szolg�ltat�sainak legt�bbje muk�dik
�s
a szokatlanabb probl�m�k, illetve a hibakezel�si k�rd�sek j� r�sz�t is �rintett�k.
Ekkor ideje
elv�gezni a tervez�s �s programoz�s k�vetkezo l�p�s�t.
23. Fejleszt�s �s tervez�s 949
Amikor a program felhaszn�l�si ter�leteit haszn�lati esetek seg�ts�g�vel pr�b�ljuk
felbecs
�lni, hasznos lehet azokat elsodleges �s m�sodlagos haszn�lati esetekre
sz�tv�lasztani.
Az elsodlegesek a rendszer leg�ltal�nosabb, .norm�lis. tev�kenys�geit, a
m�sodlagosak
a szokatlanabb, illetve a hibakezel�ssel kapcsolatos tev�kenys�geket �rj�k le. A
m�sodlagos
haszn�lati esetre p�lda a .telefonh�v�s. egy v�ltozata, ahol a h�vott �llom�s
kagyl�j�t felemelt
�k, mert �ppen a h�v� sz�m�t t�rcs�zz�k. Gyakran mondj�k, hogy ha az elsodleges
haszn�lati esetek 80%-�t �s n�h�ny m�sodlagosat m�r kipr�b�ltunk, ideje
tov�bbmenni, de
mivel elore nem tudhatjuk, mi alkotja az .�sszes esetet., ez csup�n ir�nyelv. Itt
a tapasztalat
�s a j� �rz�k sz�m�t.
A fogalmak, muveletek �s kapcsolatok a programok alkalmaz�si ter�leteibol
term�szetszer
uen ad�dnak vagy az oszt�lyszerkezeten v�gzett tov�bbi munk�b�l sz�letnek. Ezek
jelzik,
hogy alapvetoen �rtj�k a program muk�d�s�t �s k�pesek vagyunk az alapfogalmak
oszt�-
lyoz�s�ra. P�ld�ul a tuzolt�kocsi egy tuzolt� g�p, ami egy teheraut�, ami egy
j�rmu.
A �23.4.3.2 �s �23.4.5 pontok bemutatnak n�h�ny m�dszert, amelyekkel az
oszt�lyokra �s
oszt�lyhierarchi�kra a tov�bbfejleszt�s sz�nd�k�val n�zhet�nk.
�vakodjunk a rajzos tervez�stol! Term�szetesen a fejleszt�s bizonyos szakasz�ban
megk�rnek
majd, hogy mutassuk be a tervet valakinek, �s akkor bemutatunk egy sereg
diagramot,
melyek az �p�lo rendszer fel�p�t�s�t magyar�zz�k. Ez nagyon hasznos lehet, mert
seg�t,
hogy figyelm�nket arra �sszpontos�tsuk, ami a rendszerben fontos, �s k�nytelenek
vagyunk
�tleteinket m�sok �ltal is �rtheto szavakkal kifejezni. A bemutat� �rt�kes
tervez�si eszk�z.
Elk�sz�t�se azzal a c�llal, hogy val�ban meg�rts�k azok, akiket �rdekel �s akik
k�pesek �p�-
to b�r�latot alkotni, j� gyakorlat a gondolatok megfogalmaz�s�ra �s tiszta
kifejez�s�re.
A terv hivatalos bemutat�sa azonban vesz�lyes is lehet, mivel eros a k�s�rt�s,
hogy az ide�-
lis rendszert mutassuk be . olyat, amit b�rcsak meg tudn�nk �p�teni, egy
rendszert, melyre
a vezetos�g v�gyik . ahelyett, amivel rendelkez�nk, �s amit elfogadhat� ido alatt
meg tudunk
csin�lni. Amikor k�l�nb�zo megk�zel�t�sek vet�lkednek �s a d�nt�shoz�k nem igaz
�n �rtik a r�szleteket (vagy nem is t�rodnek azokkal), a bemutat�k
hazugs�gversenny�
v�lnak, amelyben a leggrandi�zusabb rendszert bemutat� csapat nyeri el a munk�t.
Ilyen
esetekben a gondolatok vil�gos kifejez�s�t gyakran szakzsargon �s r�vid�t�sek
helyettes�-
tik. Ha ilyen bemutat�t hallgatunk . �s k�l�n�sen, ha d�nt�shoz�k vagyunk �s
fejleszt�si
eroforr�sokr�l rendelkez�nk . l�tfontoss�g�, hogy k�pesek legy�nk k�l�nbs�get
tenni
v�gy�lom �s re�lis terv k�z�tt. A j� bemutat�anyag nem garant�lja a le�rt rendszer
minos�-
g�t. Tapasztalatom szerint a val�s probl�m�kra �sszpontos�t� c�gek, amikor
eredm�nyeik
bemutat�s�ra ker�l sor, r�vidre fogj�k a sz�t azokhoz k�pest, akik kev�sb�
�rdekeltek val
�s rendszerek elk�sz�t�s�ben.
950 Tervez�s a C++ seg�ts�g�vel
Amikor oszt�lyokkal �br�zoland� fogalmakat keres�nk, vegy�k �szre, hogy a
rendszernek
vannak olyan fontos tulajdons�gai is, melyeket nem �br�zolhatunk oszt�lyokkal. A
megb�zhat
�s�g, a teljes�tm�ny, a tesztelhetos�g fontos m�rheto rendszertulajdons�gok.
M�gsem lehet
m�g a legtiszt�bban objektumokra alapozott rendszer megb�zhat�s�g�t sem egy .megb
�zhat�s�gi objektummal. �br�zolni. A rendszerben minden�tt jelenlevo tulajdons�gok

meghat�rozhat�k, megtervezhetok �s m�r�ssel igazolhat�k; gondot kell ford�tani


r�juk
minden oszt�lyn�l, �s t�kr�zodni�k kell az egyes oszt�lyok �s �sszetevok tervez�si
�s megval
�s�t�si szab�lyaiban (�23.4.3).
23.4.3.2. M�sodik l�p�s: hat�rozzuk meg a muveleteket
Finom�tsuk az oszt�lyokat a rajtuk v�gezheto muveletek meghat�roz�s�val.
Term�szetes,
hogy nem lehet az oszt�lyok keres�s�t elv�lasztani att�l, hogy kigondoljuk, milyen
muveleteket
kell rajtuk v�gezni. Gyakorlati k�l�nbs�g van azonban abban, hogy az oszt�lyok
keres
�sekor a fo fogalmakra �sszpontos�tunk �s tudatosan h�tt�rbe szor�tjuk a
sz�m�t�stechnikai
szempontokat, m�g a muveletek meghat�roz�sakor azt tartjuk szem elott, hogy teljes

�s haszn�lhat� muvelethalmazt tal�ljunk. �ltal�ban t�l neh�z egyszerre mindkettore


gondolni,
k�l�n�sen az�rt, mert az egym�ssal kapcsolatban l�vo oszt�lyokat egy�tt kell
megtervezni,
de ebben is seg�thetnek a CRC k�rty�k (�23.4.3.1).
Amikor az a k�rd�s, milyen szolg�ltat�sokr�l gondoskodjunk, t�bbf�le megk�zel�t�s
lehets
�ges. �n a k�vetkezo strat�gi�t javaslom:
1. Gondoljuk v�gig, hogyan j�n l�tre, hogyan m�sol�dik (ha egy�ltal�n m�sol�-
dik) �s hogyan semmis�l meg az oszt�ly egy objektuma.
2. Hat�rozzuk meg az oszt�ly �ltal ig�nyelt muveletek minim�lis halmaz�t. �ltal�-
ban ezek lesznek a tagf�ggv�nyek.
3. Gondoljuk v�gig, milyen muveleteket lehetne m�g megadni a k�nyelmesebb jel
�l�s �rdek�ben. Csak n�h�ny val�ban fontos muveletet adjunk meg. Ezekbol
lesznek a nem tag seg�df�ggv�nyek (�10.3.2).
4. Gondoljuk v�gig, mely muveleteknek kell virtu�lisaknak lenni�k, vagyis olyan
muveleteknek, melyekkel az oszt�ly fel�letk�nt szolg�lhat egy sz�rmaztatott
oszt�ly �ltal adott megval�s�t�s sz�m�ra.
5. Gondoljuk v�gig, milyen k�z�s elnevez�si m�dszert �s szolg�ltat�sokat
biztos�thatunk
egy �sszetevo minden oszt�ly�ra vonatkoz�an.
Vil�gos, hogy ezek a minimalizmus elvei. Sokkal k�nnyebb minden hasznosnak gondolt

f�ggv�nyt megadni �s minden muveletet virtu�liss� tenni. Min�l t�bb f�ggv�ny�nk


van
azonban, ann�l val�sz�nubb, hogy nem fogj�k haszn�lni azokat, �s hogy a f�l�s
f�ggv�-
23. Fejleszt�s �s tervez�s 951
nyek korl�tozni fogj�k a rendszer megval�s�t�s�t, tov�bbi fejlod�s�t. Nevezetesen
azok
a f�ggv�nyek, melyek egy oszt�ly egy objektuma �llapot�nak valamely r�sz�t
k�zvetlen�l
olvass�k vagy �rj�k, gyakran egyedi megval�s�t�st k�vetelnek az oszt�lyt�l �s
komoly m�rt
�kben korl�tozz�k az �jratervez�s lehetos�g�t. Az ilyen f�ggv�nyek az elvont
�br�zol�st
a fogalom szintj�rol a megval�s�t�s szintj�re sz�ll�tj�k le. A f�ggv�nyek
hozz�ad�sa a programoz
�nak is t�bb munk�t jelent . �s a tervezonek is, a k�vetkezo �jratervez�skor.
Sokkal
k�nnyebb egy f�ggv�nyt megadni, amikor vil�goss� v�lt, hogy sz�ks�g van r�, mint
elt�vol
�tani azt, ha koloncc� v�lik.
Annak oka, hogy egy f�ggv�nyrol vil�gosan el kell d�nteni, hogy virtu�lis legyen
vagy sem,
�s ez nem alap�rtelmezett viselked�s vagy megval�s�t�si r�szlet, az, hogy egy
f�ggv�ny virtu
�liss� t�tele alapjaiban befoly�solja oszt�ly�nak haszn�lat�t �s az oszt�ly
kapcsolatait m�s
oszt�lyokkal. Egy olyan oszt�ly objektumainak elrendez�se, melyben ak�r csak
egyetlen
virtu�lis f�ggv�ny is van, jelentos m�rt�kben k�l�nb�zik a C vagy Fortran nyelvek
objektumait
�l. A virtu�lis f�ggv�nyt is tartalmaz� oszt�lyok fel�letet ny�jthatnak a k�sobb
defini�land� oszt�lyok sz�m�ra, de egy virtu�lis f�ggv�ny egyben f�gg�st is jelent
azokt�l
(�24.3.2.1).
Vegy�k �szre, hogy a minimalizmus ink�bb t�bb, mint kevesebb munk�t k�vetel a
tervezotol.
Amikor kiv�lasztjuk a muveleteket, fontos, hogy ink�bb arra �sszpontos�tsunk, mit
kell tenni,
nem pedig arra, hogyan tegy�k. Vagyis ink�bb a k�v�nt viselked�sre, mint a
megval�s�-
t�s k�rd�seire figyelj�nk.
N�ha hasznos az oszt�lyok muveleteit aszerint oszt�lyozni, hogyan haszn�lj�k az
objektumok
belso �llapot�t:
� Alapveto muveletek: konstruktorok, destruktorok �s m�sol� oper�torok.
� Lek�rdez�sek: muveletek, melyek nem m�dos�tj�k egy objektum �llapot�t.
� M�dos�t�k: muveletek, melyek m�dos�tj�k egy objektum �llapot�t.
� Konverzi�k: muveletek, melyek m�s t�pus� objektumot hoznak l�tre annak az
objektumnak az �rt�ke (�llapota) alapj�n, amelyre alkalmazzuk oket.
� Bej�r�k: oper�torok, melyek a tartalmazott objektumsorozatokhoz val� hozz�f�-
r�st, illetve azok haszn�lat�t teszik lehetov�.
A fentiek nem egym�st kiz�r� kateg�ri�k. Egy bej�r� p�ld�ul lehet egyben lek�rdezo
vagy
m�dos�t� is. Ezek a kateg�ri�k egyszeruen egy oszt�lyoz�st jelentenek, mely
seg�thet az
oszt�lyfel�letek megtervez�s�ben. Term�szetesen lehets�gesek m�s oszt�lyoz�s is.
Az ilyen
oszt�lyoz�sok k�l�n�sen hasznosak az �sszetevok�n bel�li oszt�lyok egys�gess�g�nek

fenntart�s�ban.
952 Tervez�s a C++ seg�ts�g�vel
A C++ a lek�rdezok �s m�dos�t�k megk�l�nb�ztet�s�t a konstans �s nem konstans tagf
�ggv�nyekkel seg�ti. Ugyan�gy a konstruktorok, destruktorok, m�sol� oper�torok �s
konverzi
�s f�ggv�nyek is k�zvetlen�l t�mogatottak.
23.4.3.3. Harmadik l�p�s: hat�rozzuk meg az �sszef�gg�seket
Finom�tsuk az oszt�lyokat az �sszef�gg�sek meghat�roz�s�val. A k�l�nf�le
�sszef�gg�seket
a �24.3 t�rgyalja. A tervez�ssel kapcsolatosan vizsg�land� fo �sszef�gg�sek a
param�-
terez�si, �r�kl�si (inheritance) �s haszn�lati (use) kapcsolatok. Mindegyikn�l meg
kell vizsg
�lni, mit jelent, hogy az oszt�ly a rendszer egyetlen tulajdons�g��rt felelos.
Felelosnek lenni
biztos, hogy nem azt jelenti, hogy az oszt�ly az �sszes adatot maga kell, hogy
tartalmazza,
vagy hogy az �sszes sz�ks�ges muveletet k�zvetlen�l tagf�ggv�nyei kell, hogy
v�grehajts
�k. Ellenkezoleg: az, hogy minden oszt�lynak egyetlen feleloss�gi ter�lete van,
azt biztos
�tja, hogy egy oszt�ly munk�ja jobb�ra abb�l �ll, hogy a k�r�seket egy m�sik
oszt�lyhoz
ir�ny�tja, mely az adott r�szfeladat�rt felelos. Legy�nk azonban �vatosak, mert e
m�dszer
t�lzott m�rt�ku haszn�lata kis hat�konys�g� �s �ttekinthetetlen tervekhez vezet,
az�ltal,
hogy olyan m�rt�kben elburj�nzanak az oszt�lyok �s objektumok, hogy m�s munka nem
t�rt�nik, mint a k�r�sek tov�bb�t�sa. Amit az adott helyen �s idoben meg lehet
tenni, azt
meg kell tenni.
Annak sz�ks�gess�ge, hogy az �r�kl�si �s haszn�lati kapcsolatokat a tervez�si
szakaszban
vizsg�ljuk (�s nem csak a megval�s�t�s sor�n), k�zvetlen�l k�vetkezik abb�l, hogy
az oszt
�lyokat fogalmak �br�zol�s�ra haszn�ljuk. Ez pedig azt is mag�ban foglalja, hogy
nem az
egyedi oszt�ly, hanem a komponens (�23.4.3, �24.4) a tervez�s val�di egys�ge.
A param�terez�s . mely gyakran sablonok (template) haszn�lat�hoz vezet . egy m�d
arra,
hogy a m�g�ttes f�gg�seket nyilv�nval�v� tegy�k, �gy, hogy �j fogalmak hozz�ad�sa
n�lk
�l t�bb lehets�ges megold�s legyen. Gyakran v�laszthatunk, meghagyunk-e valamit
k�rnyezett
ol f�ggo . egy �r�kl�si fa �gak�nt �br�zolt . elemk�nt, vagy ink�bb param�tert
haszn�lunk (�24.4.1).
23.4.3.4. Negyedik l�p�s: hat�rozzuk meg a fel�leteket
Hat�rozzuk meg a fel�leteket. A priv�t f�ggv�nyekkel a tervez�si szakaszban nem
kell foglalkozni.
Azt, hogy ekkor a megval�s�t�s mely k�rd�seit vessz�k figyelembe, legjobb a
harmadik
l�p�sben, a f�gg�si viszonyok meghat�roz�sakor eld�nteni. Vil�gosabban kifejezve:
vegy�k alapszab�lynak, hogy ha egy oszt�lynak nem lehets�ges legal�bb k�t
jelentosen elt
�ro megval�s�t�sa, akkor val�sz�nu, hogy ezzel az oszt�llyal valami nincs rendben,
�s val
�j�ban �lc�zott megval�s�t�ssal (implementation), nem pedig igazi fogalommal
�llunk
23. Fejleszt�s �s tervez�s 953
szemben. Sok esetben az .El�gg� f�ggetlen ennek az oszt�lynak a fel�lete a
megval�s�t�s
m�dj�t�l?. k�rd�s j� megk�zel�t�se, ha megvizsg�ljuk, alkalmazhat�-e az oszt�lyra
valamilyen
takar�kos ki�rt�kel�si m�dszer (.lusta ki�rt�kel�s., lazy evaluation).
Vegy�k �szre, hogy a nyilv�nos (public) alaposzt�lyok �s bar�t f�ggv�nyek (friend)
az oszt
�ly nyilv�nos fel�let�nek r�szei (l�sd m�g �11.5 �s �24.4.2). Kifizetodo lehet, ha
k�l�n fel
�letekrol gondoskodunk az �r�kl�s, illetve az �ltal�nos felhaszn�l�k sz�m�ra,
az�ltal, hogy
k�l�n protected �s public fel�leteket adunk meg.
Ez az a l�p�s, amelyben a param�terek pontos t�pus�t meghat�rozzuk. Az az ide�lis,
ha
annyi statikus, programszintu t�pusokat tartalmaz� fel�let�nk van, amennyi csak
lehets�ges
(�24.2.3 �s �24.4.2).
Amikor a fel�leteket (interface) meghat�rozzuk, vigy�zni kell azokn�l az
oszt�lyokn�l, ahol
a muveletek l�tsz�lag t�bb fogalmi szintet t�mogatnak. A File oszt�ly egyes
tagf�ggv�nyei
p�ld�ul File_descriptor (f�jlle�r�) t�pus� param�tereket kaphatnak, m�sok pedig
karakterl
�nc param�tereket, melyek f�jlneveket jel�lnek. A File_descriptor muveletek m�s
fogalmi
szinten dolgoznak, mint a f�jln�v-muveletek, �gy elgondolkozhatunk azon, vajon
ugyanabba
az oszt�lyba tartoznak-e. Lehet, hogy jobb lenne, ha k�t f�jloszt�lyunk lenne, az
egyik
a f�jlle�r� fogalm�nak t�mogat�s�ra, a m�sik a f�jln�v fogalomhoz. �ltal�ban egy
oszt�ly
minden muvelete ugyanazt a fogalmi szintet kell, hogy t�mogassa. Ha nem �gy van,
�t kell
szervezni az oszt�lyt �s a vele kapcsolatban l�vo oszt�lyokat.
23.4.3.5. Oszt�lyhierarchi�k �jraszervez�se
Az elso �s a harmadik l�p�sben megvizsg�ltuk az oszt�lyokat �s
oszt�lyhierarchi�kat, hogy
l�ssuk, megfeleloen kiszolg�lj�k-e ig�nyeinket. A v�lasz �ltal�ban nem �s ilyenkor
�t kell
szervezn�nk, oszt�lyainkat, hogy t�k�letes�ts�k a szerkezetet, a tervet vagy �ppen
a megval
�s�t�s m�dj�t. Az oszt�lyhierarchia legk�z�ns�gesebb �tszervez�si m�dszere k�t
oszt�ly
k�z�s r�sz�nek kiemel�se egy �j oszt�lyba, illetve az oszt�ly k�t �j oszt�lyra
bont�sa. Mindk
�t esetben h�rom oszt�ly lesz az eredm�ny: egy b�zisoszt�ly (base class) �s k�t
sz�rmaztatott
oszt�ly (derived class). Mikor kell �gy �jraszervezni? Mi jelzi azt, hogy egy
ilyen �jraszervez
�s hasznos lehet?
Sajnos ezekre a k�rd�sekre nincsenek egyszeru, �ltal�nos v�laszok. Ez nem igaz�n
meglep
o, mert amirol besz�l�nk, nem apr� r�szletek, hanem egy rendszer alapfogalmainak
m�-
dos�t�sa. Az alapveto . b�r nem egyszeru . feladat az oszt�lyok k�z�s
tulajdons�gainak
megkeres�se �s a k�z�s r�sz kiemel�se. Azt, hogy mi sz�m�t k�z�snek, nem lehet
pontosan
meghat�rozni, de a k�z�s r�sznek a fogalmak k�zti, �s nem csak a megval�s�t�s
k�nyelm
�t szolg�l� k�z�ss�get kell t�kr�znie. Arr�l, hogy k�t vagy t�bb oszt�ly olyan
k�z�s tu-
954 Tervez�s a C++ seg�ts�g�vel
lajdons�gokkal rendelkezik, melyeket egy b�zisoszt�lyban foglalhatunk �ssze, a
k�z�s
haszn�lati minta, a muvelethalmazok hasonl�s�ga, illetve a hasonl� megval�s�t�s
�rulkodik,
valamint az, hogy ezek az oszt�lyok gyakran egy�tt mer�lnek fel a tervez�si vit�k
sor
�n. Ezzel szemben egy oszt�ly val�sz�nuleg k�t m�sikra bonthat�, ha muveleteinek
r�szhalmazai
elt�ro haszn�lati mint�j�ak, ha ezen r�szhalmazok az �br�zol�s k�l�n
r�szhalmazaihoz
f�rnek hozz�, vagy ha az oszt�ly egym�ssal nyilv�nval�an nem kapcsolatos tervez�-
si vit�k sor�n mer�l fel. A rokon oszt�lyok halmaz�nak sablonba (template)
foglal�sa rendszerezett
m�dot ad a sz�ks�ges alternet�v�k biztos�t�s�ra (�24.4.1).
Az oszt�lyok �s fogalmak k�zti szoros kapcsolatok miatt az oszt�lyhierarchi�k
szervez�si
probl�m�i gyakran mint az oszt�lyok elnevez�si probl�m�i mer�lnek fel. Ha az
oszt�lynevek
neh�zkesen hangzanak vagy az oszt�lyhierarchi�kb�l k�vetkezo oszt�lyoz�sok t�ls�-
gosan bonyolultak, val�sz�nuleg itt az alkalom, hogy t�k�letes�ts�k a
hierarchi�kat. V�lem
�nyem szerint k�t ember sokkal jobban tud egy oszt�lyhierarchi�t elemezni, mint
egy. Ha
t�rt�netesen nincs valaki, akivel egy tervet meg tudn�nk vitatni, hasznos lehet,
ha �runk egy
bevezeto tervismertetot, amelyben az oszt�lyok neveit haszn�ljuk.
A terv egyik legfontosabb c�lkituz�se olyan fel�letek (interface) biztos�t�sa,
melyek a v�ltoz
�sok sor�n �lland�ak maradnak (�23.4.2). Ezt gyakran �gy �rhetj�k el legjobban, ha
egy
oszt�lyt, amelytol sz�mos oszt�ly �s f�ggv�ny f�gg, olyan absztrakt oszt�lly�
tesz�nk, mely
csak nagyon �ltal�nos muveleteket biztos�t. A r�szletesebb muveletek jobb, ha
egyedi c�l�
sz�rmaztatott oszt�lyokhoz kapcsol�dnak, melyektol kevesebb oszt�ly �s f�ggv�ny
f�gg
k�zvetlen�l. Vil�gosabban: min�l t�bb oszt�ly f�gg egy oszt�lyt�l, ann�l
�ltal�nosabbnak
kell lennie.
Eros a k�s�rt�s, hogy egy sokak �ltal haszn�lt oszt�lyhoz muveleteket (�s
adatokat) tegy�nk
hozz�. Ezt gyakran �gy tekintik, mint ami egy oszt�lyt haszn�lhat�bb� �s (tov�bbi)
v�ltoztat
�st kev�sb� ig�nylov� tesz. Pedig az eredm�ny csak annyi, hogy a fel�let megh�zik
(.k�-
v�r fel�let., �24.4.3) �s olyan adattagjai lesznek, melyek sz�mos gyeng�n
kapcsol�d� szolg
�ltat�st t�mogatnak. Ez ism�t azzal j�r, hogy az oszt�lyt m�dos�tani kell, amikor
az �ltala
t�mogatott oszt�lyok k�z�l ak�r csak egy is jelentosen megv�ltozik. Ez viszont
mag�val
vonja olyan felhaszn�l�i oszt�lyok �s sz�rmaztatott oszt�lyok m�dos�t�s�t is,
melyek nyilv
�nval�an nincsenek vele kapcsolatban. Ahelyett, hogy bonyol�tan�nk egy, a tervben
k�zponti
szerepet j�tsz� oszt�lyt, rendszerint �ltal�nosnak �s elvontnak kellene hagynunk.
Ha
sz�ks�ges, az egyedi szolg�ltat�sokat sz�rmaztatott oszt�lyokk�nt kell
biztos�tani. (P�ld�kat
l�sd [Martin,1995]).
Ez a gondolatf�z�r absztrakt (abstract) oszt�lyok hierarchi�j�hoz vezet, ahol a
gy�k�rhez
k�zeli oszt�lyok a leg�ltal�nosabbak, �s ezektol f�gg a legt�bb m�s oszt�ly �s
f�ggv�ny.
A lev�l oszt�lyok a legegyedibbek �s csak nagyon kev�s k�dr�sz f�gg k�zvetlen�l
tol�k.
P�ldak�nt eml�thetn�nk az lval_box hierarchia v�gso v�ltozat�t (�12.4.3, �12.4.4).

23. Fejleszt�s �s tervez�s 955


23.4.3.6. Modellek haszn�lata
Amikor cikket �rok, egy megfelelo modellt pr�b�lok k�vetni. Vagyis ahelyett, hogy
azonnal
elkezdem a g�pel�st, hasonl� t�m�j� cikkeket keresek, hogy l�ssam, tal�lok-e
olyat, amely
a cikkem kezdeti mint�jak�nt szolg�lhat. Ha az �ltalam v�lasztott modell egy
saj�t, rokon
t�m�r�l sz�l� cikk, m�g arra is k�pes vagyok, hogy hely�k�n hagyok sz�vegr�szeket,
m�-
sokat sz�ks�g szerint m�dos�tok �s �j inform�ci�t csak ott teszek hozz�, ahol
mondand�m
logik�ja megk�v�nja. Ez a k�nyv p�ld�ul ilyen m�don �r�dott, az elso �s m�sodik
kiad�s
alapj�n. Ennek a m�dszernek sz�lsos�ges esete egy lev�lsablon haszn�lata. Ekkor
egyszer
uen egy nevet �rok be �s esetleg hozz��rok m�g n�h�ny sort, hogy a lev�l
.szem�lyre sz�-
l�. legyen. Az ilyen leveleket l�nyeg�ben �gy �rom meg, hogy a sablont csak az
alapmodellt
ol elt�ro r�szekkel eg�sz�tem ki.
A l�tezo rendszerek ilyen, �j rendszerek modelljeik�nt val� felhaszn�l�sa
�ltal�nos elj�r�s
az alkot� t�rekv�sek minden form�j�n�l. Amikor csak lehets�ges, a tervez�s �s
programoz
�s elozo munk�ra kell, hogy alapoz�djon. Ez korl�tozza a tervezo szabads�g�t, de
leheto-
v� teszi, hogy figyelm�t egyszerre csak n�h�ny k�rd�sre �sszpontos�tsa. Egy nagy
projekt
tiszta lappal ind�t�sa friss�to hat�ssal lehet, de k�nnyen .m�rgezov�. is v�lhat,
mert a tervez
�si m�dszerek k�z�tti k�v�lyg�st eredm�nyezheti. Ennek ellen�re, ha van modell�nk,
az
nem jelent korl�toz�st �s nem k�veteli meg, hogy szolgai m�don k�vess�k;
egyszeruen
megszabad�tja a tervezot att�l, hogy egy tervet egyszerre csak egy szempontb�l
k�zel�thessen
meg.
Vegy�k �szre, hogy a modellek haszn�lata elker�lhetetlen, mivel minden terv
tervezoinek
tapasztalataib�l tevodik �ssze. Egy adott modell birtok�ban a modellv�laszt�s
tudatos elhat
�roz�ss� v�lik, felt�telez�seink megalapozottak, a haszn�lt kifejez�sek k�re pedig
meghat
�rozott lesz, a tervnek lesz egy kezdeti v�za �s no a val�sz�nus�ge, hogy a
tervezok meg
tudnak egyezni egy k�z�s megk�zel�t�sben.
Term�szetesen a kiindul� modell kiv�laszt�sa �nmag�ban is fontos tervez�si d�nt�s,
amely
gyakran csak a lehets�ges modellek keres�se �s az alternat�v�k gondos ki�rt�kel�se
ut�n
hozhat� meg. Tov�bb� sok esetben egy modell csak akkor felel meg, ha meg�rtj�k,
hogy
az elk�pzel�seknek egy �j konkr�t alkalmaz�shoz val� igaz�t�sa sz�mos m�dos�t�st
ig�-
nyel. A programtervez�s nem k�nnyu, �gy minden megszerezheto seg�ts�gre sz�ks�g�nk

van. Nem szabad visszautas�tanunk a modellek haszn�lat�t, csak a .rossz ut�nz�s.


eroltet�-
s�t. Az ut�nz�s a h�zelg�s legoszint�bb m�dja, �s a modellek �s elozo munk�k
�szt�nz�sk
�nt val� felhaszn�l�sa . a tulajdon �s a m�sol�s jog�nak t�rv�nyes hat�rain
bel�l . az innovat
�v munka minden ter�leten elfogadhat� m�dszer: ami j� volt Shakespeare-nek, az j�
nek�nk is. Vannak, akik a modellek ilyen haszn�lat�t a tervez�sben .terv-
�jrahasznos�t�snak
. nevezik.
956 Tervez�s a C++ seg�ts�g�vel
Az �ltal�nosan haszn�lt, t�bb programban elofordul� elemek feljegyz�se . az
�ltaluk megoldott
probl�ma �s haszn�latuk felt�teleinek le�r�s�val egy�tt . k�zenfekvo �tlet;
felt�ve,
hogy esz�nkbe jut. Az ilyen �ltal�nos �s hasznos tervez�si elemek le�r�s�ra
�ltal�ban
a minta (pattern) sz�t haszn�ljuk, a mint�k dokument�l�s�nak �s haszn�lat�nak
pedig komoly
irodalma van (pl. [Gamma, 1994] �s [Coplien, 1995]).
C�lszeru, hogy a tervezo ismerje az adott alkalmaz�si ter�let n�pszeru mint�it.
Mint programoz
�, olyan mint�kat r�szes�tek elonyben, melyekhez valamilyen k�d is tartozik, ami
p�ldak
�nt tekintheto. Mint a legt�bb ember, egy �ltal�nos �tletet (ebben az esetben
mint�t) akkor
tartok a legjobbnak, ha seg�ts�gemre van egy konkr�t p�lda is (ebben az esetben
egy,
a minta haszn�lat�t illusztr�l� k�dr�szlet). Akik gyakran haszn�lnak mint�kat,
szakzsargont
haszn�lnak egym�s k�z�tt, ami sajnos priv�t nyelvv� v�lhat, ami k�v�l�ll�k sz�m�ra
lehetetlenn
� teszi a meg�rt�st. Mint mindig, elengedhetetlen a megfelelo kommunik�ci� biztos
�t�sa a projekt k�l�nb�zo r�szeiben r�sztvevok (�23.3) �s �ltal�ban a tervezo �s
programoz
� k�z�ss�gek k�z�tt.
Minden sikeres nagy rendszer egy valamivel kisebb muk�do rendszer �ttervez�se. Nem
ismerek
kiv�telt e szab�ly al�l. M�g legink�bb olyan tervek jutnak eszembe, melyek �vekig
szenvedtek zurzavaros �llapotban �s nagy k�lts�ggel, �vekkel a tervezett
befejez�si d�tum
ut�n esetleg sikeresek lettek. Az ilyen projektek eredm�nye . sz�nd�kolatlanul �s
persze elismer
�s n�lk�l . elosz�r muk�d�sk�ptelen rendszer lett, amit k�sobb muk�dok�pess�
tettek,
v�g�l �jraterveztek olyan rendszerr�, mely megk�zel�ti az eredeti c�lkituz�seket.
Ebbol
k�vetkezik, hogy ostobas�g egy nagy rendszert �jonnan megtervezni �s meg�p�teni,
pontosan
k�vetve a legfrissebb elveket. Min�l nagyobb �s nagyrat�robb a rendszer, melyet
megc�loztunk, ann�l fontosabb, hogy legyen egy modell�nk, melybol dolgozunk. Egy
nagy rendszerhez az egyetlen val�ban elfogadhat� modell egy valamivel kisebb,
muk�do
rokon rendszer.
23.4.4. K�s�rletez�s �s elemz�s
Egy ig�nyes fejleszt�s kezdet�n nem tudjuk a m�dj�t, hogyan alkossuk meg legjobban

a rendszert. Gyakran m�g azt sem tudjuk pontosan, mit kellene a rendszernek
tennie, mivel
a konkr�tumok csak akkor tisztulnak ki, amikor a rendszert �p�tj�k, tesztelj�k �s
haszn
�ljuk. Hogyan kapjuk meg a teljes rendszer fel�p�t�se elott a sz�ks�ges
inform�ci�kat ahhoz,
hogy meg�rts�k, melyek a jelentos tervez�si d�nt�sek �s felbecs�lj�k azok
buktat�it?
23. Fejleszt�s �s tervez�s 957
K�s�rleteket folytatunk. Mihelyt van mit, elemezz�k a terveket �s azok
megval�s�t�s�t is.
A leggyakoribb �s legfontosabb a lehetos�gek megvitat�sa. A tervez�s �ltal�ban
k�z�ss�gi
tev�kenys�g, melyben a tervek bemutat�k �s vit�k �ltal fejlodnek. A legfontosabb
tervezo-
eszk�z a t�bla; en�lk�l az embrion�lis �llapot� tervez�si fogalmak nem tudnak
kifejlodni �s
elterjedni a tervezok �s programoz�k k�z�tt.
A k�s�rlet legn�pszerubb form�ja egy protot�pus �p�t�se, vagyis a rendszer vagy
egy r�sz�-
nek lekicsiny�tett v�ltozatban val� l�trehoz�sa. A protot�pus teljes�tm�ny�re
n�zve nincsenek
szigor� elo�r�sok, �ltal�ban elegendo a g�pi �s programoz�si k�rnyezetbeli
eroforr�s, a tervez
ok �s programoz�k pedig igyekeznek k�l�n�sen k�pzettnek, tapasztaltnak �s
motiv�ltnak
l�tszani. Arr�l van sz�, hogy egy v�ltozatot a leheto leggyorsabban futtatni
lehessen,
hogy lehetov� tegy�k a tervez�si �s megval�s�t�si m�dszerek v�laszt�k�nak
felder�t�s�t.
Ez a megk�zel�t�s nagyon sikeres lehet, ha j�l csin�ljuk, de lehet �r�gy a
pongyolas�gra is.
Az a probl�ma, hogy a protot�pus s�lypontja a lehetos�gek felder�t�s�tol
eltol�dhat .a lehet
o leghamarabb valamilyen muk�dok�pes rendszert kapni. fel�. Ez k�nnyen a
protot�pus
belso fel�p�t�se ir�nti �rdektelens�ghez (.v�g�l is csak protot�pusr�l van sz�.)
�s a tervez�-
si erofesz�t�sek elhanyagol�s�hoz vezet, mert a protot�pus gyors elk�sz�t�se
ezekkel szemben
elonyt �lvez. Az a b�kkeno, hogy az ily m�don elk�sz�tett v�ltozatban sokszor
nyoma
sincs az eroforr�sok helyes felhaszn�l�s�nak vagy a m�dos�that�s�g lehetos�g�nek,
mik�zben
egy .majdnem teljes. rendszer ill�zi�j�t adja. Szinte t�rv�nyszeru, hogy a
protot�pus
nem rendelkezik azzal a belso fel�p�t�ssel, hat�konys�ggal �s �ttekinthetos�ggel,
mely
megengedn�, hogy rajta kereszt�l a val�s haszn�latot felm�rhess�k.
K�vetkez�sk�ppen
egy .protot�pus., melybol .majdnem term�k. lesz, elsz�vja azt az idot �s energi�t,
amit a val
�di term�kre lehetett volna ford�tani. Mind a fejlesztok, mind a vezetok sz�m�ra
k�s�rt�st
jelent, hogy a protot�pusb�l term�ket csin�ljanak �s a .teljes�tm�ny
megtervez�s�t. elhalassz
�k a k�vetkezo kiad�sig. A protot�pusk�sz�t�snek ez a helytelen haszn�lata
tagad�sa
mindennek, ami�rt a tervez�s l�tezik.
Rokon probl�ma, hogy a protot�pus fejlesztoi beleszerethetnek az eszk�zeikbe.
Elfelejthetik,
hogy az �ltaluk �lvezett k�nyelem k�lts�geit egy val�di rendszer nem mindig
engedheti
meg mag�nak, �s az a korl�tok n�lk�li szabads�g, melyet kis kutat�csoportjuk
ny�jtott,
nemigen tarthat� fenn egy nagyobb k�z�ss�gben, mely szoros . �s egym�st�l f�ggo .
hat
�ridok szerint dolgozik.
M�sr�szrol, a protot�pusok felbecs�lhetetlen �rt�kuek. Vegy�k p�ld�ul egy
felhaszn�l�i fel
�let tervez�s�t. Ebben az esetben a rendszer a felhaszn�l�val k�zvetlen
k�lcs�nhat�sban
nem levo r�sz�nek belso fel�p�t�se t�nyleg l�nyegtelen, �s a protot�pus
haszn�lat�n k�v�l
nincs m�s lehets�ges m�d, hogy tapasztalatokat szerezz�nk arr�l, mi a v�lem�nye a
felhaszn
�l�knak a rendszer k�lsej�vel �s haszn�lat�val kapcsolatban. De p�ldak�nt vehetj�k

958 Tervez�s a C++ seg�ts�g�vel


az ellenkezoj�t is, egy olyan protot�pust, melyet szigor�an egy program belso
muk�d�s�-
nek tanulm�nyoz�s�ra terveztek. Itt a felhaszn�l�i fel�let lehet kezdetleges .
lehetos�g szerint
a val�di felhaszn�l�k helyett szimul�ltakkal.
A protot�pusk�sz�t�s a k�s�rletez�s egy m�dja. Eredm�nyei pedig azok a megl�t�sok
kellenek,
hogy legyenek, melyeket nem maga a protot�pus, hanem annak �p�t�se hoz mag�val.
Tulajdonk�ppen a protot�pus legfobb ism�rvek�nt a t�k�letlens�get kellene
meghat�rozni,
hogy vil�gos legyen, ez csup�n k�s�rleti eszk�z �s nem v�lhat term�kk� nagym�rt�ku
�jratervez
�s n�lk�l. Ha .t�k�letlen. protot�pusunk van, az seg�t, hogy a k�s�rletre
�sszpontos�tsunk
�s a leheto legkisebbre cs�kkenti annak vesz�ly�t, hogy a protot�pusb�l term�k
legyen, valamint megsz�nteti azt a k�s�rt�st is, hogy a term�k tervez�s�t t�l
szorosan a protot
�pusra alapozzuk, elfelejtve vagy elhanyagolva annak eredendo korl�tait. A
protot�pus
haszn�lat ut�n eldoband�.
Vannak olyan k�s�rleti m�dszerek is, melyeket a protot�pusk�sz�t�s helyett
alkalmazhatunk.
Ahol ezek haszn�lhat�k, gyakran elonyben is r�szes�tj�k oket, mert szigor�bbak �s
kevesebb
tervezoi idot �s rendszer-eroforr�st ig�nyelnek. Ilyenek p�ld�ul a matematikai
modellek
�s a k�l�nf�le szimul�torok. Tulajdonk�ppen fel is v�zolhatunk egy folyamatot,
a matematikai modellektol az egyre r�szletesebb szimul�ci�kon, a protot�pusokon,
�s
a r�szleges megval�s�t�son �t a teljes rendszerig.
Ez ahhoz az �tlethez vezet, hogy egy rendszert a kezdeti tervbol �s
megval�s�t�sb�l t�bbsz
�ri �jratervez�ssel �s �jb�li elk�sz�t�ssel finom�tsunk. Ez az ide�lis m�dszer, de
nagyon
nagy ig�nyeket t�maszthat a tervezoi �s fejlesztoi eszk�z�kkel szemben. A
megk�zel�t�s
azzal a kock�zattal is j�r, hogy t�l sok k�d k�sz�l a kezdeti d�nt�sek alapj�n,
�gy egy jobb
tervet nem lehet megval�s�tani. �gy ez a strat�gia egyelore csak kis �s k�zepes
m�retu programok
k�sz�t�s�n�l muk�dik j�l, melyekben nem val�sz�nu, hogy az �tfog� tervek k�l�n�-
sebben m�dosuln�nak, illetve a programok elso kiad�sa ut�ni �jratervez�sekre �s
�jb�li
megval�s�t�sokra, ahol elker�lhetetlen az ilyen megk�zel�t�s.
A tervez�si lehetos�gek �ttekint�s�re szolg�l� k�s�rleteken k�v�l egy terv vagy
megval�s�-
t�s elemz�se �nmag�ban is �tleteket adhat. A legnagyobb seg�ts�g p�ld�ul az
oszt�lyok
k�zti k�l�nb�zo �sszef�gg�sek (�24.3) tanulm�nyoz�sa lehet, de nem elhanyagolhat�k

a hagyom�nyos eszk�z�k sem, mint a h�v�si f�k (call graphs) megrajzol�sa, a


teljes�tm�nym
�r�sek stb.
Ne feledj�k, hogy a fogalmak meghat�roz�sa (az elemz�si szakasz .kimenete.) �s a
tervez
�s sor�n �pp�gy elk�vethet�nk hib�kat, mint a megval�s�t�s folyam�n. Val�j�ban m�g
t�bbet is, mivel ezen tev�kenys�gek eredm�nye kev�sb� konkr�t, kev�sb� pontosan
meghat
�rozott, nem .v�grehajthat�. �s �ltal�ban nem t�mogatj�k olyan kifinomult
eszk�z�k,
23. Fejleszt�s �s tervez�s 959
mint amilyenek a megval�s�t�s elemz�s�hez �s ellenorz�s�hez haszn�lhat�k. Ha a
tervez�s
kifejez�s�re haszn�lt nyelvet vagy jel�l�sm�dot form�lisabb� tessz�k, valamilyen
m�rt�kig
ilyen eszk�zt adhatunk a tervezo kez�be, ezt azonban nem tehetj�k annak az �r�n,
hogy
szeg�nyebb� tessz�k a megval�s�t�sra haszn�lt programoz�si nyelvet (�24.3.1).
Ugyanakkor
egy form�lis jel�l�sm�d maga is probl�m�k forr�sa lehet, p�ld�ul ha a haszn�lt
jel�l�srendszer
nem illik j�l arra a gyakorlati probl�m�ra, melyre alkalmazzuk; amikor a formai
k�vetelm�nyek szigora t�ll�pi a r�sztvevo tervezok �s programoz�k matematikai
felk�-
sz�lts�g�t �s �retts�g�t; vagy amikor a form�lis le�r�s elszakad a le�rand�
rendszertol.
A tervez�s eredendoen ki van t�ve a hib�knak �s neh�z t�mogatni hat�kony
eszk�z�kkel.
Ez�rt n�lk�l�zhetetlen a tapasztalat �s a visszajelz�s. K�vetkez�sk�ppen
alapvetoen hib�s
a programfejleszt�st egyenes vonal� folyamatk�nt tekinteni, mely az elemz�ssel
kezdodik �s
a tesztel�ssel v�gzodik. Figyelmet kell ford�tani az ism�telt tervez�sre �s
megval�s�t�sra,
hogy a fejleszt�s k�l�nb�zo szakaszaiban elegendo visszajelz�s�nk legyen a
tapasztaltakr�l.
23.4.5. Tesztel�s
Az a program, melyet nem teszteltek, nem tekintheto muk�donek. Az eszm�nyk�p, hogy

egy programot �gy k�sz�ts�nk el, hogy m�r az elso alkalommal muk�dj�n, a
legegyszerubb
programokat kiv�ve el�rhetetlen. T�rekedn�nk kell erre, de nem szabad ostob�n azt
hinn
�nk, hogy tesztelni k�nnyu.
A .Hogyan tesztelj�nk?. olyan k�rd�s, melyre nem lehet csak �gy �ltal�ban
v�laszolni.
A .Mikor tesztelj�nk?. k�rd�sre azonban van �ltal�nos v�lasz: olyan hamar �s olyan
gyakran,
amennyire csak lehets�ges. A tesztel�si m�dszert c�lszeru m�r a tervez�s �s
megval�s�-
t�s r�szek�nt, de legal�bb azokkal p�rhuzamosan kidolgozni. Mihelyt van egy fut�
rendszer, el kell kezdeni a tesztel�st. A komoly tesztel�s elhalaszt�sa a
.befejez�s. ut�nig
a hat�ridok cs�sz�s�t �s /vagy hib�s kiad�st eredm�nyezhet.
Ha csak lehets�ges, a rendszert �gy kell megtervezni, hogy viszonylag k�nnyen
tesztelhet
o legyen. Az ellenorz�st gyakran bele lehet tervezni a rendszerbe. N�ha ezt nem
tessz�k,
att�l val� f�lelm�nkben, hogy a fut�si ideju tesztel�s rontja a hat�konys�got,
vagy hogy az
ellenorz�shez sz�ks�ges redund�ns elemek t�ls�gosan nagy adatszerkezeteket eredm�-

nyeznek. Az ilyen f�lelem rendszerint alaptalan, mert a legt�bb tesztk�d sz�ks�g


eset�n lev
�laszthat� a t�nyleges k�dr�l, mielott a rendszert �tadjuk. Az assertion-�k
(�24.3.7.2) haszn
�lata n�ha hasznos lehet.
Magukn�l a tesztekn�l is fontosabb, hogy a rendszer olyan fel�p�t�su legyen, ami
elfogadhat
� es�lyt ad arra, hogy saj�t magunkat �s felhaszn�l�inkat/fogyaszt�inkat
meggyozz�k
960 Tervez�s a C++ seg�ts�g�vel
arr�l, hogy a hib�kat statikus ellenorz�s, statikus elemz�s �s tesztel�s egy�ttes
haszn�lat�-
val ki tudjuk k�sz�b�lni. Ahol a hibatur�s biztos�t�s�ra kidolgoztak valamilyen
m�dszert
(�14.9), ott �ltal�ban a tesztel�s is be�p�theto a teljes tervbe.
Ha a tervez�si szakaszban a tesztel�si k�rd�sekkel egy�ltal�n nem sz�moltunk,
akkor az ellen
orz�ssel, a hat�ridok betart�s�val �s a program m�dos�t�s�val probl�m�ink lesznek.

Az oszt�lyfel�letek �s az oszt�lyf�gg�sek rendszerint j� kiindul�pontot jelentenek


a tesztel
�si m�dszer kidolgoz�s�hoz(�24.3, �24.4.2).
Rendszerint neh�z meghat�rozni, mennyi tesztel�s elegendo. A t�l kev�s tesztel�s
azonban
�ltal�nosabb probl�ma, mint a t�l sok. Az, hogy a tervez�shez �s megval�s�t�shoz
viszony
�tva pontosan mennyi eroforr�st kell a tesztel�sre kijel�lni, term�szetesen f�gg a
rendszer
term�szet�tol �s a m�dszerektol, melyeket �p�t�s�hez haszn�lunk. Ir�nyelvk�nt
javasolhatom
azonban, hogy idoben, erofesz�t�sben �s tehets�gben t�bb eroforr�st ford�tsunk
a rendszer tesztel�s�re, mint elso v�ltozat�nak elk�sz�t�s�re. A tesztel�snek
olyan probl�-
m�kra kell �sszpontos�tania, melyeknek v�gzetes k�vetkezm�nyei lenn�nek �s
olyanokra,
melyek gyakran forduln�nak elo.
23.4.6. A programok .karbantart�sa.
A .program-karbantart�s. (software maintenance) helytelen elnevez�s. A
.karbantart�s. sz�
f�lrevezeto hasonlatot sugall a hardverrel. A programoknak nincs sz�ks�g�k
olajoz�sra,
nincsenek mozg� alkatr�szeik, amelyek kopnak, �s nincsenek reped�seik, ahol a v�z
�sszegy
ulik �s rozsd�sod�st okoz. A szoftver pontosan lem�solhat� �s percek alatt nagy
t�vols
�gra �tviheto. A szoftver nem hardver.
Azok a tev�kenys�gek, melyeket program-karbantart�s n�ven emleget�nk, val�j�ban az
�jratervez
�s �s az �jb�li megval�s�t�s, teh�t a szok�sos programfejleszt�si folyamathoz
tartoznak.
Amikor a tervez�sben hangs�lyosan szerepel a rugalmass�g, bov�thetos�g �s
hordozhat
�s�g, k�zvetlen�l a program fenntart�s�val kapcsolatos hib�k hagyom�nyos
forr�saira
�sszpontos�tunk.
A tesztel�shez hasonl�an a karbantart�s sem lehet ut�lagos megfontol�s vagy a
fejleszt�s fo
sodr�t�l elv�lasztott tev�kenys�g. K�l�n�sen fontos, hogy a projektben v�gig
ugyanazok
a szem�lyek vegyenek r�szt, vagy legal�bbis biztos�tsuk a folytonoss�got . Nem
k�nnyu
ugyanis .karbantart�st. v�geztetni egy olyan �j (�s �ltal�ban kisebb tapasztalat�)
emberekb
ol �ll� csoporttal, akik az eredeti tervezokkel �s programoz�kkal nem �llnak
kapcsolatban.
Ha m�gis m�soknak kell �tadni a munk�t, hangs�lyt kell fektetni arra, hogy az �j
emberek
tiszt�ban legyenek a rendszer fel�p�t�s�vel �s c�lkituz�seivel. Ha a .karbantart�
23. Fejleszt�s �s tervez�s 961
szem�lyzet. mag�ra marad abban, hogy kital�lja a rendszer szerkezet�t, vagy hogy a
rendszer
�sszetevoinek c�lj�t megval�s�t�sukb�l k�vetkeztesse ki, a rendszer a helyi
.foltozgat
�s. hat�s�ra gyorsan degener�l�dik. A dokument�ci� nem seg�t, mert az ink�bb a
r�szletek
le�r�s�ra val�, nem pedig arra, hogy az �j munkat�rsakat seg�tse a fo �tletek �s
elvek
meg�rt�s�ben.
23.4.7. Hat�konys�g
Donald Knuth megfigyelte, hogy .az ido elotti optimaliz�l�s a gy�kere minden
rossznak..
N�melyek t�ls�gosan megtanult�k ezt a leck�t �s minden hat�konys�gi t�rekv�st
rossznak
tekintenek, pedig a hat�konys�gra v�gig �gyelni kell a tervez�s �s megval�s�t�s
sor�n. Ez
azonban nem azt jelenti, hogy a tervezonek minden .apr�s�got. hat�konny� kell
tennie,
hanem csak azt, hogy az elsorendu hat�konys�gi k�rd�sekkel foglalkoznia kell.
A hat�konys�g el�r�s�hez a legjobb m�dszer egy vil�gos �s egyszeru terv k�sz�t�se.
Csak
egy ilyen terv maradhat viszonylag �lland� a projekt �lettartama alatt �s
szolg�lhat a teljes
�tm�ny behangol�s�nak alapj�ul. L�nyeges, hogy elker�lj�k a nagy projekteket s�jt�
megalom
�ni�t. T�l gyakori, hogy a programoz�k .ha sz�ks�g lenne r�. tulajdons�gokat
(�23.4.3.2, �23.5.3) �p�tenek be, majd a .sallangok. t�mogat�s�val megk�tszerezik,
megn
�gyszerezik a rendszerek m�ret�t �s fut�si idej�t. Enn�l is rosszabb, hogy az
ilyen t�lfinom
�tott rendszereket gyakran sz�ks�gtelen�l neh�z elemezni, �gy neh�z lesz
megk�l�nb�ztetni
az elker�lheto t�lterhel�st az elker�lhetetlentol. Ez pedig m�g az alapveto
elemz�st �s
optimaliz�l�st is akad�lyozza. Az optimum be�ll�t�sa elemz�s �s teljes�tm�nym�r�s
eredm�-
nye kell, hogy legyen, nem tal�lomra piszmog�s a k�ddal. A nagy rendszerek
eset�ben
a tervezoi vagy programoz�i .intu�ci�. k�l�n�sen megb�zhatatlan �tmutat� a
hat�konys�gi
k�rd�sekben.
Fontos, hogy elker�lj�k az eredendoen rossz hat�konys�g� szerkezeteket, illetve az
olyanokat,
melyeknek elfogadhat� teljes�tm�nyszintre val� optimaliz�l�sa sok idot �s �gyess�-

get k�v�n. Hasonl�k�ppen fontos, hogy cs�kkents�k az eredendoen .hordozhatatlan.


szerkezetek
�s eszk�z�k haszn�lat�t, mert ez arra k�rhoztatja a projektet, hogy r�gebbi
(kisebb
teljes�tm�nyu) vagy �ppen dr�g�bb g�peken fusson.
962 Tervez�s a C++ seg�ts�g�vel
23.5. Vezet�s
Felt�ve, hogy legal�bb valamilyen �rtelme van, a legt�bb ember azt teszi, amire
r�veszik.
Nevezetesen, ha egy projekttel �sszef�gg�sben bizonyos .muk�d�si m�dokat. d�jazunk
�s
m�sokat b�ntet�nk, csak kiv�teles programoz�k �s tervezok fogj�k kock�ztatni a
karrierj�-
ket, hogy azt tegy�k, amit helyesnek tartanak, a vezet�s ellenv�lem�ny�vel,
k�z�ny�vel �s
b�rokr�ci�j�val szemben?.3 Ebbol k�vetkezik, hogy a c�gnek kell, hogy legyen egy
jutalmaz
�si rendszere, mely megfelel az �ltala meg�llap�tott tervez�si �s programoz�si
c�lkituz�-
seknek. Mindazon�ltal gyakran nem ez a helyzet: a programoz�si st�lusban nagy
v�ltoz�s
csak a tervez�si st�lus megfelelo m�dos�t�s�val �rheto el �s ahhoz, hogy hat�sos
legyen, �ltal
�ban mindketto a vezet�si st�lus megv�ltoztat�s�t ig�nyli. A szellemi �s
szervezeti tehetetlens
�g k�nnyen eredm�nyezhet olyan helyi v�ltoztat�sokat, melyeket nem t�mogatnak
a siker�t biztos�t� glob�lis v�ltoztat�sok. Meglehetosen jellemzo p�lda egy
objektumorient
�lt programoz�st t�mogat� nyelvre (mondjuk a C++-ra) val� �t�ll�s, a nyelv
lehetos�-
geit kihaszn�l� megfelelo tervez�si strat�giabeli v�ltoztat�s n�lk�l, vagy �ppen
ford�tva,
.objektumorient�lt tervez�sre. v�lt�s azt t�mogat� programoz�si nyelv bevezet�se
n�lk�l.
23.5.1. �jrahasznos�t�s
A k�dok �s tervek �jrahasznos�t�s�t gyakran emlegetik, mint fo okot egy �j
programoz�si
nyelv vagy tervez�si m�dszer bevezet�s�re. A legt�bb szervezet azonban azokat az
egy�-
neket t�mogatja, akik a melegv�z �jrafeltal�l�s�t v�lasztj�k. P�ld�ul ha egy
programoz� teljes
�tm�ny�t k�dsorokban m�rik; vajon kis programokat fog �rni a standard k�nyvt�rakra
t�-
maszkodva, bev�tel�nek �s esetleg st�tusz�nak rov�s�ra? �s ha egy vezetot a
csoportj�ban
l�vo emberek sz�m�val ar�nyosan fizetnek, vajon fel fogja-e haszn�lni a m�sok
�ltal k�sz�-
tett programot, ha helyette a saj�t csoportj�ba �jabb embereket vehet fel? Vagy ha
egy c�gnek
oda�t�lnek egy korm�nyszerzod�st, ahol a profit a fejleszt�si k�lts�geknek egy
r�gz�-
tett sz�zal�ka, vajon ez a c�g k�zvetetten cs�kkenteni fogja-e a profitj�t a
leghat�konyabb
fejlesztoeszk�z�k haszn�lat�val? Az �jrahasznos�t�st neh�z jutalmazni, de ha a
vezet�s nem
tal�l m�dot az �szt�nz�s�re �s jutalmaz�s�ra, nem lesz �jrahasznos�t�s. Az
�jrahasznos�t�snak
m�s vonatkoz�sai is vannak. Akkor haszn�lhatjuk fel valaki m�s programj�t, ha:
1. Muk�dik: ahhoz, hogy �jrahasznos�that� legyen, a programnak elobb haszn�lhat
�nak kell bizonyulnia.
23. Fejleszt�s �s tervez�s 963
3 Az olyan szervezetnek, mely a programoz�ival �gy b�nik, mint az idi�t�kkal,
hamarosan olyan programoz�i
lesznek, akik csak idi�tak�nt akarnak �s k�pesek cselekedni.
2. �ttekintheto: fontos a program szerkezete, a megjegyz�sek, a dokument�ci� �s
az oktat�anyag.
3. Egy�tt l�tezhet egy olyan programmal, melyet nem kimondottan a vele val�
egy�ttmuk�d�sre �rtak.
4. T�mogatott (vagy magunk akarjuk t�mogatni; �n �ltal�ban nem akarom).
5. Gazdas�gos (megoszthatom-e m�s felhaszn�l�kkal a fejleszt�si �s karbantart�si
k�lts�geket?).
6. Meg lehet tal�lni.
Ehhez hozz�tehetj�k, hogy egy �sszetevo nem �jrahasznos�that�, am�g nincs valaki,
aki
.�jra felhaszn�lta.. Egy �sszetevo valamely k�rnyezetbe beilleszt�se jellemzoen
muk�d�s�-
nek finom�t�s�val, viselked�s�nek �ltal�nos�t�s�val �s m�s programokkal val�
egy�ttmuk�-
d�si k�pess�g�nek jav�t�s�val j�r egy�tt. Am�g legal�bb egyszer el nem v�gezt�k
ezt
a feladatot, m�g a leggondosabban megtervezett �s elk�sz�tett �sszetevoknek is
lehetnek
sz�nd�kolatlan �s v�ratlan egyenetlens�gei.
Az a tapasztalatom, hogy az �jrahasznos�t�snak csak akkor vannak meg a sz�ks�ges
felt�telei,
ha valaki k�z�s �gynek tekinti, hogy ilyen munkamegoszt�s muk�dj�n. Egy kis
csoportban
ez �ltal�ban azt jelenti, hogy valaki . tervezetten vagy v�letlen�l . a k�z�s
k�nyvt
�rak �s dokument�ci� gazd�ja lesz, egy nagyobb c�gn�l pedig azt, hogy megb�znak
egy
csoportot vagy oszt�lyt, hogy gyujtse �ssze, k�sz�tse el, dokument�lja,
n�pszerus�tse �s
.tartsa karban. a t�bb csoport �ltal felhaszn�lt program�sszetevoket. Nem lehet
t�lbecs�lni
a .szabv�nyos �sszetevokkel. foglalkoz� csoport fontoss�g�t. Vegy�k �szre, hogy
egy
program azt a k�z�ss�get t�kr�zi, amely l�trehozta. Ha a k�z�ss�gnek nincs
egy�ttmuk�-
d�st �s munkamegoszt�st eloseg�to �s jutalmaz� rendszere, ritk�n lesz
egy�ttmuk�d�s �s
munkamegoszt�s. A szabv�nyos �sszetevokkel foglalkoz� csoport akt�van kell, hogy
n�pszer
us�tse ezeket az �sszetevoket. Ebbol k�vetkezik, hogy a j�l meg�rt dokument�ci�
n�lk
�l�zhetetlen, de nem elegendo. A csoportnak ezen k�v�l gondoskodnia kell
oktat�anyagokr
�l �s minden m�s inform�ci�r�l is, ami lehetov� teszi, hogy a rem�nybeli
felhaszn�l�
megtal�ljon egy �sszetevot �s meg�rtse, mi�rt seg�thet az neki. Ennek
k�vetkezm�nye,
hogy a piackutat�ssal �s az oktat�ssal kapcsolatos tev�kenys�geket ennek a
csoportnak kell
v�llalnia.
Ha lehets�ges, e csoport tagjainak szorosan egy�tt kell muk�dni�k az
alkalmaz�sfejlesztokkel.
Csak �gy tudnak megfeleloen �rtes�lni a felhaszn�l�k ig�nyeirol �s felh�vni a
figyelmet
az alkalmakra, amikor egyes �sszetevoket k�l�nb�zo programok k�z�sen
haszn�lhatnak.
Ezzel amellett �rvelek, hogy az ilyen csoportoknak legyen v�lem�ny-nyilv�n�t�si �s
tan�csad
�i szerepe, �s hogy muk�djenek a belso kapcsolatok a csoportba bej�vo �s onnan
kimen
o inform�ci� �tvitel�re.
964 Tervez�s a C++ seg�ts�g�vel
Az .komponens-csoport. siker�t az �gyfelek siker�vel kell m�rni. Ha a sikert
egyszeruen
azzal m�rj�k, hogy mennyi eszk�zt �s szolg�ltat�st tudnak elfogadtatni a fejleszto
c�gekkel,
az ilyen csoport kereskedelmi �gyn�kk� alacsonyodik �s �lland�an v�ltoz� h�bortok
elo-
mozd�t�ja lesz.
Nem minden k�dnak kell �jrahasznos�that�nak lennie, ez nem .mindenhat�.
tulajdons�g.
Ha azt mondjuk, hogy egy �sszetevo .�jrahasznos�that�., ez azt jelenti, hogy
felhaszn�l�sa
bizonyos kereteken bel�l kev�s vagy semmi munk�t nem ig�nyel. A legt�bb esetben
egy
m�s v�zba t�rt�no �tk�lt�ztet�s jelentos munk�val j�r. Ebbol a szempontb�l az
�jrahasznos
�t�s erosen eml�keztet a hordozhat�s�gra (vagyis m�s rendszerre val� �t�ltet�sre).
Fontos
megjegyezni, hogy az �jrahasznos�t�s az ezt c�lz� tervez�snek, az �sszetevok
tapasztalat
alapj�n val� finom�t�s�nak �s annak a sz�nd�kos erofesz�t�snek az eredm�nye, hogy
m�r
l�tezo �sszetevoket keress�nk (�jb�li) felhaszn�l�sra. Az �jrahasznos�t�s nem az
egyes
nyelvi tulajdons�gok vagy k�dol�si m�dszerek v�letlenszeru haszn�lat�b�l
keletkezik,
mintegy csodak�nt. A C++ olyan szolg�ltat�sai, mint az oszt�lyok, a virtu�lis
f�ggv�nyek �s
a sablonok lehetov� teszik, hogy a tervez�s kifejez�sm�dja az �jrahasznos�t�st
k�nnyebb�
(�s ez�ltal val�sz�nubb�) tegye, de �nmagukban nem biztos�tj�k azt.
23.5.2. M�ret �s egyens�ly
Az �n�ll� vagy k�z�ss�gben dolgoz� programoz�t sokszor arra k�nyszer�tik, hogy
dolg�t
.a megfelelo m�don. v�gezze. Int�zm�nyes fel�ll�sban ez gyakran �gy hangzik: .a
megfelel
o elj�r�sok kifejleszt�se �s szigor� k�vet�se sz�ks�ges.. Mindk�t esetben elsok�nt
a j�-
zan �sz eshet �ldozatul annak a k�v�ns�gnak, hogy minden�ron jav�tsunk .a dolgok
v�gz�-
s�nek. m�dj�n. Sajnos, ha egyszer hi�nyzik a j�zan �sz, az akaratlanul okozhat�
k�roknak
nincs hat�ra.
Vegy�k a fejleszt�si folyamat �23.4-ben felsorolt szakaszait �s a �23.4.3-ban
felsorolt tervez
�si l�p�seket. E l�p�sekbol viszonylag k�nnyen kidolgozhat� egy megfelelo
tervez�si
m�dszer, ahol minden szakasz pontosan k�r�lhat�rolt, meghat�rozott .bemenete �s
kimenete
. van, valamint rendelkezik az ezek kifejez�s�hez sz�ks�ges, r�szben form�lis
jel�l�sm
�ddal. Ellenorzo list�kkal biztos�thatjuk, hogy a tervez�si m�dszer k�vetkezetesen
t�mogassa
a nagy sz�m� elj�r�si �s jel�l�sbeli szab�ly �rv�nyre juttat�s�t, �s hogy ehhez
eszk�z�ket lehessen kifejleszteni. Tov�bb�, az �sszef�gg�sek �24.3-ban bemutatott
oszt�-
lyoz�s�t n�zve valaki kinyilatkoztathatn�, hogy bizonyos kapcsolatok j�k, m�sok
pedig
rosszak, �s elemzo eszk�z�ket adna annak biztos�t�s�ra, hogy ezeket az
�rt�k�t�leteket az
adott projekten bel�l egys�gesen alkalmazz�k. A programfejleszt�si folyamat e
.megeros�-
t�s�t. t�k�lyre fejlesztendo, valaki le�rhatn� a dokument�l�s szab�lyait
(bele�rtve a helyes-
�r�si, nyelvtani �s g�pel�si szab�lyokat) �s a k�d �ltal�nos k�llem�re vonatkoz�
elo�r�sokat
23. Fejleszt�s �s tervez�s 965
(bele�rtve azt is, mely nyelvi tulajdons�gokat �s k�nyvt�rakat szabad �s melyeket
nem szabad
haszn�lni, hol haszn�lhat� beh�z�s, hogyan lehet elnevezni a f�ggv�nyeket,
v�ltoz�-
kat �s t�pusokat stb.).
Ezek k�z�tt akad olyan, amely eloseg�theti a sikert. Term�szetesen ostobas�g lenne
egy
esetleg t�zmilli� k�dsorb�l �ll� rendszer tervez�s�t elkezdeni . melyet t�bb sz�z
ember fejlesztene
�s t�bb ezer ember .tartana karban. �s t�mogatna t�z vagy m�g t�bb �vig . egy becs
�letesen kidolgozott �s meglehetosen szil�rd v�z n�lk�l.
Szerencs�re a legt�bb program nem ebbe a kateg�ri�ba esik. Ha azonban egyszer
elfogadtuk,
hogy egy ilyen tervez�si m�dszer vagy egy ilyen k�dol�si �s dokument�l�si
szabv�nygy
ujtem�nyhez val� ragaszkod�s .a helyes �t., k�telezo lesz annak �ltal�nos �s
minden
r�szletre kiterjedo haszn�lata. Ez kis programokn�l nevets�ges korl�toz�sokhoz �s
t�bbletmunk
�hoz vezethet: a halad�s �s siker m�rt�k�t jelento hat�kony munka helyett
aktatologat
�s �s urlapt�lt�get�s folyik majd. Ha ez t�rt�nik, az igazi tervezok �s
programoz�k t�-
vozni fognak �s b�rokrat�k l�pnek a hely�kbe.
Ha egy k�z�ss�gen bel�l m�r elofordult, hogy egy tervez�si m�dszert ilyen
nevets�gesen
rosszul alkalmaztak, annak sikertelens�ge �r�gyet szolg�ltat arra, hogy
elker�ljenek szinte
minden szab�lyoz�st a fejleszt�si folyamatban. Ez viszont �ppen olyan zurzavarhoz
�s balsikerekhez
vezet, mint amilyeneket az �j tervez�si m�dszer kialak�t�s�val meg akartunk
elozni.
Az igazi probl�ma megtal�lni az egyens�lyt a megfelelo fok� szab�lyoz�s �s az
adott program
fejleszt�s�hez sz�ks�ges szabads�g k�z�tt. Ne higgy�k, hogy erre a probl�m�ra
k�nnyu lesz megold�st tal�lni. L�nyeg�ben minden megk�zel�t�s csak kis
projektekn�l mu-
k�dik, pontosabban .ami m�g rosszabb, hiszen a rendszer rosszul tervezett �s
kegyetlen
a belevont egy�nekkel szemben . nagy projektekn�l is, felt�ve, hogy szem�rmetlen�l
sok
idot �s p�nzt akarunk elpocs�kolni a probl�m�ra.
Minden programfejlesztoi munka kulcsprobl�m�ja, hogyan tartsuk magunkat a terv
eredeti
szempontjaihoz. Ez a probl�ma a m�rettel hatv�nyozottan n�vekszik. Csak egy �n�ll�

programoz� vagy egy kis csoport tudja szil�rdan k�zbentartani �s betartani egy
nagyobb
munka �tfog� c�lkituz�seit. A legt�bb embernek olyan sok idot kell t�ltenie
r�szprojektekkel,
technikai r�szletk�rd�sekkel, napi adminisztr�ci�val stb., hogy az �tfog� c�lok
k�nnyen feled�sbe mer�lnek vagy al�rendelodnek helyi �s k�zvetlenebb c�loknak. Az
is
sikertelens�ghez vezet, ha nincs egy egy�n vagy egy csoport, melynek kiz�r�lag az
a feladata,
hogy fenntartsa a terv s�rtetlens�g�t. Recept a siker ellen, ha egy ilyen egy�nnek
vagy csoportnak nem engedj�k, hogy a munka eg�sz�re hasson.
966 Tervez�s a C++ seg�ts�g�vel
Egy �sszeru hossz� t�v� c�lkituz�s hi�nya k�rosabb, mint b�rmilyen egyedi
tulajdons�g hi-
�nya. Egy ilyen �tfog� c�lkituz�s megfogalmaz�sa, �szben tart�sa, az �tfog�
tervdokument
�ci� meg�r�sa, a fo fogalmak ismertet�se, �s �ltal�ban m�sokat seg�teni, hogy
�szben tarts
�k az �tfog� c�lt, kis sz�m� egy�n feladata kell, hogy legyen.
23.5.3. Egy�nek
Az itt le�rtak szerinti tervez�s jutalom a tehets�ges tervezok �s programoz�k
sz�m�ra, viszont
a sikerhez elengedhetetlen, hogy ezeket a tervezoket �s programoz�kat megtal�ljuk.

A vezetok gyakran elfelejtik, hogy a szervezetek egy�nekbol �llnak. N�pszeru


v�lem�ny,
hogy a programoz�k egyform�k �s csereszabatosak. Ez t�veszme, mely t�nkreteheti a
k�-
z�ss�get, az�ltal, hogy elzavarja a leghat�konyabb egy�neket �s m�g a
megmaradtakat is
arra �t�li, hogy j�val a k�pess�geik alatti szinten dolgozzanak. Az egy�nek csak
akkor felcser
�lhetok, ha nem engedj�k, hogy hasznos�ts�k azokat a k�pess�geiket, melyek a
k�rd�-
ses feladat �ltal megk�vetelt minimum f�l� emelik oket. A csereszabatoss�g elve
teh�t nem
hum�nus �s eredendoen pazarl�.
A legt�bb programoz�si teljes�tm�nym�r�s �szt�nzi a pazarl�st �s kihagyja a
sz�m�t�sb�l az
egy�ni hozz�j�rul�st. A legk�zenfekvobb p�lda az a viszonylag elterjedt gyakorlat,
hogy
a halad�st a meg�rt k�dsorok, a dokument�ci� lapjainak, vagy az elv�gzett tesztek
sz�m�-
val m�rik. Az ilyen sz�mok j�l mutatnak diagramokon, de a val�s�ghoz vajmi kev�s
k�z�k
van. P�ld�ul, ha a termel�kenys�get a k�dsorok sz�m�val m�rj�k, akkor egy
�sszetevo sikeres
�jrahasznos�t�sa negat�v programoz�i teljes�tm�nynek minos�lhet. Egy nagy programr
�sz �jratervez�s�n�l a legjobb elvek sikeres alkalmaz�sa ugyanilyen hat�s�.
A teljes�tett munka minos�g�t sokkal nehezebb m�rni, mint a .kimenet. mennyis�g�t,
az
egy�neket �s csoportokat viszont a munka minos�ge alapj�n kell jutalmazni, nem
durva
mennyis�gm�r�s alapj�n. Sajnos a minos�g gyakorlati m�r�se . legjobb tud�som
szerint
. gyerekcipoben j�r. Ezenk�v�l azon teljes�tm�ny-elo�r�sok, melyek a munk�nak csak

egy szakasz�ra vonatkoznak, hajlamosak befoly�solni a fejleszt�st. Az emberek


alkalmazkodnak
a helyi hat�ridokh�z �s az egy�ni �s csoportteljes�tm�nyt a kv�t�k �ltal elo�rthoz

igaz�tj�k. Ezt k�zvetlen�l a rendszer �tfog� �ps�ge �s teljes�tm�nye szenvedi meg.


Ha egy
hat�ridot p�ld�ul az elt�vol�tott vagy a megmaradt programhib�kkal hat�roznak meg,
bel�thatjuk,
hogy a hat�rido csak a fut�si ideju teljes�tm�ny figyelmen k�v�l hagy�s�val vagy
a rendszer futtat�s�hoz sz�ks�ges hardver-eroforr�sok optimaliz�l�s�nak
melloz�s�vel lesz
tarthat�. Ellenben ha csak a fut�si ideju teljes�tm�nyt m�rj�k, a hibaar�ny
biztosan n�vekedni
fog, amikor a fejlesztok a rendszert a fut�si teljes�tm�nyt m�ro programokra
igyekeznek
optimaliz�lni. Az �rtelmes minos�gi elo�r�sok hi�nya nagy k�vetelm�nyeket t�maszt
a ve-
23. Fejleszt�s �s tervez�s 967
zetok szak�rtelm�vel szemben, de az alternat�va az, hogy a halad�s helyett egyes
tal�lomra
kiv�lasztott tev�kenys�geket fognak jutalmazni. Ne feledj�k, hogy a vezetok is
emberek.
Nekik is legal�bb annyi oktat�sra van sz�ks�g�k, mint az �ltaluk vezetetteknek.
Mint
a programfejleszt�s m�s ter�letein, itt is hosszabb t�vra kell tervezn�nk.
L�nyeg�ben lehetetlen
meg�t�lni egy egy�n teljes�tm�ny�t egyetlen �v munk�ja alapj�n. A k�vetkezetesen
�s
hossz� t�von vezetett feljegyz�sek azonban megb�zhat� elorejelz�st biztos�tanak az
egyes
munkat�rsak teljes�tm�ny�vel kapcsolatban �s hasznos seg�ts�get adnak a k�zvetlen
m�lt
�rt�kel�s�hez. Az ilyen feljegyz�sek figyelmen k�v�l hagy�sa . ahogy akkor
t�rt�nik, amikor
az egy�neket puszt�n cser�lheto fogasker�knek tekintik a szervezet g�pezet�-
ben . a vezetoket kiszolg�ltatja a f�lrevezeto mennyis�gi m�r�seknek.
A hossz� t�vra tervez�s egyik k�vetkezm�nye, hogy az egy�nek (mind a fejlesztok,
mind
a vezetok) az ig�nyesebb �s �rdekesebb feladatokhoz hosszabb idot ig�nyelnek. Ez
elveszi
a kedv�t az �ll�sv�ltoztat�knak �pp�gy, mint a .karriercsin�l�s. miatt munkak�rt
v�ltoztat
�knak. T�rekedni kell arra, hogy kicsi legyen a fluktu�ci� mind a muszakiak, mind
a kulcsfontoss
�g� vezetok k�r�ben. Egyetlen vezeto sem lehet sikeres a kulcsemberekkel val�
egyet�rt�s �s friss, a t�rgyra vonatkoz� technikai tud�s n�lk�l, de ugyan�gy
egyetlen tervez
okbol �s fejlesztokbol �ll� csoport sem lehet hossz� t�von sikeres alkalmas
vezetok t�mogat
�sa n�lk�l �s an�lk�l, hogy alapjaiban �rts�k azt a k�rnyezetet, melyben
dolgoznak.
Ahol sz�ks�ges az innov�ci�, az idosebb szakemberek, elemzok, tervezok,
programoz�k
stb. l�tfontoss�g� szerepet j�tszanak az �j elj�r�sok bevezet�s�ben. Ok azok,
akiknek �j
m�dszereket kell megtanulniuk �s sok esetben el kell felejteni�k a r�gi
szok�sokat, ami
nem k�nnyu, hiszen �ltal�ban komoly erofesz�t�seket tettek a r�gi munkam�dszerek
elsaj
�t�t�s�ra, r�ad�sul az e m�dszerekkel el�rt sikereikre, szakmai tekint�ly�kre
t�maszkodnak.
Sok szakmai vezetovel ugyanez a helyzet.
Term�szetesen az ilyen egy�nek gyakran f�lnek a v�ltoz�st�l. Ez�rt a v�ltoz�ssal
j�r� probl
�m�kat t�lbecs�lik �s nehezen ismerik el a r�gi m�dszerekkel kapcsolatos
probl�m�kat.
Ugyanilyen term�szetes, hogy a v�ltoz�s mellett �rvelok hajlamosak t�lbecs�lni az
�j m�dszerek
elonyeit �s al�becs�lni a v�ltoz�ssal j�r� probl�m�kat. A k�t csoportnak kommunik
�lnia kell: meg kell tanulniuk ugyanazon a nyelven besz�lni �s seg�teni�k kell
egym�snak,
hogy az �tmenetre megfelelo m�dszert dolgozhassanak ki. Ha ez nem t�rt�nik meg, a
szervezet
megb�nul �s a legjobb k�pess�gu egy�nek t�voznak mindk�t csoportb�l. Mindk�t
csoportnak eml�keznie kell arra, hogy a legsikeresebb .�regek. gyakran azok, akik
tavaly
az .ifj� tit�nok. voltak. Ha adott az es�ly arra, hogy megal�zkod�s n�lk�l
tanuljanak,
a tapasztaltabb programoz�k �s tervezok lehetnek a legsikeresebb �s legnagyobb
betekint
�ssel rendelkezo h�vei a v�ltoztat�snak. Eg�szs�ges szkepticizmusuk, a
felhaszn�l�k ismerete
�s a szervezet muk�d�s�vel kapcsolatban szerzett tapasztalataik
felbecs�lhetetlen�l
�rt�kesek lehetnek. Az azonnali �s gy�keres v�ltoz�sok javasl�i �szre kell vegy�k,
hogy az
968 Tervez�s a C++ seg�ts�g�vel
�tmenet, amely az �j elj�r�sok fokozatos elsaj�t�t�s�val j�r, t�bbnyire
elengedhetetlen.
Azoknak viszont, akik nem k�v�nnak v�ltoztatni, olyan ter�leteket kell keresni�k,
ahol nem
sz�ks�ges v�ltoztatni, nem pedig d�h�s h�tv�dharcot v�vni olyan ter�leteken, ahol
az �j k�-
vetelm�nyek m�r jelentosen megv�ltoztatt�k a siker felt�teleit.
23.5.4. Hibrid tervez�s
�j munkam�dszerek bevezet�se egy c�gn�l f�rads�gos lehet. Jelentos t�r�st okozhat
mind
a szervezetben, mind az egy�nekben. Egy v�ratlan v�ltoz�s, mely a .r�gi iskola.
hat�kony
�s tapasztalt tagjait egyik napr�l a m�sikra az .�j iskola. z�ldf�lu �joncaiv�
v�ltoztatja, �ltal
�ban elfogadhatatlan. V�ltoz�sok n�lk�l azonban ritk�n �rhet�nk el nagy
nyeres�get, a jelent
os v�ltoz�sok pedig t�bbnyire kock�zattal j�rnak.
A C++-t �gy tervezt�k, hogy a kock�zatot a leheto legkisebbre cs�kkentse, az�ltal,
hogy
lehetov� teszi a m�dszerek fokozatos elsaj�t�t�s�t. B�r vil�gos, hogy a C++
haszn�lat�nak
legnagyobb elonyei az elvont adat�br�zol�sb�l �s az objektumorient�lt szeml�letbol
ad�dnak,
nem biztos, hogy e nyeres�geket a leggyorsabban a m�lttal val� gy�keres
szak�t�ssal
lehet el�rni. Egyszer-egyszer kereszt�lviheto az ilyen egy�rtelmu szak�t�s, de
gyakoribb,
hogy a jav�t�s v�gy�t egy idore f�lre kell tenn�nk, hogy meggondoljuk, hogyan
kezelj�k az
�tmenetet. A k�vetkezoket kell figyelembe venn�nk:
� A tervezoknek �s programoz�knak ido kell az �j szakismeretek megszerz�s�hez.
� Az �j k�dnak egy�tt kell muk�dnie a r�gi k�ddal.
� A r�gi k�dot karban kell tartani (gyakran a v�gtelens�gig).
� A l�tezo terveket �s programokat be kell fejezni (idore).
� Az �j elj�r�sokat t�mogat� eszk�z�ket be kell vezetni az adott k�rnyezetbe.
Ezek a t�nyezok term�szetesen hibrid (kevert) tervez�si st�lushoz vezetnek . m�g
ott is,
ahol n�melyik tervezonek nem ez a sz�nd�ka. Az elso k�t pontot k�nnyu
alul�rt�kelni.
Az�ltal, hogy sz�mos programoz�si ir�nyelvet t�mogat, a C++ v�ltozatos m�don
t�mogatja
a nyelv haszn�lat�nak fokozatos bevezet�s�t:
� A programoz�k produkt�vak maradhatnak a C++ tanul�sa k�zben.
� A C++ jelentos elony�ket ny�jt egy eszk�zszeg�ny k�rnyezetben.
� A C++ programr�szek j�l egy�ttmuk�dnek a C-ben vagy m�s hagyom�nyos
nyelven �rt k�ddal.
� A C++-nak jelentos .C-kompatibilis. r�szhalmaza van.
23. Fejleszt�s �s tervez�s 969
Az alap�tlet az, hogy a programoz�k egy hagyom�nyos nyelvrol �gy t�rhetnek �t a C+
+-ra,
hogy a nyelvre �tt�rve elosz�r m�g megtartj�k a hagyom�nyos (elj�r�sk�zpont�)
programoz
�si st�lust, azut�n haszn�lni kezdik az elvont adat�br�zol�s m�dszereit, v�g�l .
amikor
m�r elsaj�t�tott�k a nyelvet �s a hozz� tartoz� eszk�z�k haszn�lat�t . �tt�rnek az
objektumorient
�lt (object-oriented) �s az �ltal�nos�tott programoz�sra (generic programming).
Egy
j�l tervezett k�nyvt�rat sokkal k�nnyebb haszn�lni, mint megtervezni �s
elk�sz�teni, �gy
egy kezdo m�r az elorehalad�s korai szakaszaiban is r�szes�lhet az elvont
�br�zol�s haszn
�lat�nak elonyeibol.
Az objektumorient�lt tervez�st �s programoz�st, valamint a C++ fokozatosan t�rt�no
megtanul
�s�t t�mogatj�k azok a szolg�ltat�sok, melyekkel a C++ k�dot keverhetj�k olyan
nyelveken �rt k�ddal, melyek nem t�mogatj�k a C++ elvont adat�br�zol�si �s
objektumorient
�lt programoz�si fogalmait (�24.2.1). Sok fel�let elj�r�sk�zpont� maradhat, mivel
nincs k�zvetlen haszna, ha valamit bonyolultabb� tesz�nk. Sok kulcsfontoss�g�
k�nyvt�rn
�l az �t�ltet�st m�r elv�gezte a k�nyvt�r l�trehoz�ja, �gy a C++ programoz�nak nem
kell
tudnia, mi a t�nyleges megval�s�t�s nyelve. A C-ben vagy hasonl� nyelven �rt
k�nyvt�rak
haszn�lata az �jrahasznos�t�s elsodleges �s kezdetben legfontosabb form�ja a C++-
ban.
A k�vetkezo l�p�s . melyet csak akkor kell elv�gezni, amikor t�nylegesen sz�ks�g
van a kifinomultabb
elj�r�sokra . a C, Fortran vagy hasonl� nyelven �rt szolg�ltat�sok oszt�lyok form
�j�ban val� .t�lal�sa., az adatszerkezetek �s f�ggv�nyek C++ nyelvu
fel�letoszt�lyokba
z�r�sa �ltal. Egy egyszeru p�lda a jelent�s bov�t�s�re az .elj�r�s �s
adatszerkezet. szintj�rol
az elvont adat�br�zol�s szintj�re a �11.12 string oszt�lya. Itt a C karakterl�nc-
�br�zol�s�t �s
szabv�nyos karakterl�nc-f�ggv�nyeit haszn�ljuk fel egy sokkal egyszerubben
haszn�lhat�
karakterl�nc-t�pus l�trehoz�s�ra.
Hasonl� m�dszer haszn�lhat� egy be�p�tett vagy egyedi t�pusnak egy
oszt�lyhierarchi�ba
illeszt�s�re (�23.5.1). Ez lehetov� teszi, hogy a C++-ra k�sz�lt terveket az
elvont adat�br�-
zol�s �s az oszt�lyhierarchi�k haszn�lat�hoz tov�bbfejlessz�k m�g olyan nyelveken
�rt k�d
jelenl�t�ben is, ahonnan hi�nyoznak ezek a fogalmak, sot azzal a megszor�t�ssal
is, hogy az
eredm�ny�l kapott k�d elj�r�sk�zpont� nyelvekbol is megh�vhat� legyen.
970 Tervez�s a C++ seg�ts�g�vel
23.6. Jegyzetek
Ez a fejezet csak �rintette a programoz�s tervez�si �s vezet�si k�rd�seit A
tov�bbi tanulm�-
nyokat seg�tendo �sszegyujt�tt�nk egy r�vid irodalomjegyz�ket. R�szletesebbet
[Booch,
1994] alatt tal�lunk.
[Anderson, 1990] Bruce Anderson �s Sanjiv Gossain: An Iterative Design Model for
Reusable Object-
Oriented Software. Proc. OOPSLA.90. Ottawa, Canada. Egy tervezo �s �jratervezo
modell le�r�sa, p�ld�kkal �s a tapasztalatok t�rgyal�s�val.
[Booch, 1994] Grady Booch: Object-Oriented Analysis and Design with Applications.
Benjamin/Cummings. 1994. ISBN 0-8053-5340-2. R�szletes le�r�st tartalmaz a tervez
�srol, �s egy grafikai jel�l�sm�ddal t�mogatott tervez�si m�dr�l. Sz�mos nagyobb
tervez�si p�lda �ll rendelkez�sre C++ nyelven. Kiv�l� k�nyv, melybol e fejezet is
sokat mer�tett. Az e fejezetben �rintett k�rd�sek j� r�sz�t nagyobb m�lys�gben
t�rgyalja.
[Booch, 1996] Grady Booch: Object Solutions. Benjamin/Cummings. 1996. ISBN 0-8053-
0594-7.
Az objektumk�zpont� rendszerek fejleszt�s�t a vezet�s szemsz�g�bol vizsg�lja.
Sz�mos C++ p�ld�t tartalmaz.
[Brooks, 1982] Fred Brooks: The Mythical man Month. Addison-Wesley. 1982. Ezt a
k�nyvet mindenkinek
p�r �vente �jra el kellene olvasnia! Int�s a nagyk�pus�g ellen. Technikailag
kiss� elj�rt felette az ido, de az emberi, szervezeti �s m�retez�si vonatkoz�sai
idot�ll�ak. 1997-ben kibov�tve �jra kiadt�k. ISBN 1-201-83595-9.
[Brooks, 1987] Fred Brooks: No Silver Bullet. IEEE Computer. Vol 20. No. 4. 1987
�prilis. A nagybani
szoftverfejleszt�s megk�zel�t�seinek �sszegz�se, a r�g�ta aktu�lis figyelmeztet
�ssel: nincsenek csodaszerek (.nincs ez�stgoly�.).
[Coplien, 1995] James O. Coplien �s Douglas C. Schmidt (szerk.): Pattern Languages
of Program
Design. Addison-Wesley. 1995. ISBN 1-201-60734-4.
[De Marco, 1987] T. DeMarco �s T. Lister: Peopleware. Dorset House Publishing Co.
1987. Azon ritka
k�nyvek egyike, melyek az egy�nnek a programfejleszt�sben bet�lt�tt szerep�vel
foglalkoznak. Vezetoknek k�telezo, kellemes esti olvasm�ny, sz�mos ostoba hiba
ellenszer�t tartalmazza.
[Gamma, 1994] Eric Gamma �s m�sok: Design Patterns. Addison-Wesley. 1994. ISBN 0-
201-63361-
2. Gyakorlati katal�gus, mely rugalmas �s �jrahasznos�that� programok k�sz�t�si
m�dszereit tartalmazza, bonyolultabb, j�l kifejtett p�ld�kkal. Sz�mos C++ p�ld�t
tartalmaz.
[Jacobson, 1992] Ivar Jacobson �s m�sok: Object-Oriented Software Engineering.
Addison-Wesley.
1992. ISBN 0-201-54435-0. Alapos �s gyakorlati le�r�s, amely haszn�lati esetek
(use
case, �23.4.3.1) alkalmaz�s�val �rja le a szoftverfejleszt�st ipari k�rnyezetben.
F�lre
�rti a C++ nyelvet, 10 �vvel ezelotti �llapot�val le�rva.
23. Fejleszt�s �s tervez�s 971
[Kerr, 1987] Ron Kerr: A Materialistic View of the Software .Engineering. Analogy.
SIGPLAN
Notices, 1987 m�rcius. Az ebben �s a k�vetkezo fejezetekben haszn�lt hasonlatok
nagyban �p�tenek e cikkre �s a Ron �ltal tartott bemutat�kra, illetve vele
folytatott
besz�lget�sekre.
[Liskov, 1987] Barbara Liskov: Data Abstraction and Hierarchy. Proc. OOPSLA.87
(F�ggel�k).
Orlando, Florida. Az �r�klod�s szerepe az elvont adat�br�zol�sban. Megjegyzend
o, hogy a C++ sz�mos eszk�zt biztos�t a felvetett probl�m�k t�bbs�g�nek megold
�s�ra (�24.3.4).
[Martin, 1995] Robert C. Martin: Designing Object-Oriented C++ Applications Using
the Booch
Method. Prentice-Hall. 1995. ISBN 0-13-203837-4. Rendszerezetten mutatja be,
hogyan
jutunk el a probl�m�t�l a C++ k�dig. Lehets�ges tervez�si m�dokat �s a k�zt
�k val� d�nt�s elveit ismerteti. A t�bbi tervez�ssel foglalkoz� k�nyvn�l
gyakorlatiasabb
�s konkr�tabb. Sz�mos C++ p�ld�t tartalmaz.
[Meyer, 1988] Bertrand Meyer: Object Oriented Software Construction. Prentice
Hall. 1988. Az 1-64.
�s 323-334. oldalakon j� bevezet�st ad az objektumk�zpont� programoz�s �s tervez
�s egy n�zet�rol, sz�mos haszn�lhat� gyakorlati tan�ccsal. A k�nyv marad�k r�sze
az Eiffel nyelvet �rja le. Hajlamos az Eiffelt �s az �ltal�nos elveket
�sszekeverni.
[Parkinson, 1957] C. N. Parkinson: Parkinson.s Law and other Studies in
Administration. Houghton
Mifflin. Boston. 1957. Az egyik leghumorosabb �s legpontosabb le�r�s, melyet a b�-

rokr�ci�r�l �rtak.
[Shlaer, 1988] S. Shlaer �s S. J. Mellor: Object-Oriented Systems Analysis �s
Object Lifecycles.
Yourdon Press. ISBN 0-13-629023-X �s 0-13-629940-7. Az elemz�s, tervez�s �s
programoz�s egy olyan szeml�let�t mutatja be, mely jelentosen elt�r az itt
bemutatott
�l �s a C++ �ltal t�mogatott�l.
[Snyder, 1986] Alan Snyder: Encapsulation and Inheritance in Object-Oriented
Programming
Languages. Proc. OOPSLA.86. Portland, Oregon. Val�sz�nuleg a betokoz�s
(enkapszul�ci�) �s �r�klod�s kapcsolat�nak elso j� le�r�sa. A t�bbsz�r�s �r�klo-
d�st ugyancsak t�rgyalja.
[Wirfs-Brock, 1990] Rebecca Wirfs-Brock, Brian Wilkerson �s Lauren Wiener:
Designing Object-
Oriented Software. Prentice Hall. 1990. Szerepmint�kon alapul� emberk�zpont�
tervez�si m�dszertant �r le CRC k�rty�k haszn�lat�val. A sz�veg (tal�n a
m�dszertan
is) r�szrehajl� a Smalltalk ir�ny�ban.
972 Tervez�s a C++ seg�ts�g�vel
23.7. Tan�csok
[1] Legy�nk tiszt�ban vele, mit akarunk el�rni. �23.3.
[2] Tartsuk �szben, hogy a programfejleszt�s emberi tev�kenys�g. �23.2, �23.5.3.
[3] Hasonlat �ltal bizony�tani �m�t�s. �23.2.
[4] Legyenek meghat�rozott, k�zzelfoghat� c�ljaink. �23.4.
[5] Ne pr�b�ljunk emberi probl�m�kat technikai megold�sokkal orvosolni. �23.4.
[6] Tekints�nk hosszabb t�vra a tervez�sben �s az emberekkel val� b�n�sm�dban.
�23.4.1, �23.5.3.
[7] Nincs m�retbeli als� hat�ra azon programoknak, melyekn�l �rtelme van a k�-
dol�s elotti tervez�snek. �23.2.
[8] �szt�n�zz�k a visszajelz�st. �23.4.
[9] Ne cser�lj�k �ssze a tev�kenys�get a halad�ssal. �23.3, �23.4.
[10] Ne �ltal�nos�tsunk jobban, mint sz�ks�ges, mint amivel kapcsolatban k�zvetlen

tapasztalataink vannak, �s ami tesztelheto. �23.4.1, �23.4.2.


[11] �br�zoljuk a fogalmakat oszt�lyokk�nt. �23.4.2, �23.4.3.1.
[12] A program bizonyos tulajdons�gait nem szabad oszt�lyk�nt �br�zolni.
�23.4.3.1.
[13] A fogalmak k�z�tti hierarchikus kapcsolatokat �br�zoljuk oszt�lyhierarchi�kk
�nt. �23.4.3.1.
[14] Akt�van keress�k a k�z�s von�sokat az alkalmaz�s �s a megval�s�t�s
fogalmaiban
�s az eredm�ny�l kapott �ltal�nosabb fogalmakat �br�zoljuk b�zisoszt�-
lyokk�nt. �23.4.3.1, �23.4.3.5.
[15] M�shol alkalmazott oszt�lyoz�sok nem sz�ks�gszeruen haszn�lhat�ak egy
program �r�kl�si modellj�ben. �23.4.3.1.
[16] Az oszt�lyhierarchi�kat a viselked�s �s a nem v�ltoz� (invari�ns)
tulajdons�gok
alapj�n �p�ts�k fel. �23.4.3.1, �23.4.3.5, �24.3.7.1.
[17] Vizsg�ljuk meg a haszn�lati eseteket. �23.4.3.1.
[18] Haszn�ljunk CRC k�rty�kat, ha sz�ks�ges. �23.4.3.1.
[19] Modellk�nt, �szt�nz�sk�nt �s kiindul�pontk�nt haszn�ljunk l�tezo
rendszereket.
�23.4.3.6.
[20] �vakodjunk a rajzos tervez�stol. �23.4.3.1.
[21] Dobjuk el a protot�pust, mielott teherr� v�lik. �23.4.4.
[22] Sz�moljunk a v�ltoztat�s lehetos�g�vel, �sszpontos�tsunk a rugalmass�gra, a
bo-
v�thetos�gre, a hordozhat�s�gra �s az �jrahasznos�that�s�gra. �23.34.2.
[23] A k�z�ppontba az �sszetevok tervez�s�t helyezz�k. �23.4.3.
[24] A fel�letek az egyes fogalmakat egyetlen elvonatkoztat�si szinten �br�zolj�k.

�23.4.3.1.
[25] A v�ltoztat�s k�sz�b�n tartsuk szem elott a stabilit�st. �23.4.2.
23. Fejleszt�s �s tervez�s 973
[26] A gyakran haszn�lt fel�letek legyenek kicsik, �ltal�nosak �s elvontak, hogy
az
eredeti terv l�nyeg�t ne kelljen m�dos�tani. �23.4.3.2, �23.4.3.5..
[27] T�rekedj�nk a minimalizmusra. Ne haszn�ljunk .ha sz�ks�g lenne r�. tulajdons
�gokat. �23.4.3.2.
[28] Mindig vizsg�ljuk meg egy oszt�ly m�s lehets�ges �br�zol�sait. Ha nincs
k�zenfekv
o alternat�va, az oszt�ly val�sz�nuleg nem k�pvisel tiszta fogalmat. �23.4.3.4.
[29] T�bbsz�r is vizsg�ljuk fel�l �s finom�tsuk mind a tervez�st, mind a
megval�s�t�s
m�dj�t. �23.4, �23.4.3.
[30] Haszn�ljuk az el�rheto legjobb eszk�z�ket a tesztel�shez �s a probl�ma, a
terv,
illetve a megval�s�t�s elemz�s�hez. �23.3, �23.4.1, �23.4.4.
[31] K�s�rletezz�nk, elemezz�nk �s tesztelj�nk a leheto leghamarabb �s
leggyakrabban.
�23.4.4, �23.4.5.
[32] Ne feledkezz�nk meg a hat�konys�gr�l. �23.4.7.
[33] Teremts�nk egyens�lyt a formalit�sok szintje �s a projekt m�rete k�z�tt.
�23.5.2.
[34] Mindenk�ppen b�zzunk meg valakit, aki az �tfog� tervez�s�rt felel. �23.5.2.
[35] Dokument�ljuk, n�pszerus�ts�k �s t�mogassuk az �jrahasznos�that� �sszetevo-
ket. �23.5.1.
[36] Dokument�ljuk a c�lokat �s elveket �pp�gy, mint a r�szleteket. �23.4.6.
[37] Gondoskodjunk oktat�anyagr�l az �j fejlesztok r�sz�re a dokument�ci� r�szek
�nt. $�23.4.6.
[38] Jutalmazzuk �s �szt�n�zz�k a tervek, k�nyvt�rak �s oszt�lyok
�jrahasznos�t�s�t.
�23.5.1.
974 Tervez�s a C++ seg�ts�g�vel
Tervez�s �s programoz�s
.Legyen egyszeru: annyira egyszeru,
amennyire csak lehet . de ne egyszerubb..
(A. Einstein)
A tervez�s �s a programoz�si nyelv . Oszt�lyok . �r�kl�s . T�pusellenorz�s .
Programoz�s . Mit �br�zolnak az oszt�lyok? . Oszt�lyhierarchi�k . F�ggos�gek .
Tartalmaz�s . Tartalmaz�s �s �r�kl�s . Tervez�si kompromisszumok . Haszn�lati
kapcsolatok
. .Beprogramozott. kapcsolatok . Invari�nsok . Hibaellenorz�s felt�telez�sekkel .
Betokoz�s . Komponensek . Sablonok . Fel�let �s megval�s�t�s . Tan�csok
24.1. �ttekint�s
Ebben a fejezetben azt vizsg�ljuk meg, hogy a programoz�si nyelvek . �s maga a C++
. hogyan
t�mogatj�k a tervez�st.
�24.2 Az oszt�lyok, oszt�lyhierarchi�k, a t�pusellenorz�s �s maga a programoz
�s alapveto szerepe
�24.3 Az oszt�lyok �s oszt�lyhierarchi�k haszn�lata, k�l�n�s tekintettel a
programr
�szek k�z�tti f�ggos�gekre
24
�24.4 A komponens . mint a tervez�s alapegys�ge . fogalma, �s a fel�letek fel-
�p�t�s�re vonatkoz� gyakorlati megfigyel�sek
Az �ltal�nosabb tervez�si k�rd�sekkel a 23. fejezetben foglalkoztunk, m�g az
oszt�lyok k�-
l�nb�zo haszn�lati m�djait r�szletesebben a 25. fejezet t�rgyalja.
24.2. A tervez�s �s a programoz�si nyelv
Ha hidat szeretn�nk �p�teni, figyelembe kellene venn�nk az anyagot, amibol
�p�tj�k. A h�d
tervez�s�t erosen befoly�soln� az anyag megv�laszt�sa �s viszont. A kohidakat
m�sk�pp
kell megtervezni, mint az ac�lhidakat vagy a fahidakat �s �gy tov�bb. Nem lenn�nk
k�pesek
kiv�lasztani a h�dhoz a megfelelo anyagot, ha nem tudn�nk semmit a k�l�nb�zo
anyagokr
�l �s haszn�latukr�l. Term�szetesen nem kell �csmesternek lenni ahhoz, hogy valaki

fahidat tervezzen, de ismernie kell a faszerkezetek alapelveit, hogy v�lasztani


tudjon, f�b�l
vagy vasb�l �p�tsen-e hidat. Tov�bb� . b�r nem kell valakinek szem�lyesen
�csmesternek
lennie egy fah�d tervez�s�hez . kell, hogy r�szletesen ismerje a fa tulajdons�gait
�s az �csok
szok�sait.
Ehhez hasonl�an, ahhoz, hogy valamilyen programhoz nyelvet v�lasszunk, t�bb nyelv
ismerete sz�ks�ges, a program egyes r�szeinek sikeres megtervez�s�hez pedig
megleheto-
sen r�szletesen kell ismern�nk a megval�s�t�shoz v�lasztott nyelvet . m�g akkor
is, ha szem
�lyesen egyetlen k�dsort sem �runk. A j� h�dtervezo figyelembe veszi az anyagok
tulajdons
�gait �s azok megfelelo felhaszn�l�s�val n�veli a terv �rt�k�t. A j�
szoftvertervezo
ugyan�gy a v�lasztott programoz�si nyelv eross�geire �p�t �s . amennyire csak
lehet . elker
�li annak olyan haszn�lat�t, ami probl�m�kat okozhat a k�d �r�inak.
Azt gondolhatn�nk, hogy ez a nyelvi k�rd�sek ir�nti �rz�kenys�g term�szetes, ha
csak
egyetlen tervezot vagy programoz�t �rint. Sajnos azonban m�g az �n�ll� programoz�
is .k�-
s�rt�sbe. eshet, hogy a nyelvet . hi�nyos tapasztalata vagy gy�keresen elt�ro
nyelvekben
kialakult programoz�si st�lusa . miatt helytelen�l haszn�lja. Amikor a tervezo �s
a programoz
� nem azonos . �s k�l�n�sen ha szakmai �s kultur�lis h�tter�k k�l�nb�zo ., szinte
bizonyos,
hogy a program hib�s, k�r�lm�nyes vagy nem hat�kony lesz.
Mit ny�jthat teh�t a programoz�si nyelv a tervezonek? Olyan tulajdons�gokat,
melyek lehet
ov� teszik a terv alapfogalmainak k�zvetlen �br�zol�s�t a programban. Ez
megk�nny�ti
976 Tervez�s a C++ seg�ts�g�vel
a k�d meg�r�s�t, k�nnyebb� teszi a tervez�s �s megval�s�t�s k�z�tti k�lcs�n�s
megfelel�s
fenntart�s�t, jav�tja a tervezok �s programoz�k k�z�tti kapcsolattart�st �s jobb
eszk�z�k k�-
sz�t�s�t teszi lehetov� mindk�t csoport t�mogat�s�ra.
A legt�bb tervez�si m�dszer a program k�l�nb�zo r�szei k�zti f�ggos�gekkel
foglalkozik
(rendszerint az�rt, hogy a leheto legkisebbre cs�kkentse sz�mukat �s biztos�tsa,
hogy a f�gg
os�gek pontosan meghat�rozottak �s �tl�that�ak legyenek). Egy nyelv, mely
t�mogatja
a programr�szek kapcsolat�t biztos�t� fel�leteket, k�pes t�mogatni az ezekre �p�lo
tervez
�st is, illetve garant�lni tudja, hogy t�nylegesen csak az elore l�tott f�ggos�gek
l�tezzenek.
Mivel az ilyen nyelvekben sok f�gg�s k�zvetlen�l a k�dban is megjelenik,
beszerezhetok
olyan eszk�z�k, melyek a programot olvasva f�ggos�gi diagramokat k�sz�tenek. Ez
megk
�nny�ti a tervezok �s azok dolg�t, akiknek sz�ks�g�k van a program szerkezet�nek
meg-
�rt�s�re. Egy olyan programoz�si nyelv, mint a C++ felhaszn�lhat� a terv �s a
program k�zti
szakad�k kisebb�t�s�re �s a zavarok �s f�lre�rt�sek k�r�nek k�vetkezetes
szuk�t�s�re.
A C++ legfontosabb fogalma az oszt�ly. A C++ oszt�lyai t�pusok. A n�vterekkel
egy�tt az
oszt�lyok is az adatrejt�s elsodleges eszk�zei. A programok felhaszn�l�i t�pusok
hierarchi-
�ik�nt �p�thetok fel. Mind a be�p�tett, mind a felhaszn�l�i t�pusok a statikusan
ellenorz�tt
t�pusokra vonatkoz� szab�lyoknak engedelmeskednek. A virtu�lis f�ggv�nyek ezen
szab�-
lyok megs�rt�se n�lk�l a fut�si ideju k�t�srol gondoskodnak. A sablonok a
param�terezett
t�pusok tervez�s�t t�mogatj�k, a kiv�telek pedig szab�lyozottabb hibakezel�sre
adnak m�-
dot. A C++ ezen szolg�ltat�sai an�lk�l haszn�lhat�k, hogy t�bbletterhet
jelenten�nek a C
programokhoz k�pest. Ezek a C++ azon elsorendu tulajdons�gai, melyeket a
tervezonek
meg kell �rtenie �s tekintetbe kell vennie. Ezenk�v�l a sz�les k�rben el�rheto
nagy programk
�nyvt�rak . a m�trixk�nyvt�rak, adatb�zis-fel�letek, a grafikus felhaszn�l�i
fel�letek
k�nyvt�rai �s a p�rhuzamoss�got t�mogat� k�nyvt�rak . is erosen befoly�solhatj�k a
tervez
�si d�nt�seket.
Az �jdons�gt�l val� f�lelem n�ha a C++ optim�lisn�l rosszabb felhaszn�l�s�hoz
vezet.
A m�s nyelvekn�l, m�s rendszereken �s alkalmaz�si ter�leteken tanultak helytelen
alkalmaz
�sa ugyanezt eredm�nyezi. A gyenge tervezoeszk�z�k szint�n elronthatj�k a
terveket. �me
�t a leggyakrabban elk�vetett . a nyelvi tulajdons�gok rossz kihaszn�l�s�t �s
korl�toz�sok
felr�g�s�t eredm�nyezo . tervezoi hib�k k�z�l:
1. Az oszt�lyok figyelmen k�v�l hagy�sa �s olyan tervez�s, amely a programoz
�kat arra k�nyszer�ti, hogy csak a C r�szhalmazt haszn�lj�k.
2. A sz�rmaztatott oszt�lyok �s virtu�lis f�ggv�nyek figyelmen k�v�l hagy�sa,
csak az absztrakt adat�br�zol�si m�dszerek r�szhalmaz�nak haszn�lata.
3. A statikus t�pusellenorz�s figyelmen k�v�l hagy�sa �s olyan tervez�s, amely
a programoz�kat arra k�nyszer�ti, hogy ut�nozz�k a dinamikus t�pusellenorz�st.
24. Tervez�s �s programoz�s 977
4. A programoz�s figyelmen k�v�l hagy�sa �s a rendszer olyan megtervez�se,
amely a programoz�k kik�sz�b�l�s�t c�lozza.
5. Az oszt�lyhierarchi�k kiv�tel�vel mindennek a figyelmen k�v�l hagy�sa.
Ezeket a hib�kat �ltal�ban a k�vetkezo h�tt�rrel rendelkezo tervezok k�vetik el:
1. akik kor�bban a C-vel, a hagyom�nyos CASE eszk�zzel, vagy strukt�r�lt tervez
�ssel foglalkoztak,
2. akik kor�bban Ada83, Visual Basic vagy m�s absztrakt �br�zol�st t�mogat�
nyelven dolgoztak,
3. akik Smalltalk vagy Lisp m�lttal rendelkeznek,
4. akik nem muszaki vagy nagyon speci�lis ter�leten dolgoztak, �s
5. akik olyan ter�letrol �rkeztek, ahol eros hangs�lyt kapott a .tiszta.
objektumorient
�lt programoz�s.
Mindegyik esetben k�telkedn�nk kell, vajon j�l v�lasztott�k-e meg a megval�s�t�s
nyelv
�t, a tervez�si m�dszert, illetve hogy a tervezo elsaj�t�totta-e a kez�ben l�vo
eszk�z�k
haszn�lat�t.
Nincs semmi szokatlan vagy sz�gyellni val� az ilyen probl�m�kban. Ezek egyszeruen
olyan
hi�nyoss�gok, amelyek nem optim�lis terveket eredm�nyeznek �s a programoz�kra
felesleges
terheket h�r�tanak. A tervezok ugyanezekkel a probl�m�kkal tal�lj�k magukat
szemben,
ha a tervez�si m�dszer fogalmi fel�p�t�se �szrevehetoen szeg�nyesebb, mint a C++-
�.
Ez�rt ahol lehets�ges, ker�lj�k az ilyen hib�kat.
A k�vetkezo fejteget�s ellenvet�sekre adott v�laszokb�l �ll, mivel ez a val�s�gban
is �gy
szokott lenni.
24.2.1. Az oszt�lyok figyelmen k�v�l hagy�sa
Vegy�k azt a tervez�st, amely figyelmen k�v�l hagyja az oszt�lyokat. Az eredm�ny�l
kapott
C++ program nagyj�b�l egyen�rt�ku az ugyanezen tervez�si folyamat eredm�nyek�nt
kaphat
� C programmal . �s ez a program ugyancsak nagyj�b�l egyen�rt�ku azzal a COBOL
programmal, melyet ugyanezen tervez�si folyamat eredm�nyek�nt kapn�nk. A tervez�s
l�-
nyeg�ben .programoz�si nyelvtol f�ggetlen�l. folyt, a programoz�t arra
k�nyszer�tve, hogy
a C �s a COBOL k�z�s r�szhalmaz�ban k�doljon. Ennek a megk�zel�t�snek vannak elo-
nyei. P�ld�ul az adat �s a k�d szigor� elk�l�n�t�se, ami k�nnyuv� teszi az ilyen
programokhoz
tervezett hagyom�nyos adatb�zisok haszn�lat�t. Mivel egy .minim�lis. programoz�si
nyelvet haszn�lunk, kevesebb tud�st . vagy legal�bb is kevesebb f�le tud�st .
k�vetel�nk
978 Tervez�s a C++ seg�ts�g�vel
meg a programoz�kt�l. Sok programn�l . mondjuk egy hagyom�nyos, szekvenci�lis
adatb
�zist friss�ton�l . ez a gondolkod�sm�d eg�szen �sszeru, az �vtizedek alatt
kifejlesztett hagyom
�nyos elj�r�sok pedig megfeleloek a feladathoz.
Tegy�k fel azonban, hogy a program a rekordokat (vagy karaktereket) a hagyom�nyos
szekvenci�lis feldolgoz�st�l elt�roen kezeli, vagy bonyolultabb . mondjuk, egy
interakt�v
CASE rendszerrol van sz�. Az absztrakt adat�br�zol�s nyelvi t�mogat�s�nak hi�nya,
amit az
oszt�lyok elhanyagol�sa melletti d�nt�s okoz, f�j� lesz. Az eredendo bonyolults�g
az alkalmaz
�sban valahol meg fog mutatkozni, �s ha a rendszert egy szeg�nyes nyelven
k�sz�tett
�k, a k�d nem fogja a tervet k�zvetlen�l t�kr�zni. A program k�dja t�l hossz�
lesz, hi�nyzik
belole a t�pusellenorz�s �s �ltal�ban nem megk�zel�theto seg�deszk�z�k sz�m�ra.
A program fenntart�sa �s k�sobbi m�dos�that�s�ga szempontj�b�l ez igazi r�m�lom.
A probl�m�ra �ltal�nos megold�s, ha eszk�z�ket k�sz�t�nk a tervez�si m�dszer
fogalmainak
t�mogat�s�ra. Ezek az eszk�z�k magasabb szintu �p�tkez�st �s ellenorz�st tesznek
lehet
ov�, ami ellens�lyozza a (sz�nd�kosan legyeng�tett) programoz�si nyelv
gyenges�g�t.
A tervez�si m�dszer teh�t egy egyedi c�l� (�s �ltal�ban test�leti tulajdont
k�pezo) programoz
�si nyelvv� v�lik. Az ilyen programoz�si nyelvek legt�bb esetben csak gyenge
p�tl�kai
a sz�les k�rben el�rheto �ltal�nos c�l� programoz�si nyelveknek, melyeket hozz�juk
val�
tervezoeszk�z�k t�mogatnak.
Az oszt�lyok tervez�sbol val� kihagy�s�nak leg�ltal�nosabb oka egyszeruen a
tehetetlens
�g. A hagyom�nyos programoz�si nyelvek nem t�mogatj�k az oszt�ly fogalm�t, a
hagyom
�nyos tervez�si m�dszerek pedig t�kr�zik ezt a gyenges�get. A tervez�s legt�bbsz�r

a probl�m�k elj�r�sokra bont�s�ra �sszpontosul, melyek a k�v�nt muveleteket


hajtj�k v�gre.
Ezt a 2. fejezetben elj�r�sk�zpont� (procedur�lis) programoz�snak nevezett
fogalmat
a tervez�ssel �sszef�gg�sben �ltal�ban funkcion�lis (f�ggv�nyekre vagy muveletekre
val�)
lebont�snak (functional decomposition) nevezz�k. Gyakori k�rd�s, hogy .tudjuk-e
haszn
�lni a C++-t egy funkcion�lis lebont�son alapul� tervez�si m�dszerrel egy�tt?. A
v�lasz
igen, de a legval�sz�nubb, hogy a C++-t v�g�l egyszeruen csak mint egy jobb C-t
fogjuk
haszn�lni �s a fentebb eml�tett probl�m�kkal fogunk k�nl�dni. �tmeneti idoszakban,
m�r
befejezett tervez�sn�l, vagy olyan alrendszerekn�l, ahol (a bevont szem�lyek
tapasztalat�t
figyelembe v�ve) nem v�rhat�, hogy az oszt�lyok jelentos elonnyel j�rnak, ez
elfogadhat�.
Hosszabb t�von �s �ltal�ban azonban az oszt�lyok haszn�lat�nak . a funkcion�lis
lebont�sb
�l k�vetkezo . ellenz�se nem �sszeegyeztetheto a C++ vagy b�rmely m�s, az
absztrakt �br
�zol�st t�mogat� nyelv hat�kony haszn�lat�val.
A programoz�s elj�r�sk�zpont� �s objektumorient�lt szeml�letei alapvetoen
k�l�nb�znek
�s ugyanarra a probl�m�ra jellemzoen gy�keresen k�l�nb�zo megold�sokat adnak. Ez
24. Tervez�s �s programoz�s 979
a megfigyel�s �pp�gy igaz a tervez�si, mint a megval�s�t�si szakaszra: lehet
�sszpontos�tani
az elv�gzendo tev�kenys�gekre �s az �br�zoland� fogalmakra, de nem lehet egyszerre

mindkettore.
Mi�rt r�szes�tj�k elonyben az .objektumorient�lt tervez�st. a funkcion�lis
lebont�son alapul
� hagyom�nyos tervez�si m�dszerekkel szemben? Elsosorban az�rt, mert az ut�bbi nem

biztos�t elegendo lehetos�get az absztrakt adat�br�zol�sra. Ebbol pedig az


k�vetkezik,
hogy az eredm�ny�l kapott terv
� kev�sb� m�dos�that�,
� eszk�z�kkel kev�sb� t�mogathat�,
� kev�sb� alkalmas p�rhuzamos fejleszt�sre,
� kev�sb� alkalmas p�rhuzamos v�grehajt�sra.
A probl�ma az, hogy a funkcion�lis lebont�s k�vetkezt�ben a l�nyeges adatok
glob�lisak
lesznek, mivel amikor egy rendszer f�ggv�nyekbol �ll� fa szerkezetu, b�rmely adat,
melyre
k�t f�ggv�nynek van sz�ks�ge, mindketto sz�m�ra el�rheto kell, hogy legyen. Ez azt

eredm�nyezi, hogy az .�rdekes. adatok egyre feljebb v�ndorolnak a f�n a gy�k�r


fel� (ne
feledj�k, a sz�m�t�stechnik�ban a f�k mindig a gy�k�rtol lefel� n�vekednek), ahogy
egyre
t�bb f�ggv�ny akar hozz�juk f�rni. Pontosan ugyanez a folyamat figyelheto meg az
egygy
�keru oszt�lyhierarchi�kban, melyekben az .�rdekes. adatok �s f�ggv�nyek
hajlamosak
felfel� v�ndorolni egy gy�k�roszt�ly fel� (�24.4). A probl�m�t �gy oldhatjuk meg,
ha az
oszt�lyok meghat�roz�s�ra �s az adatok .betokoz�s�ra. (encapsulation)
�sszpontos�tunk,
�gy ugyanis a programr�szek k�z�tti f�gg�seket �ttekinthetov� tehetj�k, �s . ami
m�g fontosabb
. cs�kkentj�k a programban levo f�ggos�gek sz�m�t, az�ltal, hogy az adatokra val
� hivatkoz�sok lok�lisak lesznek.
Egyes probl�m�kat azonban a legjobban a megfelelo elj�r�sok meg�r�s�val oldhatunk
meg.
Az objektumorient�lt megk�zel�t�sn�l a tervez�s l�nyege nem az, hogy egyetlen nem
tag
f�ggv�ny se legyen a programban vagy hogy a rendszer egyetlen r�sze se legyen
elj�r�sk
�zpont�. L�nyegesebb, hogy a program k�l�nb�zo r�szeit �gy v�lasszuk el, hogy
jobban
t�kr�zz�k a fogalmakat. Ez �ltal�ban �gy �rheto el a legjobban, ha elsosorban az
oszt�lyok
�s nem a f�ggv�nyek �llnak a tervez�s k�z�ppontj�ban. Az elj�r�sk�zpont� st�lus
haszn�-
lata tudatos d�nt�s kell, hogy legyen, nem pedig az .alap�rtelmez�s.. Az
oszt�lyokat �s elj
�r�sokat az alkalmaz�snak megfeleloen kell haszn�lni, nem egy rugalmatlan
tervez�si
m�dszer .mell�kterm�keik�nt..
980 Tervez�s a C++ seg�ts�g�vel
24.2.2. Az �r�kl�s elker�l�se
Tegy�k fel, hogy a tervez�sn�l nem �p�t�nk az �r�kl�sre. Az eredm�ny�l kapott
program
nem fog �lni a C++ egyik legelony�sebb tulajdons�g�val, mik�zben persze
kihaszn�lja
a C++ sok m�s elony�t a C, Pascal, Fortran, COBOL stb. nyelvekkel szemben. A
leggyakrabban
hangoztatott �rvek . a .tehetetlens�gtol. eltekintve . .az �r�kl�s haszn�lata csak

r�szletk�rd�s a megval�s�t�s sor�n., .az �r�kl�s megs�rti az adatrejt�s elv�t.


�s .az �r�kl�s
megnehez�ti az egy�ttmuk�d�st m�s programokkal..
Az �r�kl�st puszt�n r�szletk�rd�snek tekintve nem vessz�k figyelembe azt, hogy az
oszt
�lyhierarchi�k k�zvetlen�l �br�zolj�k az alkalmaz�si ter�let fogalmai k�z�tti
kapcsolatokat.
M�rpedig az ilyen kapcsolatokat nyilv�nval�v� kell tenni a tervez�sben, hogy a
tervez
ok vitatkozhassanak r�luk.
Elofordulhat az is, hogy az �r�kl�st olyan C++ programr�szekbol z�rjuk ki, amelyek
k�zvetlen
�l �rintkeznek m�s nyelveken �rott k�ddal. Ez azonban nem el�gs�ges ok arra, hogy
a program eg�sz�ben elker�lj�k az �r�kl�st, csup�n a program .k�lvil�g. fel�
mutatott fel
�let�t kell gondosan le�rnunk �s .betokoznunk.. Hasonl�k�ppen, az adatrejt�snek az

�r�kl�s �ltali vesz�lyeztet�se miatti agg�lyok (�24.3.2.1) csak arra adnak okot,
hogy elovigy
�zatosak legy�nk a virtu�lis f�ggv�nyek �s v�dett tagok haszn�lat�val (�15.3), az
�r�klo-
d�s �ltal�nos elker�l�s�re nem.
Sok esetben nem sz�rmazik val�di elony az �r�kl�sbol. A nagyobb programokn�l
azonban
a .nincs �r�kl�s. megk�zel�t�s kev�sb� �ttekintheto �s rugalmatlanabb rendszert
eredm�-
nyez. Az �r�kl�st ekkor csak .tettetj�k., hagyom�nyos nyelvi szerkezetek �s
tervez�si m�-
dok haszn�lat�val. Az is val�sz�nu, hogy az ilyen hozz��ll�s ellen�re az �r�kl�st
m�gis haszn
�lni fogjuk, mert a C++ programoz�k a program t�bb r�sz�ben is meggyozo �rveket
fognak tal�lni az �r�kl�s alap� tervez�s mellett. Ez�rt a .nincs �r�kl�s. csak azt
fogja eredm
�nyezni, hogy a program fel�p�t�se nem lesz k�vetkezetes �s az oszt�lyhierarchi�k
haszn
�lata csak egyes alrendszerekre fog korl�toz�dni.
M�s sz�val, ne legy�nk elfogultak. Az oszt�lyhierarchi�k nem minden j� program
n�lk�l�zhetetlen
r�szei, de sok esetben seg�teni tudnak mind az alkalmaz�s meg�rt�s�ben, mind
egy megold�s kifejez�s�ben. Az a t�ny, hogy az �r�kl�st lehet helytelen vagy
t�lzott m�-
don haszn�lni, ok az �vatoss�gra, de a tilt�sra nem.
24. Tervez�s �s programoz�s 981
24.2.3. A statikus t�pusellenorz�s figyelmen k�v�l hagy�sa
Vegy�nk azt az esetet, amikor a tervez�sn�l elhanyagoljuk a statikus
t�pusellenorz�st. Ezt �ltal
�ban a k�vetkezokkel indokolj�k: .a t�pusok a programoz�si nyelv term�kei.,
.term�szetesebb
objektumokban �s nem t�pusokban gondolkodni. �s .a statikus t�pusellenorz�s arra
k�nyszer�t, hogy t�l kor�n gondoljunk a megval�s�t�s k�rd�seire.. Ez a hozz��ll�s
addig j�,
am�g nem okoz k�rt. Tervez�skor �sszerunek tunhet nem foglalkozni a
t�pusellenorz�s
r�szleteivel, �s az elemz�si �s a korai tervez�si szakaszban �ltal�ban nyugodtan
figyelmen
k�v�l is hagyhatjuk ezeket a k�rd�seket. Az oszt�lyok �s oszt�lyhierarchi�k
azonban nagyon
hasznosak a tervez�sben. Nevezetesen megengedik, hogy a fogalmakat �br�zolhassuk,
kapcsolataikat meghat�rozhassuk, �s seg�tenek, hogy a fogalmakr�l vit�zzunk. A
tervez
�s elorehaladt�val ez a pontos �br�zol�s az oszt�lyokr�l �s fel�leteikrol tett
egyre
prec�zebb meg�llap�t�sok form�j�ban jelentkezik.
Fontos, hogy �szrevegy�k, hogy a pontosan meghat�rozott �s erosen t�pusos
(l�nyeg�ben
t�pusokra �p�to) fel�letek a tervez�s alapveto eszk�zei. A C++ fel�p�t�se is ennek
figyelembe
v�tel�vel t�rt�nt. Egy erosen t�pusos fel�let biztos�tja (egy hat�rig), hogy csak
kompatibilis
programr�szeket lehessen egy�tt ford�tani �s �sszeszerkeszteni, ami lehetov�
teszi,
hogy ezek a programr�szek egym�sr�l viszonylag eros felt�telez�sekkel �lhessenek.
Ezeket
a felt�telez�seket a t�pusrendszer biztos�tja; hat�s�ra cs�kkenteni lehet a fut�si
ideju ellen
orz�st, ez�ltal no a hat�konys�g �s jelentosen r�vid�l a t�bbszem�lyes projektek
integr�l�si szakasza. Val�j�ban az erosen t�pusos fel�letekrol gondoskod�
rendszerek integr
�l�s�ban szerzett nagyon pozit�v tapasztalatok okozz�k, hogy az integr�l�s nem kap

nagy teret e fejezetben.


N�zz�nk egy hasonlatot. Gyakran kapcsolunk �ssze k�l�nb�zo szerkentyuket, a
csatlakoz
�-szabv�nyok sz�ma pedig l�tsz�lag v�gtelen. A dugaszokn�l k�zenfekvo, hogy egyedi

c�lra tervezettek, ami lehetetlenn� teszi k�t szerkezet egym�ssal val�


�sszekapcsol�s�t,
hacsak nem pont erre tervezt�k oket, ez esetben viszont csak a helyes m�don
kapcsolhat
�k �ssze. Nem lehet egy villanyborotv�t egy nagyfesz�lts�gu aljzatba bedugni. Ha
lehetne,
az eredm�ny vagy egy .s�lt villanyborotva. vagy �g�si s�r�l�s lenne. A tervezok
igen tal�-
l�konynak bizonyultak, hogy biztos�ts�k, hogy az �ssze nem illo hardvereszk�z�ket
ne lehessen
egym�ssal �sszedugni. A nem megfelelo dugaszok ellen lehet olyan k�sz�l�keket
k�sz�teni, melyek az aljzataikba dugott k�sz�l�kek nemk�v�natos viselked�s�vel
szemben
megv�dik magukat. J� p�lda erre egy elektromos zavarv�do. Miut�n a dugaszok
szintj�n
nem garant�lhat� a teljes �sszeegyeztethetos�g, alkalmank�nt sz�ks�g�nk van
dr�g�bb v�-
do�ramk�r�kre, melyek dinamikusan alkalmazkodnak a bemenethez vagy v�delmet
ny�jtanak
azzal szemben.
982 Tervez�s a C++ seg�ts�g�vel
A hasonlat majdnem pontos. A statikus t�pusellenorz�s a dugasz megfelelos�g�nek
biztos�-
t�s�val egyen�rt�ku, a dinamikus ellenorz�s pedig az alkalmazkod�/v�do �ramk�rnek
felel
meg. Ha mindk�t ellenorz�s hi�nyzik, az komoly k�rt okozhat. Nagy rendszerekben
mindk�t ellenorz�si form�t haszn�lj�k. A tervez�s korai szakasz�ban �sszeru lehet
egyszer
uen kijelenteni, hogy .ezt a k�t k�sz�l�ket �ssze kell dugni., hamarosan fontos
lesz azonban,
hogy pontosan megmondjuk, hogyan kell �sszedugni oket. Milyen garanci�kat ad
a dugasz a viselked�ssel kapcsolatban? Milyen k�r�lm�nyek k�z�tt fordulhatnak elo
hib�k?
Milyen k�lts�gekkel j�r a megfelelo viselked�s biztos�t�sa?
A statikus t�pusellenorz�s haszn�lata nem korl�toz�dik a .fizikai vil�gra.. A
m�rt�kegys�-
gek (pl. m�ter, kilogramm, m�sodperc) haszn�lata a fizik�ban �s a m�rn�ki
tudom�nyokban
az �ssze nem egyeztetheto elemek �sszekever�s�t akad�lyozza meg.
Amikor a �23.4.3-ban a tervez�s l�p�seit ismertett�k, a t�pusinform�ci�k a 2.
l�p�sben ker
�ltek elo (az 1. l�p�sben rendszerint csak fel�letesen foglalkozunk vel�k), �s a
4. l�p�sben
v�ltak k�zponti k�rd�ss�.
A statikusan ellenorz�tt fel�letek a k�l�nb�zo programoz�i csoportok �ltal
fejlesztett C++
programok egy�ttmuk�d�s�nek fo biztos�t�kai. Ezek dokument�ci�ja (bele�rtve a
haszn�lt
t�pusok�t is) az elsodleges kapcsolattart�si eszk�z az egyes programoz�i csoportok
k�z�tt.
Ezen fel�letek jelentik a tervez�si folyamat legfontosabb eredm�ny�t �s ezek
�llnak a tervez
ok �s programoz�k k�z�tti kapcsolat k�z�ppontj�ban.
A t�pusok elhanyagol�sa a fel�letek kialak�t�s�n�l olyan fel�p�t�shez vezet, amely
hom�lyba
burkolja a program szerkezet�t �s a fut�s idej�ig elhalasztja a hib�k �szlel�s�t.
Tegy�k
fel p�ld�ul, hogy egy fel�letet �nazonos�t� objektumokkal �runk le:
// a p�lda dinamikus t�pusellenorz�st felt�telez statikus ellenorz�s helyett
Stack s; // a verem b�rmilyen t�pus� objektumra hivatkoz� mutat�kat t�rolhat
void f()
{
s.push(new Saab900); // ez egy aut�t�pus
s.push(new Saab37B); // ez egy rep�lot�pus
s.pop()->takeoff(); // j�: a Saab 37B egy rep�log�p
s.pop()->takeoff(); // fut�si ideju hiba: egy aut� nem tud felsz�llni
}
24. Tervez�s �s programoz�s 983
Ez a fel�let (a Stack::push() fel�let�nek) komoly t�legyszerus�t�se, ami statikus
ellenorz�s
helyett dinamikus ellenorz�sre �p�t. Az s verem .rep�log�pek. (Plane) t�rol�s�ra
val�, de
ez a k�dban rejtett maradt, �gy a felhaszn�l� k�teless�ge lesz e k�vetelm�ny
betart�s�t biztos
�tani.
Egy prec�zebb meghat�roz�s . egy sablon �s egy virtu�lis f�ggv�ny a megszor�t�s
n�lk�li dinamikus t�-
pusellenorz�s helyett . a hib�k �szlel�s�t a fut�si idobol �tteszi a ford�t�si
idobe:
Stack<Plane*> s; // a verem Plane-ekre hivatkoz� mutat�kat t�rolhat
void f()
{
s.push(new Saab900); // hiba: a Saab900 nem Plane t�pus�
s.push(new Saab37B);
s.pop()->takeoff(); // rendben: a Saab 37B egy rep�log�p
s.pop()->takeoff();
}
Hasonl� k�rd�st t�rgyal a �16.2.2 pont. A k�l�nbs�g a fut�si ideju dinamikus
ellenorz�s �s
a statikus ellenorz�s k�z�tt jelentos lehet. A dinamikus ellenorz�s rendszerint 3-
10-szer
t�bb feladatot r� a rendszerre. Nem szabad viszont a m�sik v�gletbe sem esni. Nem
lehet
statikus ellenorz�ssel minden hib�t elcs�pni. M�g a legalaposabb statikusan
ellenorz�tt
program is ki van t�ve a hardverhib�k okozta s�r�l�snek. A �25.4.1 pontban tov�bbi
p�ld�t
tal�lhatunk arra, hogy nem lehet t�k�letes statikus ellenorz�st megval�s�tani, az
ide�lis
azonban az, ha a fel�letek nagy t�bbs�ge alkalmaz�sszintu statikus t�pusokat
haszn�l (l�sd
�24.4.2).
Egy m�sik probl�ma, hogy a terv elvont szinten lehet t�k�letesen �sszeru, de
komoly probl
�m�kat okozhat, ha nem sz�mol a haszn�lt eszk�z (eset�nkben a C++) korl�taival.
P�ld�-
ul, egy f() f�ggv�ny, mely egy param�ter�n a turn_right() muveletet hajtja v�gre,
csak akkor
hozhat� l�tre, ha minden param�tere ugyanolyan t�pus�:
class Plane {
// ...
void turn_right();
};
class Car {
// ...
void turn_right();
};
984 Tervez�s a C++ seg�ts�g�vel
void f(X* p) // milyen t�pus kell legyen X?
{
p->turn_right();
// ...
}
Egyes nyelvek (mint a Smalltalk �s a CLOS) megengedik k�t ugyanazon muveletekkel
rendelkez
o t�pus felcser�lt haszn�lat�t, az�ltal, hogy minden t�pust egy k�z�s b�zisoszt�ly
�ltal
kapcsolnak �ssze �s a fut�si idore halasztj�k a n�v felold�s�t. A C++ azonban ezt
(sz�nd
�kosan) csak sablonokkal (template) �s ford�t�si ideju felold�ssal t�mogatja. Egy
nem
sablon f�ggv�ny k�t k�l�nb�zo t�pus� param�tert csak akkor fogad el, ha a k�t
t�pus automatikusan
k�z�s t�pusra konvert�lhat�. Az elobbi p�ld�ban teh�t az X-nek a Plane �s Car
(Aut�) k�z�s b�zisoszt�ly�nak kell lennie (pl. a Vehicle (J�rmu) oszt�lynak).
A C++-t�l idegen fogalmakra �p�lo rendszerek term�szetesen �br�zolhat�k a C++-ban
is,
ha a kapcsolatokra vonatkoz� felt�telez�seket kifejezetten megadjuk. A Plane �s a
Car p�ld
�ul (k�z�s b�zisoszt�ly n�lk�l is) oszt�lyhierarchi�ba helyezheto, ami lehetov�
teszi, hogy
�tadjunk egy Car-t vagy Plane-t tartalmaz� objektumot f(X*)-nek (�25.4.1). Ha
azonban ezt
tessz�k, az gyakran nemk�v�natos mennyis�gu muveletet �s �gyess�get k�vetel, de a
sablonok
hasznos eszk�znek bizonyulhatnak az ilyen lek�pez�sek egyszerus�t�s�re. A tervez
�si fogalmak �s a C++ k�zti rossz megfeleltet�s �ltal�ban .term�szetellenes
kin�zetu. �s
kis hat�konys�g� k�dhoz vezet. A .karbantart�. programoz�k nem szeretik a nyelvben

szokatlan k�dot, amely ilyen rossz megfeleltet�sekbol sz�rmazik.


A tervez�si m�d �s a megval�s�t�shoz haszn�lt nyelv k�zti rossz megfeleltet�s
hasonl�t
a (term�szetes nyelvek eset�ben v�gzett) .sz�r�l sz�ra. ford�t�shoz. P�ld�ul az
angol nyelv
magyar nyelvtannal ugyanolyan neh�zkes, mint a magyar nyelv angol nyelvtannal,
annak
pedig, aki csak a k�t nyelv egyik�t besz�li foly�konyan, mindk�t v�ltozat
�rthetetlen lehet.
A programban l�vo oszt�lyok a tervez�s fogalmainak konkr�t �br�zol�sai.
K�vetkez�sk�ppen,
ha az oszt�lyok k�z�tti kapcsolatok nem vil�gosak, a terv alapfogalmai sem lesznek

azok.
24.2.4. A programoz�s elker�l�se
A programoz�s sok m�s tev�kenys�ghez k�pest k�lts�ges �s elore nehezen felm�rheto
munka, az eredm�ny�l kapott k�d pedig gyakran nem 100%-ig megb�zhat�. A programoz
�s munkaig�nyes �s . sz�mos okb�l . a munk�t �ltal�ban az h�tr�ltatja a
legkomolyabban,
ha egy k�dr�sz nem �tad�sra k�sz. Nos, mi�rt ne k�sz�b�lj�k ki a programoz�st,
mint tev
�kenys�get, eg�sz�ben v�ve?
24. Tervez�s �s programoz�s 985
Sok vezeto sz�m�ra jelentos elonnyel j�rna megszabadulni az arrog�ns, t�lfizetett,
szakmailag
megsz�llott, nem megfelelo �lt�z�ku stb. programoz�kt�l?4. Egy programoz�nak
persze ez a javaslat abszurdnak hangzik. Vannak azonban olyan fontos ter�letek,
melyekn�l
a programoz�snak vannak val�s alternat�v�i. Egyes esetekben lehet k�zvetlen�l egy
magas
szintu �br�zol�sb�l l�trehozni a k�dot; m�sutt a k�pernyon l�vo alakzatok
kezel�s�vel. K�zvetlen
kezel�ssel haszn�lhat� felhaszn�l�i fel�leteket lehet �p�teni annak az idonek t�rt
r�-
sze alatt, ami ugyanezen fel�letnek hagyom�nyos k�ddal val� le�r�s�hoz kellene.
Ugyan�gy
k�dot k�sz�thet�nk adatb�zis-kapcsolatokhoz �s az adatok ilyen kapcsolatok
szerinti hozz�-
f�r�s�hez puszt�n azokb�l a specifik�ci�kb�l, melyek sokkal egyszerubbek, mint a
muveletek
k�zvetlen kifejez�s�hez sz�ks�ges . C++-ban vagy m�s, �ltal�nos c�l� programoz�si
nyelven . �rt k�d. Ilyen le�r�sokb�l/meghat�roz�sokb�l vagy egy k�zvetlen
kezelofel�let seg
�ts�g�vel �llapotautomat�k (state machines) k�sz�thetok, melyek kisebbek,
gyorsabbak �s
jobban muk�dnek, mint amit a legt�bb programoz� k�pes volna alkotni.
Ezek a m�dszerek olyan ter�leteken haszn�lhat�k j�l, ahol erosek az elm�leti
alapok (pl.
matematika, �llapotautomat�k, rel�ci�s adatb�zisok) vagy van egy �ltal�nos v�z,
amelybe
be lehet �gyazni kis programt�red�keket (pl. grafikus felhaszn�l�i fel�letek,
h�l�zatszimul�ci�k, adatb�zis-s�m�k). Az a t�ny, hogy ezen m�dszerek egyes
l�nyeges ter
�leteken (b�r ezek k�re korl�tozott) igen hasznosak lehetnek, elhitethetik vel�nk,
hogy
a hagyom�nyos programoz�s kiv�lt�sa e m�dszerek seg�ts�g�vel .m�r a k�sz�b�n �ll..

Nem �gy van: ha az �br�zol�si m�dszerek az eros elm�leti v�zon t�ll�pnek, a le�r�
nyelv
sz�ks�gszeruen �ppoly bonyolult lesz, mint egy �ltal�nos c�l� programoz�si nyelv.
N�ha elfelejtj�k, hogy a v�z, mely valamely ter�leten lehetos�get ad a hagyom�nyos
programoz
�s kik�sz�b�l�s�re, val�j�ban egy hagyom�nyos m�don tervezett, programozott �s
tesztelt rendszer vagy k�nyvt�r. A C++ �s az e k�nyvben le�rt elj�r�sok egyik
n�pszeru felhaszn
�l�sa is pontosan ilyen rendszerek tervez�se �s �p�t�se.
A legrosszabb eset, ha egy �ltal�nos c�l� nyelv kifejezo k�pess�g�nek csak a
t�red�k�t biztos
�t� kompromisszumos megold�st az eredeti (korl�tozott) alkalmaz�si ter�leten k�v�l
kell
felhaszn�lnunk. A tervezok, akik egy magas szintu modellez�si szemponthoz
ragaszkodnak,
bosszankodnak a bonyolults�g miatt �s olyan rendszerle�r�st k�sz�tenek, melybol
sz�rny
us�ges k�d j�n l�tre, a k�z�ns�ges programoz�si elj�r�sokat haszn�l� programoz�k
pedig
csal�dottak lesznek a nyelvi t�mogat�s hi�nya miatt, �s jobb k�dot csak t�lzott
erofesz�t�ssel �s a magasszintu modellek elhagy�s�val lesznek k�pesek k�sz�teni.
Nem l�tom jel�t annak, hogy a programoz�s, mint tev�kenys�g sikeresen
kik�sz�b�lheto
lenne az olyan ter�leteken k�v�l, amelyeknek j�l megalapozott elm�lete van vagy
amelyekben
az alapveto programoz�si m�dszer egy v�zhoz igazodik. A hat�konys�g mindk�t
esetben
dr�mai m�don lecs�kken, amint elhagyjuk az eredeti v�zat �s �ltal�nosabb c�l� mun-

986 Tervez�s a C++ seg�ts�g�vel


4 Igen. �n programoz� vagyok.
k�t k�s�rel�nk meg elv�gezni. M�st sz�nlelni cs�b�t�, de vesz�lyes dolog.
Ugyanakkor or�lts
�g lenne figyelmen k�v�l hagyni a magas szintu le�r�sokat �s a k�zvetlen kezel�sre
szolg�-
l� elj�r�sokat olyan ter�leteken, ahol azok j�l megalapozottak �s meglehetosen
kiforrottak.
Az eszk�z�k, k�nyvt�rak �s v�zak tervez�se a tervez�s �s programoz�s egyik
legmagasabb
rendu fajt�ja. J�l haszn�lhat� matematikai alap� modellt �p�teni egy alkalmaz�si
ter�letre
az egyik legmagasabb rendu elemz�sfajta. Adni egy eszk�zt, nyelvet, v�zat stb.,
amely az
ilyen munka eredm�ny�t ezrek sz�m�ra teszi el�rhetov�, m�dot ad a programoz�knak
�s
a tervezoknek elker�lni a csapd�t, hogy tucatterm�kek k�sz�toiv� v�ljanak.
A legfontosabb, hogy az adott le�r� rendszer vagy alapk�nyvt�r k�pes legyen
fel�letk�nt
hat�sosan egy�ttmuk�dni egy �ltal�nos c�l� programoz�si nyelvvel. Egy�bk�nt az
adott
v�z mag�ban hordja korl�tait. Ebbol k�vetkezik, hogy azon le�r� vagy k�zvetlen
kezel�st
biztos�t� rendszereknek, melyek megfeleloen magas szintu k�dot k�sz�tenek
valamilyen elfogadott
�ltal�nos c�l� programoz�si nyelven, nagy elony�k van. Az egyedi nyelvek hossz�
t�von csak k�sz�toiknek jelentenek k�nnyebbs�get. Ha a l�trehozott k�d olyan
alacsony
szintu, hogy a hozz�tett �ltal�nos k�dot az absztrakt �br�zol�s elonyei n�lk�l
kell meg�rni,
elvesz�tj�k a megb�zhat�s�got, a m�dos�that�s�got �s a gazdas�goss�got. Egy
k�dk�sz�to
rendszert l�nyeg�ben �gy kell meg�rni, hogy egyes�tj�k a magasabb szintu le�r�sok
�s a magasabb
szintu nyelvek eross�geit. Kihagyni az egyiket vagy a m�sikat annyi, mint
fel�ldozni
a rendszer�p�tok �rdekeit az eszk�zk�sz�tok �rdekei�rt. A sikeres nagy rendszerek
t�bbszint
uek, modul�risak �s folytonosan fejlodnek. K�vetkez�sk�ppen az ilyen rendszerek
megalkot�s�t c�lz� sikeres erofesz�t�sekbe sokf�le nyelvet, k�nyvt�rat, eszk�zt �s
m�dszert
kell bevonni.
24.2.5. Az oszt�lyhierarchi�k kiz�r�lagos haszn�lata
Amikor �gy tal�ljuk, hogy egy �jdons�g t�nyleg muk�dik, gyakran es�nk t�lz�sba, �s
nyakra-
fore azt alkalmazzuk. M�s sz�val, az egyes probl�m�k eset�ben j� megold�sr�l
gyakran
hissz�k, hogy gy�gy�rt jelenthet majdnem minden probl�m�ra. Az oszt�lyhierarchi�k
�s az
objektumokon v�gzett t�bbalak� (polimorf) muveletek sok probl�m�ra adnak j� megold
�st, de nem minden fogalom �br�zolhat� a legjobban egy hierarchia r�szek�nt, �s
nem
minden programkomponens legjobb �br�zol�sa egy oszt�lyhierarchia.
Mi�rt nem? Az oszt�lyhierarchia kapcsolatokat fejez ki oszt�lyai k�z�tt, az
oszt�ly pedig egy
fogalmat k�pvisel. Nos, akkor mi a k�z�s kapcsolat egy mosoly, a CD-meghajt�m,
Richard
Strauss Don Juanj�nak egy felv�tele, egy sor sz�veg, egy muhold, az orvosi
leleteim �s egy
val�sideju �ra k�z�tt? Ha az eg�szet egyetlen hierarchi�ba helyezz�k, mik�zben
egyetlen
k�z�s tulajdons�guk, hogy mindny�jan programoz�si elemek (.objektumok.), csak
kev�s
24. Tervez�s �s programoz�s 987
�rt�kkel b�r�, zavaros rendszert hozunk l�tre (�15.4.5). Ha mindent egyetlen
hierarchi�ba
eroltet�nk, mesters�ges hasonl�s�gok j�hetnek l�tre �s elhom�lyos�thatj�k a val�di
egyez
�seket. Hierarchi�t csak akkor szabad haszn�lnunk, ha az elemz�s fogalmi
k�z�ss�get mutat
ki, vagy ha a tervez�s �s programoz�s fed fel egyez�seket a fogalmak �br�zol�s�ra
haszn
�lt szerkezetekben. Az ut�bbi esetben nagyon figyeln�nk kell arra, hogy
megk�l�nb�ztess�k a val�di (alt�pusok �ltal �r�k�lt nyilv�nos tulajdons�gban
t�kr�zodo)
k�z�ss�get �s a hasznos egyszerus�t�seket (ami priv�t �r�kl�sben t�kr�zodik,
�24.3.2.1).
Ez a gondolatmenet olyan programhoz vezet, melyben sz�mos egym�ssal kapcsolatban
nem l�vo, vagy gyeng�n kapcsol�d� oszt�lyhierarchia van, �s ezek mindegyike
szorosan
�sszekapcsolt fogalmak halmaz�t k�pviseli. Elvezet a konkr�t oszt�ly (�25.2)
fogalm�hoz is,
mely nem hierarchia tagja, mert egy ilyen oszt�lyt hierarchi�ba helyezve
csorb�tan�nk az
oszt�ly teljes�tok�pess�g�t �s f�ggetlens�g�t a rendszer t�bbi r�sz�tol. A
hat�konys�g
szemsz�g�bol egy oszt�lyhierarchia r�sz�t k�pezo oszt�ly legl�nyegesebb
muveleteinek
virtu�lis f�ggv�nyeit kell tekinten�nk, tov�bb� az oszt�ly sz�mos adat�nak priv�t
(private)
helyett v�dettnek (protected) kell lennie. Ez persze sebezhetov� teszi a tov�bbi
sz�rmaztatott
oszt�lyok m�dos�t�saival szemben �s komoly bonyodalmakat okozhat a tesztel�sn�l.
Ott, ahol tervez�si szempontb�l szigor�bb betokoz�st (enkapszul�ci�t) �rdemes
haszn�lni,
nem virtu�lis f�ggv�nyeket �s priv�t adatokat kell alkalmazni (�24.3.2.1).
Ha egy muveletnek egyetlen param�tere van (az, amelyik .az objektumot. jel�li), a
terv �ltal
�ban torzul. Ha t�bb param�terrel egyform�n lehet b�nni, a muvelet egy nem tag
f�ggv
�nnyel �br�zolhat� a legjobban. Ebbol nem k�vetkezik, hogy az ilyen f�ggv�nyeket
glob
�liss� kell tenn�nk, csup�n az, hogy majdnem minden ilyen �n�ll� f�ggv�nynek egy
n�vt�r tagj�nak kell lennie (�24.4).
24.3. Oszt�lyok
Az objektumorient�lt tervez�s �s programoz�s alapveto elve, hogy a program a
val�s�g valamely
r�sz�nek modellje. A programban az oszt�lyok a modellezett .val�s�g.
alapfogalmait,
m�g ezen oszt�lyok objektumai a val�s vil�gbeli objektumokat �s a megval�s�t�s
sor�n
l�trehozott elemeket �br�zolj�k.
Az oszt�lyok k�zti �s egy oszt�ly r�szein bel�li kapcsolatok elemz�se a rendszer
tervez�s�-
ben k�zponti szerepet j�tszik:
988 Tervez�s a C++ seg�ts�g�vel
�24.3.2 �r�kl�si kapcsolatok
�24.3.3 Tartalmaz�si kapcsolatok
�24.3.5 Haszn�lati kapcsolatok
�24.2.4 Beprogramozott kapcsolatok
�24.3.7 Oszt�lyon bel�li kapcsolatok
Mivel a C++ oszt�lyai t�pusok, az oszt�lyok �s az oszt�lyok k�z�tti kapcsolatok
jelentos t�-
mogat�st kapnak a ford�t�program r�sz�rol �s �ltal�ban a statikus elemz�s al�
tartoznak.
Ahhoz, hogy a rendszerben fontos legyen, egy oszt�lynak nemcsak haszn�lhat�
fogalmat
kell �br�zolnia; megfelelo fel�letet is kell ny�jtania. Az ide�lis oszt�ly
alapvetoen csek�ly
m�rt�kben, de pontosan meghat�rozottan f�gg a t�bbi programelemtol, �s olyan
fel�letet
ny�jt, amely azok sz�m�ra csak a felt�tlen�l sz�ks�ges inform�ci�kat biztos�tja
(�24.4.2).
24.3.1. Mit �br�zolnak az oszt�lyok?
Egy rendszerben l�nyeg�ben k�tfajta oszt�ly van:
1. Oszt�lyok, melyek k�zvetlen�l az alkalmaz�si ter�let fogalmait �br�zolj�k; azaz

olyan fogalmakat, melyeket a v�gfelhaszn�l�k haszn�lnak a probl�m�k �s megold


�sok �br�zol�s�ra.
2. Oszt�lyok, melyek a megval�s�t�sb�l k�vetkeznek, vagyis olyan fogalmak,
melyeket
a tervezok �s programoz�k a megval�s�t�si m�dszerek le�r�s�ra haszn�lnak.
N�h�ny oszt�ly, mely a megval�s�t�s .term�ke., �br�zolhat val�s�gos dolgot is. A
rendszer
hardver- �s szoftver-eroforr�sai p�ld�ul alkalmasak arra, hogy egy programban
oszt�lyok
legyenek. (Ez azt a t�nyt t�kr�zi, hogy egy rendszer t�bb n�zopontb�l is
tekintheto.) Ebbol
k�vetkezik, hogy ami valaki sz�m�ra csak a megval�s�t�s r�szletk�rd�se, az m�s
sz�m�ra
a teljes alkalmaz�s lehet. Egy j�l tervezett rendszer olyan oszt�lyokat tartalmaz,
melyek
a rendszer logikailag �n�ll� n�zeteit �br�zolj�k:
1. Felhaszn�l�i szintu fogalmakat �br�zol� oszt�lyok (pl. aut�k �s teheraut�k)
2. Felhaszn�l�i fogalmak �ltal�nos�t�sait �br�zol� oszt�lyok (pl. j�rmuvek)
3. Hardver-eroforr�sokat �br�zol� oszt�lyok (pl. egy mem�riakezelo oszt�ly)
4. Rendszer-eroforr�sokat �br�zol� oszt�lyok (pl. kimeneti adatfolyamok)
5. M�s oszt�lyok megval�s�t�sa haszn�lt oszt�lyok (pl. list�k, v�rakoz�si sorok,
z�rak)
6. Be�p�tett adatt�pusok �s vez�rl�si szerkezetek
24. Tervez�s �s programoz�s 989
Nagyobb rendszerekben kih�v�st jelent a logikailag �n�ll� oszt�lyt�pusok
elv�laszt�sa �s
a k�l�nb�zo elvonatkoztat�si (fogalmi) szintek k�z�tti elk�l�n�t�s fenntart�sa.
Vegy�nk
egy egyszeru p�ld�t, ahol h�rom fogalmi szint�nk van:
1+2 A rendszer alkalmaz�sszintu n�zete
3+4 Annak a g�pnek az �br�zol�sa, amelyen a .modell. fut
5+6 A megval�s�t�s alacsonyszintu (programoz�si nyelvi) n�zete
Min�l nagyobb a rendszer, ann�l t�bb fogalmi szintre van sz�ks�g annak le�r�s�hoz
�s ann�l
nehezebb a szinteket meghat�rozni �s fenntartani. Vegy�k �szre, hogy az ilyen
fogalmi szinteknek
k�zvetlen megfeleloi vannak mind a term�szetben, mind a m�s t�pus�, ember �ltal
l�trehozott rendszerekben. Egy h�z p�ld�ul �gy is tekintheto, mint ami az
al�bbiakb�l �ll:
1. atomok,
2. molekul�k,
3. faanyag �s t�gla,
4. padl�, falak �s mennyezet,
5. szob�k.
Mindaddig, am�g ezek a szintek k�l�n maradnak, fenntarthat� a h�z fogalm�nak
k�vetkezetes
megk�zel�t�se, ha azonban keverj�k oket, abszurdit�sok keletkeznek. P�ld�ul az a
kijelent
�s, hogy .Az �n h�zam t�bbezer kil� sz�nbol, komplex polimerbol, kb. 5000
t�gl�b�l,
k�t f�rdoszob�b�l �s 13 mennyezetbol �ll., ostobas�g. A programok absztrakt
term�szet�-
bol ad�dik, hogy ha egy bonyolult programrendszerrol hasonl� kijelent�st tesz�nk,
azt nem
mindig lehet ilyen egyszeruen minos�teni.
Az alkalmaz�si ter�let valamely fogalm�nak .leford�t�sa. egy tervez�si oszt�lyra
nem egyszer
u, mechanikus muvelet, gyakran jelentos �ttekint�st k�vetel. Vegy�k �szre, hogy
magukat
az adott alkalmaz�si ter�let fogalmait is elvonatkoztat�s seg�ts�g�vel �rjuk le.
P�ld�ul
.ad�fizetok., .szerzetesek. �s .alkalmazottak. a term�szetben nem l�teznek; az
ilyen fogalmak
csup�n c�mk�k, melyeket egy�nekre aggatunk, hogy valamely rendszer szerint oszt�-
lyozzuk oket. A val�s, sot a k�pzelt vil�gb�l (az irodalomb�l, k�l�n�sen a
tudom�nyos fantasztikumb
�l) mer�tett fogalmak gy�keresen megv�ltoznak, amikor oszt�lyokkal �br�zoljuk
azokat. A PC k�pernyoje p�ld�ul nem igaz�n eml�keztet az �r�asztalra, sokszor
m�gis ezzel
a hasonlattal �rj�k le?5, a k�pernyon l�vo ablakok pedig csak halv�nyan
eml�keztetnek
azokra a szerkezetekre, melyek huzatot engednek be az irod�ba. A val�s�g
modellez�s�n�l
nem az a l�nyeg, hogy szolgai m�don k�vess�k azt, amit l�tunk, hanem hogy a
tervez�s kiindul
� pontjak�nt, �szt�nzo forr�sk�nt, �s horgonyk�nt haszn�ljuk azt, melybe
kapaszkodhatunk,
amikor a program megfoghatatlan term�szete azzal fenyeget, hogy legyozi azt a k�-
pess�g�nket, hogy meg�rts�k saj�t programjainkat.
990 Tervez�s a C++ seg�ts�g�vel
5 �n semmik�ppen sem turn�k akkora rendetlens�get a k�pernyom�n.
Egy figyelmeztet�s: a kezdok gyakran nehezen .tal�lj�k meg az oszt�lyokat., de ezt
a probl
�m�t rendszerint hamarosan lek�zdik, .maradand�. k�ros hat�sok n�lk�l. Ezt azonban

gyakran k�veti egy szakasz, amelyben az oszt�lyok . �s azok �r�kl�si kapcsolatai .


l�tsz�-
lag ellenorizhetetlen�l megsokszoroz�dnak, ami hossz� t�von viszont bonyolultabb�
�s �ttekinthetetlenebb
� teheti az eredm�ny�l kapott programot �s ronthatja annak hat�konys�-
g�t. Nem kell minden kis r�szletet k�l�n oszt�llyal �s minden oszt�lyok k�z�tti
kapcsolatot
�r�kl�si kapcsolattal �br�zolni. Pr�b�ljuk �szben tartani, hogy a tervez�s c�lja a
rendszer
megfelelo r�szletess�ggel �s megfelelo elvonatkoztat�si szinten val� modellez�se.
Az egyszer
us�g �s az �ltal�noss�g k�z�tt nem k�nnyu az egyens�lyt megtal�lni.
24.3.2. Oszt�lyhierarchi�k
Vegy�k egy v�ros forgalm�nak szimul�ci�j�t: meg kell hat�roznunk, v�rhat�an mennyi
ido-
re van sz�ks�g, hogy a mentoj�rmuvek rendeltet�si hely�kre �rjenek. Vil�gos, hogy
�br�-
zolnunk kell aut�kat, teheraut�kat, mentoaut�kat, k�l�nf�le tuzolt�j�rmuveket,
rendoraut
�kat, buszokat �s �gy tov�bb. Az �r�kl�s mindenk�ppen szerephez jut, mivel a val�s

vil�gbeli fogalmak nem l�teznek elszigetelten, csak m�s fogalmakkal kapcsolatban.


A kapcsolatok
meg�rt�se n�lk�l nem �rthetj�k meg a fogalmakat sem. K�vetkez�sk�ppen az
a modell, amely nem �br�zol ilyen kapcsolatokat, nem �br�zolja megfeleloen a
fogalmakat
sem. Programjainkban teh�t sz�ks�g�nk van oszt�lyokra a fogalmak �br�zol�s�hoz, de
ez
nem el�g; sz�ks�g�nk van az oszt�lyok kapcsolatainak �br�zol�s�ra is. Az �r�kl�s
kituno
m�dszer hierarchikus kapcsolatok k�zvetlen �br�zol�s�ra. P�ld�nkban a
mentoj�rmuveket
val�sz�nuleg k�l�nlegesnek tekinten�nk �s megk�l�nb�ztetn�nk .aut�szeru. �s
.teheraut
�szeru. j�rmuveket is. Az oszt�lyhierarchia ezek alapj�n �gy n�zne ki:
24. Tervez�s �s programoz�s 991
Police_car
Car
Vehicle
Emergency Truck
Ambulance Fire_engine
Hook_and_ladder
Itt az Emergency a megk�l�nb�ztetett j�rmuvek azon jellemzoit k�pviseli, melyek a
szimul
�ci� szempontj�b�l l�nyegesek: megs�rthet bizonyos forgalmi szab�lyokat,
elsobbs�ge
van az �tkeresztezod�sekben, diszp�cser ir�ny�tja stb.
�me a C++ v�ltozat:
class Vehicle { /* ... */ }; // J�rmu
class Emergency { /* ... */ }; // Megk�l�nb�ztetett
class Car : public Vehicle { /* ... */ }; // Aut�
class Truck : public Vehicle { /* ... */ }; // Teheraut�
class Police_car : public Car , protected Emergency { /* ... */ }; // Rendoraut�
class Ambulance : public Car , protected Emergency { /* ... */ }; // Mentoaut�
class Fire_engine : public Truck , protected Emergency { /* ... */ }; //
Tuzolt�aut�
class Hook_and_ladder : public Fire_engine { /* ... */ }; // L�tr�saut�
Az �r�kl�s a C++-ban k�zvetlen�l �br�zolhat� legmagasabb szintu kapcsolat, �s a
tervez�s
korai szakasz�ban a legnagyobb a szerepe. Gyakran v�laszthatunk, hogy �r�kl�st
vagy tags
�got haszn�lunk-e egy kapcsolat �br�zol�s�ra. N�zz�nk egy m�sik megk�zel�t�st, mit
is jelent
megk�l�nb�ztetett j�rmunek lenni: egy j�rmu megk�l�nb�ztetett, ha villog�
f�nyjelzo-
je van. Ez lehetov� tenn�, hogy �gy egyszerus�ts�k az oszt�lyhierarchi�t, hogy az
Emergency oszt�lyt a Vehicle oszt�ly egyik tagj�val helyettes�tj�k:
Az Emergency oszt�lyt most egyszeruen azon oszt�lyok tagjak�nt haszn�ljuk,
melyeknek
sz�ks�g�k lehet arra, hogy megk�l�nb�ztetett j�rmuk�nt szerepeljenek:
992 Tervez�s a C++ seg�ts�g�vel
Police_car
Car
Vehicle { eptr }
Truck
Ambulance Fire_engine
Hook_and_ladder
class Emergency { /* ... */ };
class Vehicle { protected: Emergency* eptr; /* ... */ }; // jobb: helyes
hozz�f�r�st biztos�t eptrhez
class Car : public Vehicle { /* ... */ };
class Truck : public Vehicle { /* ... */ };
class Police_car : public Car { /* ... */ };
class Ambulance : public Car { /* ... */ };
class Fire_engine : public Truck { /* ... */ };
class Hook_and_ladder : public Fire_engine { /* ... */ };
Itt egy j�rmu akkor megk�l�nb�ztetett, ha a Vehicle::eptr nem nulla. A .sima.
aut�kn�l �s
teheraut�kn�l a Vehicle::eptr kezdo�rt�ke nulla; a t�bbin�l nem nulla:
Car::Car() // Car konstruktor
{
eptr = 0;
}
Police_car::Police_car() // Police_car konstruktor
{
eptr = new Emergency;
}
Az elemek ilyen meghat�roz�sa lehetov� teszi, hogy egy megk�l�nb�ztetett j�rmuvet
k�-
z�ns�ges j�rmuv� alak�tsunk �t �s megford�tva:
void f(Vehicle* p)
{
delete p->eptr;
p->eptr = 0; // T�bb� nem megk�l�nb�ztetett j�rmu
// ...
p->eptr = new Emergency; // Ism�t megk�l�nb�ztetett j�rmu
}
Nos, melyik jobb oszt�lyhierarchia? Az �ltal�nos v�lasz: .Az a program, amely a
val�s vil�g
benn�nket legjobban �rdeklo r�sz�t a legk�zvetlenebb m�don modellezi.. Vagyis a
modellek
k�zti v�laszt�skor a c�l a val�s�g min�l jobb megk�zel�t�se, persze a
hat�konys�gra �s
egyszerus�gre val� t�rekv�s mellett. Eset�nkben a k�nnyu .�tv�ltoz�s. a k�z�ns�ges
�s
megk�l�nb�ztetett j�rmuvek k�z�tt sz�momra nem tunik val�szerunek. A tuzolt�aut�k
�s
a mentoaut�k k�l�nleges c�lra k�sz�lt j�rmuvek, kik�pzett szem�lyzettel;
eligaz�t�suk pedig
egyedi kommunik�ci�s berendez�seket ig�nyel. Ez a szeml�let jelzi, hogy megk�l�n-
24. Tervez�s �s programoz�s 993
b�ztetett j�rmunek lenni alapveto fogalom �s a programban k�zvetlen�l kell
�br�zolni,
hogy seg�tse a t�pusellenorz�st �s m�s eszk�z�k haszn�lat�t. Ha olyan helyet
modellezn
�nk, ahol a j�rmuvek szerepe kev�sb� szigor�an meghat�rozott . mondjuk egy olyan
ter
�letet, ahol mag�nj�rmuveket szok�s a mentoszem�lyzet helysz�nre sz�ll�t�s�ra
haszn�lni
�s ahol a kommunik�ci� elsosorban hordozhat� r�di�kon kereszt�l folyik, m�s
modellez�-
si m�dszer megfelelobb lenne. Azok sz�m�ra, akik a forgalomszimul�ci�t elvontnak
tekintik,
�rdemes lehet r�mutatni, hogy az �r�klod�s �s a tags�g k�zti v�laszt�s szinte
minden
esetben elker�lhetetlen (l�sd a �24.3.3 g�rd�tos�v p�ld�j�t).
24.3.2.1. Oszt�lyhierarchi�n bel�li f�gg�sek
A sz�rmaztatott oszt�lyok term�szetesen f�ggnek b�zisoszt�lyaikt�l. Ritk�bban esik
sz� r�-
la, de az ellenkezoje is igaz lehet?6. Ha egy oszt�lynak van virtu�lis f�ggv�nye,
az oszt�ly
f�gg a belole sz�rmaztatott oszt�lyokt�l, melyek e f�ggv�ny fel�lb�r�l�s�val az
oszt�ly
egyes szolg�ltat�sait biztos�tj�k. Ha mag�nak a b�zisoszt�lynak egy tagja h�vja
meg az oszt
�ly egyik virtu�lis f�ggv�ny�t, megint csak a b�zisoszt�ly f�gg a sz�rmaztatott
oszt�lyait�l,
saj�t megval�s�t�sa miatt. Vegy�k az al�bbi p�ld�t:
class B {
// ...
protected:
int a;
public:
virtual int f();
int g() { int x = f(); return x-a; }
};
Mit csin�l g() ? A v�laszt jelentosen befoly�solja, defini�lja f()-et valamelyik
sz�rmaztatott
oszt�ly. �me egy v�ltozat, mely biztos�tja, hogy g() visszat�r�si �rt�ke 1 lesz:
class D1 : public B {
int f() { return a+1; }
};
�me egy m�sik, amely ki�rja a .Hell�, vil�g!. sz�veget �s null�val t�r vissza:
class D2 : public B {
int f() { cout<<"Hell�, vil�g!\n"; return a; }
};
994 Tervez�s a C++ seg�ts�g�vel
6 Ez a megfigyel�s �gy �sszegezheto: .Az esztelens�g �r�k�lheto. A gyerekeidtol
kapod meg..
A fentiek a virtu�lis f�ggv�nyekkel kapcsolatos egyik legfontosabb dolgot
szeml�ltetik. Mi-
�rt rossz a p�lda? Mi�rt nem �rna programoz� soha ilyet? Az�rt, mert a virtu�lis
f�ggv�nyek
a b�zisoszt�ly fel�let�nek r�szei, �s az oszt�ly feltehetoen a belole sz�rmaz�
oszt�lyok ismerete
n�lk�l is haszn�lhat�. K�vetkez�sk�ppen �gy kell tudnunk meghat�rozni a
b�zisoszt�ly egy objektum�nak elv�rt viselked�s�t, hogy a sz�rmaztatott oszt�lyok
ismerete
n�lk�l is �rhassunk programokat. Minden oszt�ly, mely fel�l�rja (override) a
virtu�lis f�ggv
�nyt, e viselked�snek egy v�ltozat�t kell, hogy le�rja. P�ld�ul a Shape (Alak)
oszt�ly
rotate() (forgat�s) virtu�lis f�ggv�nye egy alakzatot forgat el. A sz�rmaztatott
Circle (K�r)
�s Triangle (H�romsz�g) oszt�lyok rotate() f�ggv�nyeinek a nekik megfelelo t�pus�
objektumokat
kell forgatniuk, k�l�nben megs�rten�nek egy alapveto felt�telez�st a Shape oszt
�lyr�l. A fenti B oszt�lyr�l �s a belole sz�rmaz� D1 �s D2 oszt�lyokr�l ilyesmit
nem t�telezt
�nk fel, ez�rt a p�lda �rtelmetlen. M�g a B, D1, D2, f �s g neveket is �gy
v�lasztottuk
meg, hogy b�rmilyen lehets�ges jelent�st hom�lyban hagyjanak. A virtu�lis
f�ggv�nyek elv
�rt viselked�s�nek meghat�roz�sa az oszt�lyok tervez�s�nek egyik fo szempontja. J�
neveket
v�lasztani az oszt�lyok �s f�ggv�nyek sz�m�ra szint�n fontos . de nem mindig
k�nnyu.
J� vagy rossz-e egy f�gg�s az ismeretlen (esetleg m�g meg sem �rt) sz�rmaztatott
oszt�lyokt
�l? Term�szetesen ez f�gg a programoz� sz�nd�k�t�l. Ha egy oszt�lyt �gy akar
elszigetelni
minden k�lso befoly�st�l, hogy az meghat�rozott m�don viselkedjen, akkor legjobb
elker
�lni a v�dett (protected) tagokat �s a virtu�lis f�ggv�nyeket. Ha azonban egy
v�zat akar
adni, amelyhez egy k�sobbi programoz� (vagy saj�t maga n�h�ny h�ttel k�sobb) k�dot
adhat
hozz�, a virtu�lis f�ggv�nyek haszn�lata ehhez eleg�ns m�dszert jelenthet, a
protected
tagf�ggv�nyek pedig j�l t�mogatj�k az ilyen megold�sokat. Ezt a megold�st
v�lasztottuk az
adatfolyam I/O k�nyvt�rban (�21.6), az Ival_box hierarchia v�gso v�ltozat�n�l
(�12.4.2) pedig
p�ld�t is mutattunk r�.
Ha egy virtu�lis f�ggv�nyt csak a sz�rmaztatott oszt�lyok �ltali k�zvetett
haszn�latra sz�-
nunk, private maradhat. P�ldak�nt vegy�k egy �tmeneti t�r (puffer) egyszeru
sablonj�t:
template<class T> class Buffer {
public:
void put(T); // overflow(T) megh�v�sa, ha az �tmeneti t�r megtelt
T get(); // underflow() megh�v�sa, ha a t�r �res
// ...
private:
virtual int overflow(T);
virtual int underflow();
// ...
};
24. Tervez�s �s programoz�s 995
A put() �s get() f�ggv�nyek a virtu�lis overflow(), illetve underflow()
f�ggv�nyeket h�vj�k
meg. A felhaszn�l� ezen f�ggv�nyek fel�l�r�s�val a k�l�nb�zo ig�nyek szerint egy
sor t�rt
�pust hat�rozhat meg:
template<class T> class Circular_buffer : public Buffer<T> {
int overflow(T); // k�rbel�p, ha teli
int underflow();
// ...
};
template<class T> class Expanding_buffer : public Buffer<T> {
int overflow(T); // megn�veli az �tmeneti t�rat, ha megtelt
int underflow();
// ...
};
Az overflow() �s underflow() f�ggv�nyeknek csak akkor kellene private helyett
protectednek
lenni�k, ha a sz�rmaztatott oszt�lynak sz�ks�ge lenne e f�ggv�nyek k�zvetlen megh
�v�s�ra.
24.3.3. Tartalmaz�si kapcsolatok
Ott, ahol tartalmaz�st haszn�lunk, egy X oszt�ly egy objektum�t k�t fo m�dszerrel
�br�zolhatjuk:
1. Bevezet�nk egy X t�pus� tagot.
2. Bevezet�nk egy X* t�pus� vagy egy X& t�pus� tagot.
Ha a mutat� �rt�ke sohasem v�ltozik, ezek a megold�sok egyen�rt�kuek, kiv�ve a
hat�-
konys�g k�rd�seit �s azt a m�dot, ahogyan konstruktorokat �s destruktorokat �runk:

class X {
public:
X(int);
// ...
};
class C {
X a;
X* p;
X& r;
public:
996 Tervez�s a C++ seg�ts�g�vel
C(int i, int j, int k) : a(i), p(new X(j)), r(*new X(k)) { }
~C() { delete p; delete &r; }
};
Ilyen esetekben rendszerint elonyben kell r�szes�ten�nk mag�nak az objektumnak a
tags�-
g�t (C::a), mert ez biztos�tja a leggyorsabb muk�d�st, ez ig�nyli a legkevesebb
helyet, �s
persze ezt lehet a leggyorsabban le�rni. Kevesebb hiba forr�sa is, mivel a
tartalmaz� �s a tartalmazott
objektum kapcsolata a l�trehoz�s �s megsemmis�t�s szab�lya al� tartozik (�10.4.1,
�12.2.2, �14.4.1, de l�sd m�g: �24.4.2 �s �25.7).
A mutat�t haszn�l� megold�st akkor haszn�ljuk, ha a .tartalmaz�. objektum
�lettartama
alatt a .tartalmazott. objektumra hivatkoz� mutat�t meg kell v�ltoztatnunk:
class C2 {
X* p;
public:
C2(int i) : p(new X(i)) { }
~C2() { delete p; }
X* change(X* q)
{
X* t = p;
p = q;
return t;
}
};
Egy m�sik ok a mutat� tag haszn�lat�ra, hogy meg akarjuk engedni a .tartalmazott.
objektum
param�terk�nt val� szerepl�s�t:
class C3 {
X* p;
public:
C3(X* q) : p(q) { }
// ...
};
Az�ltal, hogy olyan objektumaink vannak, melyek m�s objektumokra hivatkoz�
mutat�kat
tartalmaznak, tulajdonk�ppen egy objektumhierarchi�t hoztunk l�tre. Ez az
oszt�lyhierarchi
�k haszn�lat�t egyszerre helyettes�theti �s kieg�sz�theti. Mint a �24.3.2 .j�rmu.
p�ld�ja
mutatta, gyakran neh�z tervez�skor v�lasztani, hogy egy oszt�lytulajdons�got
b�zisoszt�lyk
�nt vagy tagk�nt �br�zoljunk. Ha fel�l�rt f�ggv�nyeket kell haszn�lnunk, az azt
jelzi, hogy
az elso a jobb v�laszt�s, ha pedig arra van sz�ks�g, hogy egy tulajdons�got t�bb
t�pussal
�br�zolhassunk, val�sz�nuleg c�lszerubb a m�sodik megold�s mellett d�nteni:
24. Tervez�s �s programoz�s 997
class XX : public X { /* ... */ };
class XXX : public X { /* ... */ };
void f()
{
C3* p1 = new C3(new X); // C3 "tartalmaz" egy X objektumot
C3* p2 = new C3(new XX); // C3 "tartalmaz" egy XX objektumot
C3* p3 = new C3(new XXX); // C3 "tartalmaz" egy XXX objektumot
// ...
}
Itt nem lenne megfelelo �br�zol�s, ha C3-at X-bol sz�rmaztatn�nk vagy ha C3-nak
egy X t�-
pus� tagja lenne, mivel a tag pontos t�pus�t kell haszn�lni. Ez a virtu�lis
f�ggv�nyekkel rendelkez
o oszt�lyokn�l fontos, p�ld�ul egy alakzatoszt�lyn�l (�2.6.2) vagy egy absztrakt
halmazoszt
�lyn�l (�25.3).
A mutat� tagokra �p�lo oszt�lyok egyszerus�t�s�re azokban az esetekben, amikor a
tartalmaz
� objektum �lettartama alatt csak egyetlen objektumra hivatkozunk, referenci�kat
haszn�lhatunk:
class C4 {
X& r;
public:
C4(X& q) : r(q) { }
// ...
};
Akkor is sz�ks�g van mutat� �s referencia t�pus� tagokra, amikor egy objektumon
osztozni
kell:
X* p = new XX;
C4 obj1(*p);
C4 obj2(*p); // obj1 �s obj2 most osztoznak az �j XX objektumon
Term�szetesen a k�z�sen haszn�lt objektumok kezel�se k�l�n �vatoss�got k�v�n,
foleg
a p�rhuzamos feldolgoz�st t�mogat� rendszerekben.
24.3.4. Tartalmaz�s �s �r�kl�s
Az �r�kl�si kapcsolatok fontoss�g�nak ismeret�ben nem meglepo, hogy ezeket a
kapcsolatokat
gyakran t�lzottan haszn�lj�k vagy f�lre�rtik. Ha egy D oszt�ly nyilv�nos �s a B
oszt
�lyb�l sz�rmaztatott, gyakran azt mondjuk, hogy egy D val�j�ban egy B (D is a B):
998 Tervez�s a C++ seg�ts�g�vel
class B { /* ... */ };
class D : public B { /* ... */ }; // D is a kind of B: D egyfajta B
�gy is kifejezhetj�k, hogy az �r�kl�s egy is-a kapcsolat, vagy . valamivel
prec�zebben
. hogy egy D val�j�ban egyfajta B (D is a kind of B). Ezzel szemben ha a D oszt�ly
valamelyik
tagja egy B oszt�ly, azt mondjuk, hogy van (have) egy B-je, illetve tartalmaz
(contain) egy B-t:
class D { // D tartalmaz egy B-t
public:
B b;
// ...
};
M�sk�ppen ezt �gy fejezz�k ki, hogy a tags�g egy has-a kapcsolat.
Adott B �s D oszt�lyok eset�ben hogyan v�lasszunk �r�kl�s �s tags�g k�z�tt?
Vegy�nk egy
Rep�log�p-et �s egy Motor-t. A kezdok gyakran k�v�ncsiak, j� �tlet-e egy Rep�log�p
oszt�lyt
a Motor-b�l sz�rmaztatni. Rossz �tlet, mert b�r a rep�log�pnek van motorja, a
rep�log�p
nem motor. Vegy�k figyelembe, hogy egy rep�log�pnek ketto vagy t�bb motorja is
lehet.
Mivel �sszerunek l�tszik . m�g akkor is, ha az adott programban minden Rep�log�p
egymotoros
., haszn�ljunk �r�kl�s helyett tags�got. A .lehet-e neki ketto?. k�rd�s sok
esetben
hasznos lehet, ha k�ts�g mer�l fel. Mint rendszerint, a programok megfoghatatlan
term�-
szete az, ami fontoss� teszi ezt a vizsg�latot. Ha minden oszt�lyt olyan k�nnyen
elk�pzelhetn
�nk, mint a Rep�log�p-et �s a Motor-t, k�nnyen elker�lhetn�nk az olyan nyilv�nval�
t�-
ved�seket, mint egy Rep�log�p sz�rmaztat�sa egy Motor-b�l. Az ilyen t�ved�sek
azonban
igen gyakoriak . k�l�n�sen azokn�l, akik a sz�rmaztat�st egyszeruen egy olyan
elj�r�snak
tekintik, mellyel programoz�si nyelvi szintu szerkezeteket lehet egy�tt haszn�lni.
Annak ellen
�re, hogy az �r�kl�s haszn�lata k�nyelmes �s a k�dot is r�vid�ti, majdnem kiv�tel
n�lk
�l olyan kapcsolatok kifejez�s�re haszn�ljuk, melyeket a tervez�sn�l pontosan
meghat�-
roztunk. Vegy�k a k�vetkezot:
class B {
public:
virtual void f();
void g();
};
class D1 { // D1 tartalmaz egy B-t
public:
B b;
void f(); // nem �rja fel�l a b.f() virtu�lis f�ggv�nyt
};
24. Tervez�s �s programoz�s 999
void h1(D1* pd)
{
B* pb = pd; // hiba: nincs konverzi� D1* -r�l B* -ra
pb = &pd->b;
pb->g(); // B::g() megh�v�sa
pd->g(); // hiba: D1-nek nincs g() tagja
pd->b.g();
pb->f(); // B::f() megh�v�sa (D1::f() nem �rta fel�l)
pd->f(); // D1::f() megh�v�sa
}
Vegy�k �szre, hogy egy oszt�ly nem konvert�lhat� automatikusan (implicit m�don)
saj�t
tagj�v�, �s egy oszt�ly, mely egy m�sik oszt�ly egy tagj�t tartalmazza, nem �rja
fel�l a tag
virtu�lis f�ggv�nyeit. Ez ellent�tes a nyilv�nos sz�rmaztat�ssal:
class D2 : public B { // D2 egy B
public:
void f(); // fel�l�rja a B::f() virtu�lis f�ggv�nyt
};
void h2(D2* pd)
{
B* pb = pd; // rendben: automatikus konverzi� D2* -r�l B* -ra
pb->g(); // B::g() megh�v�sa
pd->g(); // B::g() megh�v�sa
pb->f(); // virtu�lis h�v�s: D2::f() megh�v�sa
pd->f(); // D2::f() megh�v�sa
}
A D2 p�lda a D1 p�ld�hoz k�pest k�nyelmesebb jel�l�st biztos�t, �s ez olyan
t�nyezo, ami
a megold�s t�lzott haszn�lat�hoz vezethet. Eml�keztetni kell arra, hogy ez�rt a
k�nyelem�rt
a B �s a D2 k�zti nagyobb f�gg�ssel kell fizetni (l�sd �24.3.2.1). A D2-rol B-re
t�rt�no automatikus
konverzi�r�l k�l�n�sen k�nnyu megfeledkezni. Hacsak az ilyen konverzi�k
nem tartoznak szorosan a haszn�lt oszt�lyok fogalom�br�zol�s�hoz, ker�lj�k a
public sz�rmaztat
�st. Ha egy oszt�lyt egy fogalom �br�zol�s�ra haszn�lunk, az �r�kl�s pedig is-a
kapcsolatot
fejez ki, szinte biztos, hogy �ppen ilyen konverzi�kra lesz sz�ks�g�nk.
Vannak esetek, melyekben �r�kl�st szeretn�nk, de nem engedhetj�k meg, hogy
konverzi�
t�rt�njen. Vegy�k egy Cfield oszt�ly �r�s�t (controlled field, ellenorz�tt mezo),
amely .
egyebeken k�v�l . fut�si ideju hozz�f�r�s-ellenorz�st biztos�t egy m�sik Field
oszt�ly r�sz�-
re. Elso r�n�z�sre a Cfield meghat�roz�sa a Field-bol val� sz�rmaztat�ssal �ppen
j�nak
l�tszik:
class Cfield : public Field { /* ... */ };
1000 Tervez�s a C++ seg�ts�g�vel
Ez kifejezi, hogy egy Cfield val�j�ban egyfajta Field, k�nyelmesebb jel�l�st
biztos�t, amikor
olyan Cfield f�ggv�nyt �runk, mely a Cfield Field r�sz�nek egy tagj�t haszn�lja �s
. ez a legfontosabb
. megengedi, hogy egy Cfield fel�l�rja a Field virtu�lis f�ggv�nyeit. Az a baj,
hogy
a Cfield*-r�l Field*-ra t�rt�no konverzi�, amit a Cfield deklar�ci�ja sugall,
meghi�s�t minden,
a Field-hez val� hozz�f�r�s ellenorz�s�re ir�nyul� k�s�rletet:
void g(Cfield* p)
{
*p = "asdf"; // a Field el�r�se a Cfield �rt�kad� oper�tor�val vez�relt:
// p->Cfield::operator=("asdf")
Field* q = p; // automatikus �talak�t�s Cfield*-r�l Field*-ra
*q = "asdf"; // hopp�! nincs Cfield-en kereszt�li ellenorz�s
}
Egy megold�s az lehetne, hogy �gy hat�rozzuk meg a Cfield-et, mint amelynek Field
egy
tagja, de ha ezt tessz�k, eleve kiz�rjuk, hogy Cfield fel�l�rhassa Field virtu�lis
f�ggv�nyeit.
Jobb megold�s, ha private �r�klod�st haszn�lunk:
class Cfield : private Field { /* ... */ };
Tervez�si szempontb�l a priv�t sz�rmaztat�s egyen�rt�ku a tartalmaz�ssal, kiv�ve a
fel�l-
�r�s (alkalmank�nt l�nyeges) k�rd�s�t. E m�dszer fontos felhaszn�l�si ter�lete egy
oszt�ly
nyilv�nos sz�rmaztat�sa egy fel�letet le�r� absztrakt b�zisoszt�lyb�l, valamint a
priv�t vagy
v�dett sz�rmaztat�s egy konkr�t oszt�lyb�l, implement�ci� c�lj�b�l (�2.5.4, �12.3,
�25.3).
Mivel a private �s protected sz�rmaztat�sb�l k�vetkezo �r�klod�s nem t�kr�zodik a
sz�rmaztatott
oszt�ly t�pus�ban, n�ha implement�ci�s �r�klod�snek nevezz�k a nyilv�nos
sz�rmaztat
�ssal szemben, melyn�l a b�zisoszt�ly fel�lete �r�klodik �s az alapt�pus
automatikus
konverzi�ja megengedett. Az ut�bbira n�ha mint alt�pusk�sz�t�sre (subtyping) vagy
fel�let-
�r�kl�sre (interface inheritance) hivatkozunk.
�gy is megfogalmazhatjuk ezt, hogy r�mutatunk, egy sz�rmaztatott oszt�ly objektuma
haszn
�lhat� kell legyen minden�tt, ahol b�zisoszt�ly�nak objektumai haszn�lhat�k. Ezt
n�ha
.Liskov-f�le helyettes�t�si elvnek. (Liskov Substitution Principle) nevezik (�23.6
[Liskov,
1987]). A nyilv�nos/v�dett/priv�t megk�l�nb�ztet�s k�zvetlen�l t�mogatja ezt,
amikor
t�bbalak� t�pusokat mutat�kon �s hivatkoz�sokon kereszt�l kezel�nk.
24. Tervez�s �s programoz�s 1001
24.3.4.1. Tag vagy hierarchia?
Hogy tov�bb vizsg�ljuk a tartalmaz�st �s �r�kl�st mag�val von� tervez�si
v�laszt�sokat, vegy
�k egy g�rd�tos�v (scrollbar) �br�zol�s�t egy interakt�v grafikus rendszerben �s
azt, hogyan
kapcsolhatunk egy g�rd�tos�vot egy ablakhoz. K�tf�le g�rd�tos�vra van sz�ks�g�nk:
v�zszintesre �s f�ggolegesre. Ezt k�t t�pussal �br�zolhatjuk .
Horizontal_scrollbar �s
Vertical_scrollbar . vagy egyetlen olyan Scrollbar t�pussal, mely param�terk�nt
megkapja,
v�zszintes vagy f�ggoleges-e. Az elobbi v�laszt�s k�vetkezm�nye, hogy egy harmadik
t�-
pusra, a sima Scrollbar-ra is sz�ks�g van, mint a k�t g�rd�tos�v-t�pus
alapt�pus�ra. Az ut�bbi
v�laszt�s azt eredm�nyezi, hogy egy k�l�n param�tert kell haszn�lnunk �s �rt�keket
kell
v�lasztanunk a k�t t�pus �br�zol�s�ra:
enum Orientation { horizontal, vertical };
V�laszt�sunk meghat�rozza, milyen m�dos�t�sok sz�ks�gesek a rendszer bov�t�s�hez.
Lehet,
hogy be kell vezetn�nk egy harmadik t�pus� g�rd�tos�vot. Eredetileg �gy
gondolhattuk,
el�g k�tf�le g�rd�tos�v (.egy ablaknak v�g�l is csak k�t dimenzi�ja van.), de
szinte
minden esetben lehets�gesek bov�t�sek, melyek az �jratervez�s sz�ks�gess�g�t
vonj�k maguk
ut�n. P�ld�ul lehet, hogy valaki a k�t g�rd�tos�v helyett egy .navig�l� gombot.
szeretne
haszn�lni. Egy ilyen gomb k�l�nb�zo ir�ny� g�rget�st okozna, aszerint, hol nyomja
meg
a felhaszn�l�. Fel�l k�z�pen nyomva .felfel�. g�rget, bal oldalon k�z�pen
nyomva .balra.,
m�g a bal felso sarkot nyomva .balra felfel�.. Az ilyen gombok nem szokatlanok.
A g�rd�tos�vok tov�bbfejlesztett v�ltozatainak tekinthetok, �s k�l�n�sen illenek
olyan
programokhoz, melyekben a g�rgetett adatok nem csup�n sz�vegek, hanem k�pek.
Ha egy programba, melyben egy h�rom g�rd�tos�vb�l �ll� oszt�lyhierarchia van, egy
navig
�l� gombot tesz�nk, l�tre kell hoznunk hozz� egy �j oszt�lyt, de a g�rd�tos�v r�gi
k�dj�t
nem kell m�dos�tanunk:
1002 Tervez�s a C++ seg�ts�g�vel
Horizontal_scrollbar Vertical_scrollbar Navigation_button
Scrollbar
Ez a .hierarchikus. megold�s sz�p oldala.
Ha param�terben adjuk meg a g�rget�s ir�ny�t, a g�rd�tos�v-objektumokban
t�pusmezoknek,
a g�rd�tos�v-tagf�ggv�nyek k�dj�ban pedig switch utas�t�soknak kell szerepelni�k.
Ez
azt jelenti, hogy v�lasztanunk kell, deklar�ci�k vagy k�d �ltal fejezz�k ki a
rendszer szerkezet
�nek ezt a von�s�t. Az elobbi n�veli a statikus ellenorz�s fok�t �s azt az
adatmennyis
�get, melyet az eszk�z�knek fel kell dolgozniuk. Az ut�bbi a fut�si idore
halasztja el a d�nt
�seket �s az egyes f�ggv�nyek m�dos�t�s�val an�lk�l tesz lehetov� v�ltoztat�sokat,
hogy
befoly�soln� a rendszer �tfog� szerkezet�t a t�pusellenorzo �s m�s eszk�z�k
szempontj�-
b�l. A legt�bb helyzetben azt javaslom, haszn�ljunk oszt�lyhierarchi�t a fogalmak
kapcsolatainak
k�zvetlen modellez�s�re.
Az egyetlen t�pust haszn�l� megold�s megk�nny�ti a g�rd�tos�v fajt�j�t le�r�
adatok t�rol�-
s�t �s tov�bb�t�s�t:
void helper(Orientation oo)
{
// ...
p = new Scrollbar(oo);
// ...
}
void me()
{
helper(horizontal);
// ...
}
Ez az �br�zol�sm�d megk�nny�ti a g�rget�s ir�ny�nak fut�si idoben t�rt�no
megv�ltoztat�-
s�t. Nem val�sz�nu, hogy ennek itt nagy jelentos�ge van, de m�s hasonl� p�ld�k
eset�ben
fontos lehet. A l�nyeg, hogy mindig v�lasztani kell, �s a v�laszt�s gyakran nem
k�nnyu.
24.3.4.2. Tartalmaz�s vagy hierarchia?
Most vegy�k azt a k�rd�st, hogyan kapcsoljunk egy g�rd�tos�vot egy ablakhoz. Ha
egy
Window_with_scrollbar-t �gy tekint�nk, mint ami egyszerre Window �s Scrollbar is,
valami
ilyesmit kapunk:
class Window_with_scrollbar : public Window, public Scrollbar {
// ...
};
24. Tervez�s �s programoz�s 1003
Ez megengedi, hogy egy Window_with_scrollbar �gy is viselkedhessen, mint egy
Scrollbar
�s �gy is, mint egy Window, de arra k�nyszer�t, hogy az egyetlen t�pust haszn�l�
megold�st
haszn�ljuk.
M�sr�szt, ha a Window_with_scrollbar-t egy Scrollbar-ral rendelkezo Window-nak
tekintj
�k, valami ilyesmit kapunk:
class Window_with_scrollbar : public Window {
// ...
Scrollbar* sb;
public:
Window_with_scrollbar(Scrollbar* p, /* ... */) : Window(/* ...*/), sb(p) { /* ...
*/ }
// ...
};
Ez megengedi, hogy a g�rd�tos�v-hierarchia megold�st haszn�ljuk. Ha a g�rd�tos�vot
param
�terben adjuk �t, az ablak figyelmen k�v�l hagyhatja annak pontos t�pus�t. Sot,
egy
Scrollbar-t ahhoz hasonl�an is �tadhatunk, ahogy az Orientation-t a �24.3.4.1
pontban. Ha
arra van sz�ks�g, hogy a Window_with_scrollbar g�rd�tos�vk�nt muk�dj�n, hozz�tehet
�nk egy konverzi�s muveletet:
Window_with_scrollbar::operator Scrollbar&()
{
return *sb;
}
�n azt r�szes�tem elonyben, ha az ablak a g�rd�tos�vot tartalmazza. K�nnyebb egy
olyan
ablakot elk�pzelni, melynek g�rd�tos�vja van, mint egy olyat, amely amellett, hogy
ablak,
m�g g�rd�tos�v is. Kedvenc m�dszerem az, hogy olyan g�rd�tos�vot hat�rozok meg,
amely
egy k�l�nleges ablak, �s ezt tartalmazza egy, a g�rd�tos�v-szolg�ltat�sokat
ig�nylo ablak.
Ez a tartalmaz�s haszn�lat�t ig�nyli, de emellett sz�l egy m�sik �rv is, mely a
.lehet neki
ketto is. szab�lyb�l k�vetkezik (�24.3.4). Mivel nincs logikus indok, mi�rt ne
lehetne egy
ablaknak k�t g�rd�tos�vja (val�j�ban sok ablaknak van v�zszintes �s f�ggoleges
is), nem k�-
telezo a Window_with_scrollbar-t a Scrollbar-b�l sz�rmaztatni.
Vegy�k �szre, hogy ismeretlen oszt�lyb�l nem lehet sz�rmaztatni, ford�t�skor
ismerni kell a
b�zisoszt�ly pontos t�pus�t (�12.2). M�sr�szt, ha egy oszt�ly egy tulajdons�g�t
param�terben
adjuk �t konstruktor�nak, akkor valahol az oszt�lyban kell, hogy legyen egy tag,
mely
azt �br�zolja. Ha azonban ez a tag egy mutat� vagy referencia, akkor a taghoz
megadott
oszt�lyb�l sz�rmaztatott oszt�ly egy objektum�t is �tadhatjuk. Az elozo p�ld�ban
p�ld�ul
a Scrollbar* sb tagja mutathat egy olyan Scrollbar t�pusra, mint a
Navigation_button, amely
a Scrollbar* felhaszn�l�ja sz�m�ra ismeretlen.
1004 Tervez�s a C++ seg�ts�g�vel
24.3.5. Haszn�lati kapcsolatok
Annak ismerete, hogy egy oszt�ly milyen m�s oszt�lyokat haszn�l �s milyen m�don,
gyakran
l�tfontoss�g� a programszerkezet kifejez�se �s meg�rt�se szempontj�b�l. Az ilyen
f�gg
�seket a C++ csak rejtetten (implicit m�don) t�mogatja. Egy oszt�ly csak olyan
elemeket
haszn�lhat, melyeket (valahol) deklar�ltak, de azok felsorol�sa nem szerepel a C++
forr�sk
�dban. Eszk�z�k sz�ks�gesek (vagy megfelelo eszk�z�k hi�ny�ban gondos elolvas�s)
az
ilyen adatok kinyer�s�hez. A m�dok, ahogy egy X oszt�ly egy Y oszt�lyt
felhaszn�lhat,
t�bbf�lek�ppen oszt�lyozhat�k. �me egy lehets�ges v�ltozat:
� X haszn�lja az Y nevet.
� X haszn�lja Y-t.
. X megh�vja Y egy tagf�ggv�ny�t.
. X olvassa Y egy tagj�t.
. X �rja Y egy tagj�t.
� X l�trehoz egy Y-t.
. X lefoglal egy auto vagy static Y v�ltoz�t.
. X a new seg�ts�g�vel l�trehoz egy Y-t.
� veszi egy Y m�ret�t.
Az utols� az�rt ker�lt k�l�n kateg�ri�ba, mivel ehhez ismerni kell az oszt�ly
deklar�ci�j�t,
de f�ggetlen a konstruktorokt�l. Az Y nev�nek haszn�lata szint�n k�l�n m�dszert
jelent,
mert ehhez �nmag�ban . p�ld�ul egy Y* deklar�l�s�n�l vagy Y-nak egy k�lso f�ggv�ny

deklar�ci�j�ban val� eml�t�s�n�l . egy�ltal�n nem kell hozz�f�rni Y


deklar�ci�j�hoz (�5.7):
class Y; // Y az oszt�ly neve
Y* p;
extern Y f(const Y&);
Gyakran fontos, hogy k�l�nbs�get tegy�nk egy oszt�ly fel�let�nek (az oszt�ly
deklar�ci�-
j�nak) �s az oszt�ly megval�s�t�s�nak f�gg�sei k�z�tt. Egy j�l tervezett
rendszerben az
ut�bbinak �ltal�ban j�val t�bb f�ggos�ge van, �s azok egy felhaszn�l� sz�m�ra
sokkal kev
�sb� �rdekesek, mint az oszt�ly deklar�ci�j�nak f�gg�sei (�24.4.2). A tervez�skor
arra kell
t�rekedn�nk, hogy a fel�letek f�gg�seinek sz�m�t cs�kkents�k, mert ezekbol az
oszt�ly
felhaszn�l�inak f�gg�sei lesznek (�8.2.4.1, �9.3.2, �12.4.1.1 �s �24.4).
A C++ nem k�v�nja meg egy oszt�ly k�sz�toj�tol, hogy r�szletesen le�rja, milyen
m�s oszt�-
lyokat �s hogyan haszn�l fel. Ennek egyik oka, hogy a legjelentosebb oszt�lyok oly
sok m�s
oszt�lyt�l f�ggnek, hogy az olvashat�s�g miatt ezen oszt�lyok r�vid�tett
felsorol�s�ra . p�ld
�ul egy #include utas�t�sra . lenne sz�ks�g. A m�sik ok, hogy az ilyen f�gg�sek
oszt�lyo-
24. Tervez�s �s programoz�s 1005
z�sa nem a programoz�si nyelv k�rd�se. Az, hogy a .haszn�lja. (use) t�pus�
f�gg�seket
pontosan hogyan szeml�lj�k, f�gg a tervezo, a programoz� vagy az eszk�z c�lj�t�l,
az pedig,
hogy mely f�gg�sek az �rdekesek, f�gghet az adott fejlesztok�rnyezettol is.
24.3.6. Beprogramozott kapcsolatok
Egy programoz�si nyelv nem k�pes k�zvetlen�l t�mogatni . �s nem is szabad, hogy
t�mogassa
. minden tervez�si m�dszer minden fogalm�t. Hasonl�k�ppen egy tervez�si nyelvnek
sem c�lszeru t�mogatnia minden programoz�si nyelv minden tulajdons�g�t. Egy tervez
�si nyelv legyen gazdagabb �s kev�sb� t�rodj�n a r�szletekkel, mint amennyire ez
egy
rendszerprogramoz�si nyelvn�l sz�ks�ges. Megford�tva, egy programoz�si nyelvnek
k�pesnek
kell lennie t�bbf�le tervez�si filoz�fia t�mogat�s�ra, k�l�nben csorbul az
alkalmazhat
�s�ga.
Ha egy programoz�si nyelvben nincs lehetos�g egy tervez�si fogalom k�zvetlen
�br�zol�-
s�ra, nem szabad hagyom�nyos lek�pez�st alkalmazni a tervez�si szerkezetek �s a
programoz
�si nyelv szerkezetei k�z�tt. A tervez�si m�dszer p�ld�ul haszn�lhatja a deleg�l�s

(delegation) fogalm�t, vagyis a terv meghat�rozhatja, hogy minden olyan muveletet,


amely
A oszt�lyhoz nincs defini�lva, egy p mutat� �ltal mutatott B oszt�lybeli objektum
szolg�ltasson.
A C++ ezt nem tudja k�zvetlen�l kifejezni, de rendelkez�sre �llnak olyan
szerkezetek,
melyek seg�ts�g�vel k�nnyu elk�pzelni egy programot, mely a fogalomb�l k�dot hoz
l�tre.
Vegy�k az al�bbiakat:
class B {
// ...
void f();
void g();
void h();
};
class A {
B* p;
// ...
void f();
void ff();
};
Annak meghat�roz�sa, hogy A oszt�ly az A::p mutat�n kereszt�l �truh�zza
(.deleg�lja.)
a feladatot B-re, ilyen k�dot eredm�nyezne:
1006 Tervez�s a C++ seg�ts�g�vel
class A {
B* p; // deleg�l�s p-n kereszt�l
// ...
void f();
void ff();
void g() { p->g(); } // g() deleg�l�s
void h() { p->h(); // h() deleg�l�s
};
Egy programoz� sz�m�ra nyilv�nval�, hogy mi t�rt�nik itt, de vil�gos, hogy egy
tervez�si
fogalom k�ddal val� ut�nz�sa kevesebb, mint valamely .egy az egyhez.
megfeleltet�s.
Az ilyen .beprogramozott. kapcsolatokat a programoz�si nyelv nem .�rti. olyan j�l,
ez�rt
nehezebb azokat eszk�z�kkel t�mogatni. A szabv�nyos eszk�z�k p�ld�ul nem ismern�k
fel, hogy az A::p-n kereszt�l A feladat�t ruh�ztuk �t B-re, nem pedig m�s c�lra
haszn�ltuk
a B*-ot.
Ahol csak lehets�ges, haszn�ljunk .egy az egyhez. lek�pez�st a tervez�s �s a
programoz�-
si nyelv fogalmai k�z�tt. Az ilyen lek�pez�s biztos�tja az egyszerus�get, �s azt,
hogy a program
val�ban t�kr�zi a tervez�st, hogy a programoz�k �s az eszk�z�k hasznos�thass�k
annak
fogalmait. A beprogramozott kapcsolatokkal rendelkezo oszt�lyok kifejez�s�t a
nyelv
konverzi�s muveletekkel seg�ti. Ez azt jelenti, hogy az X::operator Y() konverzi�s
oper�tor
meghat�rozza, hogy ahol elfogadhat� egy Y, ott haszn�lhatunk egy X-et is
(�11.4.1).
A Y::Y(X) konstruktor ugyanezt a kapcsolatot fejezi ki. Vegy�k �szre, hogy a
konverzi�s
oper�torok (�s a konstruktorok) �j objektumokat hoznak l�tre, nem pedig l�tezo
objektumok
t�pus�t v�ltoztatj�k meg. Egy konverzi�s f�ggv�ny deklar�l�sa Y-ra nem m�s, mint
egy
Y-t visszaad� f�ggv�ny rejtett alkalmaz�s�nak egy m�dja. Mivel a konstruktorok �s
konverzi�s oper�torok �ltal defini�lt �talak�t�sok automatikus alkalmaz�sa csal�ka
lehet,
n�ha hasznos, ha a terven bel�l k�l�n elemezz�k azokat.
Fontos, hogy biztos�tsuk, hogy egy program konverzi�s diagramjai ne tartalmazzanak
ciklusokat.
Ha tartalmaznak, az ebbol ad�d� t�bb�rtelmus�gek megakad�lyozz�k, hogy a
ciklusokban
szereplo t�pusokat egy�tt haszn�lhassuk:
class Rational;
class Big_int {
public:
friend Big_int operator+(Big_int,Big_int);
operator Rational();
// ...
};
24. Tervez�s �s programoz�s 1007
class Rational {
public:
friend Rational operator+(Rational,Rational);
operator Big_int();
// ...
};
A Rational �s a Big_int t�pusok nem fognak olyan g�rd�l�kenyen egy�ttmuk�dni, mint

rem�ln�nk:
void f(Rational r, Big_int i)
{
g(r+i); // hiba, t�bb�rtelmu: operator+(r,Rational(i)) vagy operator+
(Big_int(r),i) ?
g(r+Rational(i)); // explicit felold�s
g(Big_int(r)+i); // m�sik explicit felold�s
}
Az ilyen .k�lcs�n�s. konverzi�kat elker�lhetj�k, ha legal�bb n�h�nyat k�z�l�k
explicitt�
tesz�nk. A Big_int �talak�t�sa Rational-l� p�ld�ul konverzi�s oper�tor helyett
defini�lhat�
lett volna make_Rational()-k�nt, az �sszead�st pedig g(Big_int�,i)-re lehetett
volna feloldani.
Ahol nem ker�lhetok el az ilyen .k�lcs�n�s. konverzi�k, a keletkezett ellentmond�-

sokat vagy explicit �talak�t�sokkal (l�sd fent), vagy k�toperandus� oper�torok


(pl. +) t�bb
k�l�n v�ltozat�nak deklar�l�s�val kell feloldanunk.
24.3.7. Oszt�lyon bel�li kapcsolatok
Az oszt�lyok a megval�s�t�s m�dj�t (�s a rossz megold�sokat) csaknem teljes
eg�sz�ben elrejthetik
. �s n�ha el is kell rejteni�k. A legt�bb oszt�ly objektumainak azonban szab�lyos
szerkezete van �s oly m�don kezelheto, amit meglehetosen k�nnyu le�rni. Egy
oszt�ly valamely
objektuma alobjektumok (tagok) gyujtem�nye, melyek k�z�l sok m�s objektumokra
mutat vagy hivatkozik. Egy objektum teh�t �gy tekintheto, mint egy objektumfa
gy�kere,
a benne szereplo objektumok pedig mint egy .objektum-hierarchia. alkot�elemei, ami

az oszt�lyhierarchia kieg�sz�toje (l�sd 25.3.2.1). Vegy�nk p�ld�ul egy nagyon


egyszeru
String-et:
class String {
int sz;
char* p;
public:
String(const char* q);
~String();
// ...
};
1008 Tervez�s a C++ seg�ts�g�vel
Egy String objektum grafikusan �gy �br�zolhat�:
24.3.7.1. Invari�nsok
A tagok �s a tagok �ltal hivatkozott objektumok �rt�keit gyujton�ven az objektum
�llapot
�nak (vagy egyszeruen �rt�k�nek) nevezz�k. Egy oszt�ly tervez�s�n�l fontos az
objektumok
pontosan defini�lt �llapotba hoz�sa (kezdeti �rt�kad�s/l�trehoz�s), ezen �llapot
fenntart
�sa a muveletek v�grehajt�sa sor�n, �s v�g�l az objektumok megfelelo
megsemmis�t�se.
Az a tulajdons�g, amely pontosan defini�lt� teszi egy objektum �llapot�t, az
objektum invari
�nsa (�llapotbiztos�t�ja, invariant).
A kezdeti �rt�kad�s c�lja teh�t az objektumot abba az �llapotba helyezni, amelyet
az
invari�ns le�r. Ezt �ltal�ban egy konstruktorral v�gezz�k. Egy oszt�lyon v�gzett
minden mu-
velet felt�telezheti, hogy bel�p�skor �rv�nyesnek tal�lja az �llapotot (vagyis
hogy az invari
�ns logikai �rt�ke igaz) �s kil�p�skor ugyanez a helyzet �ll fenn. Az invari�nst
v�g�l
a destruktor �rv�nytelen�ti, az objektum megsemmis�t�s�vel. A String::String(const
char*)
konstruktor p�ld�ul biztos�tja, hogy p egy legal�bb sz+1 elemu t�mbre mutat, ahol
sz-nek
�rtelmes �rt�ke van �s p[sz]==0. Ezt az �ll�t�st minden karakterl�nc-muveletnek
.igaznak.
kell hagynia.
Az oszt�lytervez�sben a legt�bb szak�rtelem ahhoz kell, hogy az adott oszt�lyt
el�g egyszer
uv� tegy�k, hogy haszn�lhat�, egyszeruen kifejezheto invari�nssal val�s�thassuk
meg.
El�g k�nnyu kijelenteni, hogy minden oszt�lynak sz�ks�ge van invari�nsra. Ami
neh�z, egy
haszn�lhat� invari�nssal .elohozakodni., amely k�nnyen �rtheto �s nem j�r
elfogadhatatlan
megszor�t�sokkal a k�sz�tore vagy a muveletek hat�konys�g�ra vonatkoz�an. Vegy�k
�szre, hogy az .invari�nst. itt egy olyan k�dr�szlet megjel�l�s�re haszn�ljuk,
melyet futtathatunk
egy objektum �llapot�nak ellenorz�s�re. Vil�gos, hogy be lehetne vezetni egy
szigor
�bb, .matematikaibb. �s . bizonyos k�rnyezetben . megfelelobb fogalmat is. Az
invari
�ns, ahogyan itt t�rgyaljuk, az objektum �llapot�nak egyfajta gyakorlati . �s
emiatt
�ltal�ban gazdas�gos, de logikailag nem t�k�letes . ellenorz�se.
24. Tervez�s �s programoz�s 1009
int sz ;
char* p ;
...elemek...\0
Az invari�ns fogalma Floyd, Naur �s Hoare elofelt�telekkel �s ut�felt�telekkel
foglalkoz�
munk�ib�l ered �s l�nyeg�ben minden absztrakt adatt�pusokr�l �s programhelyess�g-
ellen
orz�srol sz�l� munka eml�ti, amit az ut�bbi 30 �vben �rtak, �gy a C hibakeres�snek
is
fontos elem�t k�pezi. Az invari�ns ellenorz�s�re a tagf�ggv�nyek v�grehajt�sa
k�zben �ltal
�ban nem ker�l sor. Azok a f�ggv�nyek, melyek megh�vhat�k, mik�zben az invari�ns
�rv
�nytelen, nem lehetnek a nyilv�nos fel�let r�szei; e c�lra a priv�t �s v�dett
f�ggv�nyek
szolg�lhatnak.
Hogyan fejezhetj�k ki egy C++ programban az invari�ns fogalm�t? Erre egy egyszeru
m�d
egy invari�ns-ellenorzo f�ggv�nyt megadni �s a nyilv�nos muveletekbe e f�ggv�ny
megh�-
v�s�t beiktatni:
class String {
int sz;
char* p;
public:
class Range {}; // kiv�teloszt�ly
class Invariant {}; // kiv�teloszt�ly
enum { TOO_LARGE = 16000 }; // m�rethat�r
void check(); // �llapot-ellenorz�s
String(const char* q);
String(const String&);
~String();
char& operator[](int i);
int size() { return sz; }
// ...
};
void String::check()
{
if (p==0 || sz<0 || TOO_LARGE<=sz || p[sz]) throw Invariant();
}
char& String::operator[](int i)
{
check(); // ellenorz�s bel�p�skor
if (i<0 || sz<=i) throw Range();
// itt v�gezz�k a t�nyleges munk�t
check(); // ellenorz�s kil�p�skor
return p[i];
}
1010 Tervez�s a C++ seg�ts�g�vel
Ez sz�pen fog muk�dni �s alig jelent munk�t a programoz� sz�m�ra. Viszont egy
egyszeru
oszt�lyn�l, mint a String, az �llapotellenorz�s d�ntoen befoly�solja a fut�si idot
�s lehet,
hogy m�g a k�d m�ret�t is. Ez�rt a programoz�k gyakran csak hibakeres�s alatt
hajtj�k v�gre
az invari�ns ellenorz�s�t:
inline void String::check()
{
#ifndef NDEBUG
if (p==0 || sz<0 || TOO_LARGE<=sz || p[sz]) throw Invariant();
#endif
}
Itt az NDEBUG makr�t haszn�ljuk, hasonl� m�don, mint ahogy azt a szabv�nyos C
assert()
makr� haszn�lja. Az NDEBUG rendszerint azt jelzi, hogy nem t�rt�nik hibakeres�s.
Az invari�nsok megad�sa �s hibakeres�s alatti haszn�lata felbecs�lhetetlen
seg�ts�get jelent
a k�d .bel�v�s�n�l. �s . ami m�g fontosabb . akkor, amikor az oszt�lyok �ltal
�br�zolt fogalmakat
pontosan meghat�rozott� �s szab�lyoss� tessz�k. A l�nyeg az, hogy az invari�nsok
be�p�t�s�vel az oszt�lyokat m�s szempontb�l vizsg�lhatjuk �s a k�dban ellenorz�st
helyezhet
�nk el. Mind a ketto n�veli a val�sz�nus�g�t, hogy megtal�ljuk a hi�nyoss�gokat,
k�vetkezetlens�geket �s t�ved�seket.
24.3.7.2. Felt�telez�sek
Az invari�ns k�d egyfajta felt�telez�s (assertion), ami viszont nem m�s, mint
annak a kijelent
�se, hogy egy adott logikai felt�telnek teljes�lnie kell. Az a k�rd�s, mit kell
tenni, amikor
nem teljes�l.
A C standard k�nyvt�ra . �s k�vetkez�sk�ppen a C++ standard k�nyvt�ra .
tartalmazza az
assert() makr�t a <cassert>-ben vagy <assert.h>-ban. Az assert() ki�rt�keli a
param�ter�t �s
megh�vja az abort()-ot, ha az eredm�ny nulla (vagyis .hamis.):
void f(int* p)
{
assert(p!=0); // felt�telezi, hogy p!=0; abort() megh�v�sa, ha p nulla
// ...
}
A program megszak�t�sa elott az assert() ki�rja saj�t forr�sf�jlj�nak nev�t �s
annak a sornak
a sz�m�t, amelyben elofordult. Ez�ltal az assert() hasznos hibakereso eszk�zt
jelent.
Az NDEBUG be�ll�t�sa rendszerint ford�t�i utas�t�sok seg�ts�g�vel t�rt�nik,
ford�t�si egys�-
24. Tervez�s �s programoz�s 1011
genk�nt. Ebbol k�vetkezik, hogy az assert() haszn�lata tilos olyan helyben
kifejtett (inline)
f�ggv�nyekben �s sablon f�ggv�nyekben, melyek t�bb ford�t�si egys�gben is
elofordulnak,
hacsak nem ford�tunk igen nagy gondot az NDEBUG k�vetkezetes be�ll�t�s�ra
(�9.2.3).
Mint minden .makr�-var�zslat., az NDEBUG haszn�lata is t�l alacsony szintu,
rendetlen �s
hibaforr�st jelenthet. �ltal�ban j� �tlet, ha m�g a legjobban ellenorz�tt
programban is hagyunk
n�h�ny ellenorzo k�dot; az NDEBUG viszont erre nem nagyon alkalmas, �s az
abort() megh�v�sa is ritk�n fogadhat� el a v�gleges k�dban.
A m�sik megold�s egy Assert() sablon haszn�lata, mely a programb�l val� kil�p�s
helyett
egy kiv�telt v�lt ki, �gy k�v�ns�gra a v�gleges k�dban bennmaradhatnak az
ellenorz�sek.
Sajnos a standard k�nyvt�r nem gondoskodik ilyen Assert()-rol, de mi k�nnyen
elk�sz�thetj
�k:
template<class X, class A> inline void Assert(A assertion)
{
if (!assertion) throw X();
}
Az Assert() egy X() kiv�telt v�lt ki, ha az assertion hamis:
class Bad_arg { };
void f(int* p)
{
Assert<Bad_arg>(p!=0); // felt�telezi, hogy p!=0; Bad_arg kiv�telt v�lt ki, hacsak
p!=0
// ...
}
Az ellenorz�sben a felt�telt pontosan meg kell hat�roznunk, teh�t ha csak
hibakeres�s alatt
akarunk ellenorizni, jelezn�nk kell e sz�nd�kunkat:
void f2(int* p)
{
Assert<Bad_arg>(NDEBUG || p!=0); // vagy nem hibakeres�s folyik vagy p!=0
// ...
}
A || haszn�lata az ellenorz�sben && helyett megleponek tunhet, de az Assert<E>
(a||b)
a !(a||b)-t ellenorzi, ami !a&&!b.
Az NDEBUG ilyen m�don val� haszn�lata megk�veteli, hogy az NDEBUG-nak megfelelo
�rt
�ket adjunk, aszerint, hogy akarunk-e hibakeres�st v�gezni vagy sem. A C++ egyes
v�ltozatai
alap�rtelmez�s szerint nem teszik ezt meg nek�nk, ez�rt jobb saj�t �rt�ket
haszn�lni:
1012 Tervez�s a C++ seg�ts�g�vel
#ifdef NDEBUG
const bool ARG_CHECK = false; // nem hibakeres�s: ellenorz�s kikapcsol�sa
#else
const bool ARG_CHECK = true; // hibakeres�s
#endif
void f3(int* p)
{
Assert<Bad_arg>(!ARG_CHECK || p!=0); // vagy nem hibakeres�s folyik vagy p!=0
// ...
}
Ha egy ellenorz�ssel kapcsolatos kiv�telt nem kapunk el, az Assert() le�ll�tja a
programot
(terminate()), hasonl�an ahhoz, ahogyan a megfelelo assert() abort()-tal j�rna.
Egy kiv�telkezel
o azonban k�pes lehet valamilyen kev�sb� durva beavatkoz�sra.
A val�s�gos m�retu programokban azon veszem �szre magamat, hogy egyes csoportokban

be- �s kikapcsolom a felt�telez�seket, aszerint, hogy kell-e tesztelni. Ennek az


elj�r�snak az
NDEBUG haszn�lata a legnyersebb form�ja. A fejleszt�s elej�n a legt�bb ellenorz�s
be van
kapcsolva, m�g az �tadott k�dban csak a legfontosabbak megengedettek. Ez akkor
�rheto
el a legk�nnyebben, ha a t�nyleges ellenorz�sek k�t r�szbol �llnak, ahol az elso
egy megenged
o felt�tel (mint az ARG_CHECK), �s csak a m�sodik maga a felt�telez�s.
Amennyiben a megengedo felt�tel konstans kifejez�s, az eg�sz ellenorz�s kimarad a
ford�-
t�sb�l, ha nincs bekapcsolva. Lehet azonban v�ltoz� is, mely a hibakeres�s
sz�ks�gletei
szerint fut�si idoben be- �s kikapcsolhat�:
bool string_check = true;
inline void String::check()
{
Assert<Invariant>(!string_check || (p && 0<=sz && sz<TOO_LARGE && p[sz]==0));
}
void f()
{
String s = "csoda";
// a karakterl�ncokat itt ellenorizz�k
string_check = false;
// itt a karakterl�ncokat nem ellenorizz�k
}
24. Tervez�s �s programoz�s 1013
Term�szetesen ilyen esetekben l�trej�n a megfelelo programk�d, teh�t �gyeln�nk
kell, nehogy
a program .megh�zzon. az ilyen ellenorz�sek kiterjedt haszn�lat�t�l.
Ha azt mondjuk:
Assert<E>(a);
az egyszeruen egy m�sik m�dja ennek:
if (!a) throw E();
�gy viszont felmer�l a k�rd�s: minek bajl�djunk az Assert()-tel az utas�t�s
k�zvetlen ki�r�sa
helyett? Az�rt, mert az Assert() haszn�lata nyilv�nval�v� teszi a tervezo
sz�nd�k�t. Azt fejezi
ki, hogy valamirol felt�telezz�k, hogy mindig igaz. Ez nem a program logik�j�nak
l�nyegtelen
r�sze, hanem �rt�kes inform�ci� a program olvas�ja sz�m�ra. Gyakorlati elonye,
hogy
egy assert()-et vagy Assert()-et k�nnyu megtal�lni, m�g a kiv�teleket kiv�lt�
felt�teles utas�-
t�sokat neh�z.
Az Assert() �ltal�nos�that� olyan kiv�telek kiv�lt�s�ra is, melyek param�tereket
vagy kiv�-
tel-v�ltoz�kat vehetnek �t:
template<class A, class E> inline void Assert(A assertion, E except)
{
if (!assertion) throw except;
}
struct Bad_g_arg {
int* p;
Bad_g_arg(int* pp) : p(pp) { }
};
bool g_check = true;
int g_max = 100;
void g(int* p, exception e)
{
Assert(!g_check || p!=0, e); // a mutat� �rv�nyes
Assert(!g_check || (0<*p&&*p<=g_max),Bad_g_arg(p)); // az �rt�k �sszeru
// ...
}
Sok programban d�nto fontoss�g�, hogy ne j�jj�n l�tre k�d olyan Assert() eset�n,
ahol az
ellenorz�s a ford�t�s sor�n ki�rt�kelheto. Sajnos egyes ford�t�k az �ltal�nos�tott
Assert()-n�l
1014 Tervez�s a C++ seg�ts�g�vel
ezt k�ptelenek el�rni. K�vetkez�sk�ppen a k�tparam�teru Assert()-et csak akkor
haszn�ljuk,
ha a kiv�tel nem E() alak� vagy ha valamilyen, az ellenorz�tt �rt�ktol f�ggetlen
k�dot
kell k�sz�teni.
A �23.4.3.5 pontban eml�tett�k, hogy az oszt�lyhierarchia �tszervez�s�nek k�t
legk�z�ns�-
gesebb form�ja az oszt�ly kett�has�t�sa, illetve k�t oszt�ly k�z�s r�sz�nek
kiemel�se egy
b�zisoszt�lyba. Az �tszervez�s lehetos�g�t mindk�t esetben megfelelo
invari�nsokkal biztos
�thatjuk. Viszont ha �sszehasonl�tjuk az invari�nst a muveletek k�dj�val, egy
.has�t�sra
�rett. oszt�lyban az �llapotellenorz�st f�l�slegesnek tal�lhatjuk. Ilyen esetekben
a muveletek
r�szhalmazai csak az objektum �llapot�nak r�szhalmazaihoz fognak hozz�f�rni.
Megford
�tva, azok az oszt�lyok, melyek �sszef�s�lhetok, hasonl� invari�nsokkal
rendelkeznek
akkor is, ha megval�s�t�suk k�l�nb�zik.
24.3.7.3. Elofelt�telek �s ut�felt�telek
A felt�telez�sek (assert) egyik n�pszeru haszn�lata egy f�ggv�ny elofelt�teleinek
�s ut�felt
�teleinek kifejez�se. Ez azt jelenti, hogy ellenorizz�k a bemenetre vonatkoz�
alapfelt�telez
�sek �rv�nyess�g�t �s azt, hogy kil�p�skor a f�ggv�ny a programot a v�rt
�llapotban hagyja-
e. Sajnos amit a felt�telez�ssel ki szeretn�nk fejezni, gyakran magasabb szinten
van, mint
aminek a hat�kony kifejez�s�re a programoz�si nyelv lehetos�get ad:
template<class Ran> void sort(Ran first, Ran last)
{
Assert<Bad_sequence>("A [first,last) �rv�nyes sorozat"); // �lk�d
// ... rendezo algoritmus ...
Assert<Failed_sort>("A [first,last) n�vekvo sorrendu"); // �lk�d
}
Ez alapveto probl�ma. Amit egy programr�l felt�telez�nk, az matematikai alap�,
magasabb
szintu nyelven fejezheto ki a legjobban, nem azon az algoritmusokra �p�lo
programoz�si
nyelven, amelyben a programot �rjuk.
Az invari�nsok meghat�roz�s�hoz hasonl�an a felt�telez�sek megfogalmaz�sa is
bizonyos
fok� �gyess�get ig�nyel, mert az ellenorizni k�v�nt �ll�t�st �gy kell megadnunk,
hogy az
egy algoritmussal val�ban ellenorizheto legyen:
24. Tervez�s �s programoz�s 1015
template<class Ran> void sort(Ran first, Ran last)
{
// A [first,last) �rv�nyes sorozat; a hihetos�g ellenorz�se:
Assert<Bad_sequence>(NDEBUG || first<=last);
// ... rendezo algoritmus ...
// A [first,last) n�vekvo sorrendu; pr�ba-ellenorz�s:
Assert<Failed_sort>(NDEBUG ||
(last-first<2 || (*first<=last[-1]
&& *first<=first[(last-first)/2] && first[(last-first)/2]<=last[-1])));
}
�n gyakran egyszerubbnek tal�lom a k�z�ns�ges k�dellenorzo param�terek �s eredm�-
nyek haszn�lat�t, mint a felt�telez�sek �ssze�ll�t�s�t. Fontos azonban, hogy
megpr�b�ljuk
a val�s (ide�lis) elo- �s ut�felt�teleket kifejezni . �s legal�bb megjegyz�sek
form�j�ban dokument
�lni azokat . mielott olyan, kev�sb� absztrakt m�don �br�zoln�nk, ami a programoz
�si nyelven hat�konyan kifejezheto.
Az elofelt�telek ellenorz�se k�nnyen egyszeru param�ter�rt�k-ellenorz�ss�
fajulhat. Mivel
a param�terek gyakran t�bb f�ggv�nyen kereszt�l ad�dnak �t, az ellenorz�s
ism�tlodov�
�s k�lts�gess� v�lhat. Annak az egyszeru kijelent�se azonban, hogy minden
f�ggv�nyben
minden mutat�-param�ter nem nulla, nem sokat seg�t, �s hamis biztons�g�rzetet
adhat .
k�l�n�sen akkor, ha a t�bbletterhel�s elker�l�se v�gett az ellenorz�seket csak
hibakeres�s
alatt v�gezz�k. Ez az egyik fo oka, hogy javaslom, ford�tsunk figyelmet az
invari�nsokra.
24.3.7.4. Betokoz�s
Vegy�k �szre, hogy a C++-ban az oszt�lyok . nem az egyes objektumok . a betokoz�s
(enkapszul�ci�, encapsulation) alapegys�gei:
class List {
List* next;
public:
bool on(List*);
// ...
};
bool List::on(List* p)
{
if (p == 0) return false;
for(List* q = this; q; q=q->next) if (p == q) return true;
return false;
}
1016 Tervez�s a C++ seg�ts�g�vel
A priv�t List::next mutat� betokoz�sa elfogadhat�, mivel a List::on() hozz�f�r a
List oszt�ly
minden objektum�hoz, amelyre hivatkozni tud. Ahol ez k�nyelmetlen,
egyszerus�thet�nk,
ha nem haszn�ljuk ki azt a k�pess�get, hogy egy tagf�ggv�nybol m�s objektumok
�br�zol
�s�hoz hozz� lehet f�rni:
bool List::on(List* p)
{
if (p == 0) return false;
if (p == this) return true;
if (next==0) return false;
return next->on(p);
}
Ez azonban a bej�r�st (iter�ci�t) ism�tl�ss� (rekurzi�v�) alak�tja �t, ami komoly
teljes�tm
�nyroml�st okozhat, ha a ford�t� nem k�pes az optim�lis muk�d�shez az elj�r�st
visszaalak
�tani.
24.4. Komponensek
A tervez�s egys�gei az oszt�lyok, f�ggv�nyek stb. gyujtem�nyei, nem egy egyes
oszt�lyok.
Ezeket a gyujtem�nyeket gyakran k�nyvt�rnak (library) vagy keretrendszernek
(framework) nevezz�k (�25.8), �s az �jrahasznos�t�s (�23.5.1) �s karbantart�s is
ezeket helyezi
a k�z�ppontba. A logikai felt�telek �ltal �sszekapcsolt szolg�ltat�sok halmaz�t
jelent
o fogalom kifejez�s�re a C++ h�rom m�dot biztos�t:
1. Oszt�ly l�trehoz�sa, mely adat-, f�ggv�ny-, sablon- �s t�pustagok gyujtem�ny�t
tartalmazza.
2. Oszt�lyhierarchia l�trehoz�sa, mely oszt�lyok gyujtem�ny�t foglalja mag�ban.
3. N�vt�r meghat�roz�sa, mely adat-, f�ggv�ny-, sablon- �s t�pustagok gyujtem�-
ny�bol �ll.
Az oszt�lyok sz�mos lehetos�get biztos�tanak arra, hogy k�nyelmesen hozhassunk
l�tre �ltaluk
meghat�rozott t�pus� objektumokat. Sok jelentos komponens azonban nem �rhat� le
�gy, mint adott t�pus� objektumokat l�trehoz� rendszer. Az oszt�lyhierarchia
egym�ssal rokon
t�pusok halmaz�nak fogalm�t fejezi ki. A komponensek egyes tagjainak kifejez�s�re
azonban nem mindig az oszt�lyok jelentik a legjobb m�dszert �s nem minden oszt�ly
illeszthet
o hasonl�s�g alapj�n oszt�lyhierarchi�ba (�24.2.5). Ez�rt a komponens fogalm�nak
24. Tervez�s �s programoz�s 1017
a C++-ban a n�vt�r a legk�zvetlenebb �s leg�ltal�nosabb megtestes�t�se. A
komponenseket
n�ha .oszt�lykateg�ri�knak. nevezz�k, de nem minden esetben �llnak oszt�lyokb�l
(�s
ez nem is elo�r�s).
Ide�lis esetben egy komponens a megval�s�t�s�ra haszn�lt fel�letekkel, valamint
azokkal
a fel�letekkel �rhat� le, melyeket felhaszn�l�i r�sz�re biztos�t. Minden m�s
.r�szletk�rd�s.
�s a rendszer t�bbi r�sze sz�m�ra rejtett. A tervezo szemsz�g�bol ez a komponens
meghat
�roz�sa. A programoz� ezt a fogalmat deklar�ci�kra lek�pezve �br�zolhatja. Az
oszt�lyok
�s oszt�lyhierarchi�k adj�k a fel�leteket, melyek csoportos�t�s�ra a n�vterek
adnak leheto-
s�get, �s ugyancsak a n�vterek biztos�tj�k, hogy a programoz� elv�laszthassa a
felhaszn�lt
fel�leteket a szolg�ltatottakt�l. Vegy�k az al�bbi p�ld�t:
A �8.2.4.1-ben le�rt m�dszerek felhaszn�l�s�val ebbol az al�bbi lesz:
namespace A { // az X fel�lete �ltal haszn�lt szolg�ltat�sok
// ...
}
namespace X { // az X komponens fel�lete
using namespace A; // az A deklar�ci�it�l f�gg
// ...
void f();
}
namespace X_impl { // az X megval�s�t�s�hoz sz�ks�ges szolg�ltat�sok
using namespace X;
// ...
}
1018 Tervez�s a C++ seg�ts�g�vel
X fel�lete �ltal haszn�lt X megval�s�t�sa �ltal haszn�lt
X fel�lete
X megval�s�t�sa
void X::f()
{
using namespace X_impl; // az X_impl deklar�ci�it�l f�gg
// ...
}
Az X �ltal�nos fel�let nem f�gghet az X_impl megval�s�t�si fel�lettol.
Egy komponensnek sz�mos olyan oszt�lya lehet, melyek nem �ltal�nos haszn�latra
sz�ntak.
Az ilyen oszt�lyokat megval�s�t� oszt�lyokba vagy n�vterekbe kell .elrejteni.:
namespace X_impl { // az X megval�s�t�s�nak r�szletei
class Widget {
// ...
};
// ...
}
Ez biztos�tja, hogy a Widget-et nem haszn�lhatjuk a program m�s r�szeibol. Az
egys�ges fogalmakat
�br�zol� oszt�lyok �ltal�ban �jrahasznos�that�k, ez�rt �rdemes befoglalni azokat
a komponens fel�let�be:
class Car {
class Wheel {
// ...
};
Wheel flw, frw, rlw, rrw;
// ...
public:
// ...
};
A legt�bb k�rnyezetben el kell rejten�nk a kerekeket (Wheel), hogy megtartsuk az
aut�
(Car) �br�zol�s�nak pontoss�g�t (egy val�di aut� eset�ben sem tudjuk a kerekeket
f�ggetlen
�l muk�dtetni). Maga a Wheel oszt�ly viszont alkalmasnak tunik sz�lesebb k�ru
haszn�-
latra, �gy lehet, hogy jobb a Car oszt�lyon k�v�lre tenni:
class Wheel {
// ...
};
24. Tervez�s �s programoz�s 1019
class Car {
Wheel flw, frw, rlw, rrw;
// ...
public:
// ...
};
A d�nt�s, hogy be�gyazzuk-e az egyik fogalmat a m�sikba, att�l f�gg, mik a
tervez�s c�ljai
�s mennyire �ltal�nosak a fogalmak. Mind a be�gyaz�s, mind a .nem be�gyaz�s.
sz�les k�rben
alkalmazhat� m�dszer. Az alapszab�ly az legyen, hogy az oszt�lyokat a leheto
leg�n�ll
�bb� (.helyiv�.) tessz�k, am�g �ltal�nosabb el�r�s�ket sz�ks�gesnek nem l�tjuk.
Az .�rdekes. f�ggv�nyeknek �s adatoknak van egy kellemetlen tulajdons�ga, m�gpedig
az,
hogy a glob�lis n�vt�r fel�, a sz�les k�rben haszn�lt n�vterekbe vagy a
hierarchi�k gy�k�roszt
�lyaiba .t�rekednek.. Ez k�nnyen vezethet a megval�s�t�s r�szleteinek nem
sz�nd�kos
nyilv�noss� t�tel�hez �s a glob�lis adatokkal �s glob�lis f�ggv�nyekkel
kapcsolatos probl
�m�khoz. Ennek val�sz�nus�ge az egyetlen gy�keru hierarchi�kban �s az olyan
programokban
a legnagyobb, ahol csak nagyon kev�s n�vteret haszn�lunk. E jelens�g lek�zd�s�-
re az oszt�lyhierarchi�kkal kapcsolatban a virtu�lis b�zisoszt�lyokat (�15.2.4)
haszn�lhatjuk
fel, a n�vterekn�l pedig a kis .implement�ci�s. n�vterek kialak�t�sa lehet
megold�s.
Megjegyzendo, hogy a fej�llom�nyok (header) komoly seg�ts�get ny�jthatnak abban,
hogy
a komponenseket felhaszn�l�iknak k�l�nb�zo szempontb�l .mutathassuk., �s kiz�rj�k
azokat az oszt�lyokat, melyek a felhaszn�l� szempontj�b�l a megval�s�t�s r�szeinek
tekinthet
ok (�9.3.2).
24.4.1. Sablonok
A tervez�s szempontj�b�l a sablonok (template) k�t, laza kapcsolatban l�vo
sz�ks�gletet
szolg�lnak ki:
. �ltal�nos�tott (generic) programoz�s
. Elj�r�sm�dot (policy) meghat�roz� param�terez�s
A tervez�s korai szakasz�ban a muveletek csup�n muveletek. K�sobb, amikor az
operandusok t�pus�t meg kell hat�rozni, az olyan, statikus t�pusokat haszn�l�
programoz�-
si nyelvekben, mint a C++, a sablonok l�nyeges szerepet kapnak. Sablonok n�lk�l a
f�ggv
�ny-defin�ci�kat �jra meg �jra meg kellene ism�telni, vagy az ellenorz�seket a
fut�si ido-
re kellene elhalasztani (�24.2.3). Azokat a muveleteket, amelyek egy algoritmust
t�bbf�le
operandust�pusra kell, hogy le�rjanak, c�lszeru sablonk�nt elk�sz�teni. Ha az
�sszes ope-
1020 Tervez�s a C++ seg�ts�g�vel
randus egyetlen oszt�lyhierarchi�ba illesztheto (�s k�l�n�sen akkor, ha fut�si
idoben sz�ks
�g van �j operandust�pusok hozz�ad�s�ra is), az operandust�pusok oszt�lyk�nt,
m�gpedig
�ltal�ban absztrakt oszt�lyk�nt �br�zolhat�k a legjobban. Ha az operandust�pusok
nem illenek
bele egyetlen hierarchi�ba (�s k�l�n�sen akkor, ha a fut�si ideju teljes�tm�ny
l�tfontoss
�g�), a muveletet legjobb sablonk�nt elk�sz�teni. A szabv�nyos t�rol�k �s az
azokat t�-
mogat� algoritmusok annak p�ld�i, amikor a t�bbf�le, nem rokon t�pus� operandus
haszn�lat�nak �s a fut�si ideju teljes�tm�ny fokoz�s�nak egyideju sz�ks�gess�ge
vezet sablonok
haszn�lat�hoz (�16.2). Vegy�k egy egyszeru bej�r�s �ltal�nos�t�s�t, hogy jobban
szem�gyre vehess�k a .sablon vagy hierarchia?. dilemm�t:
void print_all(Iter_for_T x)
{
for (T* p = x.first(); p; p = x.next()) cout << *p;
}
Itt azzal a felt�telez�ssel �lt�nk, hogy az Iter_for_T olyan muveleteket biztos�t,
melyek
T*-okat hoznak l�tre.
Az Iter_for_T-t sablonparam�terr� tehetj�k:
template<class Iter_for_T> void print_all(Iter_for_T x)
{
for (T* p = x.first(); p; p = x.next()) cout << *p;
}
Ez lehetos�get ad arra, hogy egy sereg egym�ssal nem rokon bej�r�t (iterator)
haszn�ljunk,
ha ezek mindegyike biztos�tja a helyes jelent�su first()-�t �s next()-et �s ha
ford�t�si idoben
minden print_all() h�v�s bej�r�j�nak t�pus�t ismerj�k. A standard k�nyvt�r t�rol�i
�s algoritmusai
ezen az �tleten alapulnak.
Felhaszn�lhatjuk azt a megfigyel�st is, hogy a first() �s a next() a bej�r�k
sz�m�ra fel�letet
alkotnak �s l�trehozhatunk egy oszt�lyt, amely ezt az fel�letet k�pviseli:
class Iter {
public:
virtual T* first() const = 0;
virtual T* next() = 0;
};
void print_all2(Iter& x)
{
for (T* p = x.first(); p; p = x.next()) cout << *p;
}
24. Tervez�s �s programoz�s 1021
Most m�r az Iter-bol sz�rmaztatott valamennyi bej�r�t haszn�lhatjuk. A k�dok
azonosak,
f�ggetlen�l att�l, hogy sablonokat vagy oszt�lyhierarchi�t haszn�lunk a
param�terez�s �br
�zol�s�ra . csak a fut�si ido, �jraford�t�s stb. tekintet�ben k�l�nb�znek. Az Iter
oszt�ly k�-
l�n�sen alkalmas arra, hogy az al�bbi sablon param�tere legyen:
void f(Iter& i)
{
print_all(i); // a sablon haszn�lata
print_all2(i);
}
K�vetkez�sk�ppen a k�t megk�zel�t�s egym�st kieg�sz�tonek tekintheto.
Egy sablonnak gyakran van sz�ks�ge arra, hogy f�ggv�nyeket �s oszt�lyokat �gy
haszn�ljon,
mint megval�s�t�s�nak r�szeit. Soknak k�z�l�k maguknak is sablonoknak kell lenni-
�k, hogy megtartsuk az �ltal�noss�got �s a hat�konys�got. �gy az algoritmusok t�bb
t�pusra
�ltal�nos�that�k. A sablonok haszn�lat�nak ezt a m�dj�t nevezz�k �ltal�nos�tott
vagy
generikus programoz�snak (�2.7). Ha az std::sort()-ot egy vector-ra h�vjuk meg, a
sort()
operandusai a vektor elemei lesznek, vagyis a sort() az egyes elemt�pusokra
�ltal�nos�tott.
A szabv�nyos rendezo f�ggv�ny emellett �ltal�nos a t�rol�t�pusokra n�zve is, mert
b�rmely,
a szabv�nyhoz igazod� t�rol� bej�r�j�ra megh�vhat� (�16.3.1).
A sort() algoritmus az �sszehasonl�t�si felt�telekre is param�terezett (�18.7.1).
Tervez�si
szempontb�l ez m�s, mint amikor vesz�nk egy muveletet �s �ltal�nos�tjuk az
operandus t�-
pus�ra. Sokkal magasabb szintu tervez�si d�nt�s, hiszen egy objektumon (vagy
muveleten)
dolgoz� algoritmust �gy param�terez�nk, hogy az az algoritmus muk�d�sm�dj�t
vez�rli.
Ez egy olyan d�nt�s, ami r�szben a tervezo/programoz� kez�be adja a vez�rl�st az
algoritmus
muk�d�si elveinek kialak�t�s�ban.
24.4.2. Fel�let �s megval�s�t�s
Az ide�lis fel�let
. teljes �s egys�ges fogalomk�szletet ad a felhaszn�l�nak,
. a komponensek minden r�sz�re n�zve k�vetkezetes,
. nem fedi fel a megval�s�t�s r�szleteit a felhaszn�l�nak,
. t�bbf�lek�ppen elk�sz�theto,
. t�pusai ford�t�si idoben ellenorizhetok,
. alkalmaz�sszintu t�pusok haszn�lat�val kifejezett,
. m�s fel�letektol korl�tozott �s pontosan meghat�rozott m�dokon f�gg.
1022 Tervez�s a C++ seg�ts�g�vel
Miut�n megjegyezt�k, hogy az oszt�lyok k�z�tt, melyek a k�lvil�g fel� a komponens
fel�-
let�t k�pezik, k�vetkezetess�gre van sz�ks�g (�24.4), a t�rgyal�st egyetlen
oszt�lyra egyszer
us�thetj�k. Vegy�k az al�bbi p�ld�t:
class Y { /* ... */ }; // X �ltal ig�nyelt
class Z { /* ... */ }; // X �ltal ig�nyelt
class X { // p�lda a szeg�nyes fel�letre
Y a;
Z b;
public:
void f(const char * ...);
void g(int[],int);
void set_a(Y&);
Y& get_a();
};
Enn�l a fel�letn�l t�bb probl�ma is felmer�lhet:
. A fel�let Y �s Z t�pust �gy haszn�lja, hogy a ford�t�nak ismernie kell Y �s Z
deklar�ci�j�t.
. Az X::f() f�ggv�ny tetszoleges sz�m� ismeretlen t�pus� param�tert vehet �t
(val�sz�nuleg egy, az elso param�terben megkapott .form�zott karakterl�nc.
�ltal vez�relt m�don, �21.8).
. Az X::g() egy int[] param�tert vesz �t. Ez elfogadhat� lehet, de annak a jele,
hogy az elvonatkoztat�s szintje t�l alacsony. Egy eg�szekbol �ll� t�mb nem
�nle�r�, teh�t nem mag�t�l �rtetodo, h�ny eleme van.
. A set_a()�s get_a() f�ggv�nyek val�sz�nuleg felfedik X oszt�ly objektumainak
�br�zol�s�t, az�ltal, hogy X::a-hoz k�zvetlen hozz�f�r�st tesznek lehetov�.
Ezek a tagf�ggv�nyek nagyon alacsony elvonatkoztat�si (fogalmi) szinten ny�jtanak
fel�letet.
Az ilyen szintu fel�letekkel rendelkezo oszt�lyok l�nyeg�ben egy nagyobb komponens

megval�s�t�s�nak r�szletei k�z� tartoznak . ha egy�ltal�n tartoznak valahov�.


Ide�lis esetben
egy fel�letf�ggv�ny param�tere el�g inform�ci�t tartalmaz ahhoz, hogy �nle�r�
legyen.
Alapszab�ly, hogy a k�relmek .v�kony dr�ton �t. legyenek tov�bb�that�ak a t�voli
kiszolg
�l� fel�.
A C++ a programoz�nak lehetos�get ad arra, hogy az oszt�lyokat a fel�let r�szek�nt
�br�-
zolja. Az �br�zol�s lehet rejtett (private vagy protected haszn�lat�val), de a
ford�t� megengedi
automatikus v�ltoz�k l�trehoz�s�t, f�ggv�nyek helyben kifejt�s�t stb. is. Ennek
negat
�v hat�sa, hogy az oszt�lyt�pusok haszn�lata az oszt�ly �br�zol�s�ban nemk�v�natos

24. Tervez�s �s programoz�s 1023


f�gg�seket id�zhet elo. Az, hogy probl�ma-e Y �s Z t�pusok tagjainak haszn�lata,
att�l f�gg,
val�j�ban milyen fajta t�pus Y �s Z. Ha egyszeru t�pusok, mint a list, a complex
vagy a string,
haszn�latuk �ltal�ban teljesen megfelelo. Az ilyen t�pusok stabilnak minos�lnek �s
oszt�lydeklar
�ci�ik be�p�t�se a ford�t� r�sz�re elfogadhat� terhel�s. Ha azonban Y �s Z maguk
is
jelentos komponensek (p�ld�ul egy grafikus rendszer vagy egy banki kezelorendszer
oszt
�lyai), b�lcsebb lenne, ha nem f�ggn�nk tol�k t�l k�zvetlen�l. Ilyen esetekben
gyakran
jobb v�laszt�s egy mutat� vagy referencia haszn�lata:
class Y;
class Z;
class X { // X csak mutat�n �s referenci�n �t �ri el Y-t �s Z-t
Y* a;
Z& b;
// ...
};
Ez lev�lasztja X defin�ci�j�t Y �s Z defin�ci�ir�l, vagyis X defin�ci�ja csak Y �s
Z nev�tol
f�gg. X megval�s�t�sa term�szetesen m�g mindig f�gg Y �s Z defin�ci�j�t�l, de ez
nem �rinti
X felhaszn�l�it.
Ezzel egy fontos dolgot szeml�ltett�nk: egy fel�letnek, mely jelentos
adatmennyis�get rejt
el . ahogyan ez egy haszn�lhat� fel�lettol elv�rhat� . sokkal kevesebb lesz a
f�gg�se, mint
az �ltala elrejtett megval�s�t�snak. Az X oszt�ly defin�ci�ja p�ld�ul an�lk�l
ford�that� le,
hogy Y �s Z defin�ci�ihoz hozz�f�rn�nk. A f�gg�sek elemz�sekor k�l�n kell kezelni
a fel�-
let �s k�l�n a megval�s�t�s f�gg�seit. Mindk�t esetben ide�lis, ha a rendszer
f�ggos�gi �br
�i ir�ny�tott, k�rmentes gr�fok, melyek megk�nny�tik a rendszer meg�rt�s�t �s
tesztel�s�t.
Ennek el�r�se a fel�letekn�l fontosabb (�s k�nnyebb is), mint a megval�s�t�sn�l.
Vegy�k �szre, hogy egy oszt�ly h�rom fel�letet �rhat le:
class X {
private:
// csak tagok �s bar�t f�ggv�nyek sz�m�ra el�rheto
protected:
// csak tagok �s "bar�tok", valamint
// a sz�rmaztatott oszt�ly tagjai sz�m�ra el�rheto
public:
// �ltal�nosan el�rheto
};
Ezenk�v�l m�g a nyilv�nos fel�let r�sz�t k�pezik a .bar�tok. is (friend, �11.5).
1024 Tervez�s a C++ seg�ts�g�vel
A tagokat a legkorl�tozottabb el�r�su fel�let r�szek�nt c�lszeru megadni. Ez azt
jelenti,
hogy a tagok mindig priv�tok legyenek, hacsak nincs okunk arra, hogy
hozz�f�rhetobb� tegy
�k azokat. Ha hozz�f�rhetobbnek kell lenni�k, legyenek v�dettek (protected),
hacsak
nincs okunk arra, hogy nyilv�nosk�nt (public) adjuk meg oket. Az adattagokat
szinte soha
nem szerencs�s nyilv�noss� vagy v�dett� tenni. A nyilv�nos fel�letet alkot�
f�ggv�nyeknek
�s oszt�lyoknak az oszt�ly olyan n�zet�t kell biztos�taniuk, amely illik ahhoz a
szerephez,
hogy az oszt�ly egy fogalmat �br�zol.
Az �br�zol�s elrejt�s�nek egy tov�bbi szintj�t absztrakt oszt�lyok haszn�lat�val
biztos�thatjuk
(�2.5.4, �12.3, �25.3).
24.4.3. K�v�r fel�letek
Ide�lis esetben egy fel�let csak olyan muveleteket k�n�lhat fel, melyeknek
�rtelm�k van �s
a fel�letet megval�s�t� b�rmely sz�rmaztatott oszt�ly �ltal megfeleloen le�rhat�k.
Ez azonban
nem mindig k�nnyu. Vegy�k a list�kat, t�mb�ket, asszociat�v t�mb�ket, f�kat stb.
Mint
ahogy a �16.2.2 pontban r�mutattunk, cs�b�t� �s n�ha hasznos ezeket a t�pusokat
�ltal�nos
�tani . rendszerint egy t�rol� (kont�ner) haszn�lat�val, melyet mindegyik�k
fel�letek�nt
haszn�lhatunk. Ez (l�tsz�lag) felmenti a felhaszn�l�t a t�rol� r�szleteinek
kezel�se al�l. Egy
�ltal�nos t�rol�oszt�ly fel�let�nek kialak�t�sa azonban nem k�nnyu feladat. Tegy�k
fel,
hogy a Container-t absztrakt t�pusk�nt akarjuk meghat�rozni. Milyen muveleteket
biztos�tson
a Container? Megadhatn�nk csak azokat a muveleteket, melyeket minden t�rol� k�pes
t�mogatni . a muvelethalmazok metszet�t ., de ez nevets�gesen szuk fel�let. Sok
esetben
a metszet val�j�ban �res. A m�sik m�d, ha az �sszes muvelethalmaz uni�j�t adjuk
meg, fut
�skor pedig hibajelz�st adunk, ha ezen a fel�leten kereszt�l valamelyik objektumra
egy
.nem l�tezo. muvelet alkalmaz�sa t�rt�nik. Az olyan fel�letet, mely egy
fogalomhalmaz fel
�leteinek uni�ja, k�v�r fel�letnek (fat interface) nevezz�k. Vegy�nk egy T t�pus�
objektumokat
tartalmaz� .�ltal�nos t�rol�t.:
class Container {
public:
struct Bad_oper { // kiv�teloszt�ly
const char* p;
Bad_oper(const char* pp) : p(pp) { }
};
virtual void put(const T*) { throw Bad_oper("Container::put"); }
virtual T* get() { throw Bad_oper("Container::get"); }
24. Tervez�s �s programoz�s 1025
virtual T*& operator[](int) { throw Bad_oper("Container::[](int)"); }
virtual T*& operator[](const char*) { throw Bad_oper("Container::[](char*)"); }
// ...
};
A Container-eket ezut�n �gy vezethetj�k be:
class List_container : public Container, private list {
public:
void put(const T*);
T* get();
// ... nincs operator[] ...
};
class Vector_container : public Container, private vector {
public:
T*& operator[](int);
T*& operator[](const char*);
// ... nincs put() vagy get() ...
};
Am�g �vatosak vagyunk, minden rendben van:
void f()
{
List_container sc;
Vector_container vc;
// ...
user(sc,vc);
}
void user(Container& c1, Container& c2)
{
T* p1 = c1.get();
T* p2 = c2[3];
// ne haszn�ljuk c2.get() vagy c1[3] muveletet
// ...
}
Kev�s azonban az olyan adatszerkezet, mely mind az indexel�ses, mind a lista
st�lus� mu-
veleteket j�l t�mogatja. K�vetkez�sk�ppen val�sz�nuleg nem j� �tlet olyan
fel�letet meghat
�rozni, mely mindkettot megk�veteli. Ha ezt tessz�k, a hib�k elker�l�se �rdek�ben
fut�si
ideju t�puslek�rdez�st (�15.4) vagy kiv�telkezel�st (14. fejezet) kell
alkalmaznunk:
1026 Tervez�s a C++ seg�ts�g�vel
void user2(Container& c1, Container& c2) // �szlelni k�nnyu, de a helyre�ll�t�s
neh�z
lehet
{
try {
T* p1 = c1.get();
T* p2 = c2[3];
// ...
}
catch(Container::Bad_oper& bad) {
// Hopp�!
// Most mit tegy�nk?
}
}
vagy
void user3(Container& c1, Container& c2)
// a korai �szlel�s f�raszt�, de a helyre�ll�t�s m�g mindig neh�z
{
if (dynamic_cast<List_container*>(&c1) && dynamic_cast<Vector_container*>(&c2)) {
T* p1 = c1.get();
T* p2 = c2[3];
// ...
}
else {
// Hopp�!
// Most mit tegy�nk?
}
}
A fut�si ideju teljes�tm�ny mindk�t esetben cs�kkenhet �s a l�trehozott k�d
meglepoen
nagy lehet. Ez azt eredm�nyezi, hogy a programoz�k hajlamosak figyelmen k�v�l
hagyni
a lehets�ges hib�kat, rem�lve, hogy val�j�ban nem is fordulnak elo, amikor a
program a felhaszn
�l�k kez�be ker�l. E megk�zel�t�ssel az a probl�ma, hogy a kimer�to tesztel�s
szint�n
neh�z �s dr�ga munka.
K�vetkez�sk�ppen a k�v�r fel�leteket a legjobb elker�lni ott, ahol a fut�si ideju
teljes�tm
�ny elsorenduen fontos, ahol megk�vetelj�k a k�d helyess�g�re vonatkoz� garanci�t,
�s
�ltal�ban ott, ahol van m�s j� megold�s. A k�v�r fel�letek haszn�lata gyeng�ti a
megfeleltet
�st a fogalmak �s oszt�lyok k�z�tt �s �gy szabad utat enged annak, hogy a
sz�rmaztat�st
puszt�n a k�nyelmesebb megval�s�t�s kedv��rt haszn�ljuk.
24. Tervez�s �s programoz�s 1027
24.5. Tan�csok
[1] T�rekedj�nk az absztrakt adat�br�zol�sra �s az objektumorient�lt
programoz�sra.
�24.2.
[2] A C++ tulajdons�gait �s technik�it (csak) sz�ks�g szerint haszn�ljuk. �24.2.
[3] Teremts�nk �sszhangot a tervez�s �s programoz�s st�lusa k�z�tt. �24.2.1.
[4] A f�ggv�nyek �s a feldolgoz�s helyett a tervez�sben elsodlegesen az
oszt�lyokra �s
fogalmakra �sszpontos�tsunk. �24.2.1.
[5] A fogalmak �br�zol�s�ra haszn�ljunk oszt�lyokat. �24.2.1, �24.3.
[6] A fogalmak k�z�tti hierarchikus kapcsolatokat (�s csak azokat) �r�kl�ssel
�br�zoljuk.
�24.2.2, �24.2.5, �24.3.2.
[7] A fel�letekre vonatkoz� garanci�kat fejezz�k ki alkalmaz�sszintu statikus
t�pusokkal.
�24.2.3.
[8] A pontosan meghat�rozhat� feladatok elv�gz�s�nek megk�nny�t�s�re haszn�ljunk
programgener�torokat �s k�zvetlen kezeloeszk�z�ket. �24.2.4.
[9] Ker�lj�k az olyan programgener�torokat �s k�zvetlen kezeloeszk�z�ket, melyek
nem illeszkednek pontosan az adott �ltal�nos c�l� programoz�si nyelvhez. �24.2.4.
[10] Az elhat�rolhat� fogalmi szinteket v�lasszuk el. �24.3.1.
[11] �sszpontos�tsunk a komponensek tervez�s�re. �24.4.
[12] Mindig gyozodj�nk meg r�la, hogy egy adott virtu�lis f�ggv�nynek pontosan
defini�lt jelent�se van-e �s hogy az azt fel�lb�r�l� minden f�ggv�ny a k�v�nt
viselked
�s egy v�ltozat�t �rja-e le. �24.3.5, �24.3.2.1.
[13] Haszn�ljunk nyilv�nos �r�kl�st az is-a kapcsolatok �br�zol�s�ra. �24.3.4.
[14] Haszn�ljunk tags�got a has-a kapcsolatok �br�zol�s�ra. �24.3.4.
[15] �n�ll�an l�trehozott objektumra hivatkoz� mutat�k helyett haszn�ljunk ink�bb
k�zvetlen tags�got az egyszeru tartalmaz�si kapcsolatok kifejez�s�re. �24.3.3,
�24.3.4.
[16] A uses f�gg�sek legyenek vil�gosak, (ahol lehets�ges) k�lcs�n�s f�gg�stol
mentesek,
�s min�l kevesebb legyen belol�k. �24.3.5.
[17] Minden oszt�lyhoz adjunk meg invari�nsokat. �24.3.7.1.
[18] Az elofelt�teleket, ut�felt�teleket �s m�s �ll�t�sokat felt�telez�sekkel
(lehetoleg az
Assert() haszn�lat�val) fejezz�k ki. �24.3.7.2.
[19] A fel�letek csak a felt�tlen�l sz�ks�ges inform�ci�kat tegy�k el�rhetov�.
�24.4.
[20] Cs�kkents�k a fel�letek f�gg�seit m�s fel�letektol. �24.4.2.
[21] A fel�letek legyenek erosen t�pusosak. �24.4.2.
[22] A fel�leteket alkalmaz�sszintu t�pusokkal fejezz�k ki. �24.4.2.
[23] A fel�letek tegy�k lehetov�, hogy a k�r�sek �tvihetok legyenek egy t�voli
kiszolg�l�ra. �24.4.2.
[24] Ker�lj�k a k�v�r fel�leteket. �24.4.3.
1028 Tervez�s a C++ seg�ts�g�vel
[25] Haszn�ljunk private adatokat �s tagf�ggv�nyeket, ahol csak lehets�ges.
�24.4.2.
[26] A tervezok, illetve az �ltal�nos felhaszn�l�k �ltal ig�nyelt sz�rmaztatott
oszt�lyok
elk�l�n�t�s�re haszn�ljuk a public/protected megk�l�nb�ztet�st. �24.4.2.
[27] Az �ltal�nos�tott programoz�s �rdek�ben haszn�ljunk sablonokat. �24.4.1.
[28] Az algoritmusok elj�r�sm�dot megad� param�terez�s�re szint�n sablonokat haszn
�ljunk. �24.4.1.
[29] Ha ford�t�si ideju t�pusfelold�sra van sz�ks�g, haszn�ljunk sablonokat.
�24.4.1.
[30] Ha fut�si ideju t�pusfelold�sra van sz�ks�g, haszn�ljunk
oszt�lyhierarchi�kat.
�24.4.1.
24. Tervez�s �s programoz�s 1029
Az oszt�lyok szerepe
Vannak dolgok, melyek jobb, ha v�ltoznak...
de az alapveto t�m�knak �lland�nak kell maradniuk.
(Stephen J. Gould)
Az oszt�lyok fajt�i . Konkr�t t�pusok . Absztrakt t�pusok . Csom�pontok . V�ltoz�
fel�-
letek . Objektum I/O . Muveletek . Fel�letoszt�lyok . Le�r�k .
Haszn�latsz�ml�l�s .
Keretrendszerek . Tan�csok . Gyakorlatok
25.1. Az oszt�lyok fajt�i
A C++ oszt�ly egy programoz�si nyelvi szerkezet, t�bbf�le tervez�si ig�ny
kiszolg�l�s�ra.
A bonyolultabb tervez�si probl�m�k megold�sa �ltal�ban �j oszt�lyok bevezet�s�vel
j�r
(esetleg m�s oszt�lyok elhagy�s�val). Az �j oszt�lyokkal olyan fogalmakat
�br�zolunk,
amelyeket az elozo tervv�zlatban m�g nem hat�roztunk meg pontosan. Az oszt�lyok
sokf
�le szerepet j�tszhatnak, ebbol pedig az ad�dik, hogy a konkr�t ig�nyekhez egyedi
oszt
�lyfajt�kra lehet sz�ks�g�nk. E fejezetben le�runk n�h�ny alapveto oszt�lyt�pust,
azok eredend
o eross�geivel �s gyeng�ivel egy�tt:
25
�25.2 Konkr�t t�pusok
�25.2 Absztrakt t�pusok
�25.4 Csom�pontok
�25.5 Muveletek
�25.6 Fel�letek
�25.7 Le�r�k
�25.8 Keretrendszerek
Ezek az .oszt�lyfajt�k. tervez�si fogalmak, nem nyelvi szerkezetek. A val�sz�nuleg
el�rhetetlen
ide�l az lenne, ha rendelkez�sre �llna egyszeru �s �n�ll� oszt�lyfajt�k egy olyan
legkisebb
halmaza, melybol az �sszes megfeleloen viselkedo �s haszn�lhat� oszt�lyt
megalkothatn
�nk. Fontos, hogy �szrevegy�k: a fenti oszt�lyfajt�k mindegyik�nek helye van
a tervez�sben �s egyik sem eredendoen jobb minden haszn�latra a t�bbin�l. A
tervez�si �s
programoz�si vit�k sor�n sz�mos f�lre�rt�s ad�dhat abb�l, hogy vannak, akik
kiz�r�lag egy
vagy k�t fajta oszt�lyt pr�b�lnak haszn�lni. Ez rendszerint az egyszerus�g nev�ben
t�rt�nik,
de a .kedvenc. oszt�lyfajt�k torz �s term�szetellenes haszn�lat�hoz vezet.
Jelen le�r�s ezeknek az oszt�lyfajt�knak a .tiszta. alakjaival foglalkozik, de
term�szetesen
kevert form�k is haszn�lhat�k. A kever�kek azonban tervez�si d�nt�sek
eredm�nyek�nt
kell, hogy sz�lessenek, a lehets�ges megold�sok ki�rt�kel�s�vel, nem pedig a
d�nt�shozatalt
elker�lve, c�ltalan k�s�rletez�ssel. A .d�nt�sek elhalaszt�sa. sokszor val�j�ban a
.gondolkod
�s elker�l�s�t. jelenti. A kezdo tervezok rendszerint j�l teszik, ha �vakodnak a
kevert
megold�sokt�l �s egy l�tezo �sszetevo st�lus�t k�vetik, melynek tulajdons�gai az
�j
komponens k�v�nt tulajdons�gaira eml�keztetnek. Csak tapasztalt programoz�k
k�s�relj�k
meg egy �ltal�nos c�l� komponens vagy k�nyvt�r meg�r�s�t, �s minden
k�nyvt�rtervezot
arra kellene .�t�lni., hogy n�h�ny �vig a saj�t alkot�s�t haszn�lja, dokument�lja
�s t�mogassa.
(L�sd m�g: �23.5.1.)
25.2. Konkr�t t�pusok
Az olyan oszt�lyok, mint a vector (�16.3), a list (�17.2.2), a Date (�10.3) �s a
complex (�11.3,
�22.5) konkr�tak abban az �rtelemben, hogy mindegyik�k egy-egy viszonylag egyszeru
fogalmat
�br�zol, az �sszes, e fogalom t�mogat�s�hoz n�lk�l�zhetetlen muvelettel egy�tt.
Mindegyik�kn�l fenn�ll az .egy az egyhez. megfelel�s a fel�let �s a megval�s�t�s
k�z�tt �s
egyiket sem sz�nt�k b�zisoszt�lynak sz�rmaztat�shoz. A konkr�t t�pusok �ltal�ban
nem illenek
bele egym�ssal kapcsolatos oszt�lyok hierarchi�j�ba. Minden konkr�t oszt�ly �nma-
1032 Tervez�s a C++ seg�ts�g�vel
g�ban meg�rtheto, a leheto legkevesebb hivatkoz�ssal m�s oszt�lyokra. Ha egy
konkr�t t�-
pust megfeleloen �runk le, az azt haszn�l� programok m�retben �s sebess�gben
�sszem�rhet
ok lesznek azokkal a programokkal, melyekben a programoz� egy�nileg dolgozza ki
a fogalom �br�zol�s�t, majd annak egyedi c�l� (sz�rmaztatott) v�ltozataival
dolgozik. Ezenk
�v�l, ha a megval�s�t�s jelentosen v�ltozik, rendszerint a fel�let is m�dosul,
hogy t�kr�zze
a v�ltoz�st. A konkr�t t�pusok mindezekben a be�p�tett t�pusokra eml�keztetnek. A
be-
�p�tett t�pusok term�szetesen mind konkr�tak. A felhaszn�l�i konkr�t t�pusok, mint

a komplex sz�mok, m�trixok, hiba�zenetek �s szimbolikus hivatkoz�sok, gyakran az


egyes
alkalmaz�si ter�letek alapt�pusaik�nt haszn�ltak.
Az adott oszt�ly fel�let�nek term�szete hat�rozza meg, mi minos�l jelentos
v�ltoztat�snak
a megval�s�t�sban; az elvontabb fel�letek ezen v�ltoztat�soknak t�bb teret
hagynak, de
ronthatj�k a fut�si ideju hat�konys�got. Ezenk�v�l egy j� megval�s�t�s nem f�gg
m�s oszt�-
lyokt�l a felt�tlen�l sz�ks�gesn�l erosebben, �gy az oszt�ly a programban l�vo
.hasonl�.
oszt�lyokhoz val� alkalmazkod�s sz�ks�gess�g�nek elker�l�s�vel ford�t�si vagy
fut�si idej
u t�lterhel�s n�lk�l haszn�lhat�.
�sszegezve, egy konkr�t t�pust le�r� oszt�ly c�ljai a k�vetkezok:
1. Szoros illeszked�s egy konkr�t fogalomhoz �s a megval�s�t�s m�dj�hoz.
2. Az .egy�nileg kidolgozott. k�d�hoz m�rheto gyorsas�g �s kis m�ret, a helyben
kifejt�s, valamint a fogalom �s megval�s�t�sa �sszes elony�t kihaszn�l� muveletek
haszn�lat�val.
3. A m�s oszt�lyokt�l val� leheto legkisebb ar�ny� f�gg�s.
4. �rthetos�g �s �n�ll� haszn�lhat�s�g.
Az eredm�ny a felhaszn�l�i �s a megval�s�t� k�d k�zti szoros k�t�s. Ha a
megval�s�t�s b�rmilyen
m�don megv�ltozik, a felhaszn�l�i k�dot �jra kell ford�tani, mivel a felhaszn�l�i
k�d szinte mindig tartalmaz helyben kifejtett (inline) f�ggv�nyh�v�sokat vagy a
konkr�t t�-
pushoz tartoz� helyi (lok�lis) v�ltoz�kat.
A .konkr�t t�pus. elnevez�st az �ltal�nosan haszn�lt .absztrakt t�pus. elnevez�s
ellent�tek
�nt v�lasztottuk. A konkr�t �s absztrakt t�pusok k�zti viszonyt a �25.3 pont
t�rgyalja.
A konkr�t t�pusok nem tudnak k�zvetlen�l k�z�ss�get kifejezni. A list �s a vector
muvelethalmaza
p�ld�ul hasonl� �s n�h�ny sablon f�ggv�nyben egym�st helyettes�thetik.
A list<int> �s a vector<int>, vagy a list<Shape*> �s a list<Circle*> k�z�tt
azonban nincs rokons
�g (�13.6.3), j�llehet mi �szrevessz�k a hasonl�s�gokat.
25. Az oszt�lyok szerepe 1033
Ez azt is jelenti, hogy az egyes konkr�t t�pusokat hasonl� m�don haszn�l� k�dok
k�lsej�kben
k�l�nb�zok lesznek. Egy List bej�r�sa a next() muvelettel p�ld�ul jelentosen
k�l�nb�-
zik egy Vector indexel�ssel t�rt�no bej�r�s�t�l:
void my(List& sl)
{
for (T* p = sl.first(); p; p = sl.next()) { // "term�szetes" lista-bej�r�s
// egyik k�d
}
// ...
}
void your(Vector& v)
{
for (int i = 0; i<v.size(); i++) { // "term�szetes" vektor-bej�r�s
// m�sik k�d
}
// ...
}
A bej�r�s st�lusbeli k�l�nbs�ge term�szetes, abban az �rtelemben, hogy a .vedd a
k�vetkez
o elemet. muvelet n�lk�l�zhetetlen a lista fogalm�n�l, de nem ilyen mag�t�l
�rtetodo egy
vektorn�l, illetve hogy az indexel�s n�lk�l�zhetetlen a vektor fogalm�n�l, de a
list�n�l nem
az. Az, hogy a v�lasztott megval�s�t�si m�dhoz a .term�szetes. muveletek
rendelkez�sre
�lljanak, �ltal�ban l�tfontoss�g�, mind a hat�konys�g szempontj�b�l, mind az�rt,
hogy
a k�d k�nnyen meg�rhat� legyen.
Mag�t�l �rtetodo neh�zs�g, hogy az alapvetoen hasonl� muveletekhez (p�ld�ul az
elobbi
k�t ciklushoz) �rott k�d elt�roen n�zhet ki, a hasonl� muveletekhez k�l�nb�zo
konkr�t t�-
pusokat haszn�l� k�dok pedig nem cser�lhetok fel. Val�s programokn�l fejt�r�st
ig�nyel,
hogy megtal�ljuk a hasonl�s�gokat, �s jelentos �jratervez�st, hogy a megtal�lt
hasonl�s�-
gok kihaszn�l�s�ra m�dot adjunk. A szabv�nyos t�rol�k �s algoritmusok is �gy
teszik lehet
ov� a konkr�t t�pusok hasonl�s�gainak kihaszn�l�s�t, hat�konys�guk �s
.eleganci�juk. elveszt
�se n�lk�l (�16.2).
Egy f�ggv�nynek ahhoz, hogy param�terk�nt elfogadjon egy konkr�t t�pust, pontosan
az
adott t�pust kell megadnia param�tert�pusk�nt. Nem �llnak rendelkez�sre �r�kl�si
kapcsolatok,
melyeket arra haszn�lhatn�nk, hogy a param�terek deklar�l�s�t �ltal�nosabb� tegy
�k. K�vetkez�sk�ppen a konkr�t t�pusok k�zti hasonl�s�gok kihaszn�l�s�ra tett
k�s�rlet
mag�val vonja a sablonok haszn�lat�t �s az �ltal�nos�tott (generikus)
programoz�st, amint
arr�l a �3.8 pontban m�r eml�t�st tett�nk. Ha a standard k�nyvt�rat haszn�ljuk, a
bej�r�s �gy
fog kin�zni:
1034 Tervez�s a C++ seg�ts�g�vel
template<class C> void ours(const C& c)
{
for (C::const_iterator p = c.begin(); p!=c.end(); ++p) { // standard k�nyvt�rbeli
bej�r�s
// ...
}
}
Itt kihaszn�ltuk a t�rol�k alapveto hasonl�s�g�t, �s ezzel megnyitottuk az utat a
tov�bbi hasonl
�s�gok kihaszn�l�sa fel�, ahogyan azt a szabv�nyos algoritmusok is teszik (18.
fejezet).
A felhaszn�l�nak a konkr�t t�pus megfelelo haszn�lat�hoz meg kell �rtenie annak
pontos
r�szleteit. (�ltal�ban) nem l�teznek olyan �ltal�nos tulajdons�gok, melyek egy
k�nyvt�rban
az �sszes konkr�t t�pusra �rv�nyesek lenn�nek, �s amelyekre t�maszkodva a
felhaszn�l�-
nak nem kell az egyes oszt�lyok ismeret�vel t�rodnie. Ez az �ra a fut�si ideju
t�m�rs�gnek
�s hat�konys�gnak. N�ha meg�ri, n�ha nem. Olyan eset is elofordul, hogy k�nnyebb
meg-
�rteni �s haszn�lni egy konkr�t oszt�lyt, mint egy �ltal�nosabb (absztrakt)
oszt�lyt. A j�l ismert
adatt�pusokat (pl. t�mb�ket, list�kat) �br�zol� oszt�lyokn�l gyakran ez a helyzet.

Vegy�k �szre azonban, hogy az ide�lis tov�bbra is az, ha a megval�s�t�sb�l a


leheto legnagyobb
r�szt elrejtj�k, an�lk�l, hogy a teljes�tm�nyt komolyabban rontan�nk. A helyben
kifejtett
f�ggv�nyek ebben a k�rnyezetben nagy nyeres�get jelenthetnek. Szinte soha nem j�
�tlet, ha a tag v�ltoz�kat nyilv�noss� tessz�k vagy set �s get f�ggv�nyekrol
gondoskodunk,
melyekkel a felhaszn�l� k�zvetlen�l kezelheti azokat (�24.4.2). A konkr�t t�pusok
maradjanak
meg t�pusoknak, �s ne .bitcsomagok. legyenek, melyeket a k�nyelem kedv��rt n�h�ny
f�ggv�nnyel l�tunk el.
25.2.1. A konkr�t t�pusok �jrahasznos�t�sa
A konkr�t t�pusok ritk�n haszn�lhat�k alapt�pusk�nt tov�bbi sz�rmaztat�shoz.
Minden
konkr�t t�pus c�lja egyetlen fogalom vil�gos �s hat�kony �br�zol�sa. Az olyan
oszt�ly, mely
ezt a k�vetelm�nyt j�l teljes�ti, ritk�n alkalmas k�l�nb�zo, de egym�ssal rokon
oszt�lyok
nyilv�nos sz�rmaztat�s �ltali l�trehoz�s�ra. Az ilyen oszt�lyok gyakrabban tehetok
tagokk�
vagy priv�t b�zisoszt�lyokk�, mert �gy an�lk�l haszn�lhat�k hat�konyan, hogy
fel�let�ket
�s megval�s�t�sukat keverni �s rontani kellene �j oszt�lyok�val. Vegy�k egy �j
oszt�ly sz�rmaztat
�s�t a Date-bol:
class My_date : public Date {
// ...
};
25. Az oszt�lyok szerepe 1035
Szab�lyos-e a My_date-et �gy haszn�lni, mint az egyszeru Date-et? Nos, ez att�l
f�gg, mi
a My_date, de tapasztalatom szerint ritk�n lehet olyan konkr�t t�pust tal�lni,
mely m�dos�-
t�s n�lk�l megfelel b�zisoszt�lynak.
A konkr�t t�pusok ugyan�gy m�dos�t�s n�lk�l �jrahasznos�that�k, mint az int-hez
hasonl�
be�p�tett t�pusok (�10.3.4):
class Date_and_time {
private:
Date d;
Time t;
public:
// ...
};
A felhaszn�l�snak (�jrahasznos�t�snak) ez a m�dja rendszerint egyszeru �s
hat�kony.
Lehet, hogy hiba volt a Date-et nem �gy tervezni, hogy sz�rmaztat�ssal k�nnyen
lehessen
m�dos�tani? N�ha azt mondj�k, minden oszt�lynak m�dos�that�nak kell lennie
fel�l�r�s �s
sz�rmaztatott oszt�lyok tagf�ggv�nyeibol val� hozz�f�r�s �ltal. Ezt a szeml�letet
k�vetve
a Date-bol az al�bbi v�ltozatot k�sz�thetj�k el:
class Date2 {
public:
// nyilv�nos fel�let, elsosorban virtu�lis f�ggv�nyekbol �ll
protected:
// egy�b megval�s�t�si r�szletek (esetleg n�mi �br�zol�st is tartalmaz)
private:
// adat�br�zol�s �s egy�b megval�s�t�si r�szletek
};
A fel�l�r� f�ggv�nyek hat�kony meg�r�s�t megk�nny�tendo, az �br�zol�st protected-
k�nt
deklar�ltuk. Ezzel el�rt�k c�lunkat: a Date2-t sz�rmaztat�ssal tetszolegesen
.hajl�that�v�.
tett�k, v�ltozatlanul hagyva felhaszn�l�i fel�let�t. Ennek azonban �ra van:
1. Kev�sb� hat�kony alapmuveletek. A C++ virtu�lis f�ggv�nyeinek megh�v�sa kiss
� lassabb, mint a szok�sos f�ggv�nyh�v�sok; a virtu�lis f�ggv�nyek nem ford�that
�k helyben kifejtve olyan gyakran, mint a nem virtu�lis f�ggv�nyek; r�ad�sul
a virtu�lis f�ggv�nyekkel rendelkezo oszt�lyok egy g�pi sz�val t�bb helyet ig�-
nyelnek.
2. A szabad t�r haszn�lat�nak sz�ks�gess�ge. A Date2 c�lja, hogy a belole
sz�rmaztatott
oszt�lyok objektumai felcser�lhetoek legyenek. Mivel e sz�rmaztatott
1036 Tervez�s a C++ seg�ts�g�vel
oszt�lyok m�rete k�l�nb�zo, k�zenfekvo, hogy a szabad t�rban foglaljunk sz�-
mukra helyet �s mutat�kkal vagy referenci�kkal f�rj�nk hozz�juk. A val�di
lok�lis v�ltoz�k haszn�lata teh�t dr�maian cs�kken.
3. K�nyelmetlens�g a felhaszn�l�nak. A virtu�lis f�ggv�nyek t�bbalak�s�g�t
(polimorfizmus)
kihaszn�land�, a Date2-kh�z mutat�k vagy referenci�k �ltal kell
hozz�f�rn�nk.
4. Gyeng�bb betokoz�s. A virtu�lis muveletek fel�l�rhat�k �s a v�dett adatok
a sz�rmaztatott oszt�lyokb�l m�dos�that�k (�12.4.1.1).
Term�szetesen ezek a .k�lts�gek. nem mindig jelentosek �s az �gy l�trehozott
oszt�ly gyakran
pontosan �gy viselkedik, mint ahogy szerett�k volna (�25.3, �25.4). Egy egyszeru
konkr
�t t�pusn�l (mint a Date2) azonban ezek nagy �s sz�ks�gtelen k�lts�gek.
A .hajl�that�bb. t�pus ide�lis �br�zol�s�ra sokszor egy j�l megtervezett konkr�t
t�pus a legalkalmasabb:
class Date3 {
public:
// nyilv�nos fel�let, elsosorban virtu�lis f�ggv�nyekbol �ll
private:
Date d;
};
�gy a konkr�t t�pusok (a be�p�tett t�pusokat is bele�rtve) oszt�lyhierarchi�ba is
illeszthetok,
ha sz�ks�ges. (L�sd m�g �25.10[1].)
25.3. Absztrakt t�pusok
Az oszt�lyokat, valamint az objektumokat l�trehoz� �s az azokat felhaszn�l� k�d
k�z�tti
k�tel�k laz�t�s�nak legegyszerubb m�dja egy absztrakt oszt�ly bevezet�se, mely a
fogalom
k�l�nb�zo megval�s�t�sainak halmaz�hoz k�z�s fel�letet biztos�t. Vegy�nk egy
term�szetes
Set-et (halmazt):
template<class T> class Set {
public:
virtual void insert(T*) = 0;
virtual void remove(T*) = 0;
25. Az oszt�lyok szerepe 1037
virtual int is_member(T*) = 0;
virtual T* first() = 0;
virtual T* next() = 0;
virtual ~Set() { }
};
Ez meghat�rozza a halmaz fel�let�t �s tartalmazza az elemek bej�r�s�nak m�dj�t is.

A konstruktor hi�nya �s a virtu�lis destruktor jelenl�te szokv�nyos (�12.4.2).


T�bbf�le megval
�s�t�s lehets�ges (�16.2.1):
template<class T> class List_set : public Set<T>, private list<T> {
// ...
};
template<class T> class Vector_set : public Set<T>, private vector<T> {
// ...
};
Az egyes megval�s�t�sokhoz az absztrakt oszt�ly adja a k�z�s fel�letet, vagyis a
Set-tel an�lk
�l dolgozhatunk, hogy tudn�nk, melyik megval�s�t�s�t haszn�ljuk:
void f(Set<Plane*>& s)
{
for (Plane** p = s.first(); p; p = s.next()) {
// saj�t k�d
}
// ...
}
List_set<Plane*> sl;
Vector_set<Plane*> v(100);
void g()
{
f(sl);
f(v);
}
A konkr�t t�pusokn�l megk�vetelt�k a megval�s�t� oszt�lyok �jratervez�s�t, hogy
kifejezz
�k a k�z�ss�get, annak kiakn�z�s�ra pedig sablont haszn�ltunk. Itt a k�z�s
fel�letet kell
megtervezn�nk (eset�nkben a Set-et), de semmi m�s k�z�set nem k�v�nunk a
megval�s�-
t�sra haszn�lt oszt�lyokt�l, mint azt, hogy meg tudj�k val�s�tani a fel�letet.
1038 Tervez�s a C++ seg�ts�g�vel
Tov�bb�, a Set-et felhaszn�l� programelemeknek nem kell ismerni�k a List_set �s
a Vector_set deklar�ci�it, teh�t nem kell f�ggni�k ezektol. Ezenk�v�l nem kell sem
�jraford�-
tanunk, sem b�rmilyen m�s v�ltoztat�st v�gezn�nk, ha a List_set vagy a Vector_set
megv�ltozik,
vagy ha bevezetj�k a Set egy �jabb megval�s�t�s�t, mondjuk a Tree_set-et. Minden
f�gg
�st a f�ggv�nyek tartalmaznak, melyek a Set-bol sz�rmaztatott oszt�lyokat
haszn�lj�k.
Vagyis . felt�telezve, hogy a szok�sos m�don haszn�ljuk a fej�llom�nyokat . az
f(Set&)
meg�r�sakor csak a Set.h-t kell be�p�ten�nk (#include), a List_set.h-t vagy a
Vector_set.h-t
nem. Csak ott van sz�ks�g egy .implement�ci�s fej�llom�nyra., ahol egy List_set,
illetve egy
Vector_set l�trehoz�sa t�rt�nik. Az egyes megval�s�t�sok tov�bbi elszigetel�s�t
jelentheti
a t�nyleges oszt�lyokt�l, ha egy absztrakt oszt�lyt vezet�nk be, mely az objektum-
l�trehoz�-
si k�r�seket kezeli (.gy�r., factory, �12.4.4).
A fel�letnek ez az elv�laszt�sa a megval�s�t�st�l azzal a k�vetkezm�nnyel j�r,
hogy .eltu-
nik. a hozz�f�r�s azon muveletekhez, melyek .term�szetesek. egy adott megval�s�t�s
sz�-
m�ra, de nem el�g �ltal�nosak ahhoz, hogy a fel�let r�szei legyenek. P�ld�ul,
mivel a Set
nem rendelkezik a rendez�s k�pess�g�vel, a Set fel�let�ben nem t�mogathatunk egy
indexkezel
o oper�tort m�g akkor sem, ha t�rt�netesen egy t�mb�t haszn�l� Set-et hozunk
l�tre.
A .k�zi. optimaliz�l�s hi�nya miatt ez n�veli a fut�si idot, ezenk�v�l �ltal�ban
nem �lhet�nk
a helyben kifejt�s elonyeivel sem (kiv�ve azokat az egyedi eseteket, amikor a
ford�t� ismeri
a val�di t�pust), �s a fel�let minden l�nyeges muvelete virtu�lis f�ggv�nyh�v�s
lesz. Mint
a konkr�t t�pusok, az absztrakt t�pusok haszn�lata is n�ha meg�ri; n�ha nem.
�sszefoglalva,
az absztrakt t�pusok c�ljai a k�vetkezok:
1. Egy egyszeru fogalom oly m�don val� le�r�sa, mely lehetov� teszi, hogy a
programban
a fogalomnak t�bb megval�s�t�sa is l�tezhessen.
2. Elfogadhat� fut�si ido �s takar�kos helyfoglal�s biztos�t�sa virtu�lis
f�ggv�nyek
haszn�lat�val.
3. Az egyes megval�s�t�sok leheto legkisebb f�gg�se m�s oszt�lyokt�l.
4. Legyen �rtheto �nmag�ban.
Az absztrakt t�pusok nem jobbak, mint a konkr�t t�pusok, csak m�smilyenek. A
felhaszn�-
l�nak kell d�ntenie, melyiket haszn�lja. A k�nyvt�r k�sz�toje elker�lheti a
k�rd�st az�ltal,
hogy mind a kettot biztos�tja, a felhaszn�l�ra hagyva a v�laszt�st. Az a fontos,
hogy vil�gos
legyen, az adott oszt�ly melyik t�pusba tartozik. Ha korl�tozzuk egy absztrakt
t�pus �ltal�-
noss�g�t, hogy sebess�gben �llja a versenyt egy konkr�t t�pussal, rendszerint
kudarcot vallunk.
Ez ugyanis vesz�lyezteti azt a k�pess�g�t, hogy egyes megval�s�t�sait egym�ssal
helyettes
�thess�k, a v�ltoztat�s ut�ni �jraford�t�s sz�ks�gess�ge n�lk�l. Hasonl�k�ppen
rendszerint kudarccal j�r, ha konkr�t t�pusokat .�ltal�nosabb�. akarunk tenni,
hogy az
absztrakt t�pusok tulajdons�gaival �sszem�rhetok legyenek, mert �gy vesz�lybe
ker�l az
25. Az oszt�lyok szerepe 1039
egyszeru oszt�ly hat�konys�ga �s pontoss�ga. A k�t elk�pzel�s egy�tt l�tezhet .
val�j�ban
egy�tt kell, hogy l�tezzen, mivel az absztrakt t�pusok megval�s�t�s�t konkr�t
t�pusok adj
�k ., de nem szabad oket �sszekeverni egym�ssal.
Az absztrakt t�pusok gyakran k�zvetlen megval�s�t�sukon t�l nem szolg�lnak tov�bbi
sz�rmaztat
�sok alapj�ul. �j fel�let azonban fel�p�theto egy absztrakt oszt�lyb�l, ha belole
egy
m�g t�gabb absztrakt oszt�lyt sz�rmaztatunk. Ezt az �j absztrakt oszt�lyt kell
majd tov�bbi
sz�rmaztat�son kereszt�l megval�s�tani egy nem absztrakt oszt�llyal (�15.2.5).
Mi�rt nem sz�rmaztattunk a Set-bol egy l�p�sben List �s Vector oszt�lyokat,
elhagyva
a List_set �s Vector_set oszt�lyok bevezet�s�t? M�s sz�val, mi�rt legyenek konkr�t
t�pusaink,
ha absztrakt t�pusaink is lehetnek?
1. Hat�konys�g. Azt akarjuk, hogy konkr�t t�pusaink legyenek (mint a vector �s
a list), azon t�lterhel�s n�lk�l, amit a megval�s�t�snak a fel�lettol val�
elv�laszt
�sa okoz (az absztrakt t�pusokn�l ez t�rt�nik).
2. �jrahasznos�t�s. Sz�ks�g�nk van egy m�dra, hogy a .m�shol. tervezett t�pusokat
(mint a vector �s a list) beilleszthess�k egy �j k�nyvt�rba vagy alkalmaz�sba,
az�ltal, hogy �j fel�letet adunk nekik (nem pedig �jra�rjuk oket).
3. T�bb fel�let. Ha egyetlen k�z�s alapot haszn�lunk t�bbf�le oszt�lyhoz, az k�v�r

fel�letekhez vezet (�24.4.3). Gyakran jobb, ha az �j c�lra haszn�lni k�v�nt oszt


�lynak �j fel�letet adunk (mint egy vector-nak egy Set fel�letet), ahelyett, hogy
a t�bb c�lra val� haszn�lhat�s�g kedv��rt az eredeti fel�letet m�dos�tan�nk.
Term�szetesen ezek egym�ssal �sszef�ggo k�rd�sek. Az Ival_box p�ld�ban (�12.4.2,
�15.2.5) �s a t�rol�k tervez�s�vel kapcsolatban (�16.2) r�szletesebben t�rgyaltuk
ezeket. Ha
a Set b�zisoszt�lyt haszn�ltuk volna, az egy csom�pont-oszt�lyokon nyugv�
alapt�rol�t
eredm�nyezett volna (�25.4).
A �25.7 pont egy rugalmasabb bej�r�t (iter�tort) �r le, ahol a bej�r� a kezdeti
�rt�kad�sn�l
k�theto az objektumokat biztos�t� megval�s�t�shoz �s ez a k�t�s fut�si idoben
m�dos�that�.
1040 Tervez�s a C++ seg�ts�g�vel
25.4. Csom�pont-oszt�lyok
Az oszt�lyhierarchi�k m�s sz�rmaztat�si szeml�let alapj�n �p�lnek fel, mint az
absztrakt
oszt�lyokn�l haszn�lt, fel�letbol �s megval�s�t�sb�l �ll� rendszer. Itt az
oszt�lyokat alapnak
tekintj�k, melyre m�s oszt�lyokat �p�t�nk. M�g ha absztrakt oszt�ly is,
rendszerint van valamilyen
�br�zol�sa �s ad valamilyen szolg�ltat�sokat a belole sz�rmaztatott oszt�lyoknak.
Ilyen csom�pont-oszt�lyok p�ld�ul a Polygon (�12.3), a (kiindul�) Ival_slider
(�12.4.1) �s
a Satellite (�15.2).
A hierarchi�n bel�li oszt�lyok jellemzoen egy �ltal�nos fogalmat �br�zolnak, m�g a
belol�k
sz�rmaztatott oszt�lyok �gy tekinthetok, mint az adott fogalom konkretiz�lt
(egyedi c�l�,
.szakos�tott.) v�ltozatai. Az egy hierarchia szerves r�szek�nt tervezett oszt�lyok
. a csom�-
pont-oszt�lyok (node class) . a b�zisoszt�ly szolg�ltat�saira t�maszkodva
biztos�tj�k saj�t
szolg�ltat�saikat, vagyis a b�zisoszt�ly tagf�ggv�nyeit h�vj�k meg. A csom�pont-
oszt�lyok
�ltal�ban nem csup�n a b�zisoszt�lyuk �ltal meghat�rozott fel�let egy
megval�s�t�s�t adj�k
(mint egy absztrakt t�pusnak egy megval�s�t� oszt�ly), hanem maguk is hozz�tesznek
�j
f�ggv�nyeket, ez�ltal sz�lesebb fel�letet biztos�tanak. Vegy�k a �24.3.2
forgalomszimul
�ci�s p�ld�j�ban szereplo Car-t:
class Car : public Vehicle {
public:
Car(int passengers, Size_category size, int weight, int fc)
: Vehicle(passengers,size,weight), fuel_capacity(fc) { /* ... */ }
// a Vehicle l�nyeges virtu�lis f�ggv�nyeinek fel�l�r�sa
void turn(Direction);
// ...
// Car-ra vonatkoz� f�ggv�nyek hozz�ad�sa
virtual void add_fuel(int amount); // az aut� �zemanyagot ig�nyel
// ...
};
A fontos f�ggv�nyek: a konstruktor, mely �ltal a programoz� a szimul�ci�
szempontj�b�l
l�nyeges alaptulajdons�gokat hat�rozza meg �s azok a (virtu�lis) f�ggv�nyek,
melyek a szimul
�ci�s elj�r�soknak lehetov� teszik, hogy egy Car-t an�lk�l kezeljenek, hogy tudn�k
annak
pontos t�pus�t. Egy Car az al�bbi m�don hozhat� l�tre �s haszn�lhat�:
25. Az oszt�lyok szerepe 1041
void user()
{
// ...
Car* p = new Car(3,economy,1500,60);
drive(p,bs_home,MH); // bel�p�s a szimul�lt forgalmi helyzetbe
// ...
}
A csom�pont-oszt�lyoknak rendszerint sz�ks�g�k van konstruktorokra �s ez a
konstruktor
gyakran bonyolult. Ebben a csom�pont-oszt�lyok elt�rnek az absztrakt oszt�lyokt�l,
melyeknek
ritk�n van konstruktoruk.
A Car muveleteinek megval�s�t�sai �ltal�ban a Vehicle b�zisoszt�lyb�l vett
muveleteket
haszn�lj�k, a Car-okat haszn�l� elemek pedig a b�zisoszt�lyok szolg�ltat�saira
t�maszkodnak.
A Vehicle p�ld�ul megadja a s�llyal �s m�rettel foglalkoz� alapf�ggv�nyeket, �gy
a Car-nak nem kell gondoskodnia azokr�l:
bool Bridge::can_cross(const Vehicle& r)
{
if (max_weight<r.weight()) return false;
// ...
}
Ez lehetov� teszi a programoz� sz�m�ra, hogy �j oszt�lyokat (Car �s Truck) hozzon
l�tre
a Vehicle csom�pont-oszt�lyb�l, �gy, hogy csak az att�l k�l�nb�zo tulajdons�gokat
�s mu-
veleteket kell megadnia, illetve elk�sz�tenie. Ezt az elj�r�st gyakran �gy
eml�tik, mint .k�-
l�nbs�g �ltali programoz�st. vagy .bov�to programoz�st..
Sok csom�pont-oszt�lyhoz hasonl�an a Car maga is alkalmas a tov�bbi
sz�rmaztat�sra.
Az Ambulance-nek p�ld�ul tov�bbi adatokra �s muveletekre van sz�ks�ge a
v�szhelyzetek
kezel�s�hez:
class Ambulance : public Car, public Emergency {
public:
Ambulance();
// a Car l�nyeges virtu�lis f�ggv�nyeinek fel�l�r�sa
void turn(Direction);
// ...
// az Emergency l�nyeges virtu�lis f�ggv�nyeinek fel�l�r�sa
1042 Tervez�s a C++ seg�ts�g�vel
virtual void dispatch_to(const Location&);
// ...
// Ambulance-ra vonatkoz� f�ggv�nyek hozz�ad�sa
virtual int patient_capacity(); // hord�gyak sz�ma
// ...
};
�sszegezz�k a csom�pont-oszt�lyok jellemzoit:
1. Mind megval�s�t�s�t, mind a felhaszn�l�knak adott szolg�ltat�sokat tekintve
b�zisoszt�lyaira t�maszkodik.
2. Sz�lesebb fel�letet (vagyis t�bb nyilv�nos tagf�ggv�nnyel rendelkezo fel�letet)

ad felhaszn�l�inak, mint b�zisoszt�lyai.


3. Elsodlegesen (de nem felt�tlen�l kiz�r�lagosan) a nyilv�nos fel�let�ben levo
virtu�lis f�ggv�nyekre t�maszkodik.
4. F�gg az �sszes (k�zvetlen �s k�zvetett) b�zisoszt�ly�t�l.
5. Csak b�zisoszt�lyaival �sszef�gg�sben �rtheto meg.
6. Tov�bbi sz�rmaztat�s b�zisoszt�lyak�nt felhaszn�lhat�.
7. Objektumok l�trehoz�s�ra haszn�lhat�.
Nem minden csom�pont-oszt�ly fog eleget tenni az 1, 2, 6 �s 7 mindegyik�nek, de a
legt
�bb igen. A 6-nak eleget nem tevo oszt�lyok a konkr�t t�pusokra eml�keztetnek, �gy
konkr
�t csom�pont-oszt�lyoknak nevezhetok. A konkr�t csom�pont-oszt�lyok p�ld�ul
absztrakt
oszt�lyok megval�s�t�s�hoz haszn�lhat�k (�12.4.2), az ilyen oszt�lyok v�ltoz�i
sz�m�ra pedig
statikusan �s a veremben is foglalhatunk helyet. Az ilyen oszt�lyokat n�ha lev�l
oszt�-
lyoknak nevezz�k. Ne feledj�k azonban, hogy minden k�d, amely egy oszt�lyra
hivatkoz�
mutat�n vagy referenci�n virtu�lis f�ggv�nyek �ltal v�gez muveletet, sz�m�t�sba
kell, hogy
vegye egy tov�bbi oszt�ly sz�rmaztat�s�nak lehetos�g�t (vagy nyelvi t�mogat�s
n�lk�l el
kell fogadnia, hogy nem t�rt�nt tov�bbi sz�rmaztat�s). Azok az oszt�lyok, melyek
nem tesznek
eleget a 7-es pontnak, az absztrakt t�pusokra eml�keztetnek, �gy absztrakt
csom�pontoszt
�lyoknak h�vhat�k. A hagyom�nyok miatt sajnos sok csom�pont-oszt�lynak van legal
�bb n�h�ny protected tagja, hogy a sz�rmaztatott oszt�lyok sz�m�ra kev�sb�
korl�tozott
fel�letrol gondoskodjon (�12.4.1.1).
A 4-es pontb�l az k�vetkezik, hogy a csom�pont-oszt�lyok ford�t�s�hoz a
programoz�nak
be kell �p�tenie (#include) azok �sszes k�zvetlen �s k�zvetett b�zisoszt�ly-
deklar�ci�it �s
az �sszes olyan deklar�ci�t, melyektol azok f�ggnek. Ez megint csak egy k�l�nbs�g
a csom
�pont-oszt�lyok �s az absztrakt t�pusok k�z�tt, az ut�bbiakat haszn�l�
programelemek
ugyanis nem f�ggnek a megval�s�t�sukra haszn�lt oszt�lyokt�l, �gy nem kell azokat
a ford
�t�shoz be�p�teni.
25. Az oszt�lyok szerepe 1043
25.4.1. Fel�letek m�dos�t�sa
Minden csom�pont-oszt�ly egy oszt�lyhierarchia tagja, egy hierarchi�n bel�l
viszont nem
minden oszt�lynak kell ugyanazt a fel�letet ny�jtania. Nevezetesen, egy
sz�rmaztatott oszt
�ly t�bb tagf�ggv�nnyel rendelkezhet �s egy testv�roszt�ly f�ggv�nyhalmaza is
teljesen
m�s lehet. A tervez�s szempontj�b�l a dynamic_cast (�15.4) �gy tekintheto, mint az
az elj
�r�s, mellyel egy objektumot megk�rdezhet�nk, biztos�t-e egy adott fel�letet.
P�ldak�nt vegy�nk egy egyszeru objektum I/O (bemeneti/kimeneti) rendszert. A
felhaszn
�l� egy adatfolyamb�l objektumokat akar olvasni, meg k�v�nja hat�rozni, hogy a
v�rt t�-
pus�ak-e, majd fel akarja haszn�lni azokat:
void user()
{
// ... felt�telez�s szerint alakzatokat (Shape) tartalmaz� f�jl megnyit�sa
// ss �ltal azonos�tott bemeneti adatfolyamk�nt ...
Io_obj* p = get_obj(ss); // objektum olvas�sa az adatfolyamr�l
if (Shape* sp = dynamic_cast<Shape*>(p)) {
sp->draw(); // alakzat haszn�lata
// ...
}
else {
// hopp�: ez nem alakzat
}
}
A user() f�ggv�ny az alakzatokat kiz�r�lag az absztrakt Shape oszt�lyon kereszt�l
kezeli �s
ez�ltal minden fajta alakzatot k�pes haszn�lni. A dynamic_cast haszn�lata
l�nyeges, mert
az objektum I/O rendszer sz�mos objektumfajt�t kezel, a felhaszn�l� pedig
v�letlen�l olyan
f�jlt is megnyithatott, amely olyan oszt�lyok . egy�bk�nt t�k�letesen j� .
objektumait tartalmazza,
melyekrol a felhaszn�l� nem is hallott.
A rendszer felt�telezi, hogy minden olvasott vagy �rt objektum olyan oszt�lyhoz
tartozik,
amely az Io_obj lesz�rmazottja. Az Io_obj oszt�lynak t�bbalak�nak (polimorfnak)
kell lennie,
hogy lehetov� tegye sz�munkra a dynamic_cast haszn�lat�t:
class Io_obj {
public:
virtual Io_obj* clone() const =0; // t�bbalak�
virtual ~Io_obj() {}
};
1044 Tervez�s a C++ seg�ts�g�vel
A rendszer l�tfontoss�g� eleme a get_obj() f�ggv�ny, mely egy istream
adatfolyamb�l adatokat
olvas �s oszt�lyobjektumokat hoz l�tre azokra alapozva. Tegy�k fel, hogy a
bemeneti
adatfolyamban az egyik objektumot k�pviselo adatok elotagk�nt egy, az objektum
oszt�-
ly�t azonos�t� karakterl�ncot tartalmaznak. A get_obj() f�ggv�ny feladata ezt
elolvasni,
majd egy olyan f�ggv�nyt megh�vni, amely k�pes a megfelelo oszt�ly� objektumot
l�trehozni
�s kezdo�rt�ket adni neki:
typedef Io_obj* (*PF)(istream&); // Io_obj* visszat�r�si t�pus� f�ggv�nyre
hivatkoz�
mutat�
map<string,PF> io_map; // karakterl�ncok hozz�rendel�se a l�trehoz� f�ggv�nyekhez
bool get_word(istream& is, string& s); // sz� beolvas�sa is-bol s-be
Io_obj* get_obj(istream& s)
{
string str;
bool b = get_word(s,str); // a kezdo sz� beolvas�sa str-be
if (b == false) throw No_class(); // io form�tumhiba
PF f = io_map[str]; // az "str" kikeres�se, hogy kiv�lasszuk a f�ggv�nyt
if (f == 0) throw Unknown_class(); // nem tal�ljuk "str"-t
return f(s); // objektum l�trehoz�sa az adatfolyamb�l
}
Az io_map nevu map neveket tartalmaz� karakterl�ncok �s a nevekhez tartoz�
oszt�lyok
objektumait l�trehozni k�pes f�ggv�nyek p�rjaib�l �ll.
A Shape oszt�lyt a szok�sos m�don hat�rozhatjuk meg, azzal a kiv�tellel, hogy a
user() �ltal
megk�vetelten az Io_obj-b�l sz�rmaztatjuk:
class Shape : public Io_obj {
// ...
};
M�g �rdekesebb (�s sok esetben val�szerubb) lenne azonban egy meghat�rozott Shape-
et
(�2.6.2) m�dos�t�s n�lk�l felhaszn�lni:
class Io_circle : public Circle, public Io_obj {
public:
Io_circle* clone() const { return new Io_circle(*this); } // m�sol� konstruktor
haszn�lata
Io_circle(istream&); // kezdeti �rt�kad�s a bemeneti adatfolyamb�l
25. Az oszt�lyok szerepe 1045
static Io_obj* new_circle(istream& s) { return new Io_circle(s); }
// ...
};
Ez annak p�ld�ja, hogyan lehet egy oszt�lyt egy absztrakt oszt�ly haszn�lat�val
beilleszteni
egy hierarchi�ba, ami kevesebb .elorel�t�st. ig�nyel, mint amennyi ahhoz kellene,
hogy
elosz�r csom�pont-oszt�lyk�nt hozzuk l�tre (�12.4.2, �25.3).
Az Io_circle(istream&) konstruktor az objektumokat az iostream-bol kapott
adatokkal t�lti
fel. A new_circle() f�ggv�nyt az io_map-ba tessz�k, hogy az oszt�lyt a
bemeneti/kimeneti
rendszer sz�m�ra ismertt� tegy�k:
io_map["Io_circle"]=&Io_circle::new_circle;
M�s alakzatokat hasonl� m�don hozhatunk l�tre:
class Io_triangle : public Triangle, public Io_obj {
// ...
};
Ha az objektum I/O rendszer elk�sz�t�se t�l f�rads�gos, seg�thet egy sablon:
template<class T> class Io : public T, public Io_obj {
public:
Io* clone() const { return new Io(*this); } // fel�lb�r�lja Io_obj::clone()-t
Io(istream&); // kezdeti �rt�kad�s bemeneti adatfolyamb�l
static Io* new_io(istream& s) { return new Io(s); }
// ...
};
Ha a fenti adott, meghat�rozhatjuk az Io_circle-t:
typedef Io<Circle> Io_circle;
Term�szetesen tov�bbra is pontosan defini�lnunk kell az Io<Circle>::Io(istream&)-
et, mivel
annak r�szleteiben ismernie kell a Circle-t. Az Io sablon p�lda arra, hogyan
illeszthet�nk
be konkr�t t�pusokat egy oszt�lyhierarchi�ba egy le�r� (handle) seg�ts�g�vel,
amely az adott
hierarchia egy csom�pontja. A sablon saj�t param�ter�bol sz�rmaztat, hogy lehetov�
tegye
az �talak�t�st az Io_obj-r�l, de ez sajnos kiz�rja az Io-nak be�p�tett t�pusokra
t�rt�no
alkalmaz�s�t:
1046 Tervez�s a C++ seg�ts�g�vel
typedef Io<Date> Io_date; // konkr�t t�pus beburkol�sa
typedef Io<int> Io_int; // hiba: nem sz�rmaztathatunk be�p�tett t�pusb�l
A probl�ma �gy kezelheto, ha a be�p�tett t�pusok r�sz�re k�l�n sablont biztos�tunk
vagy ha
egy be�p�tett t�pust k�pviselo oszt�lyt haszn�lunk (�25.10[1]).
Ez az egyszeru objektum I/O rendszer nem teljes�thet minden k�v�ns�got, de majdnem
elf
�r egyetlen lapon �s fo elj�r�sait sz�mos c�lra felhaszn�lhatjuk, p�ld�ul
megh�vhatjuk vel
�k a felhaszn�l� �ltal karakterl�nccal megadott f�ggv�nyeket vagy ismeretlen
t�pus� objektumokat
kezelhet�nk fut�si ideju t�pusazonos�t�ssal felder�tett fel�leten kereszt�l.
25.5. Muveletek
A C++-ban a muveletek meghat�roz�s�nak legegyszerubb �s legk�zenfekvobb m�dja
f�ggv
�nyek �r�sa. Ha azonban egy adott muveletet v�grehajt�s elott k�sleltetni kell, �t
kell vinni
.m�shov�., p�ros�tani kell m�s muveletekkel vagy a muvelet saj�t adatokat ig�nyel
(�25.10 [18, 19]), gyakran c�lszerubb azt oszt�ly alakj�ban megadni, mely v�gre
tudja hajtani
a k�v�nt elj�r�st �s egy�b szolg�ltat�sokat is ny�jthat. J� p�ld�k erre a
szabv�nyos algoritmusok
�ltal haszn�lt f�ggv�ny-objektumok (�18.4), valamint az iostream-mel haszn�lt
m�dos�t�k (�21.4.6). Az elobbi esetben a t�nyleges muveletet a f�ggv�nyh�v�
oper�tor hajtja
v�gre, m�g az ut�bbin�l a << vagy a >> oper�tor. A Form (�21.4.6.3) �s a Matrix
(�22.4.7)
eset�ben a v�grehajt�s k�sleltet�s�re egyedi (compositor) oszt�lyokat haszn�lunk,
am�g
a hat�kony v�grehajt�shoz elegendo inform�ci� �ssze nem gyulik.
A muveletoszt�lyok �ltal�nos form�ja egy (jellemzoen valamilyen .csin�ld. (do_it)
nevu)
virtu�lis f�ggv�nyt tartalmaz� egyszeru oszt�ly:
class Action {
public:
virtual int do_it(int) = 0;
virtual ~Action() { }
};
Ha ez adott, olyan k�dot �rhatunk . mondjuk egy men��t . amely a muveleteket
k�sobbi
v�grehajt�sra .elrakt�rozhatja., an�lk�l, hogy f�ggv�nymutat�kat haszn�lna, b�rmit
is tudna
a megh�vott objektumokr�l vagy egy�ltal�n ismern� a megh�vott muvelet nev�t:
25. Az oszt�lyok szerepe 1047
class Write_file : public Action {
File& f;
public:
int do_it(int) { return f.write().succeed(); }
};
class Error_response : public Action {
string message;
public:
int do_it(int);
};
int Error_response::do_it(int)
{
Response_box db(message.c_str(), "Folytat","M�gse","Ism�t");
switch (db.get_response()) {
case 0:
return 0;
case 1:
abort();
case 2:
current_operation.redo();
return 1;
}
}
Action* actions[] = {
new Write_file(f),
new Error_response("Megint elrontotta"),
// ...
};
Az Action-t haszn�l� k�d teljesen elszigetelheto, nem kell, hogy b�rmit is tudjon
az olyan
sz�rmaztatott oszt�lyokr�l, mint a Write_file �s az Error_response.
Ez igen eroteljes m�dszer, mellyel �vatosan kell b�nniuk azoknak, akik legink�bb a
funkcion
�lis elemekre bont�sban szereztek tapasztalatot. Ha t�l sok oszt�ly kezd az
Action-re
hasonl�tani, lehet, hogy a rendszer �tfog� terve t�lzottan muveletk�zpont�v� v�lt.

Megeml�tendo, hogy az oszt�lyok j�vobeni haszn�latra is t�rolhatnak muveleteket,


illetve
olyanokat is tartalmazhatnak, melyeket egy t�voli g�p hajt majd v�gre (�25.10
[18]).
1048 Tervez�s a C++ seg�ts�g�vel
25.6. Fel�letoszt�lyok
Az egyik legfontosabb oszt�lyfajta a szer�ny �s legt�bbsz�r elhanyagolt
fel�letoszt�ly. Egy
fel�letoszt�ly nem sok dolgot csin�l . ha csin�lna, nem lenne fel�letoszt�ly .,
csup�n helyi
sz�ks�gletekhez igaz�tja egy szolg�ltat�s megjelen�s�t. Mivel elvileg lehetetlen
mindig,
minden sz�ks�gletet egyform�n j�l kiel�g�teni, a fel�letoszt�lyok
n�lk�l�zhetetlenek, mert
an�lk�l teszik lehetov� a k�z�s haszn�latot, hogy minden felhaszn�l�t egyetlen,
k�z�s
.k�nyszerzubbonyba. eroszakoln�nak.
A fel�letek legtiszt�bb form�jukban m�g g�pi k�dot sem ig�nyelnek. Vegy�k a �13.5-
bol
a Vector specializ�lt v�ltozat�t:
template<class T> class Vector<T*> : private Vector<void*> {
public:
typedef Vector<void*> Base;
Vector() : Base() {}
Vector(int i) : Base(i) {}
T*& operator[](int i) { return static_cast<T*&>(Base::operator[](i)); }
// ...
};
Ez a (r�szlegesen) specializ�lt v�ltozat a nem biztons�gos Vector<void*>-ot egy
sokkal
haszn�lhat�bb, t�pusbiztos vektoroszt�ly-csal�dd� teszi. A helyben kifejtett
(inline) f�ggv�-
nyek gyakran n�lk�l�zhetetlenek ahhoz, hogy a fel�letoszt�lyokat megengedhess�k
magunknak.
A fentihez hasonl� esetekben, ahol a helyben kifejtett k�zvet�to f�ggv�ny csak t�-

pusigaz�t�st v�gez, sem a fut�si ido, sem a t�rig�ny nem no.


Term�szetesen az absztrakt t�pust �br�zol� absztrakt b�zisoszt�lyok, melyeket
konkr�t t�pusok
(�25.2) val�s�tanak meg, szint�n a fel�letoszt�lyok egy form�j�t jelentik, mint
ahogy
a �25.7 le�r�i is azok. Itt azonban azon oszt�lyokra �sszpontos�tunk, melyeknek a
fel�let
igaz�t�s�n k�v�l nincs m�s feladatuk.
Vegy�k k�t, t�bbsz�r�s �r�kl�st haszn�l� hierarchia �sszef�s�l�s�nek probl�m�j�t.
Mit lehet
tenni, ha n�v�tk�z�s l�p fel, vagyis k�t oszt�ly ugyanazt a nevet haszn�lja
teljesen elt�-
ro muveleteket v�gzo virtu�lis f�ggv�nyekhez? Vegy�nk p�ld�ul egy vadnyugati
videoj�t�-
kot, melyben a felhaszn�l�i beavatkoz�sokat egy �ltal�nos ablakoszt�ly kezeli:
25. Az oszt�lyok szerepe 1049
class Window {
// ...
virtual void draw(); // k�p megjelen�t�se
};
class Cowboy {
// ...
virtual void draw(); // pisztoly elor�nt�sa a pisztolyt�sk�b�l
};
class Cowboy_window : public Cowboy, public Window {
// ...
};
A j�t�kban a cowboy mozgat�s�t egy Cowboy_window k�pviseli �s ez kezeli a
felhaszn�l� (j�-
t�kos) �s a cowboy figura k�z�tti .k�lcs�nhat�sokat. is. A Window �s a Cowboy
tagokk�nt
val� bevezet�se helyett t�bbsz�r�s �r�kl�st szeretn�nk haszn�lni, mivel sz�mos
kiszolg�l�
f�ggv�nyt kell meghat�roznunk mind a Window-k, mind a Cowboy-ok r�sz�re,
a Cowboy_window-kat pedig olyan f�ggv�nyeknek szeretn�nk �tadni, melyek nem
k�v�nnak
a programoz�t�l k�l�nleges munk�t. Ez azonban ahhoz a probl�m�hoz vezet, hogy meg
kell
adni a Cowboy::draw() �s Window::draw() f�ggv�nyek Cowboy_window v�ltozat�t.
A Cowboy_window-ban csak egy draw() nevu f�ggv�ny lehet. Ennek viszont . mivel
a Window-kat �s Cowboy-okat a Cowboy_window-k ismerete n�lk�l kezelj�k . fel�l
kell
�rnia mind a Cowboy, mind a Window draw() f�ggv�ny�t. Egyetlen v�ltozattal nem
�rhatjuk
fel�l mind a kettot, mert a k�z�s n�v ellen�re a k�t draw() f�ggv�ny szerepe m�s.
V�gezet
�l azt is szeretn�nk, hogy a Cowboy_window egyedi, egy�rtelmu neveket biztos�tson
az
�r�k�lt Cowboy::draw() �s Window:: draw() f�ggv�nyek sz�m�ra.
A probl�ma megold�s�hoz sz�ks�g�nk van egy-egy tov�bbi oszt�lyra a Cowboy-hoz �s
a Window-hoz. Ezek az oszt�lyok vezetik be a k�t �j nevet a draw() f�ggv�nyekre �s
biztos
�tj�k, hogy a Cowboy-ban �s a Window-ban a draw() f�ggv�nyh�v�sok az �j n�ven h�vj
�k a f�ggv�nyeket:
class CCowboy : public Cowboy { // fel�let a Cowboy-hoz: a draw()-t �tnevezi
public:
virtual int cow_draw() = 0;
void draw() { cow_draw(); } // fel�l�rja Cowboy::draw()-t
};
class WWindow : public Window { // fel�let a Window-hoz: a draw()-t �tnevezi
public:
virtual int win_draw() = 0;
void draw() { win_draw(); } // fel�l�rja Window::draw()-t
};
1050 Tervez�s a C++ seg�ts�g�vel
Most m�r �sszerakhatunk egy Cowboy_window-t a CCowboy �s a WWindow fel�letoszt�-
lyokb�l �s a k�v�nt hat�ssal fel�lb�r�lhatjuk a cow_draw()-t �s win_draw()-t:
class Cowboy_window : public CCowboy, public WWindow {
// ...
void cow_draw();
void win_draw();
};
Vegy�k �szre, hogy a probl�ma csak amiatt volt komoly, hogy a k�t draw()
f�ggv�nynek
ugyanaz a param�tert�pusa. Ha a param�tert�pusok k�l�nb�znek, a szok�sos
t�lterhel�sfelold
�si szab�lyoknak k�sz�nhetoen nem lesz probl�ma, annak ellen�re, hogy az egym�ssal

kapcsolatban nem l�vo f�ggv�nyeknek ugyanaz a nev�k.


Egy fel�letoszt�ly minden haszn�lat�ra elk�pzelhet�nk egy k�l�nleges c�l� nyelvi
bov�t�st,
mely a k�v�nt igaz�t�st hat�konyabban vagy eleg�nsabban tudn� elv�gezni. A
fel�letoszt�-
lyok egyes haszn�latai azonban ritk�k, �s ha mindet egyedi nyelvi szerkezettel
t�mogatn�nk,
t�lzottan bonyolultt� tenn�nk programjainkat. Az oszt�lyhierarchi�k
�sszef�s�l�s�bol eredo
n�v�tk�z�sek nem �ltal�nosak (ahhoz k�pest, hogy milyen gyakran �r oszt�lyt egy
programoz
�), ink�bb abb�l erednek, hogy elt�ro k�rnyezetben l�trehozott hierarchi�kat
olvasztunk
�ssze (pl. j�t�kokat �s ablakrendszereket). Az ilyen elt�ro hierarchi�kat nem
k�nnyu
�sszef�s�lni �s a n�v�tk�z�sek felold�sa gyakran csak csepp a tengerben a
programoz� sz�-
m�ra. Probl�m�t jelenthet az elt�ro hibakezel�s, kezdeti �rt�kad�s �s t�rkezel�si
m�d is.
A n�v�tk�z�sek felold�s�t itt az�rt t�rgyaljuk, mert a k�zvet�to/tov�bb�t�
szerepet bet�lto fel
�letoszt�lyok bevezet�se m�s ter�leteken is alkalmazhat�; nem csak nevek
megv�ltoztat�-
s�ra, hanem param�terek �s visszat�r�si �rt�kek t�pus�nak m�dos�t�s�ra, fut�si
ideju ellen-
orz�s bevezet�s�re stb. is. Minthogy a CCowboy::draw() �s WWindow::draw()
f�ggv�nyek
virtu�lisak, nem optimaliz�lhat�k egyszeru helyben kifejt�ssel. Lehets�ges
viszont, hogy
a ford�t� felismeri, hogy ezek egyszeru tov�bb�t� f�ggv�nyek, �s a rajtuk �tmeno
h�v�si l�ncok
alapj�n k�pes optim�lis k�dot k�sz�teni.
25.6.1. Fel�letek igaz�t�sa
A fel�letf�ggv�nyek egyik fo felhaszn�l�sa egy fel�let igaz�t�sa �gy, hogy az
jobban illeszkedj
�k a felhaszn�l� elv�r�saihoz; vagyis egyetlen fel�letbe helyezz�k azt a k�dot,
amely
k�l�nben a felhaszn�l�i k�don bel�l sz�t lenne sz�rva. A szabv�nyos vector p�ld�ul
nulla
alap�, azaz az elso elem indexe 0. Azoknak a felhaszn�l�knak, akik a 0-t�l size-1-
ig terjed
o tartom�nyt�l elt�rot akarnak, igaz�t�st kell v�gezni�k:
25. Az oszt�lyok szerepe 1051
void f()
{
vector v<int>(10); // [0:9] tartom�ny
// �gy tesz�nk, mintha v a [1:10] tartom�nyban lenne
for (int i = 1; i<=10; i++) {
v[i-1] = 7; // ne felejts�k az indexet igaz�tani
// ...
}
}
M�g jobb, ha a vector-nak tetszoleges hat�rokat biztos�tunk:
class Vector : public vector<int> {
int lb;
public:
Vector(int low, int high) : vector<int>(high-low+1) { lb=low; }
int& operator[](int i) { return vector<int>::operator[](i-lb); }
int low() { return lb; }
int high() { return lb+size()-1; }
};
A Vector az al�bbi m�don haszn�lhat�:
void g()
{
Vector v(1,10); // [1:10] tartom�ny
for (int i = 1; i<=10; i++) {
v[i] = 7;
// ...
}
}
Ez az elozo p�ld�hoz k�pest nem okoz t�bbletterhel�st. Vil�gos, hogy a Vector
v�ltozatot
k�nnyebb olvasni �s kisebb a hib�z�s lehetos�ge is.
A fel�letoszt�lyok rendszerint meglehetosen kicsik �s kev�s feladatot v�geznek, de
minden
�tt felbukkannak, ahol k�l�nb�zo hagyom�nyok szerint meg�rt programoknak kell
egy�ttmuk�dni�k, mivel ilyenkor a k�l�nb�zo szab�lyok k�z�tt k�zvet�t�sre van
sz�ks�g.
1052 Tervez�s a C++ seg�ts�g�vel
A fel�letoszt�lyokat gyakran haszn�lj�k p�ld�ul arra, hogy nem C++ k�dnak C++
fel�letet
adjanak, �s az alkalmaz�s k�dj�t elszigetelj�k a k�nyvt�rak�t�l (nyitva hagyva egy
k�nyvt
�r m�sikkal val� helyettes�t�s�nek a lehetos�g�t).
A fel�letoszt�lyok m�sik fontos felhaszn�l�si ter�lete az ellenorz�tt vagy
korl�tozott fel�letek
biztos�t�sa. Nem szokatlan p�ld�ul, ha olyan eg�sz t�pus� v�ltoz�ink vannak,
melyek
�rt�ke csak egy adott tartom�nyon bel�l mozoghat. Ez (fut�si idoben) egy egyszeru
sablonnal
k�nyszer�theto ki:
template<int low, int high> class Range {
int val;
public:
class Error { }; // kiv�teloszt�ly
Range(int i) { Assert<Error>(low<=i&&i<high); val = i; } // l�sd �24.3.7.2
Range operator=(int i) { return *this=Range(i); }
operator int() { return val; }
// ...
};
void f(Range<2,17>);
void g(Range<-10,10>);
void h(int x)
{
Range<0,2001> i = x; // Range::Error kiv�telt v�lthat ki
int i1 = i;
f(3);
f(17); // Range::Error kiv�telt v�lt ki
g(-7);
g(100); // Range::Error kiv�telt v�lt ki
}
A Range sablon k�nnyen bov�theto �gy, hogy tetszoleges skal�r t�pus� tartom�nyok
kezel
�s�re legyen k�pes (�25.10[7]).
Azokat a fel�letoszt�lyokat, amelyek a m�s oszt�lyokhoz val� hozz�f�r�st
ellenorzik vagy
azok fel�let�t igaz�tj�k, n�ha beburkol� (csomagol�, wrapper) oszt�lyoknak
nevezz�k.
25. Az oszt�lyok szerepe 1053
25.7. Le�r� oszt�lyok
Az absztrakt t�pusok hat�kony elv�laszt�st biztos�tanak a fel�letek �s
megval�s�t�saik k�-
z�tt, de az absztrakt t�pus �ltal adott fel�let �s annak egy konkr�t t�pus �ltal
ny�jtott megval
�s�t�sa k�z�tti kapcsolat . ahogyan a �25.3-ban haszn�ltuk . tart�s. Nem lehet
p�ld�ul
egy absztrakt bej�r�t az egyik forr�sr�l (mondjuk egy halmazr�l) �tk�tni egy
m�sikra
(mondjuk egy adatfolyamra), ha az eredeti forr�s kimer�lt.
Tov�bb�, hacsak nem mutat�kon vagy referenci�kon kereszt�l kezel�nk egy absztrakt
oszt
�lyt k�pviselo objektumot, elvesz�tj�k a virtu�lis f�ggv�nyek elonyeit. A
felhaszn�l�i k�d
f�ggni fog a megval�s�t� oszt�lyokt�l, mivel az absztrakt t�pusok sz�m�ra nem
foglalhat�
hely statikusan vagy a veremben (bele�rtve az �rt�k szerinti param�ter�tv�telt
is), an�lk�l,
hogy tudn�nk a t�pus m�ret�t. A mutat�k �s hivatkoz�sok haszn�lata azzal j�r, hogy
a t�rkezel
�s terhe a felhaszn�l� k�dra h�rul.
Az absztrakt oszt�lyos megk�zel�t�s m�sik korl�tja az, hogy az oszt�lyobjektumok
r�gz�tett
m�retuek. Az oszt�lyokat azonban fogalmak �br�zol�s�ra haszn�ljuk, melyek
megval�s�t�-
s�hoz k�l�nb�zo mennyis�gu t�rter�let kell.
E k�rd�sek kezel�s�nek kedvelt m�dja k�t r�szre osztani azt, amit egyetlen
objektumk�nt
haszn�lunk. Az egyik lesz a felhaszn�l�i fel�letet ad� le�r� (handle), a m�sik
pedig az �br
�zol�s, amely az objektum �llapot�nak eg�sz�t vagy annak java r�sz�t t�rolja. A
le�r� �s az
�br�zol�s k�z�tti kapcsolatot �ltal�ban egy, a le�r�ban levo mutat� biztos�tja. A
le�r�ban az
�br�zol�sra hivatkoz� mutat�n k�v�l �ltal�ban m�g van egy-k�t adat, de nem sok.
Ebbol k�-
vetkezik, hogy a le�r� szerkezete rendszerint stabil (m�g akkor is, ha az
�br�zol�s megv�ltozik),
illetve hogy a le�r�k meglehetosen kicsik �s viszonylag szabadon mozgathat�k, �gy
a felhaszn�l�nak nem kell mutat�kat �s referenci�kat haszn�lnia.
1054 Tervez�s a C++ seg�ts�g�vel
Le�r� �br�zol�s
A �11.12 String-je a le�r� egyszeru p�ld�ja. A le�r� fel�letet, hozz�f�r�s-
szab�lyoz�st �s t�rkezel
�st biztos�t az �br�zol�s r�sz�re. Ebben az esetben mind a le�r�, mind az
�br�zol�s
konkr�t t�pusok, b�r az �br�zol� oszt�ly t�bbnyire absztrakt oszt�ly szokott
lenni.
Vegy�k a �25.3-b�l a Set absztrakt t�pust. Hogyan gondoskodhatunk sz�m�ra egy
le�r�r�l �s
milyen elony�kkel, illetve h�tr�nyokkal j�rhat ez? Egy adott halmazoszt�lyhoz
egyszeruen
megadhatunk egy le�r�t, a -> oper�tor t�lterhel�s�vel:
template<class T> class Set_handle {
Set<T>* rep;
public:
Set<T>* operator->() { return rep; }
Set_handle(Set<T>* pp) : rep(pp) { }
};
Ez nem befoly�solja jelentosen a Set-ek haszn�lat�nak m�dj�t; egyszeruen
Set_handle-eket
adunk �t Set&-ek vagy Set*-ok helyett:
void f(Set_handle<int> s)
{
for (int* p = s->first(); p; p = s->next())
{
// ...
}
}
void user()
{
Set_handle<int> sl(new List_set<int>);
Set_handle<int> v(new Vector_set<int>(100));
f(sl);
f(v);
}
Gyakran t�bbet k�v�nunk egy le�r�t�l, mint hogy a hozz�f�r�srol gondoskodjon.
P�ld�ul,
ha a Set oszt�lyt �s a Set_handle oszt�lyt egy�tt tervezt�k, a hivatkoz�sokat
k�nnyen megsz
�ml�lhatjuk, ha minden Set-ben elhelyez�nk egy haszn�latsz�ml�l�t. Persze a le�r�t
�ltal
�ban nem akarjuk egy�tt tervezni azzal, aminek a le�r�ja, �gy �n�ll� objektumban
kell t�-
rolnunk minden adatot, amit a le�r�nak biztos�tania kell. M�s sz�val, sz�ks�g�nk
lenne nem
tolakod� (non-intensive) le�r�kra is a tolakod�k mellett. �me egy le�r�, mely
felsz�mol egy
objektumot, amikor annak utols� le�r�ja is megsemmis�l:
25. Az oszt�lyok szerepe 1055
template<class X> class Handle {
X* rep;
int* pcount;
public:
X* operator->() { return rep; }
Handle(X* pp) : rep(pp), pcount(new int(1)) { }
Handle(const Handle& r) : rep(r.rep), pcount(r.pcount) { (*pcount)++; }
Handle& operator=(const Handle& r)
{
if (rep == r.rep) return *this;
if (--(*pcount) == 0) {
delete rep;
delete pcount;
}
rep = r.rep;
pcount = r.pcount;
(*pcount)++;
return *this;
}
~Handle() { if (--(*pcount) == 0) { delete rep; delete pcount; } }
// ...
};
Egy ilyen le�r� szabadon �tadhat�:
void f1(Handle<Set>);
Handle<Set> f2()
{
Handle<Set> h(new List_set<int>);
// ...
return h;
}
void g()
{
Handle<Set> hh = f2();
f1(hh);
// ...
}
1056 Tervez�s a C++ seg�ts�g�vel
Itt az f2()-ben l�trehozott halmaz t�rlodik a g()-bol val� kil�p�skor . hacsak
f1() fenn nem
tartja annak egy m�solat�t. (A programoz�nak errol nem kell tudnia.)
Term�szetesen ennek a k�nyelemnek �ra van, de a haszn�latsz�ml�l� t�rol�s�nak �s
fenntart
�s�nak k�lts�ge a legt�bb alkalmaz�sn�l elfogadhat�.
N�ha hasznos az �br�zol�sra hivatkoz� mutat�t a le�r�b�l kinyerni �s k�zvetlen�l
felhaszn
�lni. Erre akkor lehet sz�ks�g, ha egy objektumot egy olyan f�ggv�nynek kell
�tadni,
amely nem ismeri a le�r�kat. Ez a megold�s j�l muk�dik, felt�ve, hogy a h�vott
f�ggv�ny
nem semmis�ti meg a neki �tadott objektumot vagy egy arra hivatkoz� mutat�t nem
t�rol
a h�v�hoz val� visszat�r�s ut�ni haszn�latra. Egy olyan muvelet szint�n hasznos
lehet,
amely a le�r�t egy �j �br�zol�shoz kapcsolja:
template<class X> class Handle {
// ...
X* get_rep() { return rep; }
void bind(X* pp)
{
if (pp != rep) {
if (--*pcount == 0) {
delete rep;
*pcount = 1; // pcount �jrahasznos�t�sa
}
else
pcount = new int(1); // �j pcount
rep = pp;
}
}
};
Vegy�k �szre, hogy Handle-bol �j oszt�lyokat sz�rmaztatni nem k�l�n�sebben
hasznos, ez
ugyanis egy konkr�t t�pus, virtu�lis f�ggv�nyek n�lk�l. Az alapelv, hogy egy
b�zisoszt�ly
�ltal meghat�rozott teljes oszt�lycsal�dhoz egyetlen le�r� oszt�lyunk legyen.
Ebbol a b�zisoszt
�lyb�l sz�rmaztatni viszont m�r hasznos lehet. Ez a csom�pont-oszt�lyokra �pp�gy
�rv
�nyes, mint az absztrakt t�pusokra.
Fenti form�j�ban a Handle nem foglalkozik �r�kl�ssel. Ahhoz, hogy egy olyan
oszt�lyunk
legyen, mely �gy muk�dik, mint egy val�di haszn�latsz�ml�l�, a Handle-t egy�tt
kell haszn
�lni a �13.6.3.1 Ptr-j�vel (l�sd �25.10[2]).
25. Az oszt�lyok szerepe 1057
Az olyan le�r�t, melynek fel�lete k�zel azonos azon oszt�ly�val, melynek le�r�ja,
gyakran
nevezz�k proxy-nak. Ez k�l�n�sen azokra a le�r�kra vonatkozik, melyek t�voli g�pen
l�vo
objektumokra hivatkoznak.
25.7.1. A le�r�k muveletei
A -> oper�tor t�lterhel�se lehetov� teszi, hogy egy le�r� minden hozz�f�r�skor
megkapja
a vez�rl�st, �s valamilyen muveletet v�gezzen egy objektumon. A le�r�n kereszt�l
hozz�-
f�rheto objektum felhaszn�l�sainak sz�m�r�l p�ld�ul statisztik�t k�sz�thet�nk:
template <class T> class Xhandle {
T* rep;
int no_of_accesses;
public:
T* operator->() { no_of_accesses++; return rep; }
// ...
};
Azon le�r�k, melyekn�l a hozz�f�r�s elott �s ut�n is valamilyen muveletet kell
v�gezni, kidolgozottabb
k�dot ig�nyelnek. Tegy�k fel p�ld�ul, hogy egy olyan halmazt szeretn�nk,
amely z�rolhat�, am�g besz�r�s vagy elt�vol�t�s folyik. Az �br�zol� oszt�ly
fel�let�t l�nyeg
�ben meg kell ism�telni a le�r� oszt�lyban:
template<class T> class Set_controller {
Set<T>* rep;
Lock lock;
// ...
public:
void insert(T* p) { Lock_ptr x(lock); rep->insert(p); } // l�sd �14.4.1
void remove(T* p) { Lock_ptr x(lock); rep->remove(p); }
int is_member(T* p) { return rep->is_member(p); }
T get_first() { T* p = rep->first(); return p ? *p : T(); }
T get_next() { T* p = rep->next(); return p ? *p : T(); }
T first() { Lock_ptr x(lock); T tmp = *rep->first(); return tmp; }
T next() { Lock_ptr x(lock); T tmp = *rep->next(); return tmp; }
// ...
};
1058 Tervez�s a C++ seg�ts�g�vel
Ezekrol a tov�bb�t� f�ggv�nyekrol gondoskodni f�rads�gos (�gy hib�t is v�thet�nk
k�zben),
j�llehet neh�zs�get nem jelent �s a fut�si idot sem n�veli.
Vegy�k �szre, hogy a Set-nek csak n�melyik f�ggv�nye k�v�n z�rol�st. Tapasztalatom
szerint
�ltal�nos, hogy egy elo- �s ut�tev�kenys�geket ig�nylo oszt�ly a muveleteket csak
n�-
h�ny tagf�ggv�nyn�l k�v�nja meg. A minden muveletn�l val� z�rol�s . ahogy egyes
rendszerfigyel
okn�l lenni szokott . felesleges z�rol�sokhoz vezet �s �szrevehetoen lass�thatja
a p�rhuzamos v�grehajt�st.
A le�r�n v�gzett muveletek alapos kidolgoz�s�nak elonye a -> oper�tor
t�lterhel�s�vel
szemben az, hogy a Set_controller oszt�lyb�l sz�rmaztathatunk. Sajnos a le�r�k
n�h�ny elo-
ny�s tulajdons�g�t feladjuk, ha a sz�rmaztatott oszt�lyhoz adattagokat tesz�nk,
mert a k�-
z�sen haszn�lt k�d mennyis�ge az egyes le�r�kban levo k�d mennyis�g�hez
viszony�tva
cs�kken.
25.8. Keretrendszerek
A �25.2.�25.7-ben le�rt oszt�lyfajt�kb�l �p�tett komponensek az�ltal t�mogatj�k a
k�dtervez
�st �s -�jrahasznos�t�st, hogy �p�tokock�kat �s kombin�ci�s lehetos�geket
biztos�tanak.
A programoz�k �s az alkalmaz�sk�sz�to eszk�z�k �p�tik fel azt a v�zat, amelybe
ezek az
�p�tokock�k beleillenek. A tervez�s �s �jrahasznos�t�s t�mogat�s�nak egy m�sik,
�ltal�ban
nehezebb m�dja egy olyan, k�z�s v�zat ad� k�d meg�r�sa, melybe az
alkalmaz�sk�sz�to
�p�tokock�kk�nt az adott alkalmaz�sra jellemzo k�dokat illeszti be. Ez az, amit
�ltal�ban
keretrendszernek (application framework) h�vunk. Az ilyen v�zat biztos�t�
oszt�lyok fel�-
lete gyakran olyan .k�v�r., hogy hagyom�nyos �rtelemben aligha nevezhetok
t�pusoknak;
ink�bb teljes alkalmaz�snak tunnek, b�r nem v�geznek semmilyen tev�kenys�get;
azokat
az alkalmaz�sprogramoz� biztos�tja.
P�ldak�ppen vegy�nk egy szurot, vagyis egy olyan programot, amely egy bemeneti
adatfolyamb
�l olvas, majd annak alapj�n (esetleg) elv�gez n�h�ny muveletet, (esetleg) egy
kimeneti
adatfolyamot hoz l�tre, �s (esetleg) ad egy v�geredm�nyt. Elso �tlet�nk bizony�ra
az, hogy a programhoz olyan keretrendszert k�sz�ts�nk, amely olyan muvelethalmazt
ad
meg, melyet egy alkalmaz�sprogramoz� biztos�t:
25. Az oszt�lyok szerepe 1059
class Filter {
public:
class Retry {
public:
virtual const char* message() { return 0; }
};
virtual void start() { }
virtual int read() = 0;
virtual void write() { }
virtual void compute() { }
virtual int result() = 0;
virtual int retry(Retry& m) { cerr << m.message() << '\n'; return 2; }
virtual ~Filter() { }
};
Azon f�ggv�nyeket, melyeket a sz�rmaztatott oszt�lynak kell biztos�tania, tiszt�n
virtu�lis
(pure virtual) f�ggv�nyekk�nt deklar�ltuk; a t�bbit egyszeruen �gy defini�ltuk,
mint amik
nem v�geznek muveletet.
A keretrendszer gondoskodik egy fociklusr�l �s egy kezdetleges hibakezelo
elj�r�sr�l is:
int main_loop(Filter* p)
{
for(;;) {
try {
p->start();
while (p->read()) {
p->compute();
p->write();
}
return p->result();
}
catch (Filter::Retry& m) {
if (int i = p->retry(m)) return i;
}
catch (...) {
cerr << "V�gzetes szurohiba\n";
return 1;
}
}
}
1060 Tervez�s a C++ seg�ts�g�vel
A programot v�g�l �gy �rhatjuk meg:
class My_filter : public Filter {
istream& is;
ostream& os;
int nchar;
public:
int read() { char c; is.get(c); return is.good(); }
void compute() { nchar++; }
int result() { os << nchar << " elolvasott karakter\n"; return 0; }
My_filter(istream& ii, ostream& oo) : is(ii), os(oo), nchar(0) { }
};
�s �gy ind�thatjuk el:
int main()
{
My_filter f(cin,cout);
return main_loop(&f);
}
Term�szetesen ahhoz, hogy igaz�n haszn�t vegy�k, a keretrendszernek t�bb
szerkezetet �s
j�val t�bb szolg�ltat�st kellene ny�jtania, mint ebben az egyszeru p�ld�ban. A
keretrendszer
�ltal�ban csom�pont-oszt�lyokb�l �ll� hierarchia. Ha egy m�lyen egym�sba �gyazott
elemekb
ol �ll� hierarchi�ban az alkalmaz�sprogramoz�val �ratjuk meg a lev�l oszt�lyokat,
lehet
ov� v�lik a k�z�s elemek t�bb program �ltal val� haszn�lata �s a hierarchia �ltal
ny�jtott
szolg�ltat�sok �jrahasznos�t�sa. A keretrendszert egy k�nyvt�r is t�mogathatja,
olyan oszt�-
lyokkal, melyek az alkalmaz�sprogramoz� sz�m�ra a muveletoszt�lyok
meghat�roz�s�n�l
hasznosnak bizonyulhatnak.
25.9. Tan�csok
[1] Az egyes oszt�lyok haszn�lat�ra vonatkoz�an hozzunk megfontolt d�nt�seket.
�25.1.
[2] �vakodjunk a v�laszt�s k�nyszer�tol, melyet az oszt�lyok elt�ro fajt�i
okoznak.
�25.1.
[3] Egyszeru, f�ggetlen fogalmak �br�zol�s�ra haszn�ljunk konkr�t t�pusokat.
�25.2.
[4] Haszn�ljunk konkr�t t�pusokat azon fogalmak �br�zol�s�ra, melyekn�l n�lk�-
l�zhetetlen az optim�lishoz k�zeli hat�konys�g. �25.2.
25. Az oszt�lyok szerepe 1061
[5] Konkr�t oszt�lyb�l ne sz�rmaztassunk. �25.2.
[6] Haszn�ljunk absztrakt oszt�lyokat olyan fel�letek �br�zol�s�ra, ahol az
objektumok
�br�zol�sa v�ltozhat. �25.3.
[7] Haszn�ljunk absztrakt oszt�lyokat olyan fel�letek �br�zol�s�ra, ahol az
objektumok
k�l�nb�zo �br�zol�sainak egy�tt kell l�tezni�k. �25.3.
[8] A l�tezo t�pusok �j fel�leteinek �br�zol�s�ra haszn�ljunk absztrakt
oszt�lyokat.
�25.3.
[9] Ha hasonl� fogalmak k�z�sen haszn�lj�k a megval�s�t�s egyes r�szeit,
haszn�ljunk
csom�pont-oszt�lyokat. �25.4.
[10] A megval�s�t�s fokozatos kidolgoz�s�hoz haszn�ljunk csom�pont-oszt�lyokat.
�25.4.
[11] Az objektumok fel�let�nek kinyer�s�re haszn�ljunk fut�si ideju t�pusazonos�-
t�st. �25.4.1.
[12] Az �llapothoz kapcsol�d� muveletek �br�zol�s�ra haszn�ljunk oszt�lyokat.
�25.5.
[13] Azon muveletek �br�zol�s�ra, melyeket t�rolni, �tvinni, vagy k�sleltetni
kell,
haszn�ljunk oszt�lyokat. �25.5.
[14] Ha egy oszt�lyt �j felhaszn�l�shoz kell igaz�tani (az oszt�ly m�dos�t�sa
n�lk�l),
haszn�ljunk fel�letoszt�lyokat. �25.6.
[15] Ellenorz�s hozz�ad�s�ra haszn�ljunk fel�letoszt�lyokat. �25.6.1.
[16] Haszn�ljunk le�r�kat, hogy elker�lj�k a mutat�k �s referenci�k k�zvetlen
haszn
�lat�t. �25.7.
[17] A k�z�sen haszn�lt �br�zol�sok kezel�s�re haszn�ljunk le�r�kat. �25.7.
[18] Ha az alkalmaz�si ter�let lehetov� teszi, hogy a vez�rl�si szerkezetet elore
meghat
�rozzuk, haszn�ljunk keretrendszert. �25.8.
25.10. Gyakorlatok
1. (*1) A �25.4.1 Io sablonja nem muk�dik be�p�tett t�pusokra. M�dos�tsuk �gy,
hogy muk�dj�n.
2. (*1.5) A �25.7 Handle sablonja nem t�kr�zi azon oszt�lyok �r�kl�si
kapcsolatait,
amelyeknek le�r�ja. M�dos�tsuk �gy, hogy t�kr�zze (vagyis lehessen egy
Handle<Circle>-lel egy Handle<Shape>-nek �rt�ket adni, de nem ford�tva).
3. (*2.5) Ha adott egy String oszt�ly, azt �br�zol�sk�nt haszn�lva �s muveleteit
virtu
�lis f�ggv�nyekk�nt megadva hozzunk l�tre egy m�sik karakterl�nc-oszt�lyt.
Hasonl�tsuk �ssze a k�t oszt�ly teljes�tm�ny�t. Pr�b�ljunk tal�lni egy �rtelmes
oszt�lyt, amely a legjobban a virtu�lis f�ggv�nyekkel rendelkezo karakterl�ncoszt
�lyb�l t�rt�no nyilv�nos sz�rmaztat�ssal val�s�that� meg.
1062 Tervez�s a C++ seg�ts�g�vel
4. (*4) Tanulm�nyozzunk k�t sz�les k�rben haszn�lt k�nyvt�rat. Oszt�lyozzuk
a k�nyvt�ri oszt�lyokat konkr�t t�pusokk�nt, absztrakt t�pusokk�nt, csom�pontoszt
�lyokk�nt, le�r� oszt�lyokk�nt, �s fel�letoszt�lyokk�nt. Haszn�lnak-e
absztrakt �s konkr�t csom�pont-oszt�lyokat? Van-e a k�nyvt�rakban levo oszt�-
lyokra megfelelobb oszt�lyoz�s? Haszn�lnak-e k�v�r fel�leteket? Milyen t�rkezel
�si m�dot haszn�lnak? Milyen lehetos�gek vannak . ha vannak . fut�si ideju
t�pusinform�ci�ra?
5. (*2) A Filter v�z (�25.8) seg�ts�g�vel �rjunk olyan programot, mely egy
bemeneti
adatfolyamb�l elt�vol�tja a szomsz�dos ism�telt szavakat, majd az eredm�nyt �tm
�solja a kimenetre.
6. (*2) A Filter keretrendszer seg�ts�g�vel �rjunk olyan programot, mely egy
bemeneti
adatfolyamban megsz�ml�lja a szavak gyakoris�g�t �s kimenetk�nt gyakoris
�gi sorrendben felsorolja a (sz�, sz�m) p�rokat.
7. (*1.5) �rjunk egy Range sablont, mely sablonparam�terekk�nt veszi �t a tartom
�nyt �s az elemt�pust.
8. (*1) �rjunk egy Range sablont, mely a tartom�nyt konstruktor-param�terekk�nt
veszi �t.
9. (*2) �rjunk egy egyszeru karakterl�nc-oszt�lyt, mely nem v�gez hibaellenorz�st.

�rjunk egy m�sik oszt�lyt, mely ellenorzi az elobbihez val� hozz�f�r�st. Vitassuk
meg az alapszolg�ltat�sok �s a hibaellenorz�s elv�laszt�s�nak elonyeit �s h�tr�-
nyait.
10. (*2.5) K�sz�ts�k el a �25.4.1 objektum I/O rendszer�t n�h�ny t�pusra, k�zt�k
legal�bb az eg�szekre, a karakterl�ncokra �s egy tetszolegesen kiv�lasztott oszt
�lyhierarchi�ra.
11. (*2.5) Hat�rozzuk meg a Storable oszt�lyt, mint absztrakt b�zisoszt�lyt
a write_out() �s read_in() virtu�lis f�ggv�nyekkel. Az egyszerus�g kedv��rt t�-
telezz�k fel, hogy egy perzisztens t�rol�hely meghat�roz�s�hoz egy karakterl
�nc elegendo. Haszn�ljuk fel a Storage oszt�lyt egy olyan szolg�ltat�sban, mely
a Storable-bol sz�rmaztatott oszt�lyok objektumait �rja lemezre �s ugyanilyen
objektumokat olvas lemezrol. Ellenorizz�k n�h�ny tetsz�s szerint v�lasztott oszt
�llyal.
12. (*4) Hozzuk l�tre a Persistent alaposzt�lyt a save() �s no_save()
muveletekkel,
melyek egy destruktor �ltal ellenorzik, hogy egy objektum beker�lt-e az �lland�
t�rba. A save()-en �s no_save()-en k�v�l m�g milyen haszn�lhat� muveleteket
ny�jthatna a Persistent? Tesztelj�k a Persistent oszt�lyt n�h�ny tetsz�s szerint
v�-
lasztott oszt�llyal. Csom�pont-oszt�ly, konkr�t t�pus, vagy absztrakt t�pus-e
Persistent? Mi�rt?
13. (*3) �rjunk egy Stack oszt�lyt, melynek megval�s�t�sa fut�si idoben m�dos�that
�. Tipp: .Egy �jabb indirekci� minden probl�m�t megold..
25. Az oszt�lyok szerepe 1063
14. (*3.5) K�sz�ts�k el az Oper oszt�lyt, amely egy Id t�pus� (string vagy C
st�lus� karakterl
�nc) azonos�t�t �s egy muveletet (f�ggv�nymutat�t vagy f�ggv�nyobjektumot)
tartalmaz. Hat�rozzuk meg a Cat_object oszt�lyt, mely Oper-ek list�j�t �s
egy void*-ot tartalmaz. L�ssuk el a Cat_object-et egy add_oper(Oper) muvelettel,
mely egy Oper-t ad a list�hoz; egy remove_oper(Id)-del, mely egy Id-del azonos�-
tott Oper-t elt�vol�t a list�b�l; valamint egy operator() (Id, arg)-gal, mely
megh�vja
az Id-del azonos�tott Oper-t. K�sz�ts�nk egy Cat-eket t�rol� vermet egy
Cat_object seg�ts�g�vel. �rjunk egy kis programot ezen oszt�lyok haszn�lat�ra.
15. (*3) K�sz�ts�nk egy Object sablont a Cat_object oszt�ly alapj�n. Haszn�ljuk
fel
az Object-et egy String-verem megval�s�t�s�hoz. �rjunk egy kis programot
a sablon haszn�lat�ra.
16. (*2.5) Hat�rozzuk meg az Object oszt�ly Class nevu v�ltozat�t, mely
biztos�tja,
hogy az azonos muveletekkel rendelkezo objektumok k�z�s muveletsort haszn
�ljanak. �rjunk egy kis programot a sablon haszn�lat�ra.
17. (*2) K�sz�ts�nk egy olyan Stack sablont, mely egy, az Object sablon �ltal
megval
�s�tott verem r�sz�re egy hagyom�nyos, t�pusbiztos fel�letrol gondoskodik.
Hasonl�tsuk �ssze ezt a vermet az elozo gyakorlatokban tal�lt veremoszt�lyokkal.
�rjunk egy kis programot a sablon haszn�lat�ra.
18. (*3) �rjunk egy oszt�lyt olyan muveletek �br�zol�s�ra, melyeket v�grehajt�sra
egy m�sik g�pre kell �tvinni. Tesztelj�k egy m�sik g�pnek t�nylegesen elk�ld
�tt parancsokkal vagy parancsoknak egy f�jlba �r�s�val, melyeket ezut�n a f�jlb
�l kiolvasva hajtunk v�gre.
19. (*2) �rjunk egy oszt�lyt f�ggv�nyobjektumok alakj�ban �br�zolt muveletek
egy�ttes haszn�lat�ra. Ha adott f �s g f�ggv�nyobjektum, a Compose(f,g) hozzon
l�tre egy olyan objektumot, mely egy g-hez illeszkedo x param�terrel megh
�vhat�, �s f(g(x))-et ad vissza, felt�ve, hogy a g() �ltal visszaadott �rt�k egy,
az
f() �ltal elfogadhat� param�tert�pus.
1064 Tervez�s a C++ seg�ts�g�vel
F�ggel�kek �s t�rgymutat�
A f�ggel�kek a C++ nyelvtan�val; a C �s a C++ k�z�tt, valamint a szabv�nyos �s a
szabv�-
nyos�t�s elotti C++-v�ltozatok k�z�tt felmer�lo kompatibilit�si k�rd�sekkel;
illetve a nyelv
n�h�ny egy�b szolg�ltat�s�val foglalkoznak. Az igen r�szletes t�rgymutat� a k�nyv
l�nyeges
r�sze.
Fejezetek
A Nyelvtan
B Kompatibilit�s
C Technikai r�szletek
D Helyi saj�toss�gok
E Kiv�telbiztoss�g a standard k�nyvt�rban
I T�rgymutat�
Nyelvtan
.Nincs nagyobb vesz�ly, ami egy tan�rra leselkedik,
mint hogy szavakat tan�t a dolgok helyett..
(Marc Block)
Bevezet�s . Kulcsszavak . Nyelvi egys�gek . Programok . Kifejez�sek . Utas�t�sok .

Deklar�ci�k . Deklar�torok . Oszt�lyok . Sz�rmaztatott oszt�lyok . K�l�nleges


tagf�ggv
�nyek . T�lterhel�s . Sablonok . Kiv�telkezel�s . Az elofeldolgoz� direkt�v�i
A.1. Bevezet�s
A C++ szintaxis�nak (formai k�vetelm�nyeinek) itt tal�lhat� �sszefoglal�sa a
meg�rt�s
megk�nny�t�s�t c�lozza. Nem a nyelv pontos le�r�sa a c�l; az al�bb le�rtakn�l a C+
+ t�bb
�rv�nyes nyelvtani szerkezetet is elfogad. Az egyszeru kifejez�seknek a
deklar�ci�kt�l val
� megk�l�nb�ztet�s�re a t�bb�rtelmus�g-felold�si szab�lyokat (�A.5, �A.7), a
formailag
helyes, de �rtelmetlen szerkezetek kiszur�s�re pedig a hozz�f�r�si,
t�bb�rtelmus�gi �s t�-
pusszab�lyokat egy�ttesen kell alkalmaznunk.
A
A C �s C++ szabv�ny a legkisebb k�l�nbs�geket is formai k�l�nbs�gekkel �s nem
megszor
�t�sokkal fejezi ki. Ez nagyfok� pontoss�got ad, de nem mindig jav�tja a k�d
olvashat�s�g�t.
A.2. Kulcsszavak
A typedef (�4.9.7), n�vt�r (�8.2), oszt�ly (10. fejezet), felsorol� t�pus (�4.8),
�s template (13.
fejezet) deklar�ci�k �j k�rnyezetf�ggo kulcsszavakat vezetnek be a programba.
typedef-n�v:
azonos�t�
n�vt�r-n�v:
eredeti-n�vt�r-n�v
n�vt�r-�ln�v
eredeti-n�vt�r-n�v:
azonos�t�
n�vt�r-�ln�v:
azonos�t�
oszt�lyn�v:
azonos�t�
sablon-azonos�t�
felsorol�sn�v:
azonos�t�
sablonn�v:
azonos�t�
Jegyezz�k meg, hogy egy oszt�lyt megnevezo typedef-n�v egyben oszt�lyn�v is.
Ha nem adjuk meg kifejezetten egy azonos�t�r�l, hogy egy t�pus neve, a ford�t�
felt�telezi,
hogy nem t�pust nevez meg (l�sd �C.13.5).
A C++- kulcsszavai a k�vetkezok:
1068 F�ggel�kek �s t�rgymutat�
A.3. Nyelvi egys�gek
A szabv�nyos C �s C++ nyelvtanok a nyelvi egys�geket nyelvtani szerkezetekk�nt
mutatj�k be.
Ez n�veli a pontoss�got, de a nyelvtan .m�ret�t. is, �s nem mindig jav�tja az
olvashat�s�got:
hex-quad:
hexadecim�lis-sz�mjegy hexadecim�lis-sz�mjegy hexadecim�lis-sz�mjegy
hexadecim�lis-sz�mjegy
�ltal�nos-karaktern�v:
\u hex-quad
\U hex-quad hex-quad
elofeldolgoz�-szimb�lum:
fej�llom�ny-n�v
azonos�t�
pp-sz�m
karakterliter�l
karakterl�nc-liter�l
elofeldolgoz�-utas�t�s-vagy-muveleti-jel
minden nem �reshely karakter, ami nem tartozik a fentiek k�z�
szimb�lum:
azonos�t�
kulcssz�
liter�l
A. Nyelvtan 1069
C++ kulcsszavak
and and_eq asm auto bitand bitor
bool break case catch char class
compl const const_cast continue default delete
do double dynamic_cast else enum explicit
export extern false float for friend
goto if inline int long mutable
namespace new not not_eq operator or
or_eq private protected public register reinterpret_cast
return short signed sizeof static static_cast
struct switch template this throw true
try typedef typeid typename union unsigned
using virtual void volatile wchar_t while
xor xor_eq
oper�tor
muveleti-jel
fej�llom�ny-n�v:
<h-char-sorozat>
"q-char-sorozat"
h-char-sorozat:
h-char
h-char-sorozat h-char
h-char:
a forr�s-karakterk�szlet b�rmely tagja, kiv�ve az �jsor �s > karaktereket
q-char-sorozat:
q-char
q-char-sorozat q-char
q-char:
a forr�s-karakterk�szlet b�rmely tagja, kiv�ve az �jsor �s " karaktereket
pp-sz�m:
sz�mjegy
. sz�mjegy
pp-sz�m sz�mjegy
pp-sz�m nem-sz�mjegy
pp-sz�m e elojel
pp-sz�m E elojel
pp-sz�m .
azonos�t�:
nem-sz�mjegy
azonos�t� nem-sz�mjegy
azonos�t� sz�mjegy
nem-sz�mjegy: a k�vetkezok egyike
�ltal�nos-karaktern�v
_ a b c d e f g h i j k l m n o p q r s t u v w x y z
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
sz�mjegy: a k�vetkezok egyike
0 1 2 3 4 5 6 7 8 9
1070 F�ggel�kek �s t�rgymutat�
elofeldolgoz�-utas�t�s-vagy-muveleti-jel: a k�vetkezok egyike
{ } [ ] # ## ( ) <: :> <% %> %:%:
%: ; : ? :: . .* + - * / % ^
& | ~ ! = < > += -= *= /= %= ^=
&= |= <<= >>= << >> == != <= >= && || ++
-- , -> ->* ... new delete and and_eq bitand
bitor compl not or not_eq xor or_eq xor_eq
liter�l:
eg�szliter�l
karakterliter�l
lebegopontos-liter�l
karakterl�nc-liter�l
logikai-liter�l
eg�szliter�l:
decim�lis-liter�l eg�sz-ut�tagnem k�telezo
okt�lis-liter�l eg�sz-ut�tagnem k�telezo
hexadecim�lis-liter�l eg�sz-ut�tagnem k�telezo
decim�lis-liter�l:
nem-nulla-sz�mjegy
decim�lis-liter�l sz�mjegy
okt�lis-liter�l:
0
okt�lis-liter�l okt�lis-sz�mjegy
hexadecim�lis-liter�l:
0x hexadecim�lis-sz�mjegy
0X hexadecim�lis-sz�mjegy
hexadecim�lis-liter�l hexadecim�lis-sz�mjegy
nem-nulla-sz�mjegy: a k�vetkezok egyike
1 2 3 4 5 6 7 8 9
okt�lis-sz�mjegy: a k�vetkezok egyike
0 1 2 3 4 5 6 7
hexadecim�lis-sz�mjegy: a k�vetkezok egyike
0 1 2 3 4 5 6 7 8 9
a b c d e f
A B C D E F
eg�sz-ut�tag:
elojel-n�lk�li-ut�tag long-ut�tagnem k�telezo
long-ut�tag elojel-n�lk�li-ut�tagnem k�telezo
A. Nyelvtan 1071
elojel-n�lk�li-ut�tag: a k�vetkezok egyike
u U
long-ut�tag: a k�vetkezok egyike
l L
karakterliter�l:
'c-char-sorozat'
L'c-char-sorozat'
c-char-sorozat:
c-char
c-char-sorozat c-char
c-char:
a forr�s-karakterk�szlet b�rmely tagja, kiv�ve az egyszeres id�zojelet, a
ford�tott perjelet,
�s az �jsor karaktert
escape-sorozat
�ltal�nos-karaktern�v
escape-sorozat:
egyszeru-escape-sorozat
okt�lis-escape-sorozat
hexadecim�lis-escape-sorozat
egyszeru-escape-sorozat: a k�vetkezok egyike
\' \" \? \\ \a \b \f \n \r \t \v
okt�lis-escape-sorozat:
\ okt�lis-sz�mjegy
\ okt�lis-sz�mjegy okt�lis-sz�mjegy
\ okt�lis-sz�mjegy okt�lis-sz�mjegy okt�lis-sz�mjegy
hexadecim�lis-escape-sorozat:
\x hexadecim�lis-sz�mjegy
hexadecim�lis-escape-sorozat hexadecim�lis-sz�mjegy
lebegopontos-liter�l:
t�rt-konstans kitevo-r�sznem k�telezo lebegopontos-ut�tagnem k�telezo
sz�mjegy-sorozat kitevo-r�sz lebegopontos-ut�tagnem k�telezo
t�rt-konstans:
sz�mjegy-sorozatnem k�telezo . sz�mjegy-sorozat
sz�mjegy-sorozat .
kitevo-r�sz:
e elojelnem k�telezo sz�mjegy-sorozat
E elojelnem k�telezo sz�mjegy-sorozat
1072 F�ggel�kek �s t�rgymutat�
elojel: a k�vetkezok egyike
+ -
sz�mjegy-sorozat:
sz�mjegy
sz�mjegy-sorozat sz�mjegy
lebegopontos-ut�tag: a k�vetkezok egyike
f l F L
karakterl�nc-liter�l:
"s-char-sorozatnem k�telezo"
L"s-char-sorozatnem k�telezo"
s-char-sorozat:
s-char
s-char-sorozat s-char
s-char:
a forr�s-karakterk�szlet b�rmely tagja, kiv�ve a kettos id�zojelet, a ford�tott
perjelet, �s az �jsort
escape-sorozat
�ltal�nos-karaktern�v
logikai-liter�l:
false
true
A.4. Programok
A programok �sszeszerkeszt�s �ltal �ssze�ll�tott ford�t�si egys�gek (translation
unit) gyujtem�-
nyei (�9.4). A ford�t�si egys�gek vagy m�sk�pp forr�sf�jlok, deklar�ci�k
sorozat�b�l �llnak:
ford�t�si-egys�g:
deklar�ci�-sorozatnem k�telezo
A. Nyelvtan 1073
A.5. Kifejez�sek
A kifejez�seket a 6. fejezet �rja le �s a �6.2 pont �sszegzi. A kifejez�s-lista
(expression-list)
defin�ci�ja azonos a kifejez�s�vel (expression). A f�ggv�nyparam�tereket
elv�laszt� vesszo-
nek a vesszo oper�tort�l (comma, sequencing operator, �6.2.2) val�
megk�l�nb�ztet�s�re
k�t szab�ly szolg�l.
elsodleges-kifejez�s:
liter�l
this
:: azonos�t�
:: oper�torf�ggv�ny-azonos�t�
:: minos�tett-azonos�t�
( kifejez�s )
azonos�t�-kifejez�s
azonos�t�-kifejez�s:
nem-minos�tett-azonos�t�
minos�tett-azonos�t�
nem-minos�tett-azonos�t�:
azonos�t�
oper�torf�ggv�ny-azonos�t�
�talak�t�f�ggv�ny-azonos�t�
~ oszt�lyn�v
sablon-azonos�t�
minos�tett-azonos�t�:
be�gyazott-n�v-meghat�roz�s templatenem k�telezo nem-minos�tett-azonos�t�
be�gyazott-n�v-meghat�roz�s:
oszt�ly-vagy-n�vt�r-n�v :: be�gyazott-n�v-meghat�roz�snem k�telezo
oszt�ly-vagy-n�vt�r-n�v :: template be�gyazott-n�v-meghat�roz�s
oszt�ly-vagy-n�vt�r-n�v:
oszt�lyn�v
n�vt�r-n�v
ut�tag-kifejez�s:
elsodleges-kifejez�s
ut�tag-kifejez�s [ kifejez�s ]
ut�tag-kifejez�s ( kifejez�s-listanem k�telezo )
egyszeru-t�pus-meghat�roz�s ( kifejez�s-listanem k�telezo )
typename ::nem k�telezo be�gyazott-n�v-meghat�roz�s azonos�t� ( kifejez�s-listanem
k�telezo )
1074 F�ggel�kek �s t�rgymutat�
typename ::nem k�telezo be�gyazott-n�v-meghat�roz�s templatenem k�telezo
sablon-azonos�t� ( kifejez�s-listanem k�telezo )
ut�tag-kifejez�s . templatenem k�telezo ::nem k�telezo azonos�t�-kifejez�s
ut�tag-kifejez�s -> templatenem k�telezo ::nem k�telezo azonos�t�-kifejez�s
ut�tag-kifejez�s . �l-destruktor-n�v
ut�tag-kifejez�s -> �l-destruktor-n�v
ut�tag-kifejez�s ++
ut�tag-kifejez�s --
dynamic-cast < t�pusazonos�t� > ( kifejez�s )
static-cast < t�pusazonos�t� > ( kifejez�s )
reinterpret-cast < t�pusazonos�t� > ( kifejez�s )
const-cast < t�pusazonos�t� > ( kifejez�s )
typeid ( kifejez�s )
typeid ( t�pusazonos�t� )
kifejez�s-lista:
�rt�kad�-kifejez�s
kifejez�s-lista , �rt�kad�-kifejez�s
�l-destruktor-n�v:
::nem k�telezo be�gyazott-n�v-meghat�roz�snem k�telezo t�pusn�v :: ~ t�pusn�v
::nem k�telezo be�gyazott-n�v-meghat�roz�s template sablon-azonos�t� :: ~ t�pusn�v

::nem k�telezo be�gyazott-n�v-meghat�roz�snem k�telezo ~ t�pusn�v


egyoperandus�-kifejez�s:
ut�tag-kifejez�s
++ cast-kifejez�s
-- cast-kifejez�s
egyoperandus�-oper�tor cast-kifejez�s
sizeof egyoperandus�-kifejez�s
sizeof ( t�pusazonos�t� )
new-kifejez�s
delete-kifejez�s
egyoperandus�-oper�tor: a k�vetkezok egyike
* & + - ! ~
new-kifejez�s:
::nem k�telezo new elhelyezo-utas�t�snem k�telezo new-t�pusazonos�t� new-
kezdo�rt�k-ad�nem k�telezo
::nem k�telezo new elhelyezo-utas�t�snem k�telezo ( t�pusazonos�t� ) new-
kezdo�rt�k-ad�nem k�telezo
elhelyezo-utas�t�s:
( kifejez�s-lista )
new-t�pusazonos�t�:
t�pus-meghat�roz�-sorozat new-deklar�tornem k�telezo
A. Nyelvtan 1075
new-deklar�tor:
ptr-oper�tor new-deklar�tornem k�telezo
k�zvetlen-new-deklar�tor
k�zvetlen-new-deklar�tor:
[ kifejez�s ]
k�zvetlen-new-deklar�tor [ konstans-kifejez�s ]
new-kezdo�rt�k-ad�:
( kifejez�s-listanem k�telezo )
delete-kifejez�s:
::nem k�telezo delete cast-kifejez�s
::nem k�telezo delete [ ] cast-kifejez�s
cast-kifejez�s:
egyoperandus�-kifejez�s
( t�pusazonos�t� ) cast-kifejez�s
pm-kifejez�s:
cast-kifejez�s
pm-kifejez�s .* cast-kifejez�s
pm-kifejez�s ->* cast-kifejez�s
szorz�-kifejez�s:
pm-kifejez�s
szorz�-kifejez�s * pm-kifejez�s
szorz�-kifejez�s / pm-kifejez�s
szorz�-kifejez�s % pm-kifejez�s
�sszead�-kifejez�s:
szorz�-kifejez�s
�sszead�-kifejez�s + szorz�-kifejez�s
�sszead�-kifejez�s . szorz�-kifejez�s
eltol�-kifejez�s:
�sszead�-kifejez�s
eltol�-kifejez�s << �sszead�-kifejez�s
eltol�-kifejez�s >> �sszead�-kifejez�s
viszony�t�-kifejez�s:
eltol�-kifejez�s
viszony�t�-kifejez�s < eltol�-kifejez�s
viszony�t�-kifejez�s > eltol�-kifejez�s
viszony�t�-kifejez�s <= eltol�-kifejez�s
viszony�t�-kifejez�s >= eltol�-kifejez�s
1076 F�ggel�kek �s t�rgymutat�
egyen�rt�kus�g-kifejez�s:
viszony�t�-kifejez�s
egyen�rt�kus�g-kifejez�s == viszony�t�-kifejez�s
egyen�rt�kus�g-kifejez�s != viszony�t�-kifejez�s
�s-kifejez�s:
egyen�rt�kus�g-kifejez�s
�s-kifejez�s & egyen�rt�kus�g-kifejez�s
kiz�r�-vagy-kifejez�s:
�s-kifejez�s
kiz�r�-vagy-kifejez�s ^ �s-kifejez�s
megengedo-vagy-kifejez�s:
kiz�r�-vagy-kifejez�s
megengedo-vagy-kifejez�s | kiz�r�-vagy-kifejez�s
logikai-�s-kifejez�s:
megengedo-vagy-kifejez�s
logikai-�s-kifejez�s && megengedo-vagy-kifejez�s
logikai-vagy-kifejez�s:
logikai-�s-kifejez�s
logikai-vagy-kifejez�s || logikai-�s-kifejez�s
felt�teles-kifejez�s:
logikai-vagy-kifejez�s
logikai-vagy-kifejez�s ? kifejez�s : �rt�kad�-kifejez�s
�rt�kad�-kifejez�s:
felt�teles-kifejez�s
logikai-vagy-kifejez�s �rt�kad�-oper�tor �rt�kad�-kifejez�s
throw-kifejez�s
�rt�kad�-oper�tor: a k�vetkezok egyike
= *= /= %= += -= >>= <<= &= ^= |=
kifejez�s:
�rt�kad�-kifejez�s
kifejez�s , �rt�kad�-kifejez�s
konstans-kifejez�s:
felt�teles-kifejez�s
A. Nyelvtan 1077
A f�ggv�ny st�lus� t�pus�talak�t�sok (cast) �s a deklar�ci�k hasonl�s�g�b�l
t�bb�rtelmus�-
gek ad�dhatnak. P�ld�ul:
int x;
void f()
{
char(x); // x �talak�t�sa char t�pusra
// vagy egy x nevu char deklar�ci�ja?
}
A ford�t� minden ilyen t�bb�rtelmu szerkezetet deklar�ci�k�nt �rtelmez, vagyis a
szab�ly:
.ha lehet deklar�ci�k�nt �rtelmezni, akkor deklar�ci�.. P�ld�ul:
T(a)->m; // kifejez�s-utas�t�s
T(a)++; // kifejez�s-utas�t�s
T(*e)(int(3)); // deklar�ci�
T(f)[4]; // deklar�ci�
T(a); // deklar�ci�
T(a)=m; // deklar�ci�
T(*b)(); // deklar�ci�
T(x),y,z=7; // deklar�ci�
A t�bb�rtelmus�g ilyen felold�sa tiszt�n szintaktikus. A ford�t� a n�vrol csak
annyi inform�-
ci�t haszn�l fel, hogy az egy ismert t�pus- vagy sablonn�v-e. Ha nem az, akkor
ezektol k�-
l�nb�zo jelent�st t�telez fel r�la.
A template nem-minos�tett-azonos�t� szerkezet azt jelenti, hogy a nem-
minos�tettazonos
�t� egy sablon neve, m�gpedig egy olyan k�rnyezetben, ahonnan ezt nem lehetne
levezetni (�C.13.6)
1078 F�ggel�kek �s t�rgymutat�
A.6. Utas�t�sok
L�sd �6.3-at.
utas�t�s:
c�mk�zett-utas�t�s
kifejez�s-utas�t�s
�sszetett-utas�t�s
kiv�laszt�-utas�t�s
ciklus-utas�t�s
ugr�-utas�t�s
deklar�ci�-utas�t�s
try-blokk
c�mk�zett-utas�t�s:
azonos�t� : utas�t�s
case konstans-kifejez�s : utas�t�s
default : utas�t�s
kifejez�s-utas�t�s:
kifejez�snem k�telezo ;
�sszetett-utas�t�s:
{ utas�t�s-sorozatnem k�telezo }
utas�t�s-sorozat:
utas�t�s
utas�t�s-sorozat utas�t�s
kiv�laszt�-utas�t�s:
if ( felt�tel ) utas�t�s
if ( felt�tel ) utas�t�s else utas�t�s
switch ( felt�tel ) utas�t�s
felt�tel:
kifejez�s
t�pus-meghat�roz�s-sorozat deklar�tor = �rt�kad�-kifejez�s
ciklus-utas�t�s:
while ( felt�tel ) utas�t�s
do utas�t�s while ( kifejez�s ) ;
for ( for-init-utas�t�s felt�telnem k�telezo ; kifejez�snem k�telezo ) utas�t�s
for-init-utas�t�s:
kifejez�s-utas�t�s
egyszeru-deklar�ci�
A. Nyelvtan 1079
ugr�-utas�t�s:
break ;
continue ;
return kifejez�snem k�telezo ;
goto azonos�t� ;
deklar�ci�-utas�t�s:
blokk-deklar�ci�
A.7. Deklar�ci�k
A deklar�ci�k szerkezet�t a 4. fejezet �rja le, a felsorol� t�pusokat
(enumeration) a �4.8,
a mutat�kat (pointer) �s t�mb�ket (array) az 5. fejezet, a f�ggv�nyeket (function)
a 7. fejezet,
a n�vtereket (namespace) a �8.2, az �sszeszerkeszt�si direkt�v�kat (linkage
directive)
a �9.2.4, a t�rol�si m�dokat (storage class) pedig a �10.4.
deklar�ci�-sorozat:
deklar�ci�
deklar�ci�-sorozat deklar�ci�
deklar�ci�:
blokk-deklar�ci�
f�ggv�nydefin�ci�
sablondeklar�ci�
explicit-p�ld�nyos�t�s
explicit-specializ�ci�
�sszeszerkeszt�si-m�d
n�vt�r-defin�ci�
blokk-deklar�ci�:
egyszeru-deklar�ci�
asm-defin�ci�
n�vt�r-�ln�v-defin�ci�
using-deklar�ci�
using-utas�t�s
egyszeru-deklar�ci�:
deklar�ci�-meghat�roz�s-sorozatnem k�telezo kezdo�rt�k-deklar�tor-listanem
k�telezo ;
deklar�ci�-meghat�roz�s:
t�rol�si-m�d-meghat�roz�s
t�pus-meghat�roz�s
1080 F�ggel�kek �s t�rgymutat�
f�ggv�ny-meghat�roz�s
friend
typedef
deklar�ci�-meghat�roz�s-sorozat:
deklar�ci�-meghat�roz�s-sorozatnem k�telezo deklar�ci�-meghat�roz�s
t�rol�si-m�d-meghat�roz�s:
auto
register
static
extern
mutable
f�ggv�ny-meghat�roz�s:
inline
virtual
explicit
typedef-n�v:
azonos�t�
t�pus-meghat�roz�s:
egyszeru-t�pus-meghat�roz�s
oszt�ly-meghat�roz�s
felsorol�s-meghat�roz�s
�sszetett-t�pus-meghat�roz�s
cv-minos�to
egyszeru-t�pus-meghat�roz�s:
::nem k�telezo be�gyazott-n�v-meghat�roz�snem k�telezo t�pusn�v
::nem k�telezo be�gyazott-n�v-meghat�roz�s templatenem k�telezo sablon-azonos�t�
char
wchar_t
bool
short
int
long
signed
unsigned
float
double
void
t�pusn�v:
oszt�lyn�v
felsorol�sn�v
typedef-n�v
A. Nyelvtan 1081
�sszetett-t�pus-meghat�roz�s:
oszt�lykulcs ::nem k�telezo be�gyazott-n�v-meghat�roz�snem k�telezo azonos�t�
enum ::nem k�telezo be�gyazott-n�v-meghat�roz�snem k�telezo azonos�t�
typename ::nem k�telezo be�gyazott-n�v-meghat�roz�s azonos�t�
typename ::nem k�telezo be�gyazott-n�v-meghat�roz�s templatenem k�telezo sablon-
azonos�t�
felsorol�sn�v:
azonos�t�
felsorol�s-meghat�roz�s:
enum azonos�t�nem k�telezo { felsorol�s-listanem k�telezo }
felsorol�s-lista:
felsorol�-defin�ci�
felsorol�s-lista , felsorol�-defin�ci�
felsorol�-defin�ci�:
felsorol�
felsorol� = konstans-kifejez�s
felsorol�:
azonos�t�
n�vt�r-n�v:
eredeti-n�vt�r-n�v
n�vt�r-�ln�v
eredeti-n�vt�r-n�v:
azonos�t�
n�vt�r-defin�ci�:
neves�tett-n�vt�r-defin�ci�
neves�tetlen-n�vt�r-defin�ci�
neves�tett-n�vt�r-defin�ci�:
eredeti-n�vt�r-defin�ci�
bov�tett-n�vt�r-defin�ci�
eredeti-n�vt�r-defin�ci�:
namespace azonos�t� { n�vt�r-t�rzs }
bov�tett-n�vt�r-defin�ci�:
namespace eredeti-n�vt�r-n�v { n�vt�r-t�rzs }
neves�tetlen-n�vt�r-defin�ci�:
namespace { n�vt�r-t�rzs }
1082 F�ggel�kek �s t�rgymutat�
n�vt�r-t�rzs:
deklar�ci�-sorozatnem k�telezo
n�vt�r-�ln�v:
azonos�t�
n�vt�r-�ln�v-defin�ci�:
namespace azonos�t� = minos�tett-n�vt�r-meghat�roz�s ;
minos�tett-n�vt�r-meghat�roz�s:
::nem k�telezo be�gyazott-n�v-meghat�roz�snem k�telezo n�vt�r-n�v
using-deklar�ci�:
using typenamenem k�telezo ::nem k�telezo be�gyazott-n�v-meghat�roz�s nemmin
os�tett-azonos�t� ;
using :: nem-minos�tett-azonos�t� ;
using-utas�t�s:
using namespace ::nem k�telezo be�gyazott-n�v-meghat�roz�snem k�telezo n�vt�r-
n�v ;
asm-defin�ci�:
asm ( karakterl�nc-liter�l ) ;
�sszeszerkeszt�si-m�d:
extern karakterl�nc-liter�l { deklar�ci�-sorozatnem k�telezo }
extern karakterl�nc-liter�l deklar�ci�
A nyelvtan megengedi a deklar�ci�k tetszoleges egym�sba �gyaz�s�t, de bizonyos
megszor
�t�sok �rv�nyesek. P�ld�ul nem szabad f�ggv�nyeket egym�sba �gyazni, azaz egy
f�ggv�-
nyen bel�l egy m�sik f�ggv�nyt kifejteni.
A deklar�ci�kat kezdo meghat�roz�sok (.minos�tok., specifier) list�ja nem lehet
�res (azaz
.nincs implicit int., �B.2) �s a meghat�roz�sok leghosszabb lehets�ges sorozat�b�l
�ll. P�ld�ul:
typedef int I;
void f(unsigned I) { /* ... */ }
Itt f() param�tere egy unsigned int.
Az asm() szerkezet az assembly k�d besz�r�s�ra szolg�l. Jelent�s�t az adott nyelvi
v�ltozat
hat�rozza meg, de c�lja az, hogy a megadott helyen az adott sz�vegnek megfelelo
assembly
k�d ker�lj�n be a ford�t� �ltal l�trehozott k�dba.
A. Nyelvtan 1083
Ha egy v�ltoz�t register-k�nt vezet�nk be, azzal azt jelezz�k a ford�t�program
sz�m�ra,
hogy a gyakori hozz�f�r�sekre kell optimaliz�lnia a k�dot. Az �jabb
ford�t�programok legt
�bbje sz�m�ra ezt felesleges megadni.
A.7.1. Deklar�torok
L�sd a �4.9.1 pontot, az 5. fejezetet (mutat�k �s t�mb�k), a �7.7 pontot
(f�ggv�nymutat�k)
�s a �15.5 pontot (tagokra hivatkoz� mutat�k).
kezdo�rt�k-deklar�tor-lista:
kezdo�rt�k-deklar�tor
kezdo�rt�k-deklar�tor-lista , kezdo�rt�k-deklar�tor
kezdo�rt�k-deklar�tor:
deklar�tor kezdo�rt�k-ad�nem k�telezo
deklar�tor:
k�zvetlen-deklar�tor
ptr-oper�tor deklar�tor
k�zvetlen-deklar�tor:
deklar�tor-azonos�t�
k�zvetlen-deklar�tor ( param�ter-deklar�ci�-z�rad�k ) cv-minos�to-sorozatnem
k�telezo
kiv�tel-meghat�roz�snem k�telezo
k�zvetlen-deklar�tor [ konstans-kifejez�snem k�telezo ]
( deklar�tor )
ptr-oper�tor:
* cv-minos�to-sorozatnem k�telezo
&
::nem k�telezo be�gyazott-n�v-meghat�roz�s * cv-minos�to-sorozatnem k�telezo
cv-minos�to-sorozat:
cv-minos�to cv-minos�to-sorozatnem k�telezo
cv-minos�to:
const
volatile
deklar�tor-azonos�t�:
::nem k�telezo azonos�t�-kifejez�s
::nem k�telezo be�gyazott-n�v-meghat�roz�snem k�telezo t�pusn�v
1084 F�ggel�kek �s t�rgymutat�
t�pusazonos�t�:
t�pus-meghat�roz�s-sorozat elvont-deklar�tornem k�telezo
t�pus-meghat�roz�s-sorozat:
t�pus-meghat�roz�s t�pus-meghat�roz�s-sorozatnem k�telezo
elvont-deklar�tor:
ptr-oper�tor elvont-deklar�tornem k�telezo
k�zvetlen-elvont-deklar�tor
k�zvetlen-elvont-deklar�tor:
k�zvetlen-elvont-deklar�tornem k�telezo ( param�ter-deklar�ci�-z�rad�k ) cv-
minos�to-
sorozatnem k�telezo kiv�tel-meghat�roz�snem k�telezo
k�zvetlen-elvont-deklar�tornem k�telezo [ konstans-kifejez�snem k�telezo ]
( elvont-deklar�tor )
param�ter-deklar�ci�-z�rad�k:
param�ter-deklar�ci�-listanem k�telezo ... nem k�telezo
param�ter-deklar�ci�-lista , ...
param�ter-deklar�ci�-lista:
param�ter-deklar�ci�
param�ter-deklar�ci�-lista , param�ter-deklar�ci�
param�ter-deklar�ci�:
deklar�ci�-meghat�roz�s-sorozat deklar�tor
deklar�ci�-meghat�roz�s-sorozat deklar�tor = �rt�kad�-kifejez�s
deklar�ci�-meghat�roz�s-sorozat elvont-deklar�tornem k�telezo
deklar�ci�-meghat�roz�s-sorozat elvont-deklar�tornem k�telezo = �rt�kad�-kifejez�s

f�ggv�nydefin�ci�:
deklar�ci�-meghat�roz�s-sorozatnem k�telezo deklar�tor ctor-kezdo�rt�k-ad�nem
k�telezo
f�ggv�nyt�rzs
deklar�ci�-meghat�roz�s-sorozatnem k�telezo deklar�tor f�ggv�ny-try-blokk
f�ggv�nyt�rzs:
�sszetett-utas�t�s
kezdo�rt�k-ad�:
= kezdo�rt�k-ad�-z�rad�k
( kifejez�s-lista )
kezdo�rt�k-ad�-z�rad�k:
�rt�kad�-kifejez�s
{ kezdo�rt�k-lista , nem k�telezo }
{ }
A. Nyelvtan 1085
kezdo�rt�k-lista:
kezdo�rt�k-ad�-z�rad�k
kezdo�rt�k-lista , kezdo�rt�k-ad�-z�rad�k
A volatile meghat�roz�s/minos�t�s azt jelzi a ford�t�program sz�m�ra, hogy az
objektum
a nyelv �ltal nem meghat�rozott m�don v�ltoztatja az �rt�k�t, �gy az .agressz�v
optimaliz�-
l�s. ker�lendo. Egy val�sideju �r�t p�ld�ul �gy deklar�lhatunk:
extern const volatile clock;
A clock k�t egym�st k�veto leolvas�sa k�l�nb�zo eredm�nyeket adhat.
A.8. Oszt�lyok
L�sd a 10. fejezetet.
oszt�lyn�v:
azonos�t�
sablon-azonos�t�
oszt�ly-meghat�roz�s:
oszt�lyfej { tag-meghat�roz�snem k�telezo }
oszt�lyfej:
oszt�lykulcs azonos�t�nem k�telezo alap-z�rad�knem k�telezo
oszt�lykulcs be�gyazott-n�v-meghat�roz�s azonos�t� alap-z�rad�knem k�telezo
oszt�lykulcs be�gyazott-n�v-meghat�roz�s template sablon-azonos�t� alap-z�rad�knem
k�telezo
oszt�lykulcs:
class
struct
union
tag-meghat�roz�s:
tag-deklar�ci� tag-meghat�roz�snem k�telezo
hozz�f�r�s-meghat�roz�s : tag-meghat�roz�snem k�telezo
1086 F�ggel�kek �s t�rgymutat�
tag-deklar�ci�:
deklar�ci�-meghat�roz�s-sorozatnem k�telezo tag-deklar�tor-listanem k�telezo ;
f�ggv�nydefin�ci� ;nem k�telezo
::nem k�telezo be�gyazott-n�v-meghat�roz�s templatenem k�telezo nem-minos�tett-
azonos�t� ;
using-deklar�ci�
sablondeklar�ci�
tag-deklar�tor-lista:
tag-deklar�tor
tag-deklar�tor-lista , tag-deklar�tor
tag-deklar�tor:
deklar�tor �res-meghat�roz�snem k�telezo
deklar�tor konstans-kezdo�rt�k-ad�nem k�telezo
azonos�t�nem k�telezo : konstans-kifejez�s
�res-meghat�roz�s:
= 0
konstans-kezdo�rt�k-ad�:
= konstans-kifejez�s
A C-vel val� �sszeegyeztethetos�get megorzendo egy azonos nevu oszt�ly �s egy nem-
oszt
�ly ugyanabban a hat�k�rben is deklar�lhat� (�5.7). P�ld�ul:
struct stat { /* ... */ };
int stat(char* n�v, struct stat* buf);
Ebben az esetben a sima n�v (stat) a nem-oszt�ly neve. Az oszt�lyra egy
oszt�lykulcs elo-
taggal (class, struct vagy union) kell hivatkozni.
A konstans kifejez�seket a �C.5 pont �rja le.
A.8.1. Sz�rmaztatott oszt�lyok
L�sd a 12. �s 15. fejezetet.
alap-z�rad�k:
: alap-meghat�roz�s-lista
alap-meghat�roz�s-lista:
alap-meghat�roz�s
alap-meghat�roz�s-lista , alap-meghat�roz�s
A. Nyelvtan 1087
alap-meghat�roz�s:
::nem k�telezo be�gyazott-n�v-meghat�roz�snem k�telezo oszt�lyn�v
virtual hozz�f�r�s-meghat�roz�snem k�telezo ::nem k�telezo be�gyazott-n�vmeghat
�roz�snem k�telezo oszt�lyn�v
hozz�f�r�s-meghat�roz�s virtualnem k�telezo ::nem k�telezo be�gyazott-n�vmeghat
�roz�snem k�telezo oszt�lyn�v
hozz�f�r�s-meghat�roz�s:
private
protected
public
A.8.2. K�l�nleges tagf�ggv�nyek
L�sd a �11.4 (�talak�t� oper�torok), �10.4.6 (oszt�lytagok kezdeti �rt�kad�sa) �s
�12.2.2
(alaposzt�lyok kezdeti �rt�kad�sa) pontokat.
�talak�t�f�ggv�ny-azonos�t�:
operator �talak�t�s-t�pusazonos�t�
�talak�t�s-t�pusazonos�t�:
t�pus-meghat�roz�s-sorozat �talak�t�s-deklar�tornem k�telezo
�talak�t�s-deklar�tor:
ptr-oper�tor �talak�t�s-deklar�tornem k�telezo
ctor-kezdo�rt�k-ad�:
: mem-kezdo�rt�k-lista
mem-kezdo�rt�k-lista:
mem-kezdo�rt�k-ad�
mem-kezdo�rt�k-ad� , mem-kezdort�k-lista
mem-kezdo�rt�k-ad�:
mem-kezdo�rt�k-ad�-azonos�t� ( kifejez�s-listanem k�telezo )
mem-kezdo�rt�k-ad�-azonos�t�:
::nem k�telezo be�gyazott-n�v-meghat�roz�snem k�telezo oszt�lyn�v
azonos�t�
1088 F�ggel�kek �s t�rgymutat�
A.8.3. T�lterhel�s
L�sd a 11. fejezetet.
oper�torf�ggv�ny-azonos�t�:
operator oper�tor
oper�tor: a k�vetkezok egyike
new delete new[] delete[]
+ - * / % ^ & | ~ ! = < >
+= -= *= /= %= ^= &= |= << >> >>= <<= ==
!= <= >= && || ++ -- , ->* -> () []
A.9. Sablonok
A sablonokkal a 13. fejezet �s a �C.13. pont foglalkozik r�szletesen.
sablondeklar�ci�:
exportnem k�telezo template < sablonparam�ter-lista > deklar�ci�
sablonparam�ter-lista:
sablonparam�ter
sablonparam�ter-lista , sablonparam�ter
sablonparam�ter:
t�pus-param�ter
param�ter-deklar�ci�
t�pus-param�ter:
class azonos�t�nem k�telezo
class azonos�t�nem k�telezo = t�pusazonos�t�
typename azonos�t�nem k�telezo
typename azonos�t�nem k�telezo = t�pusazonos�t�
template < sablonparam�ter-lista > class azonos�t�nem k�telezo
template < sablonparam�ter-lista > class azonos�t�nem k�telezo = sablonn�v
sablon-azonos�t�:
sablonn�v < sablonargumentum-listanem k�telezo >
sablonn�v:
azonos�t�
A. Nyelvtan 1089
sablonargumentum-lista:
sablonargumentum
sablonargumentum-lista , sablonargumentum
sablonargumentum:
�rt�kad�-kifejez�s
t�pusazonos�t�
sablonn�v
explicit-p�ld�nyos�t�s:
template deklar�ci�
explicit-specializ�ci�:
template < > deklar�ci�
Az explicit sablonargumentum-meghat�roz�s egy �rdekes t�bb�rtelmus�gre ad
lehetos�-
get. Vegy�k a k�vetkezo p�ld�t:
void h()
{
f<1>(0); // t�bb�rtelmu: ((f)<1) > (0) vagy (f<1>)(0) ?
// felold�sa: f<1> megh�v�sa a 0 param�terrel
}
A felold�s egyszeru �s hat�kony: ha f egy sablon neve, akkor f< egy minos�tett
sablonn�v
kezdete �s az azt k�veto nyelvi egys�gek eszerint �rtelmezendoek; ha nem ez a
helyzet, a <
jel a .kisebb mint. muveletet jelenti. Ugyan�gy az elso p�r n�lk�li > jel lez�rja
a sablonparam
�terek list�j�t. Ha a .nagyobb mint. jelre van sz�ks�g�nk, z�r�jelez�st kell
alkalmaznunk:
f< a>b >(0); // szintaktikus hiba
f< (a>b) >(0); // rendben
Hasonl� t�bb�rtelmus�g l�phet fel, ha a z�r� > jelek t�l k�zel ker�lnek:
list<vector<int>> lv1; // szintaktikus hiba: nem v�rt >> (jobbra l�ptet�s)
list< vector<int> > lv2; // helyes: vektorok list�ja
Figyelj�nk a sz�k�zre a k�t > jel k�z�tt (a >> a jobbra l�pteto oper�tor!), mert
nagyon
k�nnyu eln�zni.
1090 F�ggel�kek �s t�rgymutat�
A.10. Kiv�telkezel�s
L�sd a �8.3 pontot �s a 14. fejezetet.
try-blokk:
try �sszetett-utas�t�s kezelo-sorozat
f�ggv�ny-try-blokk:
try ctor-kezdo�rt�k-ad�nem k�telezo f�ggv�nyt�rzs kezelo-sorozat
kezelo-sorozat:
kezelo kezelo-sorozatnem k�telezo
kezelo:
catch ( kiv�tel-deklar�ci� ) �sszetett-utas�t�s
kiv�tel-deklar�ci�:
t�pus-meghat�roz�s-sorozat deklar�tor
t�pus-meghat�roz�s-sorozat elvont-deklar�tor
t�pus-meghat�roz�s-sorozat
...
throw-kifejez�s:
throw �rt�kad�-kifejez�snem k�telezo
kiv�tel-meghat�roz�s:
throw ( t�pusazonos�t�-listanem k�telezo )
t�pusazonos�t�-lista:
t�pusazonos�t�
t�pusazonos�t�-lista , t�pusazonos�t�
A.11. Az elofeldolgoz� direkt�v�i
Az elofeldolgoz� (preprocessor, pp) egy viszonylag egyszeru makr�-feldolgoz�
rendszer,
amely elsodlegesen nyelvi egys�geken �s nem egyes karaktereken dolgozik. A makr�k
meghat�roz�s�nak �s haszn�lat�nak (�7.8) k�pess�g�n k�v�l az elofeldolgoz� a
sz�vegf�jloknak
�s szabv�nyos fej�llom�nyoknak (�9.2.1) a forr�sba �p�t�s�re is lehetos�get ad �s
makr�kon alapul� felt�teles ford�t�st is tud v�gezni (�9.3.3). P�ld�ul:
A. Nyelvtan 1091
#if OPT==4
#include "fej�llom�ny4.h"
#elif 0<OPT
#include "fej�llom�ny.h"
#else
#include<cstdlib>
#endif
Az �sszes elofeldolgoz�i utas�t�s (direkt�va) a # jellel kezdodik, amelynek az
elso nem
�reshely karakternek kell lennie a sorban.
elofeldolgoz�-f�jl:
csoportnem k�telezo
csoport:
csoport-r�sz
csoport csoport-r�sz
csoport-r�sz:
pp-szimb�lumoknem k�telezo �jsor
if-r�sz
vez�rlosor
if-r�sz:
if-csoport elif-csoportoknem k�telezo else-csoportnem k�telezo endif-sor
if-csoport:
# if konstans-kifejez�s �jsor csoportnem k�telezo
# ifdef azonos�t� �jsor csoportnem k�telezo
# ifndef azonos�t� �jsor csoportnem k�telezo
elif-csoportok:
elif-csoport
elif-csoportok elif-csoport
elif-csoport:
# elif konstans-kifejez�s �jsor csoportnem k�telezo
else-csoport:
# else �jsor csoportnem k�telezo
endif-sor:
# endif �jsor
1092 F�ggel�kek �s t�rgymutat�
vez�rlosor:
# include pp-szimb�lumok �jsor
# define azonos�t� helyettes�to-lista �jsor
# define azonos�t� balz�r�jel azonos�t�-listanem k�telezo ) helyettes�to-lista
�jsor
# undef azonos�t� �jsor
# line pp-szimb�lumok �jsor
# error pp-szimb�lumoknem k�telezo �jsor
# pragma pp-szimb�lumoknem k�telezo �jsor
# �jsor
balz�r�jel:
a bal oldali z�r�jel karakter megelozo �reshely n�lk�l
helyettes�to-lista:
pp-szimb�lumoknem k�telezo
pp-szimb�lumok:
elofeldolgoz�-szimb�lum
pp-szimb�lumok elofeldolgoz�-szimb�lum
�jsor:
�jsor karakter
azonos�t�-lista:
azonos�t�
azonos�t�-lista , azonos�t�
A. Nyelvtan 1093
Kompatibilit�s
.Te m�sz a te utadon, a te
szok�said szerint, �s �n is k�-
vetem a saj�t elveimet..
(C. Napier)
C/C++ kompatibilit�s . .�szrev�tlen. k�l�nbs�gek a C �s a C++ k�z�tt . C program,
ami
nem C++ program . Elavult szolg�ltat�sok . C++ program, ami nem C program .
R�gebbi
C++-v�ltozatok haszn�lata . Fej�llom�nyok . A standard k�nyvt�r . N�vterek .
Helyfoglal
�si hib�k . Sablonok . A for utas�t�s kezdo�rt�k-ad� r�sze . Tan�csok .
Gyakorlatok
B.1. Bevezet�s
Ebben a f�ggel�kben azokat a k�l�nbs�geket vizsg�ljuk meg, amelyek a C �s a C++,
illetve
a szabv�nyos C++ �s a r�gebbi C++-v�ltozatok k�z�tt �llnak fenn. C�lunk az, hogy
egyr
�szt le�rjuk azokat a k�l�nbs�geket, amelyek a programoz�knak probl�m�t
okozhatnak,
m�sr�szt m�dszereket mutassunk ezen probl�m�k kezel�s�re. A legt�bb
kompatibilit�si
probl�m�val akkor ker�l�nk szembe, amikor egy C programot a C++-b�l akarunk
haszn�lni,
vagy egy nem szabv�nyos C++ rendszerben l�trehozott programot egy m�sik
k�rnyezetbe
akarunk �tvinni, esetleg �j lehetos�geket akarunk egy r�gebbi C++-v�ltozatban
haszn�l-
B
ni. A c�l nem az, hogy r�szletesen bemutassuk az �sszes kompatibilit�si probl�m�t,
ami valaha
is elofordulhat, hanem az, hogy a leggyakoribb probl�m�kra szabv�nyos megold�st
adjunk.
Amikor kompatibilit�si probl�m�kr�l besz�l�nk, a legfontosabb k�rd�s az, hogy
programunk
a k�l�nb�zo nyelvi v�ltozatok milyen sz�les k�r�ben k�pes muk�dni. A C++ nyelv
megismer�s�hez �rdemes a legteljesebb �s legk�nyelmesebb rendszert haszn�lnunk,
rendszerfejleszt
�skor azonban enn�l konzervat�vabb strat�gi�t kell k�vetn�nk, hiszen olyan
programot szeretn�nk, amely a leheto legt�bb k�rnyezetben muk�dok�pes. R�gebben ez

nagyon j� kifog�s volt arra, hogy a C++ .t�l fejlettnek. minos�tett lehetos�geit
elker�lj�k.
Az egyes v�ltozatok azonban k�zeledtek egym�shoz, �gy a k�l�nb�zo platformok
k�z�tti
hordozhat�s�g k�vetelm�nye ritk�n ig�nyel olyan komoly erofesz�t�seket a
programoz�-
t�l, mint n�h�ny �vvel ezelott.
B.2. C/C++ kompatibilit�s
Kisebb kiv�telektol eltekintve a C++ a C nyelv tov�bbfejleszt�s�nek tekintheto. A
legt�bb
k�l�nbs�g a C++ hangs�lyozottabb t�pusellenorz�s�bol k�vetkezik. A j�l meg�rt C
programok
�ltal�ban C++ programok is. A C �s C++ k�z�tti �sszes k�l�nbs�get a ford�t�nak is
jeleznie
kell.
B.2.1. .�szrev�tlen. k�l�nbs�gek
N�h�ny kiv�teltol eltekintve azok a programok, melyek C �s C++ nyelven is
�rtelmezhetok,
ugyanazt jelentik mind a k�t nyelvben. Szerencs�re azok a k�l�nbs�gek, melyek
m�gis elo-
fordulnak, �ltal�ban csak �rnyalatnyiak:
A C-ben a karakterkonstansok �s a felsorol� t�pusok m�rete sizeof(int). A C++-ban
sizeof(.a.) egyen�rt�ku sizeof(char)-ral, a felsorol� t�pusok megval�s�t�s�hoz
pedig az
egyes C++-v�ltozatok olyan m�retet haszn�lhatnak, ami az adott k�rnyezetben a
legc�lszer
ubb (�4.8).
A C++ lehetov� teszi a // jellel bevezetett megjegyz�sek haszn�lat�t; ez a C-ben
nem �ll rendelkez
�s�nkre (b�r nagyon sok C-v�ltozat tartalmazza bov�t�sk�nt). Ezt az elt�r�st olyan

programok k�sz�t�s�hez haszn�lhatjuk fel, melyek a k�t nyelvben k�l�nb�zok�ppen


viselkednek.
1096 F�ggel�kek �s t�rgymutat�
P�ld�ul:
int f(int a, int b)
{
return a //* el�g val�sz�nutlen */ b
; /* pontosvesszo a szintaktikus hiba elker�l�s�re */
}
Az ISO C ma m�r a C++-hoz hasonl�an megengedi a // haszn�lat�t.
Egy belso hat�k�rben bevezetett adatszerkezet-n�v elrejtheti egy k�lso hat�k�rben
deklar
�lt objektum, f�ggv�ny, felsorol�s, vagy t�pus nev�t:
int x[99];
void f()
{
struct x { int a; };
sizeof(x); /* a t�mb m�rete C-ben, a struct m�rete C++-ban */
}
B.2.2. C program, ami nem C++ program
A leggyakrabban probl�m�t okoz� k�l�nbs�gek �ltal�ban nem t�l �lesek. A legt�bbet
ezek
k�z�l a ford�t�k is k�nnyen �szreveszik. Ebben a pontban olyan C k�dokat mutatunk
be,
amelyek nem C++ k�dok. Ezek legt�bbj�t m�r az �jabb C-v�ltozatok is .rossz
st�lus�nak.,
sot .elavultnak. minos�tik.
A C-ben a legt�bb f�ggv�nyt deklar�l�suk elott is megh�vhatjuk:
main() /* rossz st�lus C-ben, hib�s C++-ban */
{
double sq2 = sqrt(2); /* deklar�latlan f�ggv�ny megh�v�sa */
printf("the square root of 2 is %g\n",sq2); /* deklar�latlan f�ggv�ny megh�v�sa */

}
A f�ggv�ny-deklar�ci�k (f�ggv�ny-protot�pusok) teljes �s k�vetkezetes haszn�lata
minden
C-megval�s�t�sban aj�nlott. Ha ezt a tan�csot megfogadjuk (�s ezt a ford�t�k
�ltal�ban valamilyen
kapcsol�val biztos�tani is tudj�k), C programjaink illeszkedni fognak a C++ szab�-

lyaihoz. Ha deklar�latlan f�ggv�nyeket h�vunk meg, nagyon pontosan ismern�nk kell


C
rendszer�nk f�ggv�nyh�v�ssal kapcsolatos szab�lyait, hogy eld�nthess�k, okoztunk-e
hib
�t vagy hordozhat�s�gi probl�m�t. Az elobbi main() program p�ld�ul legal�bb k�t
hib�t
tartalmaz C programk�nt is.
B. Kompatibilit�s 1097
A C-ben azok a f�ggv�nyek, melyeket param�tert�pus megad�sa n�lk�l vezet�nk be,
tetsz
oleges sz�m� �s t�pus� param�terrel megh�vhat�k. Az ilyen f�ggv�nyhaszn�lat a
Standard
C-ben is elavult, ennek ellen�re sok helyen tal�lkozhatunk vele:
void f(); /* a param�tert�pusokat elhagyjuk */
void g()
{
f(2); /* rossz st�lus C-ben, hib�s C++-ban */
}
A C-ben megengedett az a f�ggv�ny-meghat�roz�si forma, melyben a param�terek
t�pus�t
a param�terek list�j�nak megad�sa ut�n r�gz�tj�k:
void f(a,p,c) char *p; char c; { /* ... */ } /* helyes C-ben, hib�s C++-ban */
Ezeket a defin�ci�kat �t kell �rnunk:
void f(int a, char* p, char c) { /* ... */ }
A C-ben �s a C++ szabv�nyos�t�s elotti v�ltozataiban az int alap�rtelmezett t�pus
volt. P�ld
�ul:
const a = 7; /* C-ben "int" t�pust felt�telez; C++-ban hib�s */
Az ISO C, a C++-hoz hasonl�an, megtiltotta az .implicit int. haszn�lat�t.
A C megengedi, hogy a visszat�r�si t�pusok �s a param�tert�pusok deklar�ci�iban
structokat
adjunk meg:
struct S { int x,y; } f(); /* helyes C-ben, hib�s C++-ban */
void g(struct S { int x,y; } y); /* helyes C-ben, hib�s C++-ban */
A C++ t�pus-meghat�roz�sokra vonatkoz� szab�lyai az ilyen deklar�ci�kat
feleslegess� teszik
�s nem is engedik meg.
A C-ben a felsorol� t�pus� v�ltoz�knak �rt�k�l adhatunk eg�szeket is:
enum Direction { up, down };
Direction d = 1; /* hiba: int �rt�kad�s Direction-nek; C-ben helyes */
1098 F�ggel�kek �s t�rgymutat�
A C++ sokkal t�bb kulcssz�t ismer, mint a C. Ha ezek valamelyik�t azonos�t�k�nt
haszn�ljuk
egy C programban, k�nytelenek lesz�nk azt lecser�lni, hogy C++-ban is �rtelmezheto

programot kapjunk.
A C-ben n�h�ny C++ kulcssz� makr�k�nt szerepel a szabv�nyos fej�llom�nyokban:
Ez azt is jelenti, hogy a C-ben ezeket tesztelhetj�k az #ifdef seg�ts�g�vel,
meghat�roz�sukat
fel�lb�r�lhatjuk stb.
A C-ben a glob�lis adatobjektumokat t�bbsz�r is deklar�lhatjuk egy ford�t�si
egys�gen bel
�l, an�lk�l, hogy az extern kulcssz�t haszn�ln�nk. Am�g a deklar�ci�k k�z�l csak
egy ad
kezdo�rt�ket, a ford�t� az objektumot egyszer meghat�rozottnak (egyszer
defini�ltnak)
tekinti.
B. Kompatibilit�s 1099
C++ kulcsszavak, melyek a C-ben nem kulcsszavak
and and_eq asm bitand bitor bool
catch class compl const_cast delete dynamic_cast
explicit export false friend inline mutable
namespace new not not_eq operator or
or_eq private protected public reinterpret_cast static_cast
template this throw true try typeid
typename using virtual wchar_t xor xor_eq
C++ kulcsszavak, melyek C makr�k
and and_eq bitand bitor compl not
not_eq or or_eq wchar_t xor xor_eq
P�ld�ul:
int i; int i; /* egyetlen 'i' eg�szet hat�roz meg vagy vezet be; C++-ban hib�s */
A C++-ban minden elemet csak egyszer hat�rozhatunk meg (�9.2.3).
A C++-ban egy oszt�lynak nem lehet ugyanaz a neve, mint egy typedef elemnek, amely

ugyanabban a hat�k�rben valamilyen m�s t�pusra hivatkozik (�5.7).


A C-ben a void* haszn�lhat� b�rmilyen mutat� t�pus� v�ltoz� egyszeru vagy kezdeti
�rt�kad
�s�nak jobb oldal�n. A C++-ban ezt nem tehetj�k meg (�5.6.):
void f(int n)
{
int* p = malloc(n*sizeof(int)); /* C++-ban hib�s; haszn�ljuk ink�bb a 'new'
oper�tort */
}
A C megengedi, hogy ugr�sokkal kiker�lj�nk egy kezdeti �rt�kad�st, a C++-ban ez
sem
lehets�ges.
A C-ben a glob�lis konstansokat a ford�t� automatikusan extern elemekk�nt kezeli,
m�g
a C++-ban nem. K�telezo vagy kezdo�rt�ket adni, vagy az extern kulcssz�t haszn�lni

(�5.4.).
A C-ben a be�gyazott szerkezetek nevei ugyanabba a hat�k�rbe ker�lnek, mint a
felett�k
�ll� szerkezet�:
struct S {
struct T { /* ... */ };
// ...
};
struct T x; /* helyes C-ben, jelent�se 'S::T x;'; C++-ban hib�s */
A C-ben egy t�mbnek olyan elemmel is adhatunk kezdo�rt�ket, amelynek t�bb eleme
van,
mint amennyire a deklar�lt t�mbnek sz�ks�ge van:
char v[5] = "Oscar"; /* helyes C-ben, a lez�r� 0-t nem haszn�lja; C++-ban hib�s */

1100 F�ggel�kek �s t�rgymutat�


B.2.3. Elavult szolg�ltat�sok
Ha a szabv�nyos�t� bizotts�g egy szolg�ltat�st elavultnak nyilv�n�t, akkor ezzel
azt fejezi ki,
hogy a szolg�ltat�st el kell ker�lni. A bizotts�gnak azonban nincs joga egy
kor�bban gyakran
haszn�lhat� lehetos�get teljesen megsz�ntetni, akkor sem, ha az esetleg felesleges
vagy
kifejezetten vesz�lyes. Teh�t az .elavults�g. kimond�sa csak egy (nyomat�kos)
aj�nl�s
a programoz�knak arra, hogy ne haszn�lj�k a lehetos�get.
A static kulcssz�, melynek alapjelent�se: .statikusan lefoglalt., �ltal�ban azt
jelzi, hogy egy
f�ggv�ny vagy egy objektum helyinek (lok�lisnak) sz�m�t a ford�t�si egys�gre
n�zve:
// f�jl1:
static int glob;
// f�jl2:
static int glob;
Ennek a programnak val�j�ban k�t glob nevu, eg�sz t�pus� v�ltoz�ja lesz.
Mindkettot kiz�-
r�lag azok a f�ggv�nyek fogj�k haszn�lni, amelyekkel megegyezo ford�t�si egys�gben

szerepel.
A static kulcssz� haszn�lata a .lok�lis a ford�t�si egys�gre n�zve. �rtelemben
elavult a C++-
ban. Helyett�k a n�vtelen n�vterek haszn�lata javasolt (�8.2.5.1).
A karakterl�nc-liter�lok automatikus �talak�t�sa (nem konstans) char* t�pusra
szint�n elavult.
Haszn�ljunk ink�bb n�vvel rendelkezo karaktert�mb�ket, �gy elker�lhetj�k, hogy
karakterl�nc-liter�lokat kelljen �rt�k�l adnunk char* v�ltoz�knak (�5.2.2).
A C st�lus� t�pus�talak�t�st az �j �talak�t�soknak szint�n elavultt� kellett volna
tenni�k; sajnos
m�g sokan haszn�lj�k, pedig a felhaszn�l�nak programjaiban �rdemes komolyan
megfogadnia
a C st�lus� �talak�t�sok tilalm�t. Ha explicit t�pus�talak�t�sra van sz�ks�g�nk,
a static_cast, a reinterpret_cast, illetve a const_cast kulcssz�val vagy ezek
egy�ttes haszn�-
lat�val ugyanazt az eredm�nyt �rhetj�k el, mint a C st�lus� �talak�t�ssal. Az �j
�talak�t�sokat
az�rt is �rdemes haszn�lnunk, mert ezek sz�lesebb k�rben haszn�lhat�k �s
pontosabban
megfogalmazottak (�6.2.7).
B. Kompatibilit�s 1101
B.2.4. C++ program, ami nem C program
Ebben a pontban azokat a szolg�ltat�sokat soroljuk fel, melyek a C++-ban
megtal�lhat�k,
de a C-ben nem. A lehetos�geket szerep�k szerint soroljuk fel. Term�szetesen
sz�mtalan
oszt�lyoz�s lehets�ges, mert a legt�bb szolg�ltat�s t�bb c�lt is szolg�l, teh�t az
itt bemutatott
nem az egyetlen j� csoportos�t�s:
� Lehetos�gek, melyek elsosorban k�nyelmes jel�l�srendszert biztos�tanak:
1. A // megjegyz�sek (�2.3); a C-ben is szerepelni fognak.
2. Korl�tozott karakterk�szletek haszn�lat�nak lehetos�ge (�C.3.1).
3. Bov�tett karakterk�szletek haszn�lat�nak lehetos�ge (�C.3.3), a C-ben is
megjelenik.
4. A static t�rban levo objektumok nem-konstans kezdo�rt�ket is kaphatnak
(�9.4.1).
5. A const a konstans kifejez�sekben (�5.4, �C.5).
6. A deklar�ci�k utas�t�sokk�nt szerepelnek.
7. Deklar�ci�k szerepelhetnek a for utas�t�s kezdo�rt�k-ad� elem�ben �s az if
felt�telben is (�6.3.3, �6.3.2.1).
8. Az adatszerkezetek nevei elott nem kell szerepelnie a struct kulcssz�nak.
� Lehetos�gek, melyek elsosorban a t�pusrendszer eros�t�s�t szolg�lj�k:
1. A f�ggv�nyparam�terek t�pusellenorz�se (�7.1); k�sobb a C-ben is megjelent
(�B.2.2).
2. T�pusbiztos �sszeszerkeszt�s (�9.2, �9.2.3).
3. A szabad t�r kezel�se a new �s a delete oper�tor seg�ts�g�vel (�6.2.6, �10.4.5,

�15.6).
4. A const (�5.4, �5.4.1); k�sobb a C-be is beker�lt.
5. A logikai bool adatt�pus (�4.2).
6. �j t�pus�talak�t�si forma (�6.2.7).
� Felhaszn�l�i t�pusokat seg�to lehetos�gek:
1. Oszt�lyok (10. fejezet).
2. Tagf�ggv�nyek (�10.2.1) �s tagoszt�lyok (�11.12).
3. Konstruktorok �s destruktorok (�10.2.3, �10.4.1).
4. Sz�rmaztatott oszt�lyok (12. fejezet, 15. fejezet).
5. Virtu�lis f�ggv�nyek �s elvont oszt�lyok (�12.2.6, �12.3).
6. A public/protected/private hozz�f�r�s-szab�lyoz�s (�10.2.2, �15.3, �C.11).
7. A .bar�tok. (friend) lehetos�gei (�11.5).
8. Mutat�k tagokra (�15.5, �C.12).
9. static tagok (�10.2.4).
1102 F�ggel�kek �s t�rgymutat�
10. mutable tagok (�10.2.7.2).
11. Oper�tor-t�lterhel�s (11. fejezet).
12. Hivatkoz�sok (�5.5).
� Lehetos�gek, melyek elsosorban a program rendszerez�s�re szolg�lnak (az oszt
�lyokon t�l):
1. Sablonok (13. fejezet, �C.13).
2. Helyben kifejtett (inline) f�ggv�nyek (�7.1.1).
3. Alap�rtelmezett param�terek (�7.5).
4. F�ggv�nyn�v-t�lterhel�s (�7.4).
5. N�vterek (�8.2).
6. Explicit hat�k�r-meghat�roz�s (a :: oper�tor, �4.9.4).
7. Kiv�telkezel�s (�8.3, 14. fejezet).
8. Fut�si ideju t�pus-meghat�roz�s (�15.4).
A C++-ban bevezetett �j kulcsszavak (�B.2.2) a legt�bb olyan szolg�ltat�st
bemutatj�k, melyek
kifejezetten a C++-ban jelentek meg. Van azonban n�h�ny nyelvi elem . p�ld�ul
a f�ggv�ny-t�lterhel�s vagy a consts alkalmaz�sa konstans kifejez�sekben .,
melyeket nem
�j kulcssz� seg�ts�g�vel val�s�t meg a nyelv. Az itt felsorolt nyelvi lehetos�gek
mellett a C++
k�nyvt�r is (�16.1.2) nagy r�szben csak a C++-ra jellemzo.
A __cplusplus makr� seg�ts�g�vel mindig meg�llap�thatjuk, hogy programunkat �ppen
C
vagy C++ ford�t�val dolgozzuk-e fel (�9.2.4).
B.3. R�gebbi C++-v�ltozatok haszn�lata
A C++ nyelvet 1983 �ta folyamatosan haszn�lj�k (�1.4). Az�ta sz�mtalan v�ltozat �s
�n�ll�
fejlesztok�rnyezet k�sz�lt belole. A szabv�nyos�t�s alapveto c�lja, hogy a
programoz�k �s
felhaszn�l�k r�sz�re egy egys�ges C++ �lljon rendelkez�sre. Am�g azonban a
szabv�ny teljes
k�rben el nem terjed a C++-rendszerek k�sz�toi k�r�ben, mindig figyelembe kell
venn
�nk azt a t�nyt, hogy nem minden megval�s�t�s ny�jtja az �sszes szolg�ltat�st, ami
ebben
a k�nyvben szerepel.
Sajnos nem ritka, hogy a programoz�k elso komoly benyom�saikat a C++-r�l egy n�gy-
�t
�ves v�ltozat alapj�n szerzik meg. Ennek oka az, hogy ezek sz�les k�rben �s olcs�n
el�rhet
ok. Ha azonban a legkisebb lehetos�ge is van, egy mag�ra valamit is ad� szakember
B. Kompatibilit�s 1103
ilyen antik rendszernek a k�zel�be sem megy. Egy kezdonek a r�gebbi v�ltozatok
sz�mtalan
rejtett probl�m�t okozhatnak. A nyelvi lehetos�gek �s a k�nyvt�rban megval�s�tott
szolg
�ltat�sok hi�nya olyan probl�m�k kezel�s�t teszi sz�ks�gess�, melyek az �jabb
v�ltozatokban
m�r nem jelentkeznek. A kev�s lehetos�get biztos�t� r�gebbi v�ltozatok a kezdo
programoz� programoz�si st�lus�nak is sokat �rtanak, r�ad�sul helytelen k�p�nk
alakul ki
arr�l, mi is val�j�ban a C++. V�lem�nyem szerint a C++ elso megismer�sekor nem az
a legmegfelel
obb r�szhalmaz, amely az alacsonyszintu szolg�ltat�sokat tartalmazza (teh�t semmik
�ppen sem a C �s a C++ k�z�s r�sze). Azt aj�nlom, elosz�r a standard k�nyvt�rat �s

a sablonokat ismerj�k meg, mert ezekkel egyszeruen megoldhatunk komolyabb


feladatokat
is �s j� �zel�tot kapunk a .val�di C++. szolg�ltat�saib�l.
A C++ elso kereskedelmi kiad�sa 1985-ben jelent meg; e k�nyv elso kiad�sa alapj�n
k�sz�-
tett�k. Akkor a C++ m�g nem biztos�tott t�bbsz�r�s �r�klod�st, sablonokat, fut�si
ideju t�-
pusinform�ci�kat, kiv�teleket �s n�vtereket sem. Mai szemmel semmi �rtelm�t nem
l�tom
annak, hogy olyan rendszerrel kezdj�nk el dolgozni, amely ezen szolg�ltat�sok
legal�bb
egy r�sz�t nem biztos�tja. A t�bbsz�r�s �r�klod�s, a sablonok �s a kiv�telek 1989-
ben ker
�ltek be a C++-ba. A sablonok �s kiv�telek elso megval�s�t�sa m�g nagyon
kiforratlan �s
szeg�nyes volt. Ha ezek haszn�latakor probl�m�kba �tk�z�nk, s�rgosen szerezz�nk be

egy �jabb nyelvi v�ltozatot.


�ltal�ban igaz, hogy olyan v�ltozatot �rdemes haszn�lnunk, amely minden lehets�ges
helyen
igazodik a szabv�nyhoz, hogy elker�lhess�k a megval�s�t�sb�l eredo k�l�nbs�geket,
illetve az adott nyelvi v�ltozatnak a szabv�ny �ltal nem meghat�rozott
tulajdons�gait. Tervezz
�k programjainkat �gy, mintha a teljes nyelv a rendelkez�s�nkre �llna, majd
val�s�tsuk
meg �n�ll�an a hi�nyz� r�szletek szolg�ltat�sait. �gy jobban rendszerezett �s
k�nnyebben
tov�bbfejlesztheto programot kapunk, mint ha a C++ mindenhol megtal�lhat�, k�z�s
magj
�hoz tervezn�nk a programot. Arra is mindig figyelj�nk, hogy megval�s�t�s-f�ggo
szolg�ltat
�sokat csak akkor haszn�ljunk, ha elker�lhetetlen.
B.3.1. Fej�llom�nyok
Eredetileg minden fej�llom�ny kiterjeszt�se .h volt, �gy a C++ egyes v�ltozataiban
is megjelentek
az olyan fej�llom�nyok, mint a <map.h> vagy az <iostream.h>. A kompatibilit�s
�rdek
�ben ezek �ltal�ban ma is haszn�lhat�k.
Amikor a szabv�nyos�t� bizotts�gnak �j fej�llom�nyokat kellett bevezetnie a
szabv�nyos
k�nyvt�rak �t�rt v�ltozatai, illetve az �jonnan meghat�rozott k�nyvt�ri
szolg�ltat�sok kezel
�s�hez, a fej�llom�nyok elnevez�se probl�m�kba �tk�z�tt. A r�gi .h kiterjeszt�s
haszn�la-
1104 F�ggel�kek �s t�rgymutat�
ta �sszeegyeztethetos�gi probl�m�kat okozott volna. A megold�st a .h kiterjeszt�s
elhagy�-
sa jelentette az �j szabv�nyos fej�llom�ny-nevekben. Az ut�tag egy�bk�nt is
felesleges volt,
mert a < > en�lk�l is jelezte, hogy szabv�nyos fej�llom�nyt nevezt�nk meg.
Teh�t a standard k�nyvt�r kiterjeszt�s n�lk�li fej�llom�nyokat biztos�t (p�ld�ul
<map> vagy
<iostream>). Ezen �llom�nyok deklar�ci�i az std n�vt�rben szerepelnek. A r�gebbi
fej�llom
�nyok a glob�lis n�vt�rben kapnak helyet �s ezek nev�ben szerepel a .h
kiterjeszt�s.
P�ld�ul:
#include<iostream>
int main()
{
std::cout << "Hell�, vil�g!\n";
}
Ha ezt a programr�szletet nem siker�l leford�tanunk, pr�b�lkozzunk a
hagyom�nyosabb
v�ltozattal:
#include<iostream.h>
int main()
{
cout << "Hell�, vil�g!\n";
}
A legt�bb hordozhat�s�gi probl�m�t a nem teljesen �sszeegyeztetheto fej�llom�nyok
okozz�k. A szabv�nyos fej�llom�nyok ebbol a szempontb�l ritk�bban jelentenek
gondot.
Nagyobb programokn�l gyakran elofordul, hogy sok fej�llom�nyt haszn�lunk, �s ezek
nem
mindegyike szerepel az �sszes rendszerben vagy sok deklar�ci� nem ugyanabban a
fej�llom
�nyban jelenik meg. Az is elofordul, hogy bizonyos deklar�ci�k szabv�nyosnak
tunnek
(mert szabv�nyos nevu fej�llom�nyokban szerepelnek), de val�j�ban semmilyen
szabv�nyban
nem szerepelnek.
Sajnos nincs teljesen kiel�g�to m�dszer a fej�llom�nyok �ltal okozott
hordozhat�s�gi probl
�m�k kezel�s�re. Egy gyakran alkalmazott megold�s, hogy elker�lj�k a
fej�llom�nyokt�l
val� k�zvetlen f�gg�st �s a fennmarad� f�ggos�geket k�l�n fogalmazzuk meg. �gy a
hordozhat
�s�got a k�zvetett hivatkoz�sokkal �s az elk�l�n�tett f�ggos�gkezel�ssel jav�tjuk.

P�ld�ul, ha egy sz�ks�ges deklar�ci� a k�l�nb�zo rendszerekben k�l�nb�zo


fej�llom�nyokon
kereszt�l �rheto el, egy alkalmaz�sf�ggo fej�llom�nyt haszn�lhatunk, amely az
B. Kompatibilit�s 1105
#include seg�ts�g�vel mag�ba foglalja az egyes rendszerek megfelelo �llom�nyait.
Ugyan-
�gy, ha valamilyen szolg�ltat�st a k�l�nb�zo rendszerekben m�sk�ppen �rhet�nk el,
a szolg
�ltat�shoz alkalmaz�sf�ggo oszt�lyokat �s f�ggv�nyeket k�sz�thet�nk.
B.3.2. A standard k�nyvt�r
Term�szetesen a C++ szabv�ny elotti v�ltozataib�l hi�nyozhatnak a standard
k�nyvt�r bizonyos
r�szei. A legt�bb rendszerben szerepelnek az adatfolyamok, a complex adatt�pus
(�ltal�ban nem sablonk�nt), a k�l�nb�zo string oszt�lyok �s a C standard
k�nyvt�ra.
A map, a list, a valarray stb. azonban gyakran hi�nyozik ezekbol a
megval�s�t�sokb�l.
Ilyenkor pr�b�ljuk az el�rheto k�nyvt�rakat �gy haszn�lni, hogy k�sobb
lehetos�g�nk legyen
az �talak�t�sra, ha szabv�nyos k�rnyezetbe ker�l�nk. �ltal�ban jobban j�runk, ha
a nem szabv�nyos string, list vagy map oszt�lyt haszn�ljuk, ahelyett, hogy a
standard
k�nyvt�r oszt�lyainak hi�nya miatt visszat�rn�nk a C st�lus� programoz�shoz. Egy
m�sik lehet
os�g, hogy a standard k�nyvt�r STL r�sz�nek (16., 17., 18. �s 19. fejezet) j�
megval�s�-
t�sai t�lthetok le ingyenesen az Internetrol.
A standard k�nyvt�r r�gebbi v�ltozatai m�g nem voltak teljesek. P�ld�ul sokszor
jelentek
meg t�rol�k �gy, hogy mem�riafoglal�k haszn�lat�ra m�g nem volt lehetos�g, vagy
�ppen
ellenkezoleg, mindig k�telezo volt megadni a mem�riafoglal�t. Hasonl� probl�m�k
fordultak
elo az .elj�r�sm�d-param�terek. eset�ben is, p�ld�ul az �sszehasonl�t�si
felt�telekn�l:
list<int> li; // rendben, de n�h�ny megval�s�t�s megk�veteli a mem�riafoglal�t
list<int,allocator<int> > li2; // rendben, de n�h�ny megval�s�t�s nem ismeri
// a mem�riafoglal�t
map<string,Record> m1; // rendben, de n�h�ny megval�s�t�s megk�vetel egy
// 'kisebb mint' muveletet
map<string,Record,less<string> > m2;
Mindig azt a v�ltozatot kell haszn�lnunk, amelyet az adott fejlesztok�rnyezet
elfogad. Szerencs
�s esetben rendszer�nk az �sszes form�t ismeri.
A r�gebbi C++-v�ltozatokban gyakran istrstream �s ostrstream oszt�ly szerepelt,
a <strstream.h> nevu fej�llom�ny r�szek�nt, m�g a szabv�ny az istringstream �s
ostringstream oszt�lyokat adja meg, melyeknek helye az <sstream> fej�llom�ny.
A strstream adatfolyamok k�zvetlen�l karaktert�mb�k�n v�geztek muveleteket (l�sd
�21.10 [26]).
1106 F�ggel�kek �s t�rgymutat�
A szabv�ny elotti C++-v�ltozatokban az adatfolyamok nem voltak param�teresek. A
basic_
elotag� sablonok �jak a szabv�nyban; a basic_ios oszt�lyt r�gebben ios oszt�lynak
h�vt�k.
Kiss� meglepo m�don az iostate r�gi neve viszont io_state volt.
B.3.3. N�vterek
Ha rendszer�nk nem t�mogatja a n�vterek haszn�lat�t, a program logikai szerkezet�t
kifejezhetj
�k forr�sf�jlok seg�ts�g�vel is (9.fejezet). A fej�llom�nyok ugyan�gy j�l
haszn�lhat�k
saj�t vagy C k�ddal k�z�sen haszn�lt fel�leteink le�r�s�ra.
Ha a n�vterek nem �llnak rendelkez�sre, a n�vtelen n�vterek hi�ny�t a static
kulcssz� haszn
�lat�val ellens�lyozhatjuk. Szint�n sokat seg�thet, ha a glob�lis nevekben egy
elotaggal jelezz
�k, hogy milyen logikai egys�ghez tartoznak:
// n�vt�r elotti nyelvi v�ltozatokban:
class bs_string { /* ... */ }; // Bjarne saj�t string t�pusa
typedef int bs_bool; // Bjarne saj�t bool t�pusa
class joe_string; // Joe saj�t string t�pusa
enum joe_bool { joe_false, joe_true }; // Joe saj�t bool t�pusa
Az elotagok kiv�laszt�sakor azonban legy�nk elovigy�zatosak, mert a l�tezo C �s C+
+
k�nyvt�rak esetleg ugyanilyen elotagokat haszn�lnak.
B.3.4. Helyfoglal�si hib�k
Mielott a kiv�telkezel�s megjelent a C++-ban, a new oper�tor 0 �rt�ket adott
vissza, ha
a helyfoglal�s nem siker�lt. A szabv�nyos C++ new oper�tora ma m�r egy bad_alloc
kiv�-
tellel jelzi a hib�t.
�ltal�ban �rdemes programjainkat a szabv�nynak megfeleloen �t�rni. Itt ez annyit
jelent,
hogy nem a 0 visszat�r�si �rt�ket, hanem a bad_alloc kiv�telt figyelj�k. �ltal�ban
mindk�t
esetben nagyon neh�z a probl�m�t egy hiba�zenetn�l hat�konyabban kezelni.
Ha �gy �rezz�k, nem �rdemes a 0 �rt�k vizsg�lat�t a bad_alloc kiv�tel figyel�s�re
�talak�-
tani, �ltal�ban el�rhetj�k, hogy a program �gy muk�dj�n, mintha nem �lln�nak
rendelkez
�s�nkre a kiv�telek. Ha rendszer�nkben nincs _new_handler telep�tve, a nothrow
mem�-
riafoglal� seg�ts�g�vel kiv�telek helyett a 0 visszat�r�si �rt�kkel vizsg�lhatjuk
a helyfoglal�si hib�k elofordul�s�t:
B. Kompatibilit�s 1107
X* p1 = new X; // bad_alloc kiv�telt v�lt ki, ha nincs mem�ria
X* p2 = new(nothrow) X; // visszat�r�si �rt�ke 0, ha nincs mem�ria
B.3.5. Sablonok
A szabv�ny sz�mos �j szolg�ltat�st vezetett be a sablonok k�r�ben �s a r�gebbi
lehetos�-
gek szab�lyait is tiszt�bban fogalmazta meg.
Ha rendszer�nk nem t�mogatja a r�szlegesen egyedi c�l� v�ltozatok (specializ�ci�k)
megad
�s�t, akkor azokhoz a sablonokhoz, amelyeket egy�bk�nt egyszeru szakos�t�ssal hozn
�nk l�tre, �n�ll� nevet kell rendeln�nk:
template<class T> class plist : private list<void*> { // list<T*> kellett volna
// ...
};
Ha az adott nyelvi v�ltozat nem t�mogatja a sablon tagok haszn�lat�t, n�h�ny
m�dszerrol
k�nytelenek lesz�nk lemondani. A sablon tagok seg�ts�g�vel p�ld�ul olyan
rugalmasan hat
�rozhatjuk meg elemek l�trehoz�s�t, illetve �talak�t�s�t, amire ezek n�lk�l nincs
lehetos�-
g�nk. (�13.6.2.) N�ha kiseg�to megold�st jelent az, hogy egy �n�ll� (nem tag)
f�ggv�nyt
adunk meg, amely l�trehozza a megfelelo objektumot:
template<class T> class X {
// ...
template<class A> X(const A& a);
};
Ha nem haszn�lhatunk sablon tagokat, k�nytelenek vagyunk konkr�t t�pusokra
korl�tozni
tev�kenys�g�nket:
template<class T> class X {
// ...
X(const A1& a);
X(const A2& a);
// ...
};
A kor�bbi C++-rendszerek t�bbs�ge a sablon oszt�lyok p�ld�nyos�t�sakor a sablon
�sszes
f�ggv�ny�t lem�solja �s l�trehozza k�djukat. Ez ahhoz vezethet, hogy a nem
haszn�lt tagf
�ggv�nyek hib�t okoznak (�C.13.9.1.). A megold�st az jelenti, ha a k�rd�ses
tagf�ggv�nyek
meghat�roz�s�t az oszt�lyon k�v�l helyezz�k el.
1108 F�ggel�kek �s t�rgymutat�
A
template<class T> class Container {
// ...
public:
void sort() { /* haszn�lja < muveletet */ } // oszt�lyon bel�li meghat�roz�s
};
class Glob { /* a Glob-ban nincs < muvelet */ };
Container<Glob> cg; // n�h�ny szabv�ny elotti v�ltozatban
// Container<Glob>::sort() szerepel
helyett p�ld�ul a k�vetkezo megold�st adhatjuk:
template<class T> class Container {
// ...
public:
void sort();
};
template<class T> void Container<T>::sort() { /* a < muvelet haszn�lata */ }
// oszt�lyon k�v�li definici�
class Glob { /* a Glob-ban nincs < muvelet */ };
Container<Glob> cg; // nincs baj, am�g a cg.sort()-ot meg nem h�vjuk
A C++ r�gebbi megval�s�t�sai nem teszik lehetov� az oszt�lyban k�sobb bevezetett
tagok
kezel�s�t:
template<class T> class Vector {
public:
T& operator[](size_t i) { return v[i]; } // v k�sobb bevezetendo
// ...
private:
T* v; // hopp�: nem tal�lja!
size_t sz;
};
Ilyenkor vagy �gy rendezz�k �t a tagokat, hogy elker�lj�k az ilyen probl�m�kat,
vagy
a f�ggv�ny meghat�roz�s�t az oszt�lydeklar�ci� ut�n helyezz�k.
B. Kompatibilit�s 1109
N�h�ny, szabv�ny elotti C++-v�ltozat a sablonok eset�ben nem fogadja el az
alap�rtelmezett
param�terek haszn�lat�t (�13.4.1.). Ez esetben minden sablonparam�tert k�l�n meg
kell adnunk:
template<class Key, class T, class LT = less<T> > class map {
// ...
};
map<string,int> m; // hopp�: nem lehet alap�rtelmezett sablonparam�ter
map< string,int,less<string> > m2; // megold�s: explicit megad�s
B.3.6. A for utas�t�s kezdo�rt�k-ad� r�sze
Vizsg�ljuk meg az al�bbi p�ld�t:
void f(vector<char>& v, int m)
{
for (int i= 0; i<v.size() && i<=m; ++i) cout << v[i];
if (i == m) { // hiba: hivatkoz�s 'i'-re a 'for' utas�t�s ut�n
// ...
}
}
Az ilyen programok r�gebben muk�dtek, mert az eredeti C++-ban a v�ltoz� hat�k�re a
for
utas�t�st tartalmaz� hat�k�r v�g�ig terjedt. Ha ilyen programokkal tal�lkozunk, a
v�ltoz�t
�rdemes egyszeruen a for ciklus elott bevezetn�nk:
void f2(vector<char>& v, int m)
{
int i= 0; // 'i' kell a ciklus ut�n
for (; i<v.size() && i<=m; ++i) cout << v[i];
if (i == m) {
// ...
}
}
1110 F�ggel�kek �s t�rgymutat�
B.4. Tan�csok
[1] A C++ megtanul�s�hoz haszn�ljuk a szabv�nyos C++ leg�jabb �s legteljesebb
v�ltozat�t, amihez csak hozz� tudunk f�rni. �B.3.
[2] A C �s a C++ k�z�s r�sze egy�ltal�n nem az a r�sze a C++-nak, amit elosz�r
meg kell tanulnunk. �1.6, �B.3.
[3] Amikor komoly alkalmaz�st k�sz�t�nk, gondoljunk r�, hogy nem minden C++-
v�ltozat tartalmazza a szabv�ny �sszes lehetos�g�t. Mielott egy fobb szolg�ltat
�st haszn�lunk egy komoly programban, �rdemes kitapasztalnunk azt egy-k�t
kisebb program meg�r�s�val. Ezzel ellenorizhetj�k, hogy rendszer�nk mennyire
illeszkedik a szabv�nyhoz �s mennyire hat�kony a megval�s�t�s. P�ldak�ppen
l�sd �8.5[6-7], �16.5[10], �B.5[7]
[4] Ker�lj�k az elavult szolg�ltat�sokat, p�ld�ul a static kulcssz� glob�lis
haszn�lat
�t, vagy a C st�lus� t�pus�talak�t�st.
[5] A szabv�ny megtiltotta az .implicit int. haszn�lat�t, teh�t mindig pontosan
adjuk
meg f�ggv�nyeink, v�ltoz�ink, konstansaink stb. t�pus�t. �B.2.2.
[6] Amikor egy C programot C++ programm� alak�tunk, elosz�r a f�ggv�nydeklar�-
ci�kat (protot�pusokat), �s a szabv�nyos fej�llom�nyok k�vetkezetes haszn�lat
�t ellenorizz�k. �B.2.2.
[7] Amikor egy C programot C++ programm� alak�tunk, nevezz�k �t azokat a v�ltoz
�kat, melyek C++ kulcsszavak. �B.2.2.
[8] Amikor egy C programot C++ programm� alak�tunk, a malloc() eredm�ny�t
mindig megfelelo t�pus�ra kell alak�tanunk. M�g hasznosabb, ha a malloc()
�sszes h�v�s�t a new oper�torral helyettes�tj�k. �B.2.2.
[9] Ha a malloc() �s a free() f�ggv�nyeket a new �s a delete oper�torra cser�lj�k,

vizsg�ljuk meg, hogy a realloc() f�ggv�ny haszn�lata helyett nem tudjuk-e


a vector, a push_back() �s a reserve() szolg�ltat�sait ig�nybe venni. �3.8,
�16.3.5.
[10] Amikor egy C programot C++ programm� alak�tunk, gondoljunk r�, hogy nincs
automatikus �talak�t�s eg�szekrol felsorol� t�pusokra, teh�t meghat�rozott �talak
�t�st kell alkalmaznunk, ha ilyen �talak�t�sra van sz�ks�g. �4.8.
[11] Az std n�vt�rben meghat�rozott szolg�ltat�sok kiterjeszt�s n�lk�li fej�llom�-

nyokban szerepelnek. (Az std::cout deklar�ci�ja p�ld�ul az <iostream> fej�llom


�ny r�sze.) A r�gebbi v�ltozatokban a standard k�nyvt�r nevei is a glob�lis
n�vt�rbe ker�ltek, a fej�llom�nyok pedig .h kiterjeszt�ssel rendelkeztek.
(A ::cout deklar�ci�ja p�ld�ul az <iostream.h> fej�llom�nyban szerepelt.) �9.2.2,
�B.3.1.
[12] Ha r�gebbi C++ programok a new visszat�r�si �rt�k�t a 0 �rt�kkel hasonl�tj�k
�ssze, akkor ezt a bad_alloc kiv�tel ellenorz�s�re kell cser�ln�nk, vagy
a new(nothrow) utas�t�st kell helyette haszn�lnunk. �B.3.4.
B. Kompatibilit�s 1111
[13] Ha fejlesztok�rnyezet�nk nem t�mogatja az alap�rtelmezett sablonparam�terek
haszn�lat�t, meg kell adnunk minden param�tert. A typedef seg�ts�g�vel a
sablonparam
�terek ism�telget�se elker�lheto (ahhoz hasonl�an, ahogy a string t�-
pus-meghat�roz�s megk�m�l minket a basic_string< char, char_traits<char>,
allocator<char> > le�r�s�t�l). �B.3.5.
[14] Az std::string oszt�ly haszn�lat�hoz a <string> fej�llom�nyra van sz�ks�g�nk.

(A <string.h> �llom�nyban a r�gi, C st�lus� karakterl�nc-f�ggv�nyek szerepelnek.)


�9.2.2, �B.3.1.
[15] Minden <X.h> szabv�nyos C fej�llom�nynak (amely a glob�lis n�vt�rbe vezet
be neveket) megfelel egy <cX> fej�llom�ny, amely az elemeket az std n�vt�rbe
helyezi. �B.3.1.
[16] Nagyon sok rendszerben tal�lhat� egy .String.h. fej�llom�ny, amely egy
karakterl
�nc-t�pust �r le. Mindig gondoljunk r�, hogy ezek elt�rhetnek a szabv�nyos
string oszt�lyt�l.
[17] Ha lehetos�g�nk van r�, a szabv�nyos eszk�z�ket haszn�ljuk a nem szabv�-
nyos lehetos�gek helyett. �20.1, �B.3, �C.2.
[18] Ha C f�ggv�nyeket vezet�nk be, haszn�ljuk az extern .C. form�t.
B.5. Gyakorlatok
1. (*2.5) Vegy�nk egy C programot �s alak�tsuk �t C++-ra. Soroljuk fel a
programban
haszn�lt, a C++-ban nem haszn�lhat� elemeket, �s vizsg�ljuk meg, �rv�nyesek-
e az ANSI C szabv�ny szerint. Elso l�p�sben a programot csak ANSI C form
�tumra alak�tsuk (protot�pusokkal stb.), csak ezut�n C++-ra. Becs�lj�k meg,
mennyi idot vesz ig�nybe egy 100 000 soros C program �talak�t�sa C++-ra.
2. (*2.5) �rjunk programot, amely seg�t �talak�tani egy C programot C++-ra.
V�gezze
el azon v�ltoz�k �tnevez�s�t, melyek a C++-ban kulcsszavak, a malloc() h�-
v�sokat helyettes�tse a new oper�torral stb. Aj�nl�s: ne akarjunk t�k�letes
programot
�rni.
3. (*2) Egy C st�lus� C++ programban (p�ld�ul amit mostan�ban alak�tottak �t egy
C programb�l) a malloc() f�ggv�ny h�v�sait cser�lj�k a new oper�tor megh�v�-
s�ra. �tlet: �B.4[8-9]
4. (*2.5) Egy C st�lus� C++ programban (p�ld�ul amit mostan�ban alak�tottak �t
egy C programb�l) a makr�k, glob�lis v�ltoz�k, kezdo�rt�k n�lk�li v�ltoz�k �s
t�pus�talak�t�sok sz�m�t cs�kkents�k a minimumra.
1112 F�ggel�kek �s t�rgymutat�
5. (*3) Vegy�nk egy C++ programot, amit egy egyszeru elj�r�ssal alak�tottunk �t
egy
C programb�l, �s b�r�ljuk azt, mint C++ programot az adatrejt�s, az elvont �br�-
zol�s, az olvashat�s�g, a bov�thetos�g �s a r�szek esetleges �jrahasznos�that�s�-
ga szerint. V�gezz�nk valamilyen nagyobb �talak�t�st ezen b�r�latok alapj�n.
6. (*2) Vegy�nk egy kicsi (mondjuk 500 soros) C++ programot �s alak�tsuk azt C
programm�. Hasonl�tsuk �ssze a k�t programot a m�ret �s az elk�pzelheto tov
�bbfejleszt�sek szempontj�b�l.
7. (*3) �rjunk n�h�ny kicsi tesztprogramot, mellyel meg�llap�thatjuk, hogy egy
C++-v�ltozat rendelkezik-e a leg�jabb szabv�nyos lehetos�gekkel. P�ld�ul mi
a for utas�t�s kezdo�rt�k-ad� r�sz�ben bevezetett v�ltoz� hat�k�re? (�B.3.6.)
Haszn�lhat�k-e alap�rtelmezett sablonparam�terek? (�B.3.5.) Haszn�lhat�k-e
sablon tagok? (�8.2.6.) Aj�nl�s: �B.2.4.
8. (*2.5) Vegy�nk egy C++ programot, amely egy <X.h> fej�llom�nyt haszn�l �s
alak�tsuk �t �gy, hogy az <X> �s <cX> fej�llom�nyokat haszn�lja. Cs�kkents�k
a leheto legkevesebbre a using utas�t�sok haszn�lat�t.
B. Kompatibilit�s 1113
Technikai r�szletek
.Valahol a l�lek �s az Univerzum
legm�ly�n mindennek
megvan a maga oka"
(Slartibartfast)
Mit �g�r a szabv�ny? . Karakterk�szletek . Eg�sz liter�lok . Konstans
kifejez�sek . Kiterjeszt
�sek �s �talak�t�sok . T�bbdimenzi�s t�mb�k . Mezok �s uni�k . Mem�riakezel�s .
Szem�tgyujt�s . N�vterek . Hozz�f�r�s-szab�lyoz�s . Mutat�k adattagokra . Sablonok
.
static tagok . friend-ek . Sablonok, mint sablonparam�terek . Sablonparam�terek
levezet
�se . A typename �s a template minos�tok . P�ld�nyos�t�s . N�vk�t�s . Sablonok �s
n�vterek
. Explicit p�ld�nyos�t�s . Tan�csok
C.1. Bevezet�s �s �ttekint�s
Ebben a fejezetben olyan technikai r�szleteket �s p�ld�kat mutatok be, amelyeket
nem lehetett
eleg�nsan beilleszteni abba a szerkezetbe, amit a C++ nyelv fobb lehetos�geinek
bemutat
�s�ra haszn�ltam. Az itt k�z�lt r�szletek fontosak lehetnek programjaink
meg�r�sakor
is, de elengedhetetlenek, ha ezek felhaszn�l�s�val k�sz�lt programot kell
meg�rten�nk.
Technikai r�szletekrol besz�lek, mert nem szabad, hogy a tanul�k figyelm�t elvonja
az el-
C
sodleges feladatr�l, a C++ nyelv helyes haszn�lat�nak megismer�s�rol, vagy hogy a
programoz
�kat elt�r�tse a legfontosabb c�lt�l, gondolataik olyan tiszta �s k�zvetlen
megfogalmaz
�s�t�l, amennyire csak a C++ lehetov� teszi.
C.2. A szabv�ny
Az �ltal�nos hiedelemmel ellent�tben a felt�tlen ragaszkod�s a C++ nyelvhez �s a
szabv�-
nyos k�nyvt�rakhoz �nmag�ban v�ve nem jelent sem t�k�letes programot, sem
hordozhat
� k�dot. A szabv�ny nem mondja meg, hogy egy programr�szlet j� vagy rossz,
mind�ssze
azt �rulja el, hogy a programoz� mit v�rhat el egy megval�s�t�st�l �s mit nem.
Van, aki
a szabv�ny betart�s�val is borzalmas programokat �r, m�g a legt�bb j� program
haszn�l
olyan lehetos�geket is, melyeket a szabv�ny nem tartalmaz.
A szabv�ny nagyon sok fontos dolgot megval�s�t�s-f�ggonek (implementation-defined)
min
os�t. Ez azt jelenti, hogy minden nyelvi v�ltozatnak egy konkr�t, pontosan
meghat�rozott
megold�st kell adnia az adott k�rd�sre �s ezt a megold�st pontosan dokument�lnia
is kell:
unsigned char c1 = 64; // megfelelo meghat�roz�s: egy karakter legal�bb 8 bit �s
// mindig k�pes 64-et t�rolni
unsigned char c2 = 1256; // megval�s�t�s-f�ggo: csonkol, ha a char csak 8 bites
A c1 kezdeti �rt�kad�sa megfeleloen meghat�rozott, mert a char t�pusnak legal�bb 8
bitesnek
kell lennie, a c2-� viszont megval�s�t�s-f�ggo, mert a char t�pus �br�zol�s�hoz
haszn
�lt bitek pontos sz�ma is az. Ha a char csak 8 bites, az 1256 �rt�k 232-re csonkul

(�C.6.2.1). A legt�bb megval�s�t�s-f�ggo szolg�ltat�s a programok futtat�s�hoz


haszn�lt
hardverhez igazodik.
Amikor komoly programokat �runk, gyakran sz�ks�g van arra, hogy megval�s�t�s-f�ggo
lehet
os�geket haszn�ljunk. Ez az �ra annak, ha sz�mtalan k�l�nb�zo rendszeren
hat�konyan
futtathat� programokat akarunk �rni. Sokat egyszerus�tett volna a nyelven, ha a
karaktereket
8 bitesk�nt, az eg�szeket pedig 32 bitesk�nt hat�rozzuk meg. Nem ritk�k azonban a
16
vagy 32 bites karakterk�szletek, sem az olyan eg�sz �rt�kek, melyek nem
�br�zolhat�k 32
biten. Ma m�r l�teznek 32 gigab�jtot meghalad� kapacit�s� merevlemezek is, �gy a
lemezc
�mek �br�zol�s�hoz �rdemes lehet 48 vagy 64 bites eg�sz �rt�keket haszn�lni.
1116 F�ggel�kek �s t�rgymutat�
A hordozhat�s�g leheto leghat�konyabb megval�s�t�s�hoz �rdemes pontosan
megfogalmaznunk,
hogy milyen megval�s�t�s-f�ggo nyelvi elemeket haszn�ltunk a programunkban,
�s �rdemes vil�gosan elk�l�n�ten�nk a program azon r�szeit, ahol ezeket a
szolg�ltat�sokat
haszn�ljuk. Egy jellemzo p�lda erre a megold�sra, hogy az �sszes olyan elemet,
amely
valamilyen m�don f�gg a hardvertol, egy fej�llom�nyban, konstansok �s t�pus-
meghat�roz
�sok form�j�ban r�gz�tj�k. Ezt az elj�r�st t�mogatja a standard k�nyvt�r a
numeric_limits
oszt�llyal (�22.2).
A nem meghat�rozott (defini�latlan) viselked�s kellemetlenebb dolog. Egy nyelvi
szerkezetet
akkor nevez nem meghat�rozottnak a szabv�ny, ha semmilyen �rtelmes muk�d�st nem
v�rhatunk el a megval�s�t�st�l. A szok�sos megval�s�t�si m�dszerek �ltal�ban a nem
meghat
�rozott lehetos�geket haszn�l� programok nagyon rossz viselked�s�t eredm�nyezik:
const int size = 4*1024;
char page[size];
void f()
{
page[size+size] = 7; // nem meghat�rozhat�
}
Egy ilyen programr�szlet teljesen k�zenfekvo k�vetkezm�nye, hogy a mem�ri�ban
olyan
adatokat �runk fel�l, melyeket nem lenne szabad, vagy hardverhib�k, kiv�telek
l�pnek fel.
A megval�s�t�st�l nem v�rhatjuk el, hogy ilyen k�zenfekvo szab�lytalans�g eset�ben
is
�sszeruen muk�dj�n. Ha a programot komolyan optimaliz�ljuk, a nem meghat�rozott
szerkezetek
haszn�lat�nak eredm�nye teljesen kisz�m�thatatlann� v�lik. Ha l�tezik k�zenfekvo
�s k�nnyen megval�s�that� megold�sa egy probl�m�nak, azt ink�bb megval�s�t�s-
f�ggo-
nek minos�ti a szabv�ny �s nem defini�latlannak.
�rdemes jelentos idot �s erofesz�t�st sz�nnunk annak biztos�t�s�ra, hogy
programunk semmi
olyat ne haszn�ljon, ami a szabv�ny �ltal nem meghat�rozott helyzetekhez vezethet.
Sok
esetben k�l�n eszk�z�k seg�tik ezt a munk�t.
C. Technikai r�szletek 1117
C.3. Karakterk�szletek
E k�nyv p�ldaprogramjai az ASCII-nek (ANSI3.4-1968) nevezett, 7 bites, nemzetk�zi,
ISO
646-1983 karakterk�szlet amerikai angol v�ltozat�nak felhaszn�l�s�val k�sz�ltek.
Ez h�-
romf�le probl�m�t jelenthet azoknak, akik m�s karakterk�szletet haszn�l� C++-
k�rnyezetben �rj�k programjaikat:
1. Az ASCII tartalmaz olyan elv�laszt� karaktereket �s szimb�lumokat is . p�ld�ul
a ], a { vagy a ! ., melyek egyes karakterk�szletekben nem tal�lhat�k meg.
2. Azokhoz a karakterekhez, melyeknek nincs hagyom�nyos �br�zol�sa, valamilyen
jel�l�sm�dot kell v�lasztanunk (p�ld�ul az �jsorhoz, vagy a 17-es k�d�
karakterhez).
3. Az ASCII nem tartalmaz bizonyos karaktereket . p�ld�ul a z, a P vagy az a .,
melyeket az angolt�l elt�ro nyelvekben viszonylag gyakran haszn�lnak.
C.3.1. Korl�tozott karakterk�szletek
A k�l�nleges ASCII karakterek . [, ], {, }, | �s \ . az ISO szerint betunek
minos�tett karakterpoz
�ci�t foglalnak el. A legt�bb eur�pai ISO-646 karakterk�szletben ezeken a poz�ci�-

kon az angol �b�c�ben nem szereplo betuk szerepelnek. A d�n nemzeti


karakterk�szlet
p�ld�ul ezeket a poz�ci�kat az A, a, O, o, A, a mag�nhangz�k �br�zol�s�ra
haszn�lja �s
ezek n�lk�l nem t�l sok d�n sz�veg �rhat� le.
A trigr�f (h�rom jelbol �ll�) karakterek szolg�lnak arra, hogy tetszoleges nemzeti
karaktereket
�rhassunk le, .hordozhat�. form�ban, a legkisebb szabv�nyos karakterk�szlet
felhaszn
�l�s�val. Ez a forma hasznos lehet, ha programunkat t�nyleg �t kell vinn�nk m�s
rendszerre,
de a programok olvashat�s�g�t ronthatja. Term�szetesen a hossz� t�v� megold�s erre

a probl�m�ra a C++ programoz�k sz�m�ra az, hogy beszereznek egy olyan rendszert,
ahol
saj�t nemzeti karaktereiket �s a C++ jeleit is haszn�lhatj�k. Sajnos ez a megold�s
nem mindenhol
megval�s�that�, �s egy �j rendszer beszerz�se ideges�toen lass� megold�s lehet.
A C++ az al�bbi jel�l�sekkel teszi lehetov�, hogy a programoz�k hi�nyos
karakterk�szlettel
is tudjanak programot �rni:
1118 F�ggel�kek �s t�rgymutat�
Azok a programok melyek ezeket a kulcsszavakat �s digr�f karaktereket haszn�lj�k,
sokkal
olvashat�bbak, mint a vel�k egyen�rt�ku, de trigr�f karakterekkel k�sz�lt
programok. Ha
azonban az olyan karakterek, mint a { nem �rhetok el rendszer�nkben, k�nytelenek
vagyunk
a trigr�f karaktereket haszn�lni a karakterl�ncokban �s karakter-konstansokban a
hi-
�nyz� jelek helyett. A '{' helyett p�ld�ul a '??<' karakterkonstanst �rhatjuk.
Egyes programoz�k hagyom�nyos oper�tor-megfeleloik helyett sz�vesebben haszn�lj�k
az
and �s hasonl� kulcsszavakat.
C. Technikai r�szletek 1119
Kulcsszavak Digr�f Trigr�f
and && <% { ??= #
and_eq &= %> } ??( [
bitand & <: [ ??< {
bitor | :> ] ??/ \
compl ~ %: # ??) ]
not ! %:%: ## ??> }
or || ??' ^
or_eq |= ??! |
xor ^ ??- ~
xor_eq ^=
not_eq !=
C.3.2. Vez�rlokarakterek
A \ jel seg�ts�g�vel n�h�ny olyan karaktert �rhet�nk el, melyeknek szabv�nyos neve
is van:
Megjelen�si form�juk ellen�re ezek is egyetlen karaktert jelentenek.
Lehetos�g�nk van arra is, hogy egy karaktert egy-, k�t- vagy h�romjegyu, okt�lis
(a \ ut�n
nyolcas sz�mrendszerbeli), vagy hexadecim�lis (a \x ut�n 16-os sz�mrendszerbeli)
sz�mk
�nt adjunk meg. A hexadecim�lis jegyek sz�ma nem korl�tozott. Az okt�lis vagy
hexadecim
�lis sz�mjegyek sorozat�nak v�g�t az elso olyan karakter jelzi, amely nem
�rtelmezhet
o okt�lis, illetve hexadecim�lis jegyk�nt:
1120 F�ggel�kek �s t�rgymutat�
N�v ASCII jel�l�s C++ jel�l�s
�jsor/sort�r�s NL (LF) \n
v�zszintes tabul�tor HT \t
f�ggoleges tabul�tor VT \v
visszat�rl�s BS \b
kocsivissza CR \r
lapdob�s FF \f
csengo BEL \a
ford�tott perjel \ \\
k�rdojel ? \?
aposztr�f . \.
id�zojel . \.
okt�lis sz�m ooo \ooo
hexadecim�lis sz�m hhh \xhhh.
Okt�lis Hexadecim�lis Decim�lis ASCII
.\6. .\x6. 6 ACK
.\60. .\x30. 48 .0.
.\137. .\x05f. 95 ._.
Ez a jel�l�s lehetov� teszi, hogy az adott rendszer tetszoleges karakter�t le�rjuk
vagy karakterl
�ncokban felhaszn�ljuk azokat (l�sd �5.2.2). Viszont ha a karakterek jel�l�s�re
sz�mokat
haszn�lunk, programunk nem lesz �tviheto m�s karakterk�szletet haszn�l�
rendszerre.
Lehetos�g van arra is, hogy egy karakterliter�lban egyn�l t�bb karaktert adjunk
meg (p�ld
�ul .ab.). Ez a megold�s azonban elavult �s megval�s�t�s-f�ggo, �gy �rdemes
elker�ln�nk.
Ha egy karakterl�ncban okt�lis konstansokat haszn�lunk a karakterek jel�l�s�re,
�rdemes
mindig h�rom jegyet megadnunk. A jel�l�srendszer el�g k�nyelmetlen, �gy k�nnyen
elt�-
veszthetj�k, hogy a konstans ut�ni karakter sz�mjegy-e vagy sem. A hexadecim�lis
konstansok
eset�ben haszn�ljunk k�t sz�mjegyet:
char v1[] = "a\xah\129"; // 6 karakter: 'a' '\xa' 'h' '\12' '9' '\0'
char v2[] = "a\xah\127"; // 5 karakter: 'a' '\xa' 'h' '\127' '\0'
char v3[] = "a\xad\127"; // 4 karakter: 'a' '\xad' '\127' '\0'
char v4[] = "a\xad\0127"; // 5 karakter: 'a' '\xad' '\012' '7' '\0'
C.3.3. Nagy karakterk�szletek
C++ programot �rhatunk olyan karakterk�szletek felhaszn�l�s�val is, melyek sokkal
bovebbek,
mint a 127 karakterbol �ll� ASCII k�szlet. Ha az adott nyelvi v�ltozat t�mogatja a
nagyobb
karakterk�szleteket, az azonos�t�k, megjegyz�sek, karakter konstansok �s karakterl
�ncok is tartalmazhatnak olyan karaktereket, mint az a, a b vagy a G. Ahhoz
azonban, hogy
az �gy k�sz�lt program hordozhat� legyen, a ford�t�nak ezeket a k�l�nleges
karaktereket
valahogy olyan karakterekre kell .k�dolnia., melyek minden C++-v�ltozatban
el�rhetok.
Ezt az �talak�t�st a C++ . a k�nyvben is haszn�lt . alap karakterk�szlet�re a
rendszer �ltal
�ban m�g azelott v�grehajtja, hogy a ford�t� b�rmilyen m�s tev�kenys�gbe kezdene,
teh�t
a programok jelent�s�t ez nem �rinti.
A nagy karakterk�szletekrol a C++ �ltal t�mogatott kisebb karakterk�szletre val�
szabv�-
nyos �talak�t�st n�gy vagy nyolc jegybol �ll� hexadecim�lis sz�mok val�s�tj�k meg:

�ltal�nos karaktern�v:
\U X X X X X X X X
\u X X X X
Itt X egyetlen, hexadecim�lis sz�mjegyet jel�l (p�ld�ul \u1e2b). A r�videbb \uXXXX
jel�-
l�s egyen�rt�ku a \U0000XXXX-szel. Ha a megadott sz�mban a jegyek sz�ma nem n�gy
�s
nem is nyolc, a ford�t� hib�t jelez.
C. Technikai r�szletek 1121
A programoz� ezeket a karakterk�dol�sokat k�zvetlen�l haszn�lhatja, de val�j�ban
arra tal
�lt�k ki, hogy a programoz� �ltal l�that� karaktereket a megval�s�t�s belsoleg egy
kisebb
karakterk�szlettel t�rolhassa.
Ha a bov�tett karakterk�szletek azonos�t�kban val� haszn�lat�hoz egy adott
k�rnyezet
egyedi szolg�ltat�saira t�maszkodunk, programunk hordozhat�s�g�t erosen lerontjuk.
Ha
nem ismerj�k azt a term�szetes nyelvet, amelyet az azonos�t�k, illetve
megjegyz�sek megfogalmaz
�s�hoz haszn�ltak, a program nagyon nehezen olvashat� lesz, ez�rt a nemzetk�-
zileg haszn�lt programokban �rdemes megmaradnunk az angol nyelvn�l �s az ASCII
karakterk
�szletn�l.
C.3.4. Elojeles �s elojel n�lk�li karakterek
Megval�s�t�s-f�ggo az is, hogy az egyszeru char elojeles vagy elojel n�lk�li
t�pus-e, ami n�-
h�ny kellemetlen meglepet�st �s v�ratlan helyzeteket eredm�nyezhet:
char c = 255; // a 255 "csupa egyes", hexadecim�lis jel�l�ssel 0xFF
int i = c;
Mi lesz itt az i �rt�ke? Sajnos nem meghat�rozhat�. A v�lasz az �ltalam ismert
�sszes nyelvi
v�ltozatban att�l f�gg, hogy a char �rt�k bitmint�ja milyen �rt�ket eredm�nyez, ha
eg�szk
�nt �rtelmezz�k. Egy SGI Challenge g�pen a char elojel n�lk�li, �gy az eredm�ny
255. Egy
Sun SPARC vagy egy IBM PC g�pen viszont a char elojeles, aminek k�vetkezt�ben az i
�rt
�ke -1 lesz. Ilyenkor a ford�t�nak illik figyelmeztetnie, hogy a 255 liter�l
karakterr� alak�-
t�s�val a -1 �rt�ket kapjuk. A C++ nem ad �ltal�nos megold�st ezen probl�ma
kik�sz�b�-
l�s�re. Az egyik lehetos�g, hogy teljesen elker�lj�k az egyszeru char t�pus
haszn�lat�t �s
mindig valamelyik egyedi c�l� v�ltozatot haszn�ljuk. Sajnos a standard k�nyvt�r
bizonyos
f�ggv�nyei (p�ld�ul a strcmp()) egyszeru char t�pus� param�tert v�rnak (�20.4.1).
Egy char �rt�knek mindenk�ppen signed char vagy unsigned char t�pus�nak kell
lennie,
de mind a h�rom karaktert�pus k�l�nb�zo, �gy p�ld�ul a k�l�nb�zo char t�pusokra
hivatkoz
� mutat�k sem keverhetok �ssze:
void f(char c, signed char sc, unsigned char uc)
{
char* pc = &uc; // hiba: nincs mutat�-�talak�t�s
signed char* psc = pc; // hiba: nincs mutat�-�talak�t�s
unsigned char* puc = pc; // hiba: nincs mutat�-�talak�t�s
psc = puc; // hiba: nincs mutat�-�talak�t�s
}
1122 F�ggel�kek �s t�rgymutat�
A k�l�nb�zo char t�pusok v�ltoz�i szabadon �rt�k�l adhat�k egym�snak, de amikor
egy
elojeles char v�ltoz�ba t�l nagy �rt�ket akarunk �rni, az eredm�ny nem
meghat�rozhat�
lesz:
void f(char c, signed char sc, unsigned char uc)
{
c = 255; // megval�s�t�s-f�ggo, ha a sima karakterek elojelesek �s 8 bitesek
c = sc; // rendben
c = uc; // megval�s�t�s-f�ggo, ha a sima karakterek elojelesek �s 'uc' �rt�ke t�l
nagy
sc = uc; // megval�s�t�s-f�ggo, ha 'uc' �rt�ke t�l nagy
uc = sc; // rendben: �talak�t�s elojel n�lk�lire
sc = c; // megval�s�t�s-f�ggo, ha a sima karakterek elojel n�lk�liek �s 'c' �rt�ke
t�l nagy
uc = c; // rendben: �talak�t�s elojel n�lk�lire
}
Ha mindenhol az egyszeru char t�pust haszn�ljuk, ezek a probl�m�k nem
jelentkeznek.
C.4. Az eg�sz liter�lok t�pusa
Az eg�sz liter�lok t�pusa �ltal�ban alakjukt�l, �rt�k�ktol �s ut�tagjukt�l is
f�gg:
� Ha decim�lis �rt�krol van sz� �s a v�g�re nem �runk semmilyen ut�tagot, t�pusa
az elso olyan lesz a k�vetkezok k�z�l, amelyben �br�zolhat�: int, long int,
unsigned long int.
� Ha okt�lis vagy hexadecim�lis form�ban, ut�tag n�lk�l adjuk meg az �rt�ket,
annak t�pusa az elso olyan lesz a k�vetkezok k�z�l, amelyben �br�zolhat�: int,
unsigned int, long int, unsigned long int.
� Ha az u vagy az U ut�tagot haszn�ljuk, a t�pus a k�vetkezo lista elso olyan
t�pusa
lesz, amelyben az �rt�k �br�zolhat�: unsigned int, unsigned long int.
� Ha l vagy L ut�tagot adunk meg, az �rt�k t�pusa a k�vetkezo lista elso olyan t�-

pusa lesz, amelyben az �rt�k �br�zolhat�: long int, unsigned long int.
� Ha az ut�tag ul, lu, uL, Lu, Ul, lU, UL vagy LU, az �rt�k t�pusa unsigned long
int
lesz.
A 100000 p�ld�ul egy olyan g�pen, amelyen az int 32 bites, int t�pus� �rt�k, de
long int
egy olyan g�pen, ahol az int 16, a long int pedig 32 bites. Ugyan�gy a 0XA000
t�pusa int,
C. Technikai r�szletek 1123
ha az int 32 bites, de unsigned int, ha 16 bites. Ezeket a .megval�s�t�s-
f�ggos�geket. az
ut�tagok haszn�lat�val ker�lhetj�k el: a 100000L minden g�pen long int t�pus�,
a 0XA000U pedig minden g�pen unsigned int.
C.5. Konstans kifejez�sek
Az olyan helyeken, mint a t�mbhat�rok (�5.2.), a case c�mk�k (�6.3.2.) vagy a
felsorol� elemek
kezdo�rt�k-ad�i (�4.8.), a C++ konstans kifejez�seket haszn�l. A konstans
kifejez�s �rt
�ke egy sz�m vagy egy felsorol�si konstans. Ilyen kifejez�seket liter�lokb�l
(�4.3.1, �4.4.1,
�4.5.1), felsorol� elemekbol (�4.8) �s konstans kifejez�sekkel meghat�rozott const
�rt�kekb
ol �p�thet�nk fel. Sablonokban eg�sz t�pus� sablonparam�tereket is haszn�lhatunk
(�C.13.3). Lebegopontos liter�lok (�4.5.1) csak akkor haszn�lhat�k, ha azokat
meghat�rozott
m�don eg�sz t�pusra alak�tjuk. F�ggv�nyeket, oszt�lyp�ld�nyokat, mutat�kat �s
hivatkoz
�sokat csak a sizeof oper�tor (�6.2) param�terek�nt haszn�lhatunk.
A konstans kifejez�s egy olyan egyszeru kifejez�s, melyet a ford�t� ki tud
�rt�kelni, mielott
a programot �sszeszerkeszten�nk �s futtatn�nk.
C.6. Automatikus t�pus�talak�t�s
Az eg�sz �s a lebegopontos t�pusok (�4.1.1) szabadon keverhetok az �rt�kad�sokban
�s
a kifejez�sekben. Ha lehetos�g van r�, a ford�t� �gy alak�tja �t az �rt�keket,
hogy ne vesz�ts
�nk inform�ci�t. Sajnos az inform�ci�veszt�ssel j�r� �talak�t�sok is automatikusan
v�grehajt
�sra ker�lnek. Ebben a r�szben az �talak�t�si szab�lyokr�l, az �talak�t�sok
probl�m�ir�l
�s ezek k�vetkezm�nyeirol lesz sz�.
C.6.1. Kiterjeszt�sek
Azokat az automatikus �talak�t�sokat, melyek megorzik az �rt�keket, k�z�sen
kiterjeszt�-
seknek (promotion) nevezz�k. Mielott egy aritmetikai muveletet v�grehajtunk, egy
eg�sz t�-
pus� kiterjeszt�s az int t�pusn�l kisebb �rt�keket int �rt�kre alak�tja.
Figyelj�nk r�, hogy
1124 F�ggel�kek �s t�rgymutat�
ezek a kiterjeszt�sek nem long t�pusra alak�tanak (hacsak valamelyik operandus nem

wchar_t vagy olyan felsorol� �rt�k, amely m�r eleve nagyobb, mint egy int). Ez a
kiterjeszt
�s eredeti c�lj�t t�kr�zi a C nyelvben: az operandusokat .term�szetes. m�reture
akarjuk
alak�tani az aritmetikai muveletek elv�gz�se elott.
Az eg�sz t�pus� kiterjeszt�sek a k�vetkezok:
� A char, signed char, unsigned char, short int �s unsigned short int �rt�keket
int t�pus�ra alak�tja a rendszer, ha az int az adott t�pus �sszes �rt�k�t k�pes
�br
�zolni; ellenkezo esetben a c�lt�pus unsigned int lesz.
� A wchar_t t�pust (�4.3) �s a felsorol� t�pusokat (�4.8) a rendszer a k�vetkezo
lista
elso olyan t�pus�ra alak�tja, amely �br�zolni tudja a megfelelo t�pus �sszes �rt
�k�t: int, unsigned int, long, unsigned long.
� A bitmezok (�C.8.1) int t�pus�ak lesznek, ha az k�pes a bitmezo �sszes �rt�k�t
�br�zolni. Ha az int nem, de az unsigned int k�pes erre, akkor az ut�bbi lesz
a c�lt�pus. Ha ez sem val�s�that� meg, akkor nem k�vetkezik be eg�sz t�pus�
kiterjeszt�s.
� Logikai �rt�kek int t�pusra alak�t�sa: a false �rt�kbol 0, a true �rt�kbol 1
lesz.
A kiterjeszt�sek a szok�sos aritmetikai �talak�t�sok r�sz�t k�pezik. (�C.6.3)
C.6.2. �talak�t�sok
Az alapt�pusok sz�mos m�don alak�that�k �t: v�lem�nyem szerint t�l sok is az
enged�lyezett
�talak�t�s:
void f(double d)
{
char c = d; // vigy�zat: k�tszeres pontoss�g� lebegopontos �rt�k �talak�t�sa
karakterre
}
Amikor programot �runk, mindig figyeln�nk kell arra, hogy elker�lj�k a nem
meghat�rozott
szolg�ltat�sokat �s azokat az �talak�t�sokat, melyek .sz� n�lk�l. t�ntetnek el
inform�ci�kat.
A ford�t�k a legt�bb vesz�lyes �talak�t�sra figyelmeztethetnek �s szerencs�re
�ltal�ban meg
is teszik.
C. Technikai r�szletek 1125
C.6.2.1. Eg�sz �talak�t�sok
Egy eg�sz �rt�k b�rmely m�s eg�sz t�pusra �talak�that�, de a felsorol� �rt�keket
is eg�sz t�-
pusokra alak�thatjuk.
Ha a c�lt�pus elojel n�lk�li, az eredm�ny egyszeruen annyi bit lesz a forr�sb�l,
amennyi
a c�lt�pusban elf�r. (Ha kell, a magas helyi�rt�k�ku biteket a rendszer eldobja.)
Pontosabban
fogalmazva, az eredm�ny a legkisebb olyan eg�sz, amelynek oszt�sa a 2 n-edik
hatv�-
ny�val azonos �rt�ket ad, mint a forr�s�rt�k hasonl� oszt�sa, ahol n az elojel
n�lk�li t�pus
�br�zol�s�hoz haszn�lt bitek sz�ma. P�ld�ul:
unsigned char uc = 1023; // bin�ris 1111111111: uc bin�ris 11111111 lesz; ami 255
Ha a c�lt�pus elojeles �s az �talak�tand� �rt�k �br�zolhat� vele, az �rt�k nem
v�ltozik meg.
Ha a c�lt�pus nem tudja �br�zolni az �rt�ket, az eredm�ny az adott nyelvi
v�ltozatt�l f�ggo
lesz:
signed char sc = 1023; // megval�s�t�s-f�ggo
A lehets�ges eredm�nyek: 127 �s -1 (�C.3.4).
A logikai �s felsorol� �rt�kek automatikusan a megfelelo eg�sz t�pusra alak�that�k
(�4.2,
�4.8).
C.6.2.2. Lebegopontos �talak�t�sok
Lebegopontos �rt�keket m�s lebegopontos t�pusokra alak�thatunk �t. Ha a
forr�s�rt�k pontosan
�br�zolhat� a c�lt�pusban, az eredm�ny az eredeti sz�m�rt�k lesz. Ha a forr�s�rt�k

a c�lt�pus k�t egym�st k�veto �br�zolhat� �rt�ke k�z�tt �ll, eredm�nyk�nt ezen k�t
�rt�k
valamelyik�t kapjuk. A t�bbi esetben az eredm�ny nem meghat�rozhat�:
float f = FLT_MAX; // a legnagyobb lebegopontos �rt�k
double d = f; // rendben: d == f
float f2 = d; // rendben: f2 == f
double d3 = DBL_MAX; // a legnagyobb double �rt�k
float f3 = d3; // nem meghat�rozott, ha FLT_MAX<DBL_MAX
1126 F�ggel�kek �s t�rgymutat�
C.6.2.3. Mutat�- �s hivatkoz�s-�talak�t�sok
Az objektumt�pusra hivatkoz� mutat�k mind void* (�5.6) t�pus�ra alak�that�k; a
lesz�rmazott
oszt�lyra hivatkoz� mutat�k �s hivatkoz�sok b�rmelyike �talak�that� egy el�rheto
�s
egy�rtelmu alaposzt�lyra hivatkoz� mutat�, illetve hivatkoz�s t�pus�ra (�12.2).
Fontos viszont,
hogy egy f�ggv�nyre vagy egy tagra hivatkoz� mutat� automatikusan nem alak�that
� void* t�pusra.
A 0 �rt�ku konstans kifejez�sek (�C.5) b�rmilyen mutat� �s tagra hivatkoz� mutat�
(�5.1.1)
t�pusra automatikusan �talak�that�k:
int* p =
! ! ! ! ! !
! ! ! ! ! ! !
! ! ! ! ! ! !
! ! !!!!!! !!!!! !!!!1;
Egy T* �rt�k automatikusan const T* t�pusra alak�that� (�5.4.1) �s ugyan�gy egy T&
�rt�k is
�talak�that� const T& t�pusra.
C.6.2.4. Tagra hivatkoz� mutat�k �talak�t�sa
A tagokra hivatkoz� mutat�k �s hivatkoz�sok �gy alak�that�k �t automatikusan,
ahogy
a �15.5.1 pontban le�rtuk.
C.6.2.5. Logikai �rt�kek �talak�t�sa
A mutat�k, eg�szek �s lebegopontos �rt�kek automatikusan bool t�pus�v� alak�that�k

(�4.2). A nem nulla �rt�kek eredm�nye true, a nulla eredm�nye false lesz:
void f(int* p, int i)
{
bool is_not_zero = p; // igaz, ha p!=0
bool b2 = i; // igaz, ha i!=0
}
C. Technikai r�szletek 1127
C.6.2.6. Lebegopontos.eg�sz �talak�t�sok
Amikor egy lebegopontos �rt�ket eg�ssz� alak�tunk, a t�rtr�sz elveszik, vagyis a
lebego-
pontosr�l eg�szre val� �talak�t�s csonkol�st eredm�nyez. Az int(1.6) �rt�ke
p�ld�ul 1 lesz.
Ha a csonkol�ssal keletkezo �rt�k sem �br�zolhat� a c�lt�pusban, az eredm�ny nem
meghat
�rozhat�nak minos�l:
int i = 2.7; // i �rt�ke 2 lesz
char b = 2000.7; // nem meghat�rozott 8 bites char t�pusra: a 2000 nem �br�zolhat�

// 8 bites karakterben
Az eg�szrol lebegopontosra val� �talak�t�s matematikailag annyira pontos,
amennyire
a hardver megengedi. Ha egy eg�sz �rt�k egy lebegopontos t�pus �rt�kek�nt nem
�br�zolhat
�, az eredm�ny nem lesz eg�szen pontos:
int i = float(1234567890);
Itt az i �rt�ke 1234567936 lesz az olyan g�peken, amely az int �s a float
�br�zol�s�ra is 32
bitet haszn�lnak.
Term�szetesen c�lszeru elker�lni az olyan automatikus �talak�t�sokat, ahol
inform�ci�t vesz
�thet�nk. A ford�t�k k�pesek �szlelni n�h�ny vesz�lyes �talak�t�st, p�ld�ul a
lebegopontosr
�l eg�szre vagy a long int t�pusr�l char t�pusra val�t, ennek ellen�re az
�ltal�nos, ford�-
t�si idoben t�rt�no ellenorz�s nem mindig kelloen megb�zhat�, ez�rt a
programoz�nak elo-
vigy�zatosnak kell lennie. Amennyiben az elovigy�zatoss�g nem elegendo, a
programoz�-
nak ellenorz�seket kell beiktatnia a hib�k elker�l�s�re:
class check_failed { };
char checked(int i)
{
char c = i; // figyelem: nem hordozhat� (�C.6.2.1)
if (i != c) throw check_failed();
return c;
}
void my_code(int i)
{
char c = checked(i);
// ...
}
Ha �gy szeretn�nk csonkol�st v�gezni, hogy a program m�s rendszerre is v�ltoztat�s
n�lk
�l �tviheto legyen, vegy�k figyelembe a numeric_limits-ben (�22.2) megadottakat.
1128 F�ggel�kek �s t�rgymutat�
C.6.3. Szok�sos aritmetikai �talak�t�sok
Ezek az �talak�t�sok akkor k�vetkeznek be, ha egy k�toperandus� (bin�ris) muvelet
k�t
operandus�t k�z�s t�pus�ra kell alak�tani. Ez a k�z�s t�pus hat�rozza meg az
eredm�ny t�-
pus�t is.
1. Ha az egyik operandus long double t�pus�, a rendszer a m�sikat is long double
t�pus�v� alak�tja.
. Ha egyik sem long double, de valamelyik double, a m�sik is double t�pus�v�
alakul.
. Ha egyik sem double, de valamelyik float, a m�sik is float �rt�kre lesz �talak
�tva.
. Ha a fentiek egyike sem teljes�l, a rendszer mindk�t operandusra eg�sz
kiterjeszt
�st (�C.6.1) alkalmaz.
2. Ezut�n, ha valamelyik operandus unsigned long, akkor a m�sik is unsigned
long lesz.
. Ha a fenti nem teljes�l, de az egyik operandus long int, a m�sik pedig
unsigned int, �s a long int t�pus k�pes �br�zolni az �sszes unsigned int �rt
�ket, akkor az unsigned int �rt�ket a ford�t� long int t�pus�ra alak�tja. Ha
a long int nem el�g nagy, mindk�t �rt�ket unsigned long int t�pusra kell alak
�tani.
. Ha a fenti nem teljes�l, de valamelyik operandus long, a m�sik is long t�pus
�ra alakul.
. Ha valamelyik operandus unsigned, a m�sik is unsigned �rt�kre alakul.
. Ha a fentiek egyike sem teljes�l, mindk�t �rt�k int lesz.
C.7. T�bbdimenzi�s t�mb�k
Nem ritka, hogy vektorok vektor�ra van sz�ks�g�nk, sot vektorok vektorainak
vektor�ra.
A k�rd�s az, hogy a C++-ban hogyan �br�zolhatjuk ezeket a t�bbdimenzi�s t�mb�ket.
Ebben
a pontban elosz�r megmutatjuk, hogyan haszn�ljuk a standard k�nyvt�r vector oszt�-

ly�t erre a c�lra, majd megvizsg�ljuk, hogyan kezelhetok a t�bbdimenzi�s t�mb�k a


C-ben
�s a C++-ban akkor, ha csak a be�p�tett lehetos�gek �llnak rendelkez�s�nkre.
C. Technikai r�szletek 1129
C.7.1. Vektorok
A szabv�nyos vector (�16.3) egy nagyon �ltal�nos megold�st k�n�l:
vector< vector<int> > m(3, vector<int>(5));
Ezzel az utas�t�ssal egy 3 olyan vektort tartalmaz� vektort hozunk l�tre, melyek
mindegyike
5 darab eg�sz �rt�k t�rol�s�ra k�pes. Mind a 15 eg�sz elem a 0 alap�rtelmezett
�rt�ket
kapja, melyet a k�vetkezo m�don m�dos�thatunk:
void init_m()
{
for (int i = 0; i<m.size(); i++) {
for (int j = 0; j<m[i].size(); j++) m[i][j] = 10*i+j;
}
}
Grafikusan ezt �gy �br�zolhatjuk:
A vector objektumot egy, az elemekre hivatkoz� mutat�val �s az elemek sz�m�val
�br�zoltuk.
Az elemeket �ltal�ban egy szok�sos t�mbben t�roljuk. Szeml�ltet�sk�ppen mindegyik
eg�sz elembe a koordin�t�inak megfelelo �rt�ket �rtuk.
Az egyes elemeket k�tszeres indexel�ssel �rhetj�k el. Az m[i][j] kifejez�s p�ld�ul
az i-edik
vektor j-edik elem�t v�lasztja ki. Az m elemeit a k�vetkezok�ppen �rathatjuk ki:
1130 F�ggel�kek �s t�rgymutat�
00 01
3
5
5
5
02 03 04
10 11 12 13 14
20 21 22 23 24
m:
m[0]:
m[1]:
m[2]:
void print_m()
{
for (int i = 0; i<m.size(); i++) {
for (int j = 0; j<m[i].size(); j++) cout << m[i][j] << '\t';
cout << '\n';
}
}
Ennek eredm�nye a k�vetkezo lesz:
01 2 3 4
10 11 12 13 14
20 21 22 23 24
Figyelj�k meg, hogy az m vektorok vektora, nem egyszeru t�bbdimenzi�s t�mb, ez�rt
a gyakorlatban
lehetos�g�nk van arra, hogy egyes�vel m�dos�tsuk a belso vektorok m�ret�t:
void reshape_m(int ns)
{
for (int i = 0; i<m.size(); i++) m[i].resize(ns);
}
A vector< vector<int> > szerkezetben szereplo vector<int> vektorok m�ret�nek nem
felt�tlen
�l kell azonosnak lennie.
C.7.2. T�mb�k
A be�p�tett t�mb�k jelentik a C++-ban a legfobb hibaforr�st, k�l�n�sen ha
t�bbdimenzi�s
t�mb�k k�sz�t�s�re haszn�ljuk fel azokat. Kezdok sz�m�ra ezek okozz�k a legt�bb
kevered
�st is, ez�rt amikor lehet, haszn�ljuk helyett�k a vector, list, valarray, string
stb. oszt�lyokat.
A t�bbdimenzi�s t�mb�ket t�mb�k t�mbjek�nt �br�zolhatjuk. Egy 3x5-�s m�retu t�mb�t

az al�bbi m�don vezethet�nk be:


int ma[3][5]; // 3 t�mb, mindegyikben 5 int elem
C. Technikai r�szletek 1131
Az ma adatszerkezetet a k�vetkezok�ppen t�lthetj�k fel:
void init_ma()
{
for (int i = 0; i<3; i++) {
for (int j = 0; j<5; j++) ma[i][j] = 10*i+j;
}
}
�br�val:
Az ma t�mb egyszeruen 15 eg�sz �rt�ket t�rol, melyeket �gy �r�nk el, mintha 3
darab 5 elem
u t�mbrol lenne sz�. Teh�t a mem�ri�ban nincs olyan objektum, amely mag�t az ma
m�trixot
jelenti, csak az �n�ll� elemeket t�roljuk. A 3 �s 5 dimenzi��rt�kek csak a
forr�sban jelennek
meg. Amikor ilyen programot �runk, nek�nk kell valahogy eml�kezn�nk az �rt�kekre.
Az ma t�mb�t p�ld�ul a k�vetkezo k�dr�szlet seg�ts�g�vel �rathatjuk ki:
void print_ma()
{
for (int i = 0; i<3; i++) {
for (int j = 0; j<5; j++) cout << ma[i][j] << '\t';
cout << '\n';
}
}
Az a vesszos jel�l�s, amit n�h�ny nyelv a t�bbdimenzi�s t�mb�k kezel�s�hez
biztos�t,
a C++-ban nem haszn�lhat�, mert a vesszo (,) a muveletsorozat-oper�tor (�6.2.2).
Szerencs
�re a ford�t� a legt�bb hib�ra figyelmeztethet:
int bad[3,5]; // hiba: a vesszo nem megengedett konstans kifejez�sben
int good[3][5]; // 3 t�mb, mindegyikben 5 int elem
int ouch = good[1,4]; // hiba: int kezdo�rt�ke nem lehet int* t�pus� (good[1,4]
// jelent�se good[4], ami int* t�pus)
int nice = good[1][4]; // helyes
1132 F�ggel�kek �s t�rgymutat�
ma: 00 01 02 03 04 10 11 12 13 14 20 21 22 23 24
C.7.3. T�bbdimenzi�s t�mb�k �tad�sa
K�pzelj�nk el egy f�ggv�nyt, mellyel egy t�bbdimenzi�s t�mb�t akarunk feldolgozni.
Ha
a dimenzi�kat ford�t�skor ismerj�k, nincs probl�ma:
void print_m35(int m[3][5])
{
for (int i = 0; i<3; i++) {
for (int j = 0; j<5; j++) cout << m[i][j] << '\t';
cout << '\n';
}
}
A t�bbdimenzi�s t�mbk�nt megjeleno m�trixokat egyszeruen mutat�k�nt adjuk �t (nem
k�sz�l r�la m�solat, �5.3). Az elso dimenzi� �rdektelen az egyes elemek hely�nek
meghat
�roz�sakor, csak azt r�gz�ti, hogy az adott t�pusb�l (eset�nkben az int[5]-bol)
h�ny darab
�ll egym�s ut�n (eset�nkben 3). P�ld�ul, n�zz�k meg az ma elobbi �br�zol�s�t.
Megfigyelhetj
�k, hogy ha csak annyit tudunk, hogy a m�sodik dimenzi� 5, akkor is b�rmely ma[i]
[5]
elem hely�t meg tudjuk �llap�tani. Ez�rt az elso dimenzi�t �tadhatjuk k�l�n
param�terk�nt:
void print_mi5(int m[][5], int dim1)
{
for (int i = 0; i<dim1; i++) {
for (int j = 0; j<5; j++) cout << m[i][j] << '\t';
cout << '\n';
}
}
A probl�m�s eset az, ha mindk�t dimenzi�t param�terk�nt akarjuk �tadni. A
.nyilv�nval�
megold�s. nem muk�dik:
void print_mij(int m[][], int dim1, int dim2) // nem �gy viselkedik,
// ahogy legt�bben gondoln�nk
{
for (int i = 0; i<dim1; i++) {
for (int j = 0; j<dim2; j++) cout << m[i][j] << '\t'; // meglepet�s!
cout << '\n';
}
}
C. Technikai r�szletek 1133
Elosz�r is, az m[][] deklar�ci� hib�s, mert egy t�bbdimenzi�s t�mb eset�ben a
m�sodik dimenzi
�t ismern�nk kell ahhoz, hogy az elemek hely�t meg tudjuk hat�rozni. M�sr�szt, az
m[i][j] kifejez�st (teljesen szab�lyosan) *(*(m+i)+j)-k�nt �rtelmezi a ford�t�,
ami �ltal�ban
nem azt jelenti, amit a programoz� ki akart vele fejezni. A helyes megold�s a
k�vetkezo:
void print_mij(int* m, int dim1, int dim2)
{
for (int i = 0; i<dim1; i++) {
for (int j = 0; j<dim2; j++) cout << m[i*dim2+j] << '\t'; // zavaros
cout << '\n';
}
}
A print_mij() f�ggv�nyben az elemek el�r�s�hez haszn�lt kifejez�s egyen�rt�ku
azzal, amit
a ford�t� �ll�t elo, amikor ismeri az utols� dimenzi�t.
Ennek a f�ggv�nynek a megh�v�s�hoz a m�trixot egyszeru mutat�k�nt adjuk �t:
int main()
{
int v[3][5] = { {0,1,2,3,4}, {10,11,12,13,14}, {20,21,22,23,24} };
print_m35(v);
print_mi5(v,3);
print_mij(&v[0][0],3,5);
}
Figyelj�k meg az utols� sorban a &v[0][0] kifejez�s haszn�lat�t. A v[0] szint�n
megfelelne,
mert az elobbivel teljesen egyen�rt�ku, a v viszont t�pushib�t okozna. Az ilyen
.cs�nya. �s
k�r�lm�nyes programr�szleteket jobb elrejteni. Ha k�zvetlen�l t�bbdimenzi�s
t�mb�kkel
kell foglalkoznunk, pr�b�ljuk k�l�nv�lasztani a vele foglalkoz�
programr�szleteket. Ezzel
leegyszerus�thetj�k a k�vetkezo programoz� dolg�t, akinek majd a programhoz hozz�
kell
ny�lnia. Ha k�l�n megadunk egy t�bbdimenzi�s t�mb t�pust �s benne egy megfelelo
indexel
o oper�tort, a legt�bb felhaszn�l�t megk�m�lhetj�k att�l, hogy az adatok fizikai
elrendez
�s�vel kelljen foglalkoznia (�22.4.6).
A szabv�nyos vector (�16.3) oszt�lyban ezek a probl�m�k m�r nem jelentkeznek.
1134 F�ggel�kek �s t�rgymutat�
C.8. Ha kev�s a mem�ria.
Ha komolyabb alkalmaz�st k�sz�t�nk, gyakran t�bb mem�ri�ra lenne sz�ks�g�nk, mint
amennyi rendelkez�s�nkre �ll. K�t m�dszer van arra, hogy t�bb helyet pr�selj�nk
ki:
1. Egyetlen b�jtban t�bb kisebb objektumot t�rolhatunk.
2. Ugyanazt a ter�letet k�l�nb�zo idopontokban k�l�nb�zo objektumok t�rol�s�-
ra haszn�lhatjuk.
Az elobbit a mezok, az ut�bbit az uni�k seg�ts�g�vel val�s�thatjuk meg. Ezekrol az
eszk�-
z�krol a kor�bbiakban m�r volt sz�. A mezoket �s az uni�kat szinte csak
optimaliz�l�shoz
haszn�ljuk, ami gyakran a mem�ria adott rendszerbeli fel�p�t�s�n alapul, �gy a
program
nem lesz m�s rendszerre �tviheto. Teh�t �rdemes k�tszer is meggondolnunk, mielott
ezeket
a szerkezeteket haszn�ljuk. Gyakran jobb megold�st jelent, ha az adatokat
.m�sk�pp.
kezelj�k, p�ld�ul t�bb dinamikusan lefoglalt ter�letet (�6.2.6) �s kevesebb elore
lefoglalt
(statikus) mem�ri�t haszn�lunk.
C.8.1. Mezok
Gyakran rettento pazarl�snak tunik, hogy egy bin�ris v�ltoz�t . p�ld�ul egy ki/be
kapcsol
�t . egy teljes b�jt (char vagy bool) felhaszn�l�s�val �br�zolunk, de ez a
legkisebb egys�g,
amelyet a mem�ri�ban k�zvetlen�l megc�mezhet�nk a C++ seg�ts�g�vel (�5.1).
Viszont, ha
a struct t�pusban mezoket haszn�lunk, lehetos�g van arra, hogy t�bb ilyen kis
v�ltoz�t
egyetlen csomagba fogjunk �ssze. Egy tag akkor v�lik mezov�, ha ut�na megadjuk az
�ltala
elfoglalt bitek sz�m�t. N�vtelen mezok is megengedettek. Ezek a C++ szempontj�b�l
nincsenek
hat�ssal az elnevezett mezok jelent�s�re, seg�ts�g�kkel azonban pontosan
le�rhatunk
bizonyos g�pf�ggo adatokat:
struct PPN { // R6000 fizikai lapsz�m
unsigned int PFN : 22; // lapkeret-sz�m
int : 3; // nem haszn�lt
unsigned int CCA : 3; // Cache Coherency Algorithm
bool nonreachable : 1;
bool dirty : 1;
bool valid : 1;
bool global : 1;
};
Ezzel a p�ld�val a mezok m�sik legfontosabb felhaszn�l�si ter�let�t is bemutattuk:
valamilyen
k�lso (nem C++) szerkezet r�szeit is pontosan elnevezhetj�k vel�k. A mezok eg�sz
vagy felsorol� t�pus�ak (�4.1.1). Egy mezonek nem lehet lek�rdezni a c�m�t,
viszont ettol
C. Technikai r�szletek 1135
eltekintve teljesen �tlagos v�ltoz�k�nt kezelhetj�k. Figyelj�k meg, hogy egy bool
t�pus� �rt
�ket itt t�nyleg egy bittel �br�zolhatunk. Egy oper�ci�s rendszer magj�ban vagy
egy hibakeres
oben a PPN t�pus a k�vetkezok�ppen haszn�lhat�:
void part_of_VM_system(PPN* p)
{
// ...
if (p->dirty) { // a tartalom megv�ltozott
// lemezre m�sol�s
p->dirty = 0;
}
// ...
}
Meglepo m�don, ha t�bb v�ltoz�t mezok seg�ts�g�vel egyetlen b�jtba sur�t�nk �ssze,
akkor
sem felt�tlen�l takar�tunk meg mem�ri�t. Az adatter�let cs�kken, de az ilyen
adatok kezel�s�-
hez sz�ks�ges k�d a legt�bb sz�m�t�g�pen jelentosen nagyobb. A programok m�rete
jelento-
sen cs�kkentheto azzal, hogy a bitmezokk�nt �br�zolt bin�ris adatokat char t�pusra
alak�tjuk,
r�ad�sul egy char vagy int el�r�se �ltal�ban sokkal gyorsabb, mint a bitmezok
el�r�se. A mez
ok csak egy k�nyelmes r�vid�t�st adnak a bitenk�nti logikai muveletekhez (�6.2.4),
hogy egy
g�pi sz� r�szeibe egym�st�l f�ggetlen�l tudjunk adatokat �rni, illetve onnan
kiolvasni.
C.8.2. Uni�k
Az uni� olyan struct, melyben minden tag ugyanarra a c�mre ker�l a mem�ri�ban, �gy
az
uni� csak annyi ter�letet foglal, mint a legnagyobb tagja. Term�szetesen az uni�
egyszerre
csak egy tagj�nak �rt�k�t tudja t�rolni. K�pzelj�nk el p�ld�ul egy szimb�lumt�bla-
bejegyz
�st, amely egy nevet �s egy �rt�ket t�rol:
enum Type { S, I };
struct Entry {
char* name;
Type t;
char* s; // s haszn�lata, ha t==S
int i; // i haszn�lata, ha t==I
};
void f(Entry* p)
{
if (p->t == S) cout << p->s;
// ...
}
1136 F�ggel�kek �s t�rgymutat�
Az s �s az i tagot sohasem fogjuk egyszerre haszn�lni, �gy feleslegesen pazaroltuk
a mem�-
ri�t. Ezen a probl�m�n k�nnyen seg�thet�nk a union adatszerkezet seg�ts�g�vel:
union Value {
char* s;
int i;
};
A rendszer nem tartja nyilv�n, hogy a union �ppen melyik �rt�ket t�rolja, teh�t
ezt tov�bbra
is a programoz�nak kell megtennie:
struct Entry {
char* name;
Type t;
Value v; // v.s haszn�lata, ha t==S; v.i haszn�lata, ha t==I
};
void f(Entry* p)
{
if (p->t == S) cout << p->v.s;
// ...
}
Sajnos a union bevezet�se arra k�nyszer�t minket, hogy az egyszeru s helyett a v.s
kifejez
�st haszn�ljuk. Ezt a probl�m�t a n�vtelen uni� seg�ts�g�vel ker�lhetj�k el, amely
egy
olyan uni�, amelynek nincs neve, �gy t�pust sem ad meg, csak azt biztos�tja, hogy
tagjai
ugyanarra a mem�riac�mre ker�ljenek:
struct Entry {
char* name;
Type t;
union {
char* s; // s haszn�lata, ha t==S
int i; // i haszn�lata, ha t==I
};
};
void f(Entry* p)
{
if (p->t == S) cout << p->s;
// ...
}
�gy az Entry szerkezetet haszn�l� programr�szleteken nem kell v�ltoztatnunk. A
union t�-
pus olyan felhaszn�l�sakor, amikor egy �rt�ket mindig abb�l a tagb�l olvasunk
vissza, amelyiken
kereszt�l �rtuk, csak optimaliz�l�st hajtunk v�gre. Az uni� ilyen jellegu
felhaszn�l�-
C. Technikai r�szletek 1137
s�t azonban nem mindig k�nnyu biztos�tani �s a helytelen haszn�lat nagyon
kellemetlen hib
�kat okozhat. A hib�k elker�l�se �rdek�ben az uni�t befoglalhatjuk egy olyan
egys�gbe,
amely biztos�tja, hogy az �rt�k t�pusa �s a hozz�f�r�s m�dja egym�snak megfelelo
lesz
(�10.6[20]). Az uni�t n�ha sz�nd�kosan helytelen�l haszn�ljuk, valamif�le
.t�pus�talak�t�s.
�rdek�ben. Ezt a lehetos�get �ltal�ban azok a programoz�k haszn�lj�k, akik az
explicit
t�pus�talak�t�st nem t�mogat� nyelven is �rnak programokat. Ott az ilyen
.csal�sra. t�nyleg
sz�ks�g van. Az al�bbi szerkezettel az int �s az int* t�pus k�z�tti �talak�t�st
pr�b�ljuk megval
�s�tani, egyszeru bitenk�nti egyen�rt�kus�g felt�telez�s�vel:
union Fudge {
int i;
int* p;
};
int* cheat(int i)
{
Fudge a;
a.i = i;
return a.p; // hib�s haszn�lat
}
Ez val�j�ban nem is igazi �talak�t�s. Bizonyos g�peken az int �s az int* nem
ugyanannyi helyet
foglal, m�s g�peken az eg�sz �rt�keknek nem lehet p�ratlan c�me. Teh�t az uni�
ilyen
felhaszn�l�sa nagyon vesz�lyes �s nem is viheto �t m�s rendszerre, r�ad�sul
ugyanerre
a feladatra van egy egyszerubb, biztons�gosabb �s .hordozhat�. megold�s: a
meghat�rozott
(explicit) t�pus�talak�t�s (�6.2.7).
Az uni�t idonk�nt sz�nd�kosan a t�pus�talak�t�s elker�l�s�re haszn�lj�k. P�ld�ul
sz�ks�-
g�nk lehet arra, hogy a Fudge seg�ts�g�vel meg�llap�tsuk, hogy a 0 mutat�t hogyan
�br�-
zolja a rendszer:
int main()
{
Fudge foo;
foo.p = 0;
cout << "A 0 mutat� eg�sz �rt�ke: " << foo.i << '\n';
}
C.8.3. Uni�k �s oszt�lyok
A bonyolultabb uni�k eset�ben gyakran elofordul, hogy egyes tagok j�val nagyobbak,
mint
a rendszeresen haszn�lt tagok. Mivel a union m�rete legal�bb akkora, mint a
legnagyobb
tagja, sok helyet elpazarolhatunk �gy. A pazarl�st �ltal�ban elker�lhetj�k, ha
uni� helyett
sz�rmaztatott oszt�lyokat haszn�lunk.
1138 F�ggel�kek �s t�rgymutat�
Egy konstruktorral, destruktorral �s m�sol� muvelettel rendelkezo oszt�ly nem
tartozhat
egy uni� tag t�pus�ba (�10.4.12), hiszen a ford�t� nem tudja, melyik tagot kell
t�r�lnie.
C.9. Mem�riakezel�s
A C++-ban a mem�ria kezel�s�re h�rom alapveto m�dszer �ll rendelkez�s�nkre:
Statikus mem�ria: Ebben az esetben az objektum sz�m�ra az �sszeszerkeszto
(linker) foglal helyet a program teljes fut�si idej�re. Statikus mem�ri�ban kapnak

helyet a glob�lis �s n�vt�r-v�ltoz�k, a static adattagok (�10.2.4) �s a f�ggv�-


nyekben szereplo static v�ltoz�k (�7.1.2). Azok az objektumok, melyek a statikus
mem�ri�ban kapnak helyet, egyszer j�nnek l�tre �s a program v�g�ig l�teznek.
C�m�k a program fut�sa k�zben nem v�ltozik meg. A statikus objektumok
a sz�lakat (osztott c�mu mem�riater�leteket p�rhuzamosan) haszn�l� programokban
probl�m�t jelenthetnek, mert a megfelelo el�r�shez z�rol�sokat kell alkalmaznunk.
Automatikus mem�ria: Ezen a ter�leten a f�ggv�nyparam�terek �s helyi v�ltoz�k
j�nnek l�tre. A f�ggv�ny vagy blokk minden egyes lefut�sakor saj�t p�ld�nyok
j�nnek l�tre az ilyen v�ltoz�kb�l. Ezt a t�pus� mem�ri�t automatikusan foglalja
le �s szabad�tja fel a rendszer, ez�rt kapta az automatikus mem�ria nevet.
Az automatikus mem�ri�ra gyakran hivatkozunk �gy, hogy az elemek .a veremben
helyezkednek el.. Ha felt�tlen�l hangs�lyozni akarjuk ezt a t�pus� helyfoglal
�st, a C++-ban az auto kulcssz�t haszn�lhatjuk.
Szabad t�r: Errol a ter�letrol a program b�rmikor k�zvetlen�l ig�nyelhet mem�ri�t
�s b�rmikor felszabad�thatja az itt lefoglalt ter�leteket (a new, illetve a delete

oper�tor seg�ts�g�vel). Amikor a programnak �jabb ter�letekre van sz�ks�ge


a szabad t�rb�l, a new oper�torral ig�nyelhet az oper�ci�s rendszertol. A szabad
t�rra gyakran hivatkozunk dinamikus mem�ria vagy kupac (heap) n�ven
is. A szabad t�r a program teljes �lettartama alatt csak nohet, mert az ilyen
ter�-
leteket a program befejezod�s�ig nem adjuk vissza az oper�ci�s rendszernek,
�gy m�s programok azokat nem haszn�lhatj�k.
A programoz� szemsz�g�bol az automatikus �s a statikus t�r egyszeruen,
biztons�gosan �s
automatikusan kezelheto. Az �rdekes k�rd�st a szabad t�r kezel�se jelenti. A new
seg�ts�-
g�vel k�nnyen foglalhatunk ter�leteket, de ha nincs k�vetkezetes strat�gi�nk a
mem�ria
felszabad�t�s�ra (a mem�ria visszaad�s�ra a szabad t�r kezeloj�nek), a mem�ria
elobbut
�bb elfogy, foleg ha programunk el�g sok�ig fut.
C. Technikai r�szletek 1139
A legegyszerubb m�dszer, ha automatikus objektumokat haszn�lunk a szabad t�rban
levo
objektumok kezel�s�hez. Ennek megfeleloen a t�rol�kat sokszor �gy val�s�tj�k meg,
hogy
a szabad t�rban levo elemekre mutat�kat �ll�tanak (�25.7). Az automatikus String-
ek
(�11.12) p�ld�ul a szabad t�rban levo karaktersorozatokat kezelik �s automatikusan
felszabad
�tj�k a ter�letet, amikor kiker�lnek a hat�k�rbol. Az �sszes szabv�nyos t�rol�
(�16.3, 17.
fejezet, 20. fejezet, �22.4) k�nyelmesen megval�s�that� ilyen form�ban.
C.9.1. Automatikus szem�tgyujt�s
Ha ez az egyszeru megold�s nem felel meg ig�nyeinknek, akkor haszn�lhatunk
valamilyen
mem�riakezelo rendszert, amely megkeresi az olyan objektumokat, melyekre m�r nincs
hivatkoz
�s, �s az ezek �ltal lefoglalt mem�riater�letet el�rhetov� teszi �j objektumok
sz�m�-
ra. Ezt a rendszert �ltal�ban automatikus szem�tgyujto algoritmusnak vagy
egyszeruen szem
�tgyujtonek (garbage collection) nevezz�k.
A szem�tgyujt�s alap�tlete az, hogy ha egy objektumra m�r sehonnan sem hivatkozunk

a programb�l, arra a k�sobbiekben sem fogunk, teh�t az �ltala lefoglalt


mem�riater�letet
biztons�gosan felszabad�thatjuk vagy odaadhatjuk m�s objektumoknak:
void f()
{
int* p = new int;
p = 0;
char* q = new char;
}
Itt a p=0 �rt�kad�s t�rli az egyetlen hivatkoz�st, ami a p �ltal eddig
meghat�rozott int objektumra
mutatott, �gy ezen int �rt�k ter�let�t odaadhatjuk egy �j objektumnak. A char t�-
pus� objektum teh�t m�r szerepelhet ugyanezen a mem�riater�leten, ami azt jelenti,
hogy
a q ugyanazt az �rt�ket kapja, mint eredetileg a p.
A szabv�ny nem k�veteli meg, hogy minden nyelvi v�ltozat tartalmazza a
szem�tgyujt�st, de
egyre gyakrabban haszn�lj�k az olyan ter�leteken, ahol a C++-ban a szabad t�r
egy�ni kezel
�se k�lts�gesebb, mint a szem�tgyujt�s. Amikor a k�t m�dszer k�lts�geit
�sszehasonl�tjuk, figyelembe
kell venn�nk a fut�si idot, a mem�ria-felhaszn�l�st, a megb�zhat�s�got, a
hordozhat
�s�got, a programoz�s p�nzbeli k�lts�geit �s a teljes�tm�ny megj�solhat�s�g�t is.
1140 F�ggel�kek �s t�rgymutat�
C.9.1.1. Rejtett mutat�k
Mikor nevezhet�nk egy objektumot hivatkoz�s n�lk�linek? Vizsg�ljuk meg p�ld�ul az
al�bbi
programr�szletet:
void f()
{
int* p = new int;
long i1 = reinterpret_cast<long>(p)&0xFFFF0000;
long i2 = reinterpret_cast<long>(p)&0x0000FFFF;
p = 0;
// #1 pont: nem l�tezik az int-re hivatkoz� mutat�
p = reinterpret_cast<int*>(i1|i2);
// itt az int-re ism�t l�tezik mutat�
}
Ha egy programban bizonyos mutat�kat idonk�nt nem mutat�k�nt t�rolunk, akkor
.rejtett
mutat�kr�l. besz�l�nk. Eset�nkben azt a mutat�t, amit eredetileg a p v�ltoz�
t�rolt, elrejtett
�k az i1 �s az i2 eg�szekben. A szem�tgyujto rendszertol azonban nem v�rhatjuk el,
hogy
kezelni tudja a rejtett mutat�kat, teh�t amikor a program a #1 ponthoz �r, a
szem�tgyujto
felszabad�tja az int �rt�k sz�m�ra lefoglalt ter�letet. Val�j�ban az ilyen
programok helyes
muk�d�s�t m�g az olyan rendszerekben sem garant�lhatjuk, ahol nem haszn�lunk
szem�tgy
ujto algoritmust, mert a reinterpret_cast haszn�lata eg�szek �s mutat�k k�z�tti
t�pus�talak�t�sra m�g a legjobb esetben is megval�s�t�s-f�ggo.
Az olyan union objektumok, melyek lehetov� teszik mutat�k �s nem mutat�k t�rol�s�t
is,
k�l�n probl�m�t jelentenek a szem�tgyujtok sz�m�ra. �ltal�ban nincs m�d annak
meg�llap
�t�s�ra, hogy egy ilyen szerkezet �ppen mutat�t t�rol-e:
union U { // uni� mutat� �s nem mutat� taggal
int* p;
int i;
};
void f(U u, U u2, U u3)
{
u.p = new int;
u2.i = 999999;
u.i = 8;
// ...
}
C. Technikai r�szletek 1141
A biztons�gos felt�telez�s az, hogy minden �rt�k mutat�, ami egy ilyen union
objektumban
megjelenik. Egy kelloen okos szem�tgyujto enn�l kicsit jobb megold�st is adhat.
P�ld
�ul �szreveheti, hogy (az adott rendszerben) int �rt�kek nem helyezhetok el
p�ratlan mem
�riac�men �s semmilyen objektumot nem hozhatunk l�tre olyan kicsi mem�riac�men,
mint a 8. Ezek figyelembev�tel�vel a szem�tgyujto algoritmusnak nem kell
felt�teleznie,
hogy a 999999 vagy a 8 c�men �rtelmes objektum szerepel, amit az f() esetleg
felhaszn�l.
C.9.1.2. A delete
Ha rendszer�nk automatikus szem�tgyujt�st haszn�l, a mem�ria felszabad�t�s�hoz
nincs
sz�ks�g a delete �s a delete[] oper�torokra, teh�t a szem�tgyujt�st haszn�l�
programoz�knak
nem kell ezeket haszn�lniuk. A mem�ria felszabad�t�s�n k�v�l azonban a delete �s
a delete[] destruktorok megh�v�s�ra is haszn�latos.
Ha szem�tgyujto algoritmust haszn�lunk, a
delete p;
utas�t�s megh�vja a p �ltal mutatott objektum destruktor�t (ha van ilyen), viszont
a mem�-
ria �jrafelhaszn�l�s�t elhalaszthatjuk addig, am�g a mem�riater�letre sz�ks�g
lesz. Ha sok
objektumot egyszerre szabad�tunk fel, cs�kkenthetj�k a mem�ria felt�redezod�s�nek
m�rt
�k�t (�C.9.1.4) Ez a megold�s �rtalmatlann� teszi azt az egy�bk�nt rendk�v�l
vesz�lyes hib
�t is, hogy ugyanazt az objektumot k�tszer semmis�tj�k meg, amikor a destruktor
csak
a mem�ria t�rl�s�t v�gzi.
Az olyan objektumok el�r�se, melyeket m�r t�r�lt�nk, szok�s szerint nem
meghat�rozhat�
eredm�nnyel j�r.
C.9.1.3. Destruktorok
Amikor a szem�tgyujto algoritmus egy objektumot meg akar semmis�teni, k�t
lehetos�g k�-
z�l v�laszthat:
1. Megh�vja az adott objektum destruktor�t (ha az l�tezik).
2. Felt�telezi, hogy nyers mem�riater�letrol van sz� �s nem h�v meg destruktort.
Alap�rtelmez�s szerint a szem�tgyujto algoritmus a m�sodik lehetos�get haszn�lja,
mert
a new seg�ts�g�vel l�trehozott, de a delete oper�torral nem t�r�lt objektumokat
nem kell
megsemmis�ten�nk. Teh�t a szem�tgyujto algoritmust bizonyos szempontb�l v�gtelen
m�-
1142 F�ggel�kek �s t�rgymutat�
retu mem�ria ut�nz�s�nak tekinthetj�k. Lehetos�g van arra is, hogy a szem�tgyujto
algoritmust
�gy val�s�tsuk meg, hogy a destruktor az algoritmus �ltal .bejegyzett.
objektumokra
fusson le. A .bejegyz�sre. azonban nincs szabv�nyos megold�s. Figyelj�nk arra,
hogy az
objektumokat mindig olyan sorrendben kell megsemmis�ten�nk, hogy az egyik objektum

destruktora soha ne hivatkozzon olyan objektumra, amelyet kor�bban m�r t�r�lt�nk.


A programoz� seg�ts�ge n�lk�l ilyen sorrendet a szem�tgyujto algoritmusok nagyon
ritk�n
k�pesek betartani.
C.9.1.4. A mem�ria felt�redezod�se
Ha sok k�l�nb�zo m�retu objektumot hozunk l�tre, illetve semmis�t�nk meg, a
mem�ria
.felt�redezodik.. Ez azt jelenti, hogy a mem�ri�t olyan kis darabokban haszn�ljuk,
amelyek
t�l kicsik ahhoz, hogy hat�konyan kezelhetok legyenek. Ennek oka az, hogy a
mem�riakezel
o rendszerek nem mindig tal�lnak pontosan olyan m�retu mem�riadarabot, amilyenre
egy adott objektumnak �ppen sz�ks�ge van. Ha a kellet�n�l nagyobb ter�letet
haszn�lunk,
a megmarad� mem�riat�red�k m�g kisebb lesz. Ha egy ilyen egyszeru mem�riakezelovel

programunk el�g sok�ig fut, nem ritka, hogy ak�r a rendelkez�sre �ll� mem�ria
fel�t olyan
mem�riat�red�kek t�ltik ki, melyek t�l kis m�retuek ahhoz, hogy haszn�lhat�k
legyenek.
A mem�ria-felt�redezod�s probl�m�j�nak kezel�s�re sz�mos m�dszert dolgoztak ki. A
legegyszer
ubb megold�s, hogy csak nagyobb mem�riadarabok lefoglal�s�t tessz�k lehetov�
�s minden ilyen darabban azonos m�retu objektumokat t�rolunk (�15.3, �19.4.2).
Mivel
a legt�bb helyfoglal�st kis m�retu objektumok ig�nylik (p�ld�ul a t�rol�k elemei),
ez
a m�dszer nagyon hat�kony lehet. Az elj�r�st ak�r egy �n�ll� mem�riafoglal� is
automatikusan
megval�s�thatja. A mem�riat�redezod�st mindk�t esetben tov�bb cs�kkenthetj�k,
ha az �sszes nagyobb mem�riadarabot azonos m�reture (p�ld�ul a lapm�retre)
�ll�tjuk, �gy
ezek lefoglal�sa sem okoz t�redezod�st.
A szem�tgyujto rendszerek k�t fo t�pusba tartoznak:
1. A m�sol� szem�tgyujtok az objektumokat �thelyezik a mem�ri�ban, ezzel egyes
�tik a felt�redezett mem�ria darabjait.
2. A konzervat�v szem�tgyujtok �gy pr�b�lnak helyet foglalni az objektumoknak,
hogy a mem�riat�redezod�s a leheto legkisebb legyen.
A C++ szemsz�g�bol a konzervat�v szem�tgyujtok a gyakoribbak, mert rendk�v�l neh�z

(sot a komoly programokban val�sz�nuleg lehetetlen) az objektumokat �gy


�thelyezni,
hogy minden mutat�t helyesen �t�ll�tsunk. A konzervat�v szem�tgyujtok azt is
lehetov� teszik,
hogy a C++ programr�szletek egy�ttmuk�djenek ak�r a C nyelven k�sz�lt program-
C. Technikai r�szletek 1143
r�szletekkel is. A m�sol� szem�tgyujtoket t�bbnyire csak olyan nyelvekben
val�s�tj�k meg,
melyek az objektumokat mindig k�zvetve . mutat�kon vagy hivatkoz�sokon kereszt
�l . �rik el. (Ilyen nyelv p�ld�ul a Lisp vagy a Smalltalk.) Az olyan nagyobb
programok
eset�ben, melyekn�l a mem�riafoglal� �s a lapkezelo rendszer k�z�tti
kapcsolattart�s, illetve
a m�sol�s mennyis�ge jelentos, az �jabb konzervat�v szem�tgyujtok legal�bb olyan
hat
�konynak tunnek, mint a m�sol� szem�tgyujtok. Kisebb programok eset�ben gyakran az

a legjobb megold�s, ha egy�ltal�n nem haszn�lunk szem�tgyujtot . foleg a C++


eset�ben,
ahol az objektumok t�bbs�g�t term�szetszeruleg automatikusan kezelhetj�k.
C.10. N�vterek
Ebben a pontban olyan apr�s�gokat vizsg�lunk meg a n�vterekkel kapcsolatban,
melyek
csup�n technikai r�szleteknek tunnek, de a vit�k sor�n, illetve a komoly
programokban
gyakran felsz�nre ker�lnek.
C.10.1. K�nyelem �s biztons�g
A using deklar�ci�k egy �j nevet vezetnek be a helyi hat�k�rbe, a using utas�t�sok
(direkt
�v�k) azonban nem �gy muk�dnek, csak el�rhetov� teszik a megadott hat�k�rben
szerepl
o neveket:
namespace X {
int i, j, k;
}
int k;
void f1()
{
int i = 0;
using namespace X; // az X-beli nevek el�rhetov� t�tele
i++; // helyi i
j++; // X::j
k++; // hiba: X::k vagy glob�lis k ?
::k++; // a glob�lis k
X::k++; // az X-beli k
}
1144 F�ggel�kek �s t�rgymutat�
void f2()
{
int i = 0;
using X::i; // hiba: i k�tszer deklar�lt f2()-ben
using X::j;
using X::k; // elfedi a glob�lis k nevet
i++;
j++; // X::j
k++; // X::k
}
A helyileg (�n�ll� deklar�ci�val vagy using deklar�ci�val) bevezetett nevek
elrejtik az
ugyanilyen n�ven szereplo nem helyi neveket; a ford�t� pedig minden hib�s
t�lterhel�st
a deklar�ci� hely�n jelez.
Figyelj�k meg az f1() f�ggv�nyben a k++ utas�t�s k�t�rtelmus�g�t. A glob�lis nevek
nem
�lveznek elsobbs�get azokkal a nevekkel szemben, melyek glob�lis hat�k�rben
el�rheto
n�vterekbol sz�rmaznak. Ez jelentos m�rt�kben cs�kkenti a v�letlen n�vkevered�sek
lehet
os�g�t �s biztos�tja, hogy ne a glob�lis n�vt�r .beszennyez�s�vel. jussunk
elony�kh�z.
Amikor using utas�t�sok seg�ts�g�vel olyan k�nyvt�rakat tesz�nk el�rhetov�, melyek
sok
nevet vezetnek be, komoly k�nny�t�st jelent, hogy a felhaszn�latlan nevek �tk�z�se
nem
okoz hib�t.
A glob�lis n�vt�r ugyanolyan, mint b�rmelyik m�sik, �tlagos n�vt�r. A glob�lis
n�vt�r egyetlen
k�l�nlegess�ge, hogy egy r� vonatkoz� explicit minos�t�s eset�ben nem kell
ki�rnunk
a nev�t. Teh�t a ::k jel�l�s azt jelenti, hogy .keresd meg a k nevet a glob�lis
n�vt�rben vagy
a glob�lis n�vt�rhez using utas�t�ssal csatolt n�vterekben., m�g az X::k
jelent�se: .keresd
meg a k nevet az X n�vt�rben, vagy a benne using utas�t�ssal megeml�tett
n�vterekben.
(�8.2.8).
Rem�lj�k, hogy a n�vtereket haszn�l� �j programokban radik�lisan cs�kkenni fog a
glob�-
lis nevek sz�ma a hagyom�nyos C �s C++ programokhoz viszony�tva. A n�vterek
szab�lyait
kifejezetten �gy tal�lt�k ki, hogy ne adjanak elony�ket a glob�lis nevek .lusta.
felhaszn�-
l�inak azokkal szemben, akik vigy�znak r�, hogy a glob�lis hat�k�rt ne
.szennyezz�k
�ssze..
C. Technikai r�szletek 1145
C.10.2. N�vterek egym�sba �gyaz�sa
A n�vterek egyik nyilv�nval� felhaszn�l�si ter�lete az, hogy deklar�ci�k �s
defin�ci�k valamilyen
�rtelemben z�rt halmaz�t egyetlen egys�gbe fogjuk �ssze:
namespace X {
// saj�t deklar�ci�k
}
A deklar�ci�k list�ja �ltal�ban tartalmazni fog �jabb n�vtereket is. Teh�t
gyakorlati okokb�l
is sz�ks�g van a n�vterek egym�sba �gyaz�s�ra, azon egyszeru ok mellett, hogy ha
valamilyen
rendszerben nem kifejezetten k�ptelens�g az egym�sba �gyaz�s megval�s�t�sa, akkor
illik azt lehetov� tenn�nk:
void h();
namespace X {
void g();
// ...
namespace Y {
void f();
void ff();
// ...
}
}
Az al�bbi jel�l�sek a szok�sos, hat�k�r�kre vonatkoz�, illetve minos�t�si
szab�lyokb�l
k�vetkeznek:
void X::Y::ff()
{
f(); g(); h();
}
void X::g()
{
f(); // hiba: nincs f() X-ben
Y::f(); // rendben
}
void h()
{
f(); // hiba: nincs glob�lis f()
Y::f(); // hiba: nincs glob�lis Y
X::f(); // hiba: nincs f() X-ben
X::Y::f(); // rendben
}
1146 F�ggel�kek �s t�rgymutat�
C.10.3. N�vterek �s oszt�lyok
A n�vterek elnevezett hat�k�r�k, az oszt�lyok pedig t�pusok, melyeket egy
elnevezett hat
�k�rrel hat�rozunk meg, ami azt �rja le, hogy a t�pus objektumait hogyan kell
l�trehozni �s
kezelni. Teh�t a n�vt�r egyszerubb fogalom, mint az oszt�ly, �s ide�lis esetben az
oszt�lyokat
�gy is meghat�rozhatjuk, mint tov�bbi lehetos�geket biztos�t� n�vtereket. A
meghat�-
roz�s azonban csak majdnem pontos, ugyanis a n�vt�r nyitott szerkezet (�8.2.9.3),
m�g az
oszt�ly teljesen z�rt. A k�l�nbs�g abb�l ad�dik, hogy az oszt�lyoknak objektumok
szerkezet
�t kell le�rniuk, ez pedig nem engedi meg azt a szabads�got, amit a n�vterek
ny�jtanak.
Ezenk�v�l a using deklar�ci�k �s using utas�t�sok csak nagyon korl�tozott
esetekben haszn
�lhat�k az oszt�lyokra (�15.2.2).
Ha csak a nevek egys�gbe z�r�s�ra van sz�ks�g�nk, a n�vterek jobban haszn�lhat�k,
mint
az oszt�lyok, mert ekkor nincs sz�ks�g�nk az oszt�lyok komoly t�pusellenorz�si
lehetos�-
geire �s az objektumk�sz�t�si m�dszerekre; az egyszerubb n�vt�r-kezel�si elvek is
elegend
oek.
C.11. Hozz�f�r�s-szab�lyoz�s
Ebben a pontban a hozz�f�r�s-szab�lyoz�s olyan vonatkoz�saira mutatunk p�ld�kat,
melyekr
ol a �15.3 pontban nem volt sz�.
C.11.1. Tagok el�r�se
Vizsg�ljuk meg az al�bbi deklar�ci�t:
class X {
// az alap�rtelmez�s priv�t:
int priv;
protected:
int prot;
public:
int publ;
void m();
};
C. Technikai r�szletek 1147
Az X::m() f�ggv�nynek korl�tlan hozz�f�r�se van a tagokhoz:
void X::m()
{
priv = 1; // rendben
prot = 2; // rendben
publ = 3; // rendben
}
A sz�rmaztatott oszt�lyok tagjai a public �s protected tagokat �rhetik el (�15.3):

class Y : public X {
void mderived();
};
void Y::mderived()
{
priv = 1; // hiba: priv priv�t
prot = 2; // rendben: prot v�dett �s mderived() az Y sz�rmaztatott oszt�ly tagja
publ = 3; // rendben: publ nyilv�nos
}
A glob�lis f�ggv�nyek csak a nyilv�nos tagokat l�tj�k:
void f(Y* p)
{
p->priv = 1; // hiba: priv priv�t
p->prot = 2; // hiba: prot v�dett �s f() se nem bar�t, se nem X vagy Y tagja
p->publ = 3; // rendben: publ nyilv�nos
}
C.11.2. Alaposzt�lyok el�r�se
A tagokhoz hasonl�an az alaposzt�lyokat is bevezethetj�k private, protected vagy
public
minos�t�ssel:
class X {
public:
int a;
// ...
};
class Y1 : public X { };
class Y2 : protected X { };
class Y3 : private X { };
1148 F�ggel�kek �s t�rgymutat�
Mivel az X nyilv�nos alaposzt�lya az Y1 oszt�lynak, b�rmely f�ggv�ny szabadon (�s
automatikusan)
�talak�that egy Y1* �rt�ket X* t�pusra �s el�rheti az X oszt�ly nyilv�nos tagjait
is:
void f(Y1* py1, Y2* py2, Y3* py3)
{
X* px = py1; // rendben: X nyilv�nos alaposzt�lya Y1 oszt�lynak
py1->a = 7; // rendben
px = py2; // hiba: X v�dett alaposzt�lya Y2 oszt�lynak
py2->a = 7; // hiba
px = py3; // hiba: X priv�t alaposzt�lya Y3 oszt�lynak
py3->a = 7; // hiba
}
Vegy�k az al�bbi deklar�ci�kat:
class Y2 : protected X { };
class Z2 : public Y2 { void f(Y1*, Y2*, Y3*); };
Mivel X v�dett alaposzt�lya Y2-nek, csak Y2 tagjai �s bar�t (friend) oszt�lyai,
f�ggv�nyei, illetve
Y2 lesz�rmazottainak (p�ld�ul Z2-nek) tagjai �s ezek bar�t elemei alak�thatj�k �t
(automatikusan)
az Y2* t�pus� �rt�ket X*-ra, �s csak ezek f�rhetnek hozz� az X oszt�ly public
�s protected tagjaihoz:
void Z2::f(Y1* py1, Y2* py2, Y3* py3)
{
X* px = py1; // rendben: X nyilv�nos alaposzt�lya Y1 oszt�lynak
py1->a = 7; // rendben
px = py2; // rendben: X v�dett alaposzt�lya Y2-nek,
// �s Z2 oszt�ly Y2-bol sz�rmazik
py2->a = 7; // rendben
px = py3; // hiba: X priv�t alaposzt�lya Y3 oszt�lynak
py3->a = 7; // hiba
}
V�g�l vizsg�ljuk meg az al�bbit:
class Y3 : private X { void f(Y1*, Y2*, Y3*); };
C. Technikai r�szletek 1149
Az X az Y3-nak priv�t alaposzt�lya, �gy kiz�r�lag Y3 tagjai �s .bar�tai.
alak�thatj�k �t (automatikusan)
az Y3* �rt�keket X*-ra, �s csak azok �rhetik el az X nyilv�nos �s v�dett tagjait:
void Y3::f(Y1* py1, Y2* py2, Y3* py3)
{
X* px = py1; // rendben: X nyilv�nos alaposzt�lya Y1 oszt�lynak
py1->a = 7; // rendben
px = py2; // hiba: X v�dett alaposzt�lya Y2 oszt�lynak
py2->a = 7; // hiba
px = py3; // rendben: X priv�t alaposzt�lya Y3-nak, �s Y3::f() Y3 tagja
py3->a = 7; // rendben
}
C.11.3. Tagoszt�lyok el�r�se
A tagoszt�lyok tagjainak nincs k�l�nleges jogosults�guk a befoglal� oszt�ly
tagjainak el�r�-
s�re �s ugyan�gy a befoglal� oszt�ly tagjai sem rendelkeznek k�l�nleges
hozz�f�r�ssel a be-
�gyazott oszt�ly tagjaihoz. Minden a szok�sos szab�lyok (�10.2.2) szerint muk�dik:

class Outer {
typedef int T;
int i;
public:
int i2;
static int s;
class Inner {
int x;
T y; // hiba: Outer::T priv�t
public:
void f(Outer* p, int v);
};
int g(Inner* p);
};
void Outer::Inner::f(Outer* p, int v)
{
p->i = v; // hiba: Outer::i priv�t
p->i2 = v; // rendben: Outer::i2 nyilv�nos
}
1150 F�ggel�kek �s t�rgymutat�
int Outer::g(Inner* p)
{
p->f(this,2); // rendben: Inner::f() nyilv�nos
return p->x; // hiba: Inner::x priv�t
}
Ennek ellen�re gyakran hasznos, ha a be�gyazott oszt�ly el�rheti a be�gyaz�
oszt�ly tagjait.
Ezt �gy �rhetj�k el, ha a tagoszt�lyt friend minos�t�ssel vezetj�k be:
class Outer {
typedef int T;
int i;
public:
class Inner; // a tagoszt�ly elozetes bevezet�se
friend class Inner; // el�r�si jog Outer::Inner sz�m�ra
class Inner {
int x;
T y; // rendben: Inner egy "bar�t"
public:
void f(Outer* p, int v);
};
};
void Outer::Inner::f(Outer* p, int v)
{
p->i = v; // rendben: Inner egy "bar�t"
}
C.11.4. Bar�tok
A friend minos�t�s hat�sa nem �r�klodik �s nem is tranzit�v:
class A {
friend class B;
int a;
};
class B {
friend class C;
};
C. Technikai r�szletek 1151
class C {
void f(A* p)
{
p->a++; // hiba: C nem bar�tja A-nak, b�r A bar�tj�nak bar�tja
}
};
class D : public B {
void f(A* p)
{
p->a++; // hiba: D nem bar�tja A-nak, b�r A bar�tj�b�l sz�rmazik
}
};
C.12. Adattagokra hivatkoz� mutat�k
Term�szetesen a tagokra hivatkoz� mutat�k (�15.5) fogalma az adattagokra, valamint
a r�gz
�tett param�terekkel �s visszat�r�si �rt�kkel rendelkezo f�ggv�nyekre vonatkozik:
struct C {
const char* val;
int i;
void print(int x) { cout << val << x << '\n'; }
int f1(int);
void f2();
C(const char* v) { val = v; }
};
typedef void (C::*PMFI)(int); // C oszt�ly egy int param�terrel megh�vhat�
// tagf�ggv�nyre hivatkoz� mutat�
typedef const char* C::*PM; // C oszt�ly egy char* t�pus� adattagj�ra
// hivatkoz� mutat�
void f(C& z1, C& z2)
{
C* p = &z2;
PMFI pf = &C::print;
PM pm = &C::val;
z1.print(1);
(z1.*pf)(2);
1152 F�ggel�kek �s t�rgymutat�
z1.*pm = "nv1 ";
p->*pm = "nv2 ";
z2.print(3);
(p->*pf)(4);
pf = &C::f1; // hiba: nem megfelelo visszat�r�si t�pus
pf = &C::f2; // hiba: nem megfelelo param�tert�pus
pm = &C::i; // hiba: nem megfelelo t�pus
pm = pf; // hiba: nem megfelelo t�pus
}
A f�ggv�nyekre hivatkoz� mutat�k t�pus�t a rendszer ugyan�gy ellenorzi, mint
b�rmely
m�s t�pus�t.
C.13. Sablonok
A sablon oszt�lyok azt hat�rozz�k meg, hogyan hozhat� l�tre egy oszt�ly, ha a
sz�ks�ges
sablonparam�tereket megadjuk. A sablon f�ggv�nyek ehhez hasonl�an azt r�gz�tik,
hogyan
k�sz�thet�nk el egy konkr�t f�ggv�nyt a megadott sablonparam�terekkel. Teh�t a
sablonok
t�pusok �s futtathat� k�dr�szletek l�trehoz�s�hoz haszn�lhat�k fel. Ez a nagy
kifejez
oero azonban n�h�ny bonyodalmat okoz. A legt�bb probl�ma abb�l ad�dik, hogy m�s
k�rnyezet �ll rendelkez�s�nkre a sablon meghat�roz�sakor �s felhaszn�l�sakor.
C.13.1. Statikus tagok
Az oszt�lysablonoknak is lehetnek static tagjaik. Ezekbol a tagokb�l minden, a
sablonb�l
l�trehozott oszt�ly saj�t p�ld�nnyal rendelkezik. A statikus tagokat k�l�n kell
meghat�roznunk,
de egyedi c�l� v�ltozatokat is k�sz�thet�nk belol�k:
template<class T> class X {
// ...
static T def_val;
static T* new_X(T a = def_val);
};
template<class T> T X<T>::def_val(0,0);
template<class T> T* X<T>::new_X(T a) { /* ... */ }
C. Technikai r�szletek 1153
template<> int X<int>::def_val<int> = 0;
template<> int* X<int>::new_X<int>(int i) { /* ... */ }
Ha egy objektumot vagy f�ggv�nyt a sablonb�l l�trehozott �sszes oszt�ly �sszes
p�ld�ny�-
ban k�z�sen szeretn�nk haszn�lni, bevezethet�nk egy alaposzt�lyt, amely nem
sablon:
struct B {
static B* nil; // k�z�s nullpointer minden B-bol sz�rmaztatott oszt�lynak
};
template<class T> class X : public B {
// ...
};
B* B::nil = 0;
C.13.2. Bar�tok �s sablonok
M�s oszt�lyokhoz hasonl�an a sablon is tartalmazhat friend oszt�lyokat �s
f�ggv�nyeket.
Vizsg�ljuk meg p�ld�ul a �11.5 pontban szereplo Matrix �s Vector oszt�lyt.
�ltal�ban mindk
�t oszt�lyt sablonk�nt val�s�tjuk meg:
template<class T> class Matrix;
template<class T> class Vector {
T v[4];
public:
friend Vector operator* <> (const Matrix<T>&, const Vector&);
// ...
};
template<class T> class Matrix {
Vector<T> v[4];
public:
friend Vector<T> operator* <> (const Matrix&, const Vector<T>&);
// ...
};
A bar�t f�ggv�ny neve ut�n szereplo <> jel nem hagyhat� el, mert ez jelzi, hogy a
bar�t egy
sablon f�ggv�ny. A <> jel n�lk�l a rendszer nem sablon f�ggv�nyt felt�telezne. A
fenti bevezet
�s ut�n a szorz�s oper�tort �gy hat�rozhatjuk meg, hogy a Vector �s a Matrix
tagjaira
k�zvetlen�l hivatkozunk:
1154 F�ggel�kek �s t�rgymutat�
template<class T> Vector<T> operator* <> (const Matrix<T>&, const Vector<T>&)
{
// ... m.vi[i] �s v.v[i] haszn�lata az elemek k�zvetlen el�r�s�hez
}
A bar�t nincs hat�ssal arra a hat�k�rre, melyben a sablon oszt�lyt meghat�roztuk,
sem arra,
melyben a sablon oszt�lyt felhaszn�ljuk. Ehelyett a bar�t f�ggv�nyeket �s
oper�torokat
param�tert�pusaik alapj�n tal�lja meg a rendszer (�11.2.4, �11.5.1). A
tagf�ggv�nyekhez hasonl
�an a bar�t f�ggv�nyekbol is csak akkor k�sz�l p�ld�ny, ha megh�vjuk azokat.
C.13.3. Sablonok, mint sablonparam�terek
Gyakran hasznos, ha sablonparam�terk�nt oszt�lyok vagy objektumok helyett
sablonokat
adunk �t:
template<class T, template<class> class C> class Xrefd {
C<T> mems;
C<T*> refs;
// ...
};
Xrefd<Entry,vector> x1; // az Entry kereszthivatkoz�sokat vektorban t�roljuk
Xrefd<Record,set> x2; // a Record kereszthivatkoz�sokat halmazban t�roljuk
Ahhoz, hogy egy sablont sablonparam�terk�nt haszn�ljunk, meg kell adnunk az �ltala
v�rt
param�tereket, a param�terk�nt haszn�lt sablon sablonparam�tereit viszont nem kell
ismern
�nk. Sablonokat �ltal�ban akkor haszn�lunk sablonparam�terk�nt, ha k�l�nb�zo param
�tert�pusokkal akarjuk azokat p�ld�nyos�tani (fent p�ld�ul a T �s a T* t�pussal).
Teh�t
a sablon tagjainak deklar�ci�it egy m�sik sablon fogalmaival fejezz�k ki, de ez
ut�bbi sablont
param�terk�nt szeretn�nk megadni, hogy a felhaszn�l� v�laszthassa meg t�pus�t.
Ha a sablonnak egy t�rol�ra van sz�ks�ge azon elemek t�rol�s�hoz, melyek t�pus�t
sablonparam
�terk�nt kapja meg, gyakran egyszerubb a t�rol�t�pust �tadni (�13.6, �17.3.1).
Sablonparam�terek csak sablon oszt�lyok lehetnek.
C. Technikai r�szletek 1155
C.13.4. Sablon f�ggv�nyek param�tereinek levezet�se
A ford�t� k�pes arra, hogy levezessen egy t�pus- (T vagy TT) vagy nem t�pus
sablonparam�-
tert (I) egy olyan f�ggv�nysablon-param�terbol, melyet a k�vetkezo szerkezetek
valamelyik
�vel �ll�tottunk elo:
T const T volatile T
T* T& T[konstans_kifejez�s]
t�pus[I] oszt�lysablon_n�v<T> oszt�lysablon_n�v<I>
TT<T> T<I> T<>
T t�pus::* T T::* t�pus T::*
T (*)(param�terek) t�pus (T::*)(param�terek) T (t�pus::*)(param�terek)
t�pus (t�pus::*)(param�terek_TI) T (T::*)(param�terek_TI) t�pus (T::*)
(param�terek_TI)
T (t�pus::*)(param�terek_TI) t�pus (*)(param�terek_TI)
Ebben a gyujtem�nyben a param_T1 egy olyan param�terlista, melybol egy T vagy egy
I
meghat�rozhat� a fenti szab�lyok t�bbsz�ri alkalmaz�s�val, m�g a param egy olyan
param
�terlista, amely nem tesz lehetov� k�vetkeztet�st. Ha nem minden param�ter
k�vetkeztethet
o ki ezzel a megold�ssal, a h�v�s t�bb�rtelmunek minos�l:
template<class T, class U> void f(const T*, U(*)(U));
int g(int);
void h(const char* p)
{
f(p,g); // T char, U int
f(p,h); // hiba: U nem vezetheto le
}
Ha megn�zz�k az f() elso h�v�s�nak param�tereit, k�nnyen kik�vetkeztethetj�k a
sablonparam
�tereket. Az f() m�sodik megh�v�s�ban viszont l�thatjuk, hogy a h() nem
illesztheto
az U(*)(U) mint�ra, mert param�tere �s visszat�r�si �rt�ke k�l�nb�zo.
Ha egy sablonparam�ter egyn�l t�bb f�ggv�nyparam�terbol is kik�vetkeztetheto,
akkor
mindegyiknek ugyanazt az eredm�nyt kell adnia, ellenkezo esetben hiba�zenetet
kapunk:
template<class T> void f(T i, T* p);
void g(int i)
{
f(i,&i); // rendben
f(i,"Vigy�zat!"); // hiba, t�bb�rtelmu: T int vagy T const char?
}
1156 F�ggel�kek �s t�rgymutat�
C.13.5. A typename �s a template
Az �ltal�nos�tott (generikus) programoz�s tov�bbi egyszerus�t�se �s m�g
�ltal�nosabb� t�-
tele �rdek�ben a standard k�nyvt�r t�rol�i szabv�nyos f�ggv�nyeket �s t�pusokat
biztos�tanak
(�16.3.1):
template<class T> class vector {
public:
typedef T value_type;
typedef T* iterator;
iterator begin();
iterator end();
// ...
};
template<class T> class list {
class link { /* ... */ };
public:
typedef link* iterator;
iterator begin();
iterator end();
// ...
};
Ez arra �szt�n�z minket, hogy az al�bbi form�t haszn�ljuk:
template<class C> void f(C& v)
{
C::iterator i = v.begin(); // formai hiba
}
Sajnos a ford�t� nem gondolatolvas�, �gy nem tudja, hogy a C::iterator egy t�pus
neve. Bizonyos
esetekben egy okosabb ford�t� kital�lhatja, hogy egy nevet t�pusn�vnek sz�ntunke
vagy valami eg�szen m�snak (p�ld�ul f�ggv�ny- vagy sablonn�vnek), de ez �ltal�ban
nem lehets�ges. Figyelj�k meg p�ld�ul az al�bbit:
int y;
template<class T> void g(T& v)
{
T::x(y); // f�ggv�nyh�v�s vagy v�ltoz�-deklar�ci�?
}
C. Technikai r�szletek 1157
Felt�tlen�l igaz-e, hogy ez esetben a T::x egy f�ggv�ny, melyet az y param�terrel
h�vtunk
meg? Ugyanezt a sort tekinthetj�k az y v�ltoz� deklar�ci�j�nak is, ahol a T::x egy
t�pus �s
a z�r�jelek csak felesleges �s term�szetellenes (de nem tiltott) jelek. Teh�t el
tudunk k�pzelni
olyan k�rnyezetet, melyben X::x(y) egy f�ggv�nyh�v�s, m�g az Y::x(y) egy
deklar�ci�.
A megold�s rendk�v�l egyszeru: ha m�st nem mondunk, az azonos�t�kr�l a rendszer
azt felt
�telezi, hogy olyasvalamire hivatkoznak, ami nem t�pus �s nem sablon. Ha azt
akarjuk kifejezni,
hogy egy azonos�t�t t�pusk�nt kell �rtelmezni, a typename kulcssz�t kell
haszn�lnunk:
template<class C> void h(C& v)
{
typename C::iterator i = v.begin();
// ...
}
A typename kulcssz�t a minos�tett n�v el� �rva azt fejezhetj�k ki, hogy a megadott
elem egy
t�pus. Ebbol a szempontb�l szerepe hasonl�t a struct �s a class szerep�re.
A typename kulcssz�ra mindig sz�ks�g van, ha a t�pus neve egy sablonparam�tertol
f�gg:
void k(vector<T>& v)
{
vector<T>::iterator i = v.begin(); // formai hiba: a "typename" hi�nyzik
typename vector<T>::iterator i = v.begin(); // rendben
// ...
}
Ebben az esetben a ford�t� esetleg k�pes lenne meg�llap�tani, hogy az iterator a
vector sablon
minden p�ld�nyoszt�ly�ban egy t�pusnevet ad meg, de a szabv�ny ezt nem k�veteli
meg. Teh�t, ha egy ford�t� ilyesmire k�pes, akkor az nem szabv�nyos szolg�ltat�s
�s nem
tekintheto hordozhat� nyelvkiterjeszt�snek. Az egyetlen k�rnyezet, ahol a
ford�t�nak felt�-
teleznie kell, hogy egy sablon-param�tertol f�ggo azonos�t� t�pusn�v, az a n�h�ny
helyzet,
amikor a nyelvtan csak t�pusneveket enged meg. Ilyenek p�ld�ul az alap-
meghat�roz�sok
(�A.8.1).
A sablondeklar�ci�kban a typename a class kulcssz� szinonim�jak�nt is haszn�lhat�:

template<typename T> void f(T);


Mivel a k�t v�ltozat k�z�tt nincs �rdemi k�l�nbs�g, de a k�pernyo mindig kicsinek
bizonyul,
�n a r�videbb v�ltozatot aj�nlom:
template<class T> void f(T);
1158 F�ggel�kek �s t�rgymutat�
C.13.6. Sablonok, mint minos�tok
A typename kulcssz� bevezet�s�re az�rt volt sz�ks�g, mert hivatkozhatunk olyan
adattagokra
is, melyek t�pusok, �s olyanokra is, melyek nem azok. Ugyanilyen probl�m�t jelent
a sablontagok nev�nek megk�l�nb�ztet�se m�s tagok�t�l. Vizsg�ljuk meg p�ld�ul egy
�ltal
�nos mem�riakezelo oszt�ly egy lehets�ges fel�let�t:
class Memory { // valamilyen mem�riafoglal�
public:
template<class T> T* get_new();
template<class T> void release(T&);
// ...
};
template<class Allocator> void f(Allocator& m)
{
int* p1 = m.get_new<int>(); // formai hiba: 'int' a 'kisebb mint' oper�tor ut�n
int* p2 = m.template get_new<int>(); // explicit minos�t�s
// ...
m.release(p1); // sablonparam�ter levezet�se: nem kell explicit minos�to
m.release(p2);
}
A get_new()f�ggv�ny explicit minos�t�s�re van sz�ks�g, mert a sablonparam�tert nem
lehet
levezetni. Eset�nkben a template elotagra van sz�ks�g ahhoz, hogy a ford�t�nak (�s
az
emberi olvas�nak) el�ruljuk, hogy a get_new() egy sablontag, teh�t a minos�t�s
lehets�ges
a megadott elemt�pussal. A template minos�t�s n�lk�l formai hib�t kapunk, mert a <
jelet
a ford�t� .kisebb, mint. oper�tork�nt pr�b�lja meg �rtelmezni. A template
kulcssz�val val�
minos�t�sre ritk�n van sz�ks�g, mert a legt�bb esetben a sablonparam�tereket a
ford�t� ki
tudja k�vetkeztetni.
C.13.7. P�ld�nyos�t�s
Ha adott egy sablon-meghat�roz�s �s ezt a sablont haszn�lni szeretn�nk, a ford�t�
feladata,
hogy a megfelelo programk�dot elo�ll�tsa. Egy sablon oszt�lyb�l �s a megadott
sablonparam
�terekbol a ford�t�nak elo kell �ll�tania egy oszt�ly meghat�roz�s�t �s �sszes
olyan tagf
�ggv�ny�nek defin�ci�j�t, melyet programunkban felhaszn�ltunk. Egy sablon f�ggv�ny

eset�ben a megfelelo f�ggv�nyt kell elo�ll�tani. Ezt a folyamatot nevezz�k a


sablon p�ld�-
nyos�t�s�nak.
C. Technikai r�szletek 1159
A l�trehozott oszt�lyokat �s f�ggv�nyeket egyedi c�l� (.szakos�tott.)
v�ltozatoknak
(specializ�ci�knak) nevezz�k. Ha meg akarjuk k�l�nb�ztetni a ford�t� �ltal
automatikusan
l�trehozott v�ltozatokat a programoz� �ltal megadottakt�l (�13.5), akkor ford�t�i
(gener�lt)
specializ�ci�kr�l, illetve explicit specializ�ci�kr�l besz�l�nk. Az explicit
specializ�ci�kat
n�ha felhaszn�l�i specializ�ci�knak nevezz�k.
Ahhoz, hogy a sablonokat bonyolultabb programokban is hat�konyan haszn�lhassuk,
meg
kell �rten�nk, hogy a sablon-meghat�roz�sokban szereplo neveket hogyan k�ti a
ford�t�
konkr�t deklar�ci�khoz �s hogyan tudjuk forr�sprogramunkat rendszerezni (�13.7).
Alap�rtelmez�s szerint a ford�t� olyan sablonokb�l hoz l�tre oszt�lyokat �s
f�ggv�nyeket,
melyeket a szok�sos n�vk�t�si szab�lyok szerint haszn�ltunk (�C.13.8). Ez azt
jelenti, hogy
a programoz�nak nem kell megmondania, mely sablonok mely v�ltozatait kell
elk�sz�teni.
Ez az�rt fontos, mert a programoz� �ltal�ban nagyon nehezen tudja megmondani, hogy

a sablonoknak pontosan mely v�ltozataira is van sz�ks�ge. A k�nyvt�rak gyakran


olyan
sablonokat haszn�lnak, melyekrol a programoz� m�g nem is hallott, sot az sem
ritka, hogy
egy, a programoz� �ltal egy�ltal�n nem ismert sablont annak sz�m�ra szint�n
teljesen ismeretlen
sablonparam�terekkel p�ld�nyos�tunk. �ltal�ban ahhoz, hogy megkeress�k az
�sszes olyan f�ggv�nyt, melynek k�dj�t a ford�t�nak elo kell �ll�tania, az
alkalmaz�sban �s
a k�nyvt�rakban haszn�lt sablonok t�bbsz�ri �tvizsg�l�s�ra van sz�ks�g. Az ilyen
vizsg�latok
sokkal jobban illenek a sz�m�t�g�phez, mint a programoz�hoz.
Ennek ellen�re bizonyos helyzetekben fontos, hogy a programoz� pontosan
megmondhassa,
a ford�t�nak hol kell elhelyeznie a sablonb�l l�trehozott programr�szleteket
(�C.13.10).
Ezzel a programoz� pontosan szab�lyozhatja a p�ld�ny k�rnyezet�t. A legt�bb
ford�t�si
k�rnyezetben ez azt is jelenti, hogy pontosan r�gz�tj�k, mikor j�jj�n l�tre a
p�ld�ny.
Az explicit p�ld�nyos�t�s p�ld�ul j�l haszn�lhat� arra, hogy a ford�t�si hib�kat
megj�solhat
� helyen �s idoben kapjuk, ne pedig ott �s akkor, amikor az adott ford�t� �gy
d�nt, hogy
l�tre kell hoznia egy p�ld�nyt. Bizonyos k�r�lm�nyek k�z�tt a t�k�letesen
megj�solhat�
programk�d-l�trehoz�s elengedhetetlen�l fontos lehet.
C.13.8. N�vk�t�s
Nagyon fontos, hogy a sablon f�ggv�nyeket �gy hat�rozzuk meg, hogy a leheto
legkisebb
m�rt�kben f�ggjenek nem helyi adatokt�l. Ennek oka az, hogy a sablonb�l ismeretlen
t�pusok
alapj�n, ismeretlen helyen fog a ford�t� f�ggv�nyt vagy oszt�lyt l�trehozni.
Minden apr
� k�rnyezetf�ggos�g es�lyes arra, hogy a programoz� sz�m�ra tesztel�si
probl�mak�nt jelentkezzen,
pedig a programoz� val�sz�nuleg egy�ltal�n nem is akar tudni a sablon megval
�s�t�s�nak r�szleteirol. Az az �ltal�nos szab�ly, miszerint amennyire csak lehet,
el kell ke-
1160 F�ggel�kek �s t�rgymutat�
r�ln�nk a glob�lis nevek haszn�lat�t, a sablonok eset�ben m�g elengedhetetlenebb.
Ez�rt
a sablon-meghat�roz�sokat pr�b�ljuk annyira �n�ll�v� tenni, amennyire csak lehet,
�s minden
olyan elemet, amelyet egy�bk�nt esetleg glob�lis eszk�z�kkel val�s�tan�nk meg,
sablonparam
�terk�nt adjunk �t (pl. traits a �13.4 �s a �20.2.1 pontban).
Ennek ellen�re k�nytelenek vagyunk n�h�ny nem helyi nevet is felhaszn�lni. Sokkal
gyakrabban
k�sz�t�nk p�ld�ul egym�ssal egy�ttmuk�do sablon f�ggv�nyeket, mint egyetlen
nagy, �n�ll� elj�r�st. N�ha ezek a f�ggv�nyek j�l �sszefoghat�k egy oszt�lyba, de
nem mindig.
Idonk�nt a nem helyi f�ggv�nyek haszn�lata mellett d�nt�nk. Jellemzo p�lda erre
a sort() f�ggv�nyben szereplo swap() �s less() elj�r�sh�v�s (�13.5.2). A standard
k�nyvt�r algoritmusai
nagym�retu p�ldak�nt tekinthetok (�18. fejezet).
A hagyom�nyos n�vvel �s szereppel megval�s�tott f�ggv�nyek (p�ld�ul a +, a *, a []
vagy
a sort()) egy m�s jellegu forr�st jelentenek a sablon-meghat�roz�sokban levo nem
helyi nevek
haszn�lat�ra. Vizsg�ljuk meg p�ld�ul az al�bbi programr�szletet:
#include<vector>
bool tracing;
// ...
template<class T> T sum(std::vector<T>& v)
{
T t = 0;
if (tracing) cerr << "sum(" << &v << ")\n";
for (int i = 0; i<v.size(); i++) t = t + v[i];
return t;
}
// ...
#include<quad.h>
void f(std::vector<Quad>& v)
{
Quad c = sum(v);
}
Az �rtatlan kin�zetu sum() sablon f�ggv�ny a + oper�tort�l f�gg. P�ld�nkban a +
muveletet
a <quad.h> fej�llom�ny hat�rozza meg:
Quad operator+(Quad,Quad);
C. Technikai r�szletek 1161
Fontos, hogy a sum() kifejt�sekor semmilyen, a komplex sz�mokhoz kapcsol�d� elem
nem
el�rheto �s a sum() f�ggv�ny megalkot�ja semmit sem felt�telezhet a Quad
oszt�lyr�l. �gy
k�nnyen elofordulhat p�ld�ul, hogy a + oper�tort j�val k�sobb hat�rozzuk meg, mint

a sum() elj�r�st, mind a program sz�veg�ben, mind idoben.


Azt a folyamatot, melynek sor�n a ford�t� megkeresi a sablonban elofordul� nevek
deklar
�ci�j�t, n�vk�t�snek (name binding) nevezz�k. A sablonok n�vk�t�s�n�l a legnagyobb

probl�m�t az jelenti, hogy p�ld�nyos�t�skor h�rom k�l�nb�zo k�rnyezetet kell


figyelembe
venni �s ezek nem v�laszthat�k el egym�st�l pontosan. A h�rom k�rnyezet a
k�vetkezo:
1. A sablon meghat�roz�s�nak k�rnyezete
2. A param�tert�pus bevezet�s�nek k�rnyezete
3. A sablon felhaszn�l�si hely�nek k�rnyezete
C.13.8.1. F�ggo nevek
Amikor egy f�ggv�ny sablont meghat�rozunk, biztosak szeretn�nk lenni abban, hogy
rendelkez
�s�nkre �ll a megfelelo k�rnyezet, melyben az aktu�lis param�terek fogalmaival el
tudjuk v�gezni az adott feladatot, an�lk�l, hogy a felhaszn�l�si k�rnyezet elemeit
.v�letlen
�l. be�p�ten�nk az elj�r�sba. A nyelv ennek megval�s�t�s�t azzal seg�ti, hogy a
sablon defin
�ci�j�ban felhaszn�lt neveket k�t kateg�ri�ba osztja:
1. A sablonparam�terektol f�ggo nevek. Ezeket a neveket a p�ld�nyos�t�s hely�n
k�ti le a ford�t� (�C.13.8.3). A sum() p�ldaf�ggv�nyben a + oper�tor meghat�roz
�sa a p�ld�nyos�t�si k�rnyezetben tal�lhat�, mert operandusaiban felhaszn�lja
a sablon t�pusparam�ter�t.
2. A sablonparam�terektol f�ggetlen nevek. Ezeket a neveket a sablon meghat�roz
�s�n�l k�ti le a ford�t� (�C.13.8.2). A sum() p�ldaf�ggv�nyben a vector sablont
a <vector> szabv�nyos fej�llom�ny hat�rozza meg, a logikai tracing v�ltoz� pedig
akkor is a hat�k�rben van, amikor a ford�t� tal�lkozik a sum() f�ggv�ny
meghat�roz�s�val.
Az .N f�gg a T sablonparam�tertol. kifejez�s legegyszerubb defin�ci�ja az lenne,
hogy .N
tagja a T oszt�lynak.. Sajnos ez nem mindig elegendo: A Quad elemek �sszead�sa
(�C.13.8)
j� ellenp�lda erre. Teh�t egy f�ggv�nyh�v�st egy sablonparam�tertol f�ggonek akkor
nevez
�nk, ha az al�bbi felt�telek valamelyike teljes�l:
1. Az aktu�lis param�ter t�pusa f�gg egy T sablonparam�tertol a t�puslevezet�si
szab�lyok szerint. P�ld�ul f(T(1)), f(t), f(g(t)) vagy f(&t), ha felt�telezz�k,
hogy
t t�pusa T.
1162 F�ggel�kek �s t�rgymutat�
2. A megh�vott f�ggv�nynek van egy olyan form�lis param�tere, amely f�gg a T t�-
pust�l, a t�puslevezet�si szab�lyok szerint (�13.3.1). P�ld�ul f(T), f(list<T>&)
vagy f(const T*).
Alapj�ban v�ve azt mondhatjuk, hogy a megh�vott f�ggv�ny akkor f�gg egy
sablonparam�-
tertol, ha a konkr�t �s form�lis param�tereire n�zve nyilv�nval�an f�gg tole.
Egy olyan h�v�s, melyben a f�ggv�ny egyik param�ter�nek t�pusa v�letlen�l �ppen
megfelel
az aktu�lis sablonparam�ternek, nem jelent f�ggos�get:
template<class T> T f(T a)
{
return g(1); // hiba: nincs g() a hat�k�rben �s g(1) nem f�gg T-tol
}
void g(int);
int z = f(2);
Az nem sz�m�t, hogy az f(2) h�v�sban a T �ppen az int t�pust jel�li �s a g()
param�tere is
ilyen t�pus�. Ha a g(1) h�v�st f�ggonek tekinten�nk, a sablon-meghat�roz�s
olvas�j�nak
a f�ggv�ny jelent�se teljesen �rthetetlen lenne. Ha a programoz� azt akarja, hogy
a g(int)
f�ggv�ny fusson le, akkor a g(int)-et be kell vezetnie az f() kifejt�se elott,
hogy a g(int)
f�ggv�ny el�rheto legyen az f() feldolgoz�sakor. Ez teljesen ugyanaz a szab�ly,
mint a nem
sablon f�ggv�nyek eset�ben.
A f�ggv�nyneveken k�v�l a v�ltoz�k, t�pusok, konstansok stb. neve is f�ggo, ha
t�pusuk
f�gg a sablonparam�tertol:
template<class T> void fct(const T& a)
{
typename T::Memtype p = a.p; // p �s Memtype f�gg T-tol
cout << a.i << ' ' << p->j; // i �s j f�gg T-tol
}
C.13.8.2. K�t�s meghat�roz�skor
Amikor a ford�t� egy sablon meghat�roz�s�val tal�lkozik, meg�llap�tja, mely nevek
f�ggok
(�C.13.8.1). Ha egy n�v f�ggo, deklar�ci�j�nak megkeres�s�t el kell halasztanunk a
p�ld�-
nyos�t�sig (�C.13.8.3).
C. Technikai r�szletek 1163
Azoknak a neveknek, melyek nem f�ggnek sablonparam�terektol, a sablon meghat�roz�-

sakor (defin�ci�j�n�l) el�rhetonek kell lenni�k (�4.9.4):


int x;
template<class T> T f(T a)
{
x++; // rendben
y++; // hiba: nincs y a hat�k�rben �s y nem f�gg T-tol
return a;
}
int y;
int z = f(2);
Ha a ford�t� tal�l megfelelo deklar�ci�t, mindenk�ppen azt fogja haszn�lni,
f�ggetlen�l att
�l, hogy k�sobb esetleg .jobb. deklar�ci�t is tal�lhatna hozz�:
void g(double);
template<class T> class X : public T {
public:
void f() { g(2); } // g(double) megh�v�sa
// ...
};
void g(int);
class Z { };
void h(X<Z> x)
{
x.f();
}
Amikor a ford�t� elk�sz�ti az X<Z>::f() f�ggv�nyt, nem a g(int) f�ggv�nyt fogja
haszn�lni,
mert azt az X ut�n vezett�k be. Az nem sz�m�t, hogy az X sablont nem haszn�ljuk a
g(int)
bevezet�se elott. Ehhez hasonl�an egy f�ggetlen h�v�st sem t�r�thet el egy
alaposzt�ly:
class Y { public: void g(int); };
void h(X<Y> x)
{
x.f();
}
1164 F�ggel�kek �s t�rgymutat�
Az X<Y>::f() most is a g(double) f�ggv�nyt fogja megh�vni. Ha a programoz� az
alaposzt
�ly g() f�ggv�ny�t akarja haszn�lni, az f() meghat�roz�s�t a k�vetkezok�ppen kell
megfogalmaznia:
template<class T> class XX : public T {
void f() { T::g(2); } // T::g() megh�v�sa
// ...
};
Ez term�szetesen annak az alapszab�lynak a megjelen�se, hogy a sablon
defin�ci�j�nak
a leheto leg�n�ll�bbnak kell lennie (�C.13.8).
C.13.8.3. K�t�s p�ld�nyos�t�skor
A sablon minden k�l�nb�zo sablonparam�ter-halmazzal val� felhaszn�l�sakor �j
p�ld�nyos�t�si pontot hat�rozunk meg. A p�ld�nyos�t�si pont helye a legk�zelebbi
glob�-
lis vagy n�vt�r-hat�k�rben van, k�zvetlen�l a felhaszn�l�st tartalmaz� deklar�ci�
elott:
template<class T> void f(T a) { g(a); }
void g(int);
void h()
{
extern g(double);
f(2);
}
Eset�nkben az f<int>() megfelelo p�ld�nya k�zvetlen�l a h() elott j�n l�tre, teh�t
az f()
f�ggv�nyben megh�vott g() a glob�lis g(int) lesz, nem pedig a helyi g(double).
A .p�ld�nyos�t�si pont. meghat�roz�s�b�l k�vetkezik, hogy a sablonparam�tereket
nem
k�thetj�k helyi nevekhez vagy oszt�lytagokhoz:
void f()
{
struct X { /* ... */ }; // helyi szerkezet
vector<X> v; // hiba: helyi szerkezet nem haszn�lhat� sablonparam�terk�nt
// ...
}
C. Technikai r�szletek 1165
Ugyan�gy a sablonban haszn�lt minos�tetlen neveket sem k�thetj�k helyi n�vhez. A
mino-
s�tetlen nevek akkor sem fognak egy oszt�ly tagjaihoz k�todni, ha a sablont
elosz�r ebben
az oszt�lyban haszn�ljuk. A helyi nevek elker�l�se nagyon fontos, ha nem akarunk
sz�mtalan,
.makr�szeru. probl�m�val szembeker�lni:
template<class T> void sort(vector<T>& v)
{
sort(v.begin(),v.end()); // standard k�nyvt�rbeli sort() haszn�lata
}
class Container {
vector<int> v; // elemek
// ...
public:
void sort() // elemek rendez�se
{
sort(v); // a sort(vector<int>&) megh�v�sa a Container::sort() helyett
}
// ...
};
Ha a sort(vector<T>&) a sort() f�ggv�nyt az std::sort() jel�l�ssel h�vta volna
meg, az eredm
�ny ugyanez lett volna, de program sokkal olvashat�bb lenne.
Ha egy n�vt�rben meghat�rozott sablon p�ld�nyos�t�si pontja egy m�sik n�vt�rben
tal�lhat
�, a n�vk�t�sn�l mindk�t n�vt�r nevei rendelkez�sre �llnak. A ford�t� szok�s
szerint a t�lterhel
�si szab�lyokat haszn�lja arra, hogy meg�llap�tsa, melyik n�vt�r nev�t kell
haszn�lnia
(�8.2.9.2).
Figyelj�nk r�, hogy ha egy sablont t�bbsz�r haszn�lunk ugyanazokkal a
sablonparam�terekkel,
mindig �j p�ld�nyos�t�si pontot hat�rozunk meg. Ha a f�ggetlen neveket a k�l�nb�zo

helyeken k�l�nb�zo nevekhez k�tj�k, programunk helytelen lesz. Az ilyen hib�t


nagyon neh
�z �szrevenni egy alkalmaz�sban, foleg ha a p�ld�nyos�t�si pontok k�l�nb�zo
ford�t�si
egys�gekben vannak. A legjobb, ha a n�vk�t�ssel j�r� probl�m�kat kiker�lj�k azzal,
hogy
a leheto legkevesebb nem helyi nevet haszn�ljuk a sablonban �s fej�llom�nyok
seg�ts�g�vel
biztos�tjuk, hogy mindenhol a megfelelo k�rnyezet �lljon a sablon rendelkez�s�re.
C.13.8.4. Sablonok �s n�vterek
Amikor egy f�ggv�nyt megh�vunk, annak deklar�ci�j�t a ford�t� akkor is
megtal�lhatja, ha
az nincs is az aktu�lis hat�k�rben. Ehhez az kell, hogy a f�ggv�nyt ugyanabban a
n�vt�rben
vezess�k be, mint valamelyik param�ter�t (�8.2.6). Ez nagyon fontos a sablon-
megha-
1166 F�ggel�kek �s t�rgymutat�
t�roz�sokban megh�vott f�ggv�nyek szempontj�b�l, mert ez a szolg�ltat�s teszi
lehetov�,
hogy a f�ggo f�ggv�nyeket a ford�t� a p�ld�nyos�t�s k�zben megtal�lja.
A sablon egyedi c�l� v�ltozata a p�ld�nyos�t�s tetszoleges pontj�n l�trej�het
(�C.13.8.3), de
a p�ld�nyos�t�st k�vetoen az adott ford�t�si egys�gben, esetleg egy olyan
ford�t�si egys�gben
is, mely kifejezetten az egyedi c�l� v�ltozatok l�trehoz�s�hoz k�sz�lt. Ebbol
h�rom
nyilv�nval� m�dszer alak�that� ki az egyedi c�l� v�ltozatok elk�sz�t�s�hez:
1. Akkor hozzuk l�tre azokat, amikor elso megh�v�sukkal tal�lkozunk.
2. A ford�t�si egys�g v�g�n l�trehozzuk az �sszeset, amelyre az adott ford�t�si
egys
�gben sz�ks�g van.
3. Miut�n a program �sszes ford�t�si egys�g�t megvizsg�ltuk, a programban haszn
�lt �sszes egyedi c�l� v�ltozatot egyszerre k�sz�tj�k el.
Mindh�rom m�dszernek vannak elonyei �s h�tr�nyai, ez�rt gyakran ezen lehetos�gek
valamilyen
p�ros�t�s�t haszn�lj�k.
A f�ggetlen nevek k�t�s�t mindenk�ppen a sablon meghat�roz�sakor v�gzi el a
ford�t�.
A f�ggo nevek k�t�s�hez k�t dolgot kell megvizsg�lni:
1. A sablon meghat�roz�sakor a hat�k�rben l�vo neveket
2. A f�ggo h�v�sok param�tereinek n�vter�ben szereplo neveket (a glob�lis f�ggv
�nyeket �gy tekintj�k, hogy a be�p�tett t�pusok n�vter�ben szerepelnek)
P�ld�ul:
namespace N {
class A { /* ... */ };
char f(A);
}
char f(int);
template<class T> char g(T t) { return f(t); }
char c = g(N::A()); // N::f(N::A) megh�v�s�t okozza
Itt az f(t) egy�rtelmuen f�ggo, �gy a defin�ci� feldolgoz�sakor nem k�thetj�k sem
az f(int),
sem az f(N::A) f�ggv�nyhez. A g<N::A>(N::A) .szakos�t�sakor. a ford�t� az N
n�vt�rben keresi
a megh�vott f() f�ggv�ny meghat�roz�s�t �s ott az N::f(N::A) v�ltozatot tal�lja
meg.
C. Technikai r�szletek 1167
A program hib�s, ha k�l�nb�zo eredm�nyeket kaphatunk azzal, hogy k�l�nb�zo p�ld�-
nyos�t�si pontokat v�lasztunk, vagy azzal, ha az egyedi c�l� v�ltozat
l�trehoz�sakor haszn
�lt k�rnyezetekben a n�vterek tartalm�t megv�ltoztatjuk:
namespace N {
class A { /* ... */ };
char f(A,int);
}
template<class T, class T2> char g(T t, T2 t2) { return f(t,t2); }
char c = g(N::A(),'a'); // hiba: f(t) m�s felold�sa is lehets�ges
namespace N { // az N n�vt�r kibov�t�se (�8.2.9.3)
void f(A,char);
}
Ha a p�ld�nyos�t�s pillanat�ban hozzuk l�tre a szakos�tott v�ltozatot, az
f(N::A,int) f�ggv
�ny ker�l megh�v�sra, viszont ha elk�sz�t�s�t a ford�t�si egys�g v�g�re
halasztjuk, a ford�-
t� az f(N::A,char) f�ggv�nyt tal�lja meg elobb. Teh�t a g(N::A(),.a.) h�v�s
helytelen.
Nagyon rendetlen programoz�si st�lust mutat, ha egy t�lterhelt f�ggv�nyt k�t
deklar�ci�ja
k�z�tt h�vunk meg. Egy nagyobb program eset�ben a programoz� nem gyanakodna hib�-
ra, ebben az esetben azonban a ford�t� k�pes �szrevenni a t�bb�rtelmus�get.
Hasonl�
probl�m�k jelentkezhetnek k�l�nb�zo ford�t�si egys�gekben is, �gy a hib�k
�szlel�se m�r
sokkal nehezebb� v�lik. Az egyes C++-v�ltozatoknak nem k�teless�g�k az ilyen
t�pus� hib
�k figyel�se.
A f�ggv�nyh�v�sok t�bbf�le felold�si lehetos�g�nek probl�m�ja leggyakrabban akkor
jelentkezik,
amikor be�p�tett t�pusokat haszn�lunk. Teh�t a legt�bb hib�t kiszurhetj�k azzal,
hogy a be�p�tett t�pusokat nagy k�r�ltekint�ssel haszn�ljuk a param�terekben.
Szok�s szerint a glob�lis f�ggv�nyek csak m�g bonyolultabb� teszik a dolgokat. A
glob�lis
n�vteret a be�p�tett t�pusok szintj�nek tekinthetj�k, �gy a glob�lis f�ggv�nyek
felhaszn�lhat
�k olyan f�ggo f�ggv�nyek lek�t�s�re is, melyeket be�p�tett t�pusokkal h�vtunk
meg:
int f(int);
template<class T> T g(T t) { return f(t); }
char c = g('a'); // hiba: f(t) m�s felold�sa is lehets�ges
char f(char);
1168 F�ggel�kek �s t�rgymutat�
A g<char>(char) f�ggv�ny egyedi c�l� v�ltozat�t elk�sz�thetj�k a p�ld�nyos�t�si
ponton is;
ekkor az f(int) f�ggv�nyt fogjuk haszn�lni. Ha a v�ltozatot a ford�t�si egys�g
v�g�n �ll�tjuk
elo, az f(char) f�ggv�ny fut majd le. Teh�t a g(.a.) h�v�s hib�s.
C.13.9. Mikor van sz�ks�g egyedi c�l� v�ltozatokra?
Egy sablon oszt�ly egyedi c�l� v�ltozat�t csak akkor kell elo�ll�tani, ha az adott
oszt�lyra
t�nyleg sz�ks�g van. Teh�t amikor egy, az oszt�lyra hivatkoz� mutat�t adunk meg,
az oszt
�ly t�nyleges meghat�roz�s�ra m�g nincs sz�ks�g�nk:
class X;
X* p; // rendben: X meghat�roz�s�ra nincs sz�ks�g
X a; // hiba: X meghat�roz�s�ra sz�ks�g van
A sablon oszt�lyok meghat�roz�sakor ez a k�l�nbs�g fontos lehet. A sablon oszt�lyt
mindaddig
nem p�ld�nyos�tjuk, am�g arra nincs sz�ks�g:
template<class T> class Link {
Link* suc; // rendben: Link meghat�roz�s�ra (m�g) nincs sz�ks�g
// ...
};
Link<int>* pl; // Link<int> p�ld�nyos�t�s�ra nincs sz�ks�g
Link<int> lnk; // most van sz�ks�g Link<int> p�ld�nyos�t�s�ra
A p�ld�nyos�t�si pont az a hely, ahol a defin�ci�ra elosz�r sz�ks�g van.
C.13.9.1. Sablon f�ggv�nyek p�ld�nyos�t�sa
A ford�t� a sablon f�ggv�nyeket csak akkor p�ld�nyos�tja, amikor a f�ggv�nyt
felhaszn�ljuk.
Ennek megfeleloen egy sablon oszt�ly p�ld�nyos�t�sa nem vonja maga ut�n sem �sszes

tagj�nak p�ld�nyos�t�s�t, sem a sablon oszt�ly deklar�ci�j�ban szereplo tagok


p�ld�nyos�-
t�s�t. Ez nagy rugalmass�got biztos�t a sablon oszt�lyok meghat�roz�sakor:
template<class T> class List {
// ...
void sort();
};
C. Technikai r�szletek 1169
class Glob { /* nincs �sszehasonl�t� muvelet */ };
void f(List<Glob>& lb, List<string>& ls)
{
ls.sort();
// lb muveleteinek haszn�lata, kiv�ve az lb.sort()-ot
}
Itt a List<string>::sort() f�ggv�nyt a ford�t� p�ld�nyos�tja, de a
List<Glob>::sort() f�ggv�nyre
nincs sz�ks�g. Ez egyr�szt kevesebb k�d l�trehoz�s�t teszi lehetov�, m�sr�szt
megk�m�l
minket att�l, hogy az eg�sz programot �t kelljen szervezn�nk. Ha a
List<Glob>::sort() f�ggv
�nyt is l�trehozn� a ford�t�, akkor a Glob oszt�lyban szerepelnie kellene az
�sszes olyan
muveletnek, melyet a List::sort() felhaszn�l, a sort() f�ggv�nyt ki kellene
venn�nk a List sablonb
�l, vagy a Glob objektumokat kellene valamilyen m�s t�rol�ban t�rolnunk.
C.13.10. Explicit p�ld�nyos�t�s
A p�ld�nyos�t�st �gy k�nyszer�thetj�k ki, ha a template kulcssz� ut�n (melyet ez
esetben
nem k�vet < jel) deklar�ljuk a k�v�nt egyedi c�l� v�ltozatot:
template class vector<int>; // oszt�ly
template int& vector<int>::operator[](int); // tag
template int convert<int,double>(double); // f�ggv�ny
Teh�t egy sablon deklar�ci�ja a template< kifejez�ssel kezdodik, m�g egy
p�ld�nyos�t�si k�-
relmet a template kulcssz�val fejez�nk ki. Figyelj�k meg, hogy a template sz� ut�n
a teljes
deklar�ci� szerepel, nem el�g csak a p�ld�nyos�tani k�v�nt nevet le�rnunk:
template vector<int>::operator[]; // formai hiba
template convert<int,double>; // formai hiba
A f�ggv�nyparam�terekbol levezetheto sablonparam�terek ugyan�gy elhagyhat�k, mint
a sablon f�ggv�nyek megh�v�sakor (�13.3.1):
template int convert<int,double>(double); // rendben (felesleges)
template int convert<int>(double); // rendben
Amikor egy sablon oszt�lyt �gy p�ld�nyos�tunk, a tagf�ggv�nyekbol is l�trej�n egy
p�ld�ny.
1170 F�ggel�kek �s t�rgymutat�
Az explicit p�ld�nyos�t�s k�l�nb�zo ellenorz�sek elv�gz�s�re is felhaszn�lhat�
(�13.6.2):
template<class T> class Calls_foo {
void constraints(T t) { foo(t); } // minden konstruktorb�l megh�vand�
// ...
};
template class Calls_foo<int>; // hiba: foo(int) nem meghat�rozott
template Calls_foo<Shape*>::constraints(); // hiba: foo(Shape*) nem meghat�rozott
A p�ld�nyos�t�si k�relmek hat�sa az �sszeszerkeszt�si idore �s az �jraford�t�s
hat�konys�-
g�ra n�zve jelentos lehet. Arra is l�ttam m�r p�ld�t, hogy a sablon-
p�ld�nyos�t�sok egyetlen
ford�t�si egys�gbe val� �sszefog�s�val a ford�t�si idot n�h�ny �r�r�l n�h�ny
percre siker
�lt cs�kkenteni.
Hib�t jelent, ha ugyanarra az egyedi c�l� v�ltozatra k�t meghat�roz�s is van. Nem
sz�m�t,
hogy ezek felhaszn�l� �ltal megadottak (�13.5), automatikusan l�trehozottak
(�C.13.7),
vagy p�ld�nyos�t�si k�relemmel k�sz�ltek. A ford�t� nem k�teles �szrevenni a
t�bbsz�r�s
p�ld�nyos�t�st, ha az egyes v�ltozatok k�l�nb�zo ford�t�si egys�gekben fordulnak
elo. Ez
lehetov� teszi a felesleges p�ld�nyos�t�sok eleg�ns elker�l�s�t, �gy
megszabadulhatunk
azokt�l a probl�m�kt�l, melyek a t�bb k�nyvt�rt haszn�l� programokban az explicit
p�ld
�nyos�t�sb�l sz�rmazhatnak (�C.13.7). A szabv�ny azonban nem k�veteli meg, hogy
a megval�s�t�sok .eleg�nsak. legyenek. A .kev�sb� eleg�ns. megval�s�t�sok
haszn�l�inak
�rdemes elker�lni�k a t�bbsz�r�s p�ld�nyos�t�st. Ha ezt a tan�csot m�gsem fogadjuk
meg,
programunk . a legrosszabb esetben . nem fog futni, de a programban nem k�vetkezik
be
rejtett v�ltoz�s.
A nyelv nem k�veteli meg, hogy a felhaszn�l�k explicit p�ld�nyos�t�st
haszn�ljanak. Ez
csup�n olyan optimaliz�ci�s lehetos�g, mellyel saj�t kezuleg szab�lyozhatjuk a
ford�t�s �s
�sszeszerkeszt�s menet�t (�C.13.7).
C.14. Tan�csok
[1] A technikai r�szletek helyett �sszpontos�tsunk a programfejleszt�s eg�sz�re.
�C.1.
[2] A szabv�ny szigor� betart�sa sem garant�lja a hordozhat�s�got. �C.2.
[3] Ker�lj�k a nem meghat�rozott helyzeteket (a nyelvi bov�t�sekben is). �C.2.
C. Technikai r�szletek 1171
[4] Legy�nk tiszt�ban a megval�s�t�s-f�ggo szolg�ltat�sokkal. �C.32.
[5] A {, }, [, ], | �s ! jelek helyett csak akkor haszn�ljunk kulcsszavakat �s
digr�f jeleket,
ha ezek nem el�rhetoek az adott rendszerben; trigr�f karaktereket pedig
csak akkor, ha a \ sem �ll�that� elo g�p�nk�n. �C.3.1.
[6] Az egyszeru adatk�zl�s �rdek�ben a programok le�r�s�ra haszn�ljuk az ANSI
karaktereket. �C.3.3.
[7] A karakterek sz�mmal jel�l�se helyett lehetoleg haszn�ljuk vez�rlokarakter
megfeleloiket. �C.3.2.
[8] Soha ne haszn�ljuk ki a char t�pus elojeless�g�t vagy elojel n�lk�lis�g�t.
�C.3.4.
[9] Ha k�ts�geink vannak egy eg�sz liter�l t�pus�val kapcsolatban, haszn�ljunk
ut�tagokat. �C.4.
[10] Ker�lj�k az �rt�kveszto automatikus �talak�t�sokat. �C.6.
[11] Haszn�ljuk a vector oszt�lyt a be�p�tett t�mb�k helyett. �C.7.
[12] Ker�lj�k a union t�pus haszn�lat�t. �C.8.2.
[13] A nem �ltalunk k�sz�tett szerkezetek le�r�s�ra haszn�ljunk mezoket. �C.8.1.
[14] Figyelj�nk a k�l�nb�zo mem�riakezel�si st�lusok elonyeire �s h�tr�nyaira.
�C.9.
[15] Ne .szennyezz�k be. a glob�lis n�vteret. �C.10.1.
[16] Ha nem t�pusra, hanem �n�ll� hat�k�rre (modulra) van sz�ks�g�nk, oszt�lyok
helyett haszn�ljunk n�vtereket. �C.10.3.
[17] Sablon oszt�lyokban is megadhatunk static tagokat. �C.13.1.
[18] Ha egy sablonparam�ter tagt�pusaira van sz�ks�g�nk, az egy�rtelmus�g �rdek�-
ben haszn�ljuk a typename kulcssz�t. �C.13.5.
[19] Ha sablonparam�terekkel val� kifejezett minos�t�sre van sz�ks�g�nk,
haszn�ljuk
a template kulcssz�t a sablon oszt�ly tagjainak egy�rtelmu megad�s�hoz.
�C.13.6.
[20] A sablon meghat�roz�s�t �gy fogalmazzuk meg, hogy a leheto legkevesebbet
haszn�ljuk fel a p�ld�nyos�t�si k�rnyezetbol. �C.13.8.
[21] Ha egy sablon p�ld�nyos�t�sa t�l sok�ig tart, esetleg �rdemes explicit
p�ld�nyos
�t�st alkalmaznunk. �C.13.10.
[22] Ha a ford�t�s sorrendj�nek pontosan megj�solhat�nak kell lennie, explicit
p�ld
�nyos�t�sra lehet sz�ks�g. �C.13.10.
1172 F�ggel�kek �s t�rgymutat�
Helyi saj�toss�gok
.Ha R�m�ban j�rsz, t�gy �gy, mint a r�maiak..
A kultur�lis elt�r�sek kezel�se . A locale oszt�ly . Neves�tett lok�lok . Lok�lok
l�trehoz
�sa . Lok�lok m�sol�sa �s �sszehasonl�t�sa . A global() �s classic() lok�lok .
Karakterl
�ncok �sszehasonl�t�sa . A facet oszt�ly . Jellemzok el�r�se a lok�lokban .
Egyszeru felhaszn
�l�i facet-ek . Szabv�nyos facet-ek . Karakterl�ncok �sszehasonl�t�sa . Numerikus
I/O . P�nz I/O . D�tum �s ido I/O . Alacsonyszintu idomuveletek . Egy Date oszt�ly
.
A karakterek oszt�lyoz�sa . Karakterk�d-�talak�t�sok . �zenetkatal�gusok .
Tan�csok .
Gyakorlatok
D.1. A kultur�lis elt�r�sek kezel�se
A locale (lok�l) a helyi saj�toss�gokat jelk�pezo objektum. Olyan kultur�lis
jellemzoket tartalmaz,
mint a karakterek t�rol�s�nak �s a karakterl�ncok �sszehasonl�t�s�nak m�dja,
illetve
a sz�mok megjelen�si form�ja a kimeneten. A helyi saj�toss�gok k�re bov�theto: a
programoz
� a lok�lhoz tov�bbi olyan jellemzoket (facet; .arculat., szempont) adhat,
amelyeket
a standard k�nyvt�r nem t�mogat k�zvetlen�l. Ilyenek p�ld�ul az ir�ny�t�sz�mok
vagy a telefonsz
�mok. A locale elsodleges szerepe a standard k�nyvt�rban a kimeneti adatfolyamban
(ostream) levo adatok megjelen�t�si form�j�nak, illetve a bemeneti adatfolyamok
(istream) �ltal elfogadott inform�ci� form�tum�nak szab�lyoz�sa.
D
A �21.7 pontban m�r t�rgyaltuk, hogyan m�dos�thatjuk az adatfolyamok form�tum�t;
ez
a f�ggel�k azt �rja le, hogy �p�theto fel jellemzokbol (facet) egy locale, illetve
azt magyar�zza
el, hogyan befoly�solja a lok�l az adatfolyamot. Ismerteti a facet-ek
defini�l�s�nak m�dj
�t is, felsorolja a szabv�nyos jellemzoket, amelyekkel az adatfolyamok
tulajdons�gai be�ll
�that�k �s m�dszereket mutat be mindezek l�trehoz�s�ra �s haszn�lat�ra. Az adat-
�s
ido�br�zol�st seg�to standard k�nyvt�rbeli eszk�z�ket a d�tumok be- �s kivitel�nek
t�rgyal
�sakor mutatjuk be.
A lok�lok �s jellemzok t�rgyal�s�t a k�vetkezo r�szekre bontottam:
�D.1 A kultur�lis elt�r�sek lok�lokkal val� �br�zol�sa m�g�tt rejlo alapgondolatok

bemutat�sa
�D.2 A locale oszt�ly
�D.3 A facet oszt�ly
�D.4 A szabv�nyos jellemzok �ttekint�se �s r�szletes ismertet�se:
�D.4.1 Karakterl�ncok �sszehasonl�t�sa
�D.4.2 Sz�m�rt�kek bevitele �s kivitele
�D.4.3 P�nz�rt�kek bevitele �s kivitele
�D.4.4 D�tum �s ido bevitele �s kivitele
�D.4.5 A karakterek oszt�lyoz�sa
�D.4.6 Karakterk�d-konverzi�k
�D.4.7 �zenetkatal�gusok
A locale nem a C++ fogalma, a legt�bb oper�ci�s rendszerben �s felhaszn�l�i
k�rnyezetben
l�tezik. A helyi saj�toss�gokon (.ter�leti be�ll�t�sokon.) . elvileg . az adott
rendszerben
megtal�lhat� valamennyi program osztozik, f�ggetlen�l att�l, hogy a programok
milyen
programnyelven �r�dtak. Ez�rt a C++ standard k�nyvt�r�nak locale-j�t �gy
tekinthetj�k, mint amelynek seg�ts�g�vek a programok szabv�nyos �s .hordozhat�.
m�don
f�rhetnek hozz� olyan adatokhoz, melyek �br�zol�sa a k�l�nb�zo rendszerekben
jelento-
sen elt�r. �gy a C++ locale k�z�s fel�letet biztos�t azon rendszeradatok
el�r�s�hez, melyeket
az egyes rendszerek m�s �s m�s m�don t�rolnak.
D.1.1. A kultur�lis elt�r�sek programoz�sa
K�pzelj�k el, hogy olyan programot �runk, melyet sok orsz�gban fognak haszn�lni.
Azt,
hogy a programot olyan st�lusban �rjuk meg, ami ezt lehetov� teszi, gyakran h�vj�k
nemzetk
�zi t�mogat�snak (.internacionaliz�ci�.; ez kihangs�lyozza, hogy a programot t�bb
orsz
�gban haszn�lj�k) vagy honos�t�snak (.lokaliz�ci�nak., kihangs�lyozva a program
helyi
1174 F�ggel�kek �s t�rgymutat�
viszonyokhoz igaz�t�s�t). A program �ltal kezelt adatok n�melyike . a szok�soknak
megfelel
oen . k�l�nb�zok�ppen jelenik meg az egyes orsz�gokban. A probl�m�t �gy kezelhetj
�k, hogy a bemeneti/kimeneti elj�r�sok meg�r�s�n�l ezt figyelembe vessz�k:
void print_date(const Date& d) // ki�r�s a megfelelo form�ban
{
switch(where_am_I) // felhaszn�l�i jelzo�rt�k
{
case DK: // pl. 7. marts 1999
cout << d.day() << ". " << dk_month[d.month()] << " " << d.year();
break;
case UK: // pl. 7 / 3 / 1999
cout << d.day() << " / " << d.month() << " / " << d.year();
break;
case US: // pl. 3/7/1999
cout << d.month() << "/" << d.day() << "/" << d.year();
break;
// ...
}
}
Egy ilyen k�ddal a feladat megoldhat�, de a k�d el�g cs�nya �s csak k�vetkezetes
haszn�-
lat�val biztos�thatjuk, hogy minden kimenet megfeleloen igazodjon a helyi
szok�sokhoz.
Ami m�g enn�l is rosszabb: ha �jabb d�tumform�tummal szeretn�nk kieg�sz�teni,
m�dos�-
tanunk kell a k�dot. Felmer�lhet az �tlet, hogy a probl�m�t egy oszt�lyhierarchia
l�trehoz
�s�val oldjuk meg (�12.2.4). A Date-ben t�rolt adatok azonban f�ggetlenek a
megjelen�t�s
m�dj�t�l, �gy nem Date t�pusok (p�ld�ul US_date, UK_date, �s JP_date) rendszer�t
kell l�trehoznunk,
hanem a d�tumok megjelen�t�s�re kell megadnunk t�bbf�le m�dszert (mondjuk
amerikai, brit �s jap�n st�lus� kimenetet). L�sd m�g: �D.4.4.5.
Az .engedj�k meg a felhaszn�l�nak, hogy bemeneti/kimeneti f�ggv�nyeket �rjon �s
kezelj
�k azok a helyi saj�toss�gokat. megk�zel�t�snek is vannak buktat�i:
1. Egy rendszerfejleszto programoz� nem tudja k�nnyen, m�s rendszerre �t�ltethet
o m�don �s hat�konyan m�dos�tani a be�p�tett t�pusok megjelen�s�t a standard
k�nyvt�r seg�ts�ge n�lk�l.
2. Egy nagy programban nem mindig lehet az �sszes I/O muveletet (�s minden
olyan muveletet, amely a helyi saj�toss�gokhoz igaz�tva k�sz�t elo adatot I/Ohoz)
megtal�lni.
3. A programot n�ha nem igaz�thatjuk az �j szab�lyokhoz . �s m�g ha lehets�ges
is lenne, jobban szeretn�nk egy olyan megold�st, amely nem ig�nyel �jra�r�st.
D. Helyi saj�toss�gok 1175
4. Pazarl�s lenne minden felhaszn�l�val megterveztetni �s elk�sz�ttetni az elt�ro
helyi saj�toss�gokat kezelo programelemeket.
5. A k�l�nb�zo programoz�k k�l�nf�lek�ppen kezelik a kultur�lis elt�r�seket,
ez�rt a val�j�ban ugyanazokkal az adatokkal dolgoz� programok is k�l�nb�zni
fognak, noha alapvetoen azonosnak kellene lenni�k. �gy azoknak a programoz
�knak, akik t�bb forr�sf�jlban l�vo k�dot .tartanak karban., t�bbfajta programoz
�si megk�zel�t�st kell megtanulniuk, ami f�raszt� �s hibalehetos�get rejt
mag�ban.
K�vetkez�sk�ppen a standard k�nyvt�r a helyi saj�toss�gok kezel�s�hez bov�theto
elj�r�sgy
ujtem�nyt k�n�l. Az iostream k�nyvt�r (�21.7) mind a be�p�tett, mind a
felhaszn�l�i t�pusok
kezel�s�hez ezekre az elj�r�sokra t�maszkodik. Vegy�nk p�ld�ul egy egyszeru
ciklust,
amely m�r�sek sorozat�t vagy tranzakci�k egy halmaz�t �br�zol� (Date, double)
p�rokat
m�sol:
void cpy(istream& is, ostream& os) // (Date,double) adatfolyamot m�sol
{
Date d;
double volume;
while (is >> d >> volume) os << d << � � << volume << �\n�;
}
Egy val�di program term�szetesen csin�lna valamit a rekordokkal �s egy kicsit
jobban t�-
rodne a hibakezel�ssel is.
Hogyan k�sz�thet�nk ebbol egy olyan programot, amely a francia szok�soknak
megfelelo
f�jlt olvas be (ahol . a magyarhoz hasonl�an . vesszot haszn�lnak a .tizedespont.
jel�l�s�-
re a lebegopontos sz�mokban; p�ld�ul a 12,5 jelent�se tizenketto �s f�l) �s az
amerikai form
�nak megfeleloen �rja azt ki? Lok�lok �s I/O muveletek meghat�roz�s�val a cpy()-t
haszn
�lhatjuk az �talak�t�sra:
void f(istream& fin, ostream& fout, istream& fin2, ostream& fout2)
{
fin.imbue(locale("en_US")); // amerikai angol
fout.imbue(locale("fr")); // francia
cpy(fin,fout); // amerikai angol olvas�s, francia �r�s
fin2.imbue(locale("fr")); // francia
fout2.imbue(locale("en_US")); // amerikai angol
cpy(fin2,fout2); // francia olvas�s, amerikai angol �r�s
}
1176 F�ggel�kek �s t�rgymutat�
Ha adottak a k�vetkezo adatfolyamok,
Apr 12, 1999 1000.3
Apr 13, 1999 345.45
Apr 14, 1999 9688.321
...
3 juillet 1950 10,3
3 juillet 1951 134,45
3 juillet 1952 67,9
...
a program a k�vetkezot fogja ki�rni:
12 avril 1999 1000,3
13 avril 1999 345,45
14 avril 1999 9688,321
...
July 3, 1950 10.3
July 3, 1951 134.45
July 3, 1952 67.9
...
A f�ggel�k tov�bbi r�sz�nek legjav�t annak szentelj�k, hogy le�rjuk, milyen nyelvi
tulajdons
�gok teszik ezt lehetov�, illetve hogy elmagyar�zzuk, hogyan haszn�ljuk azokat.
Jegyezz
�k meg, hogy a programoz�k t�bbs�g�nek nem kell r�szletekbe menoen foglalkoznia
a lok�lokkal vagy kifejezetten azokat kezelo k�dot �rnia. Akik m�gis megteszik,
azok is legink
�bb egy szabv�nyos locale-t fognak elokeresni, hogy az adott adatfolyamnak
elo�rj�k annak
haszn�lat�t (�21.7). Azok az elj�r�sok azonban, melyekkel a lok�lokat
l�trehozhatjuk �s
haszn�latukat egyszeruv� tehetj�k, .saj�t. programnyelvet alkotnak.
Ha egy program vagy rendszer sikeres, olyanok is haszn�lni fogj�k, akiknek az
ig�nye �s
�zl�se elt�r att�l, amire az eredeti tervezok �s programoz�k sz�m�tottak. A
legt�bb sikeres
programot haszn�lni fogj�k azokban az orsz�gokban is, ahol a (term�szetes) nyelvek
�s karakterk
�szletek elt�rnek az eredeti tervezok �s programoz�k �ltal ismertektol. Egy
program
sz�lesk�ru haszn�lata a siker jele, ez�rt a nyelvi �s kultur�lis hat�rok k�z�tt
�tviheto programok
tervez�se �s �r�sa a sikerre val� felk�sz�l�st jelenti.
A .nemzetk�zi t�mogat�s. fogalma egyszeru, a gyakorlati megszor�t�sok azonban a
locale
objektumok elk�sz�t�s�t meglehetosen bonyolultt� teszik:
1. A lok�lok az olyan helyi saj�toss�gokat tartalmazz�k, mint a d�tumok megjelen
�si form�ja. A szab�lyok azonban egy adott kult�r�n bel�l is sz�mos apr� �s
D. Helyi saj�toss�gok 1177
nem rendszerezheto m�don elt�rhetnek. A helyi szok�soknak semmi k�z�k
a programnyelvekhez, ez�rt egy programnyelv nem szabv�nyos�thatja azokat.
2. A lok�loknak bov�thetonek kell lenni�k, mert nem lehets�ges az �sszes helyi
saj�toss�got felsorolni, amely minden C++ felhaszn�l�nak fontos.
3. A locale objektumokat olyan I/O muveletekben haszn�ljuk, melyekn�l a fut�si
ido igen fontos.
4. A locale objektumoknak l�thatatlannak kell lenni�k a legt�bb programoz� sz�-
m�ra, hiszen ok an�lk�l szeretn�k kihaszn�lni a .megfelelo dolgot v�gzo.
adatfolyam-
bemenetet �s -kimenetet, hogy pontosan ismern�k annak fel�p�t�s�t,
megval�s�t�s�t.
5. A lok�loknak el�rhetonek kell lenni�k azok sz�m�ra, akik olyan eszk�z�ket
terveznek,
amelyek helyi saj�toss�gokt�l f�ggo adatokat kezelnek az adatfolyam
I/O k�nyvt�r keretein k�v�l.
Egy bemeneti �s kimeneti muveleteket v�gzo program tervez�sekor v�lasztanunk kell,

hogy a kimenet form�tum�t .szok�sos k�ddal. vagy locale-ek felhaszn�l�s�val


vez�relj�ke.
Az elobbi (hagyom�nyos) megk�zel�t�s ott c�lszeru, ahol biztos�tani tudjuk, hogy
minden
bemeneti muveletet k�nnyen �t lehet alak�tani a helyi saj�toss�goknak megfeleloen.

Ha azonban a be�p�tett t�pusok megjelen�s�nek kell v�ltoznia, ha k�l�nb�zo


karakterk�szletekre
van sz�ks�g, vagy ha a bemenetre/kimenetre vonatkoz� szab�lyok halmazai k�z�tt
kell v�lasztanunk, a locale objektumok haszn�lata tunik �sszerubbnek.
A locale objektumok �gynevezett facet-ekbol �llnak, amelyek az egyes jellemzoket
(lebeg
opontos �rt�k ki�r�sakor haszn�lt elv�laszt� karakter (decimal_point(), �D.4.2),
p�nz�rt�k
beolvas�sakor haszn�lt form�tum (moneypunct, �D.4.3) stb.) szab�lyozz�k. A facet
egy,
a locale::facet oszt�lyb�l sz�rmaz� oszt�ly objektuma (�D.3); legink�bb �gy
k�pzelhetj�k
el, hogy a locale facet-ek t�rol�ja (�D.2, �D.3.1).
D.2. A locale oszt�ly
A locale oszt�ly �s a hozz� tartoz� szolg�ltat�sok a <locale> fej�llom�nyban
tal�lhat�k:
class std::locale {
public:
class facet; // lok�ljellemzoket tartalmaz� t�pus, �D.3
class id; // lok�lt azonos�t� t�pus, �D.3
typedef int category; // facet-ek csoportos�t�s�ra szolg�l� t�pus
1178 F�ggel�kek �s t�rgymutat�
static const category // a t�nyleges �rt�kek megval�s�t�sf�ggoek
none = 0,
collate = 1,
ctype = 1<<1,
monetary = 1<<2,
numeric = 1<<3,
time = 1<<4,
messages = 1<<5,
all = collate | ctype | monetary | numeric | time | messages;
locale() throw(); // a glob�lis lok�l m�solata (�D.2.1)
locale(const locale& x) throw(); // x m�solata
explicit locale(const char* p); // a p nevu lok�l m�solata (�D.2.1)
~locale() throw();
locale(const locale& x, const char* p, category c); // x m�solata, plusz p-beli c
facet-ek
locale(const locale& x, const locale& y, category c); // x m�solata, plusz y-beli
c facet-ek
template <class Facet> locale(const locale& x, Facet* f); // x m�solata, plusz az
f facet
template <class Facet> locale combine(const locale& x); // *this m�solata,
// plusz az x-beli Facet
const locale& operator=(const locale& x) throw();
bool operator==(const locale&) const; // lok�lok �sszehasonl�t�sa
bool operator!=(const locale&) const;
string name() const; // az adott lok�l neve (�D.2.1)
template <class Ch, class Tr, class A> // karakterl�ncok �sszehasonl�t�sa
// az adott lok�l seg�ts�g�vel
bool operator()(const basic_string<Ch,Tr,A>&, const basic_string<Ch,Tr,A>&) const;

static locale global(const locale&); // a glob�lis lok�l be�ll�t�sa �s visszat�r�s


a r�givel
static const locale& classic(); // a "klasszikus" C-st�lus� lok�l
private:
// �br�zol�s
};
A locale-ekre �gy gondolhatunk, mint map<id,facet*>-ek fel�let�re, vagyis valami
olyasmire,
ami lehetov� teszi, hogy egy locale::id seg�ts�g�vel megtal�ljuk a megfelelo
objektumot,
amelynek oszt�lya a locale::facet-bol sz�rmazik. A locale megval�s�t�sa alatt az e
gondolat
alapj�n elk�sz�tett (hat�kony) szerkezeteket �rtj�k. Az elrendez�s ilyesmi lesz:
D. Helyi saj�toss�gok 1179
Itt a collate<char> �s a numpunct<char> a standard k�nyvt�r facet-jei (�D.4). Mint
mindegyik
facet, ezek is a locale::facet-bol sz�rmaznak.
A locale-nek szabadon �s .olcs�n. m�solhat�nak kell lennie. K�vetkez�sk�ppen a
locale-t
majdnem mindig �gy val�s�tj�k meg, mint egy le�r�t arra a .szakos�tott.
map<id,facet*>-re,
amely a szolg�ltat�sok legt�bbj�t tartalmazza. A lok�l jellemzoinek (a facet-
eknek) gyorsan
el�rhetonek kell lenni�k, ez�rt az egyedi c�l� map<id,facet*> a t�mb�kh�z hasonl�
gyors
hozz�f�r�st kell, hogy ny�jtson. A locale jellemzoinek el�r�se a
use_facet<Facet>(loc) jel�-
l�ssel t�rt�nik (l�sd �D.3.1-et).
A standard k�nyvt�r a facet-ek gazdag v�laszt�k�t ny�jtja. A programoz� ezeket
logikai csoportokban
kezelheti, mert a szabv�nyos facet-ek kateg�ri�kat alkotnak (pl. numeric �s
collate, �D.4).
A programoz� az egyes kateg�ri�kban levo jellemzoket kicser�lheti (�D.4,
�D.4.2.1), de
nem adhat meg �j kateg�ri�kat. A .kateg�ria. fogalma csak a standard k�nyvt�rbeli
facetekre
vonatkozik, nem terjesztheto ki a felhaszn�l�i jellemzokre. Ez�rt nem sz�ks�ges,
hogy
egy facet kateg�ri�ba tartozzon �s sok felhaszn�l�i facet nem is tartozik ilyenbe.

A lok�lokat messze a leggyakrabban az adatfolyamok bemeneti �s kimeneti


muveletin�l
haszn�ljuk, m�g ha nem is tudunk r�la. Minden istream �s ostream rendelkezik saj�t
lok�llal.
Az adatfolyamok lok�lja a folyam l�trehoz�s�nak pillanat�ban alap�rtelmez�s
szerint
a glob�lis locale (�D.2.1) lesz. A folyam lok�lj�t az imbue() (.megt�lt�s.)
muvelettel lehet
be�ll�tani, a locale m�solat�t pedig a getloc() f�ggv�nnyel kaphatjuk meg
(�21.6.3).
1180 F�ggel�kek �s t�rgymutat�
decimal_point ( )
truename ( )
...
compare ( )
hash ( )
...
locale:
collate<char>:
numpunct<char>:
D.2.1. Neves�tett lok�lok
A lok�lok m�sik locale-bol �s jellemzokbol hozhat�k l�tre. A legegyszerubb egy m�r
l�tez
o locale lem�sol�sa:
locale loc0; // az �rv�nyes glob�lis lok�l m�solata (�D.2.3)
locale loc1 = locale(); // az �rv�nyes glob�lis lok�l m�solata (�D.2.3)
locale loc2(""); // a felhaszn�l� �ltal elonyben r�szes�tett lok�l
m�solata
locale loc3("C"); // a "C" lok�l m�solata
locale loc4 = locale::classic(); // a "C" lok�l m�solata
locale loc5("POSIX"); // az adott fejlesztok�rnyezet �ltal meghat�rozott
// "POSIX" lok�l m�solata
A locale(.C.) jelent�s�t a szabv�ny .klasszikus C lok�lk�nt. hat�rozza meg; ebben
a k�nyvben
v�gig ezt a lok�lt haszn�ljuk. A t�bbi locale neve a haszn�lt C++-v�ltozatt�l
f�gg.
A locale(..) a .felhaszn�l� �ltal elonyben r�szes�tett. lok�l, melyet a program
v�grehajt�si
k�rnyezet�ben a nyelven k�v�li eszk�z�k �ll�tanak be.
A legt�bb oper�ci�s rendszer biztos�t valamilyen eszk�zt a programok .ter�leti
be�ll�t�sainak
. megad�s�ra. A be�ll�t�sra legt�bbsz�r akkor ker�l sor, amikor a felhaszn�l�
elosz�r tal
�lkozik a rendszerrel. Egy olyan g�pen p�ld�ul, ahol a rendszer alap�rtelmezett
nyelvek�nt
az argentin spanyolt adt�k meg, a locale(..) val�sz�nuleg a locale(.es_AR.)-t
jelenti.
Az egyik rendszerem gyors ellenorz�se 51 megjegyezheto n�vvel rendelkezo lok�lt
mutatott
ki (p�ld�ul POSIX, de, en_UK, en_US, es, es_AR, fr, sv, da, pl, �s iso_8859_1). A
POSIX
�ltal aj�nlott form�tum: kisbetus nyelvn�v, amit nagybetus orsz�gn�v k�vet (ez nem
k�telez
o), valamint egy k�djelzo (ez sem k�telezo); p�ld�ul jp_JP.jit. Ezek a nevek
azonban
nem szabv�nyos�tottak a k�l�nb�zo platformok k�z�tt. Egy m�sik rendszerben egy�b
locale nevek mellett a k�vetkezoket tal�ltam: g, uk, us, s, fr, sw, �s da. A C++
szabv�ny nem
adja meg az orsz�gok �s nyelvek locale-j�t, b�r az egyes platformokra l�tezhetnek
szabv�-
nyok. K�vetkez�sk�ppen, ha a programoz� neves�tett lok�lokat akar haszn�lni, a
rendszer
dokument�ci�j�ra �s tapasztalataira kell hagyatkoznia.
�ltal�ban c�lszeru elker�lni a lok�lneveket jelzo karakterl�ncok programsz�vegbe
�gyaz�-
s�t. A f�jlnevek �s .rendszer�lland�k. programban val� szerepeltet�se korl�tozza a
program
hordozhat�s�g�t, a programot �j k�rnyezetbe beilleszteni k�v�n� programoz� pedig
gyakran arra k�nyszer�l, hogy megkeresse ezeket az �rt�keket, hogy m�dos�thassa
azokat.
D. Helyi saj�toss�gok 1181
A lok�lnevek megeml�t�se is hasonl� kellemetlen k�vetkezm�nyekkel j�r. Jobb, ha a
lok�-
lokat kivessz�k a program v�grehajt�si k�rnyezet�bol (p�ld�ul a locale(..)
felhaszn�l�s�-
val) vagy a programra b�zzuk, hogy a tapasztaltabb felhaszn�l�kt�l a lok�l
meghat�roz�s�t
k�rje, mondjuk egy karakterl�nc bek�r�s�vel:
void user_set_locale(const string& question_string)
{
cout << question_string; // pl. "Ha m�s lok�lt k�v�n haszn�lni, adja meg a nev�t"
string s;
cin >> s;
locale::global(locale(s.c_str())); // a felhaszn�l� �ltal megadott glob�lis lok�l
be�ll�t�sa
}
A kezdo felhaszn�l�k sz�m�ra �ltal�ban jobb, ha lehetov� tessz�k, hogy list�b�l
v�laszthassanak.
Az ezt kezelo elj�r�snak viszont tudnia kell, hol �s hogyan t�rolja a rendszer a
lok�lokat.
Ha a param�terk�nt megadott karakterl�nc nem defini�lt locale-re hivatkozik, a
konstruktor
runtime_error kiv�telt v�lt ki (�14.10):
void set_loc(locale& loc, const char* name)
try
{
loc = locale(name);
}
catch (runtime_error) {
cerr << "A \"" << name << "\" lok�l nem defini�lt.\n";
// ...
}
Ha a locale neves�tett, a name() visszaadja annak nev�t, ha nem, a string(.*.)-gal
t�r vissza.
A n�v elsosorban arra val�, hogy hivatkozhassunk a v�grehajt�si k�rnyezetben
t�rolt lok�-
lokra, de a hibakeres�sben is seg�thet:
void print_locale_names(const locale& my_loc)
{
cout << "name of current global locale: " << locale().name() << "\n";
cout << "name of classic C locale: " << locale::classic().name() << "\n";
cout << "name of ..user�s preferred locale��: " << locale("").name() << "\n";
cout << "name of my locale: " << my_loc.name() << "\n";
}
Az alap�rtelmezett string(.*.)-t�l elt�ro, de azonos nevu lok�lok
�sszehasonl�t�skor egyen-
�rt�kunek minos�lnek, az == vagy != oper�torokkal azonban az �sszehasonl�t�s
k�zvetlenebb
m�don is elv�gezheto.
1182 F�ggel�kek �s t�rgymutat�
A n�vvel rendelkezo locale-ek m�solatai ugyanazt a nevet kapj�k, mint az eredeti
locale (ha
annak van neve), �gy azonos n�ven t�bb locale is szerepelhet. Ez logikus, mert a
lok�lok
nem m�dos�that�k, �gy ezen objektumok mindegyike a helyi saj�toss�gok ugyanazon
halmaz
�t �rja le.
A locale(loc,.Foo.,cat) h�v�s a loc-hoz hasonl� lok�lt hoz l�tre, de annak
jellemzoit (a faceteket)
a locale(.Foo.) cat kateg�ri�j�b�l veszi. Az eredm�ny�l kapott lok�lnak kiz�r�lag
akkor
lesz neve, ha a loc-nak is volt. A szabv�ny nem hat�rozza meg pontosan, milyen
nevet
kap az �j locale, de felteheto, hogy k�l�nb�zni fog a loc-�t�l. A legegyszerubb,
ha a nevet
a loc nev�bol �s a .Foo.-b�l �p�tj�k fel. P�ld�ul ha a loc neve en_UK, az �j lok�l
neve
.en_UK:Foo. lesz.
Az �j lok�lok elnevez�s�re vonatkoz� szab�lyok a k�vetkezok�ppen foglalhat�k
�ssze:
A programoz� az �jonnan l�trehozott locale-ek nevek�nt nem adhat meg C st�lus�
karakterl
�ncot. A neveket a program v�grehajt�si k�rnyezete hat�rozza meg vagy a locale
konstruktorok �p�tik fel azokat a nevek p�ros�t�s�b�l.
D.2.1.1. �j lok�lok l�trehoz�sa
�j locale objektumot �gy k�sz�thet�nk, hogy vesz�nk egy m�r l�tezo locale-t �s
ehhez jellemz
oket adunk vagy kicser�l�nk benne n�h�nyat. Az �j locale-ek jellemzoen egy m�r l�-

tezo locale kiss� elt�ro v�ltozatai:


D. Helyi saj�toss�gok 1183
Lok�l N�v
locale(.Foo.) .Foo.
locale(loc) loc.name()
locale(loc,.Foo.,cat) �j n�v, ha a loc-nak van neve; egy�bk�nt
string(.*.)
locale(loc,loc2,cat) �j n�v, ha a loc-nak �s a loc2-nek is van
neve; egy�bk�nt string(.*.)
locale(loc,Facet) string(.*.)
loc.combine(loc2) string(.*.)
void f(const locale& loc, const My_money_io* mio) // A �D.4.3.1-ben le�rt
"My_money_io"
{
locale loc1(locale("POSIX"), loc, locale::monetary); // A loc-beli p�nzform�tum-
// jellemzok haszn�lata
locale loc2 = locale(locale::classic(), mio); // a klasszikus, plusz "mio"
// ...
}
Itt loc1 a POSIX lok�l m�solata, amit �gy m�dos�tottunk, hogy a loc p�nzform�tum-
jellemz
oit haszn�lja (�D.4.3). Ehhez hasonl�an, loc2 a C lok�l m�solata, amely a
My_money_io-t
haszn�lja (�D.4.3.1). Ha a Facet* param�ter (itt a My_money_io) �rt�ke 0, az
eredm�ny�l
kapott lok�l egyszeruen a locale param�ter m�solata lesz.
Ha a k�vetkezot �rjuk,
locale(const locale& x, Facet* f);
az f param�ternek egy meghat�rozott facet t�pust kell jel�lnie. Egy egyszeru
facet* nem elegend
o:
void g(const locale::facet* mio1, const My_money_io* mio2)
{
locale loc3 = locale(locale::classic(), mio1); // hiba: a facet t�pusa nem ismert
locale loc4 = locale(locale::classic(), mio2); // rendben: a facet t�pusa ismert
// ...
}
Ennek az az oka, hogy a locale a Facet* param�ter t�pus�t haszn�lja arra, hogy
ford�t�si ido-
ben meg�llap�tsa a facet t�pus�t. Pontosabban, a locale megval�s�t�sa a jellemzo
azonos�t�-
j�t, a facet::id-t (�D.3.3) haszn�lja, hogy a jellemzot megtal�lja a lok�lban
(�D.3.1).
Jegyezz�k meg, hogy a
template <class Facet> locale(const locale& x, Facet* f);
konstruktor a nyelv �ltal ny�jtott egyetlen elj�r�s a programoz� sz�m�ra, hogy
facet-eket
adhasson meg, melyeket egy locale-en kereszt�l haszn�lni lehet. Az egy�b lok�lokat
a megval
�s�t� programoz�knak kell megadniuk, neves�tett locale-ek form�j�ban (�D.2.1),
melyeket
a program v�grehajt�si k�rnyezet�bol lehet megszerezni. Ha a programoz� �rti az
erre
haszn�latos . a fejlesztok�rnyezettol f�ggo . elj�r�st, a meglevo lok�lok k�r�t
�jakkal bo-
v�theti (�D.6[11,12]).
1184 F�ggel�kek �s t�rgymutat�
A lok�lok konstruktorainak halmaz�t �gy tervezt�k, hogy minden jellemzo t�pusa
meg�llap
�that� legyen, vagy t�puslevezet�s �tj�n (a Facet sablonparam�ter t�pus�b�l), vagy
az�rt,
mert egy m�sik lok�lb�l sz�rmazik, amely ismerte a jellemzo t�pus�t. A category
param�ter
megad�s�val a facet-ek t�pus�t k�zvetett m�don is meghat�rozhatjuk, hiszen a
lok�lok ismerik
a kateg�ri�kban l�vo jellemzok t�pus�t. Ebbol k�vetkezik, hogy a locale oszt�ly
nyomon
k�vetheti a facet-ek t�pus�t, �gy azokat k�l�n�sebb t�bbletterhel�s n�lk�l
m�dos�thatja is.
A lok�l a facet t�pusok azonos�t�s�ra a locale::id tagt�pust haszn�lja (�D.3).
N�ha hasznos lehet olyan lok�lt l�trehozni, amely egy m�sik lok�l m�solata, de az
egyik jellemz
oje egy harmadik lok�lb�l sz�rmazik. A combine() sablon tagf�ggv�ny erre val�:
void f(const locale& loc, const locale& loc2)
{
locale loc3 = loc.combine< My_money_io >(loc2);
// ...
}
Az eredm�ny�l kapott loc3 �gy viselkedik, mint a loc, de a p�nzform�tumot a loc2-
ben lev
o My_money_io (�D.4.3.1) m�solata alapj�n �ll�tja be. Ha a loc2 nem rendelkezik
a My_money_io-val, hogy �tadhassa azt az �j lok�lnak, a combine() runtime_error-t
(�14.10) v�lt ki. A combine() eredm�nyek�nt kapott lok�l nem neves�tett.
D.2.2. Lok�lok m�sol�sa �s �sszehasonl�t�sa
A lok�lok kezdeti vagy egyszeru �rt�kad�ssal m�solhat�k:
void swap(locale& x, locale& y) // ugyanaz, mint az std::swap()
{
locale temp = x;
x = y;
y = temp;
}
A m�solat az eredetivel egyen�rt�ku, de f�ggetlen, �n�ll� objektum:
void f(locale* my_locale)
{
locale loc = locale::classic(); // "C" lok�l
if (loc != locale::classic()) {
cerr << "Hiba a megval�s�t�sban: �rtes�tse a k�sz�tot.\n";
D. Helyi saj�toss�gok 1185
exit(1);
}
if (&loc != &locale::classic()) cout << "Nem meglepo: a c�mek k�l�nb�znek.\n";
locale loc2 = locale(loc, my_locale, locale::numeric);
if (loc == loc2) {
cout << "a classic() hasonl� facet-j�ben levokkel.\n";
// ...
}
// ...
}
Ha a my_locale rendelkezik olyan jellemzovel, amely a classic() lok�l szabv�nyos
numpunct<char>-j�t�l elt�roen adja meg a sz�mok elv�laszt� �r�sjeleit
(my_numpunct<char>),
az eredm�ny�l kapott lok�lok a k�vetkezok�ppen lesznek �br�zolhat�k:
1186 F�ggel�kek �s t�rgymutat�
compare ( )
hash ( )
...
decimal_point ( )
curr_symbol ( )
...
decimal_point ( )
curr_symbol ( )
...
loc:
collate<char>:
numpunct<char>:
my_numpunct<char>:
loc2:
A locale objektumok nem m�dos�that�k, muveleteik viszont lehetov� teszik �j
lok�lok l�trehoz
�s�t a m�r meglevokbol. A l�trehoz�s ut�ni m�dos�t�s tilt�sa (a lok�l .nem
v�ltoz�-
kony., immutable term�szete) alapveto fontoss�g� a fut�si ideju hat�konys�g
�rdek�ben,
ez teszi ugyanis lehetov� a felhaszn�l� sz�m�ra, hogy megh�vja a facet-ek
virtu�lis f�ggv�-
nyeit �s t�rolja a visszaadott �rt�keket. A bemeneti adatfolyamok p�ld�ul an�lk�l
tudhatj�k,
milyen karakter haszn�latos a tizedesvesszo (pontosabban .tizedespont.) jelz�s�re,
illetve
an�lk�l ismerhetik a true �br�zol�s�t, hogy minden egyes alkalommal megh�vn�k .
sz�m
beolvas�sakor . a decimal_point() f�ggv�nyt vagy . logikai �rt�k beolvas�sakor .
a truename()-et (�D.4.2). Csak az imbue() megh�v�sa az adatfolyamra (�21.6.3)
okozhatja,
hogy ezek a h�v�sok k�l�nb�zo �rt�keket adjanak vissza.
D.2.3. A global() �s classic() lok�lok
A programban �rv�nyben levo lok�l m�solat�t a locale() adja vissza, a
locale::global(x) pedig
x-re �ll�tja azt. Az �rv�nyes lok�lt gyakran .glob�lis lok�lnak. h�vj�k, utalva
arra, hogy
val�sz�nuleg glob�lis (vagy statikus) objektum.
Az adatfolyamok l�trehoz�sukkor automatikusan .felt�ltodnek. (imbue; �21.1,
�21.6.3)
a glob�lis lok�llal, vagyis a locale() m�solat�val, ami elosz�r mindig a
szabv�nyos C
locale::classic().
A locale::global() statikus tagf�ggv�ny megengedi, hogy a programoz� meghat�rozza,
melyik
lok�l legyen glob�lis. Az elozo m�solat�t a global() f�ggv�ny adja vissza; ennek
seg�ts
�g�vel a felhaszn�l� vissza�ll�thatja az eredeti glob�lis lok�lt:
void f(const locale& my_loc)
{
ifstream fin1(some_name); // fin1 felt�lt�se a glob�lis lok�llal
locale& old_global = locale::global(my_loc); // �j glob�lis lok�l be�ll�t�sa
ifstream fin2(some_other_name); // fin2 felt�lt�se a my_loc lok�llal
// ...
locale::global(old_global); // a r�gi glob�lis lok�l vissza�ll�t�sa
}
Ha az x lok�l rendelkezik n�vvel, a locale::global(x) szint�n a C glob�lis lok�lt
�ll�tja be. Ebb
ol k�vetkezik, hogy egy vegyes (C �s C++) programban egys�gesen �s k�vetkezetesen
kezelhetj
�k a lok�lt, ha megh�vjuk a C standard k�nyvt�r�nak valamelyik lok�lf�ggv�ny�t.
Ha az x lok�lnak nincs neve, akkor nem meghat�rozhat�, hogy a locale::global(x)
befoly�-
solja-e a C glob�lis lok�lt, vagyis a C++ programok nem k�pesek megb�zhat�an
(�s .hordozhat
� m�don.) �t�ll�tani a C lok�lt egy olyan lok�lra, amely nem a v�grehajt�si
k�rnye-
D. Helyi saj�toss�gok 1187
zetbol val�. Nincs szabv�nyos m�d arra sem, hogy egy C program be�ll�thassa a C++
glob
�lis lok�lt (kiv�ve ha megh�v egy C++ f�ggv�nyt, ami ezt megteszi), ez�rt a hib�k
elker�-
l�se �rdek�ben a vegyes programokban nem c�lszeru a global()-t�l elt�ro C glob�lis
lok�lt
haszn�lni.
A glob�lis lok�l be�ll�t�sa nincs hat�ssal a m�r l�tezo I/O adatfolyamokra; azok
ugyanazt
a lok�lt fogj�k haszn�lni, amivel eredetileg felt�ltodtek. A fin1-re p�ld�ul nem
hat a glob�-
lis lok�l m�dos�t�sa, de a fin2-t a muvelet a my_loc-kal t�lti fel.
A glob�lis lok�l m�dos�t�s�val ugyanaz a probl�ma, mint a glob�lis adatokat
megv�ltoztat
� egy�b elj�r�sokkal: l�nyeg�ben nem tudhat�, mire van hat�ssal a v�ltoztat�s.
Ez�rt a legjobb,
ha a global()-t a leheto legkevesebbszer haszn�ljuk �s a m�dos�t�st olyan
k�dr�szletekre
korl�tozzuk, ahol annak hat�sa pontosan nyomon k�vetheto. Szerencs�re ezt seg�ti
az a lehetos�g, hogy az adatfolyamokat meghat�rozott lok�lokkal t�lthetj�k meg
(imbue,
�21.6.3). Az�rt vigy�zzunk: ha a programban elsz�rva sz�mos explicit locale- �s
facet-kezel
o k�d tal�lhat�, a program nehezen lesz fenntarthat� �s m�dos�that�.
D.2.4. Karakterl�ncok �sszehasonl�t�sa
A lok�lokat t�bbnyire arra haszn�ljuk, hogy �sszehasonl�tsunk k�t karakterl�ncot
egy
locale alapj�n. Ezt a muveletet maga a locale ny�jtja, a felhaszn�l�knak nem kell
saj�t �sszehasonl
�t� elj�r�st �rniuk a collate jellemzobol (�D.4.1). Az elj�r�s a lok�l operator()
() �sszehasonl
�t� f�ggv�nye, �gy k�zvetlen�l haszn�lhat� predik�tumk�nt (�18.4.2):
void f(vector<string>& v, const locale& my_locale)
{
sort(v.begin(), v.end()); // rendez�s a glob�lis lok�l szerint
// ...
sort(v.begin(), v.end(), my_locale); // rendez�s a my_locale szab�lyai szerint
// ...
}
Alap�rtelmez�s szerint a standard k�nyvt�rbeli sort() a < muveletet alkalmazza a
karakterek
sz�m�rt�k�re, hogy eld�ntse a rendez�si sorrendet (�18.7, �18.6.3.1).
Jegyezz�k meg, hogy a lok�lok basic_string-eket hasonl�tanak �ssze, nem C
st�lus�akat.
1188 F�ggel�kek �s t�rgymutat�
D.3. Jellemzok
A jellemzok (facet-ek) a lok�l facet tagoszt�ly�b�l sz�rmaztatott oszt�lyok
objektumai:
class std::locale::facet {
protected:
explicit facet(size_t r = 0); // "r==0": a lok�l szab�lyozza a facet �lettartam�t
virtual ~facet(); // figyelem: v�dett destruktor
private:
facet(const facet&); // nem meghat�rozott
void operator=(const facet&); // nem meghat�rozott
// �br�zol�s
};
A m�sol� muveletek priv�t tagok �s sz�nd�kosan nincsenek defini�lva, hogy a
m�sol�st
megakad�lyozz�k (�11.2.2).
A facet oszt�ly b�zisoszt�ly szerepet t�lt be, nyilv�nos f�ggv�nye nincs.
Konstruktora v�-
dett, hogy megakad�lyozza az .egyszeru facet. objektumok l�trehoz�s�t, destruktora
pedig
virtu�lis, hogy biztos�tsa a sz�rmazott oszt�lybeli objektumok megfelelo
megsemmis�t�s�t.
A jellemzok kezel�s�t a lok�lok elvileg mutat�kon kereszt�l v�gzik. A facet
konstruktor�nak 0 �rt�ku param�tere azt jelenti, hogy a lok�lnak t�r�lnie kell az
adott jellemz
ot, ha m�r nincs r� hivatkoz�s. Ezzel szemben a nem nulla konstruktor-param�ter
azt
biztos�tja, hogy a locale sohasem t�rli a jellemzot. Ez az a ritka eset, amikor a
facet �lettartam
�t a programoz� k�zvetlen�l, nem a lok�lon kereszt�l szab�lyozza.
A collate_byname<char> szabv�nyos facet t�pus� objektumokat p�ld�ul �gy hozhatjuk
l�tre
(�D.4.1.1):
void f(const string& s1, const string& s2)
{
// szok�sos eset: a 0 (alap�rtelmezett) param�ter azt jelzi,
// hogy a lok�l felel a felsz�mol�s�rt
collate<char>* p = new collate_byname<char>("pl");
locale loc(locale(), p);
// ritka eset: a param�ter �rt�ke 1, teh�t a felhaszn�l� felel a felsz�mol�s�rt
collate<char>* q = new collate_byname<char>("ge",1);
collate_byname<char> bug1("sw"); // hiba: lok�lis v�ltoz�t nem lehet felsz�molni
collate_byname<char> bug2("no",1); // hiba: lok�lis v�ltoz�t nem lehet felsz�molni

// ...
D. Helyi saj�toss�gok 1189
// q nem t�r�lheto: a collate_byname<char> destruktora v�dett
// nincs "delete p", mert a lok�l int�zi *p felsz�mol�s�t
}
Azaz a szabv�nyos facet-ek a lok�l �ltal kezelt b�zisoszt�lyk�nt hasznosak, ritk�n
kell m�s
m�don kezeln�nk azokat.
A _byname() v�gzod�su jellemzok a v�grehajt�si k�rnyezetben tal�lhat� neves�tett
lok�l
facet-jei (�D.2.1).
Minden facet-nek rendelkeznie kell azonos�t�val (id), hogy a lok�lban a
has_facet() �s
use_facet() f�ggv�nyekkel megtal�lhat� legyen (�D.3.1):
class std::locale::id {
public:
id();
private:
id(const id&); // nem defini�lt
void operator=(const id&); // nem defini�lt
// �br�zol�s
};
A m�sol� muveletek priv�tok �s nincsenek kifejtve, hogy a m�sol�st megakad�lyozz�k

(�11.2.2).
Az azonos�t� arra val�, hogy a jellemzok sz�m�ra �j fel�letet ad� oszt�lyokban
(p�ld�ul
l�sd �D.4.1-et) id t�pus� statikus tagokat hozhassunk l�tre. A lok�lok elj�r�sai
az id-t haszn
�lj�k a facet-ek azonos�t�s�ra (�D.2, �D.3.1). Az azonos�t�k t�bbnyire egy facet-
ekre hivatkoz
� mutat�kb�l �ll� vektor index�rt�kei (vagyis map<id,facet*>, ami igen hat�kony).
A (sz�rmaztatott) jellemzoket meghat�roz� adatokat a sz�rmaztatott oszt�ly �rja
le, nem maga
a facet b�zisoszt�ly. Ebbol k�vetkezik, hogy a programoz� tetszoleges mennyis�gu
adatot
haszn�lhat a facet fogalm�nak �br�zol�s�ra �s korl�toz�s n�lk�l m�dos�thatja
azokat.
Jegyezz�k meg, hogy a felhaszn�l�i facet-ek minden f�ggv�ny�t const tagk�nt kell
meghat
�rozni, mert a facet-eknek �lland�nak kell lenni�k (�D.2.2).
1190 F�ggel�kek �s t�rgymutat�
D.3.1. Jellemzok el�r�se a lok�lokban
A lok�lok facet-jei a use_facet sablon f�ggv�nyen kereszt�l �rhetok el �s a
has_facet sablon
f�ggv�nnyel k�rdezhetj�k le, hogy a lok�l rendelkezik-e egy adott jellemzovel:
template <class Facet> bool has_facet(const locale&) throw();
template <class Facet> const Facet& use_facet(const locale&); // bad_cast kiv�telt
v�lthat
ki
Ezekre a f�ggv�nyekre �gy kell gondolnunk, mintha azok locale param�ter�kben
keresn�k
Facet sablonparam�ter�ket. M�s megk�zel�t�sben a use_facet egyfajta
t�pusk�nyszer�t�s
(cast), egy lok�l konvert�l�sa egy meghat�rozott jellemzore. Ez az�rt lehets�ges,
mert
a locale objektumok egy adott t�pus� facet-bol csak egy p�ld�nyt tartalmazhatnak:
void f(const locale& my_locale)
{
char c = use_facet< numpunct<char> >(my_locale).decimal_point() // a szabv�nyos
// facet haszn�lata
// ...
if (has_facet<Encrypt>(my_locale)) { // tartalmaz-e a my_locale Encrypt facet-et?
const Encrypt& f = use_facet<Encrypt>(my_locale); // az Encrypt facet kinyer�se
// a my_locale-b�l
const Crypto c = f.get_crypto(); // az Encrypt facet haszn�lata
// ...
}
// ...
}
Jegyezz�k meg, hogy a use_facet egy konstans facet-re val� referenci�t ad vissza,
�gy az
eredm�nyt nem adhatjuk �rt�k�l egy nem konstans v�ltoz�nak. Ez az�rt logikus, mert
a jellemz
oknek elvileg nem m�dos�that�knak kell lenni�k �s csak const tagokat
tartalmazhatnak.
Ha megh�vjuk a use_facet<X>(loc) f�ggv�nyt �s loc nem rendelkezik az X
jellemzovel,
a use_facet() bad_cast kiv�telt v�lt ki (�14.10). A szabv�nyos facet-ek
garant�ltan hozz�f�rhet
oek minden locale sz�m�ra (�D.4), �gy az o eset�kben nem kell a has_facet-et
haszn�lnunk,
ezekre a use_facet nem fog bad_cast kiv�telt kiv�ltani.
Hogyan lehetne a use_facet �s has_facet f�ggv�nyeket megval�s�tani? Eml�kezz�nk,
hogy
egy lok�lra �gy gondolhatunk, mintha map<id,facet*> lenne (�D.2). Ha a Facet
sablonparam
�terk�nt adott egy facet t�pus, a has_facet vagy use_facet a Facet::id-re
hivatkozhat �s
ezt haszn�lhatja a megfelelo jellemzo megkeres�s�re. A has_facet �s use_facet
nagyon egyszer
u v�ltozata �gy n�zhetne ki:
D. Helyi saj�toss�gok 1191
// �l-megval�s�t�s: k�pzelj�k �gy, hogy a lok�l rendelkezik egy facet_map-nek
nevezett
// map<id,facet*>-tel
template <class Facet> bool has_facet(const locale& loc) throw()
{
const locale::facet* f = loc.facet_map[Facet::id];
return f ? true : false;
}
template <class Facet> const Facet& use_facet(const locale& loc)
{
const locale::facet* f = loc.facet_map[Facet::id];
if (f) return static_cast<const Facet&>(*f);
throw bad_cast();
}
A facet::id haszn�lat�t �gy is tekinthetj�k, mint a ford�t�si ideju t�bbalak�s�g
(parametrikus
polimorfizmus) egy form�j�t. A dynamic_cast a use_facet-hez hasonl� eredm�nyt
adna, de
az ut�bbi sokkal hat�konyabb, mert kev�sb� �ltal�nos.
Az id val�j�ban ink�bb egy fel�letet �s viselked�st azonos�t, mint oszt�lyt. Azaz
ha k�t facet
oszt�lynak pontosan ugyanaz a fel�lete �s (a locale szempontj�b�l) ugyanaz a
szerep�k,
akkor ugyanaz az id kell, hogy azonos�tsa oket. A collate<char> �s
a collate_byname<char> p�ld�ul felcser�lheto egy lok�lban, �gy mindkettot
a collate<char>::id azonos�tja (�D.4.1).
Ha egy jellemzonek �j fel�letet adunk . mint az f()-ben az Encrypt-nek .,
defini�lnunk kell
sz�m�ra az azonos�t�t (l�sd �D.3.2-t �s �D.4.1-et).
D.3.2. Egyszeru felhaszn�l�i facet-ek
A standard k�nyvt�r a kultur�lis elt�r�sek legl�nyegesebb ter�leteihez . mint a
karakterk
�szletek kezel�se �s a sz�mok be- �s kivitele . szabv�nyos facet-eket ny�jt.
Ahhoz, hogy
az �ltaluk ny�jtott szolg�ltat�sokat a sz�les k�rben haszn�latos t�pusok
bonyolults�g�t�l �s
a vel�k j�r� hat�konys�gi probl�m�kt�l elk�l�n�tve vizsg�lhassuk, hadd mutassak be
elo-
sz�r egy egyszeru felhaszn�l�i t�pusra vonatkoz� facet-et:
enum Season { tavasz, ny�r, osz, t�l }; // �vszakok
1192 F�ggel�kek �s t�rgymutat�
Ez volt a legegyszerubb felhaszn�l�i t�pus, ami �ppen eszembe jutott. Az itt
felv�zolt I/O kis
m�dos�t�sokkal a legt�bb egyszeru felhaszn�l�i t�pus eset�ben felhaszn�lhat�.
class Season_io : public locale::facet {
public:
Season_io(int i = 0) : locale::facet(i) { }
~Season_io() { } // lehetov� teszi a Season_io objektumok felsz�mol�s�t (�D.3)
// x �br�zol�sa karakterl�nck�nt
virtual const string& to_str(Season x) const = 0;
// az s karakterl�ncnak megfelelo �vszak elhelyez�se x-be:
virtual bool from_str(const string& s, Season& x) const = 0;
static locale::id id; // facet-azonos�t� objektum (�D.2, �D.3, �D.3.1)
};
locale::id Season_io::id; // az azonos�t� objektum meghat�roz�sa
Az egyszerus�g kedv��rt a facet csak a char t�pust haszn�l� megval�s�t�sokra
korl�toz�dik.
A Season_io oszt�ly �ltal�nos, elvont fel�letet ny�jt minden Season_io facet
sz�m�ra.
Ha a Season be- �s kimenet�t egy adott lok�lra szeretn�nk defini�lni, a Season_io-
b�l sz�rmaztatunk
egy oszt�lyt, amelyben megfeleloen kifejtj�k a to_str() �s from_str()
f�ggv�nyeket.
A Season �rt�k�t k�nnyu ki�rni. Ha az adatfolyam rendelkezik Season_io
jellemzovel, azt
haszn�lva az �rt�ket karakterl�ncc� alak�thatjuk, ha nem, ki�rhatjuk a Season
eg�sz �rt�k�t:
ostream& operator<<(ostream& s, Season x)
{
const locale& loc = s.getloc(); // az adatfolyam lok�lj�nak kinyer�se (�21.7.1)
if (has_facet<Season_io>(loc)) return s << use_facet<Season_io>(loc).to_str(x);
return s << int(x);
}
�szrevehetj�k, hogy a << muveletet �gy defini�ltuk, hogy m�s t�pusokra h�vtuk meg
a <<-
t. Ennek sz�mos elonye van: egyszerubb a <<-t haszn�lnunk, mint a kimeneti
adatfolyam
�tmeneti t�raihoz k�zvetlen�l hozz�f�rn�nk, a << muveletet kifejezetten a lok�lhoz
igaz�thatjuk
�s a muvelet hibakezel�st is biztos�t. A szabv�nyos facet-ek a legnagyobb
hat�konys
�g �s rugalmass�g el�r�se �rdek�ben t�bbnyire k�zvetlen�l az adatfolyam �tmeneti
t�r�t
kezelik (�D.4.2.2, �D.4.2.3), de sok felhaszn�l�i t�pus eset�ben nincs sz�ks�g
arra, hogy
a streambuf absztrakci�s szintj�re s�llyedj�nk.
D. Helyi saj�toss�gok 1193
Ahogy lenni szokott, a bemenet kezel�se n�mileg bonyolultabb, mint a kimenet�:
istream& operator>>(istream& s, Season& x)
{
const locale& loc = s.getloc(); // az adatfolyam lok�lj�nak kinyer�se (�21.7.1)
if (has_facet<Season_io>(loc)) { // a sz�veges �br�zol�s beolvas�sa
const Season_io& f = use_facet<Season_io>(loc);
string buf;
if (!(s>>buf && f.from_str(buf,x))) s.setstate(ios_base::failbit);
return s;
}
int i; // a sz�m�br�zol�s beolvas�sa
s >> i;
x = Season(i);
return s;
}
A hibakezel�s egyszeru, a be�p�tett t�pusok hibakezel�s�nek st�lus�t k�veti. Azaz,
ha a bemen
o karakterl�nc nem a v�lasztott lok�l valamelyik Season-j�t jel�li, az adatfolyam
hib�s
(failure) �llapotba ker�l. Ha a kiv�telek megengedettek, ios_base::failure kiv�tel
kiv�lt�s�-
ra ker�lhet sor (�21.3.6).
Vegy�nk egy egyszeru tesztprogramot:
int main() // egyszeru teszt
{
Season x;
// az alap�rtelmezett lok�l haszn�lata (nincs Season_io facet);
// eg�sz �rt�ku I/O-t eredm�nyez:
cin >> x;
cout << x << endl;
locale loc(locale(), new US_season_io);
cout.imbue(loc); // Season_io facet-tel rendelkezo lok�l haszn�lata
cin.imbue(loc); // Season_io facet-tel rendelkezo lok�l haszn�lata
cin >> x;
cout << x << endl;
}
A
2
summer
1194 F�ggel�kek �s t�rgymutat�
bemenetre a program v�lasza:
2
summer
Ennek el�r�s�hez defini�lnunk kell a US_season_io oszt�lyt, amelyben megadjuk az
�vszakok
karakterl�nc-�br�zol�s�t �s fel�l�rjuk a Season_io azon f�ggv�nyeit, amelyek a
karakterl
�ncokat a felsorolt elemekre alak�tj�k:
class US_season_io : public Season_io {
static const string seasons[];
public:
const string& to_str(Season) const;
bool from_str(const string&, Season&) const;
// figyelem: nincs US_season_io::id
};
const string US_season_io::seasons[] = { "spring", "summer", "fall", "winter" };
const string& US_season_io::to_str(Season x) const
{
if (x<spring || winter<x) {
static const string ss = "Nincs ilyen �vszak";
return ss;
}
return seasons[x];
}
bool US_season_io::from_str(const string& s, Season& x) const
{
const string* beg = &seasons[spring];
const string* end = &seasons[winter]+1;
const string* p = find(beg,end,s); // �3.8.1, �18.5.2
if (p==end) return false;
x = Season(p-beg);
return true;
}
Vegy�k �szre, hogy mivel a US_season_io csup�n a Season_io fel�let megval�s�t�sa,
nem
adunk meg azonos�t�t a US_season_io sz�m�ra. Sot, ha a US_season_io-t Season_io-
k�nt
akarjuk haszn�lni, nem is szabad ilyet tenn�nk. A lok�lok muveletei (p�ld�ul a
has_facet,
�D.3.1) arra t�maszkodnak, hogy az azonos fogalmakat �br�zol� facet-eket ugyanaz
az id
azonos�tja (�D.3).
D. Helyi saj�toss�gok 1195
A megval�s�t�ssal kapcsolatos egyetlen �rdekes k�rd�s az, hogy mit kell tenni, ha
�rv�nytelen
Season ki�r�s�t k�rik? Term�szetesen ennek nem lenne szabad megt�rt�nnie. Az
egyszer
u felhaszn�l�i t�pusokn�l azonban nem ritka, hogy �rv�nytelen �rt�ket tal�lunk,
�gy
sz�m�t�sba kell venn�nk ezt a lehetos�get is. Kiv�lthatn�nk egy kiv�telt, de
miut�n olyan
egyszeru kimenettel foglalkozunk, amelyet emberek fognak olvasni, hasznos, ha a
tartom�-
nyon k�v�li �rt�keket az .�rt�ktartom�nyon k�v�li. sz�veg is jelzi. A bemenetn�l
itt a kiv�-
telkezel�s a >> muveletre h�rul, m�g a kimenet eset�ben ezt a facet to_str()
f�ggv�nye v�gzi
(hogy bemutathassuk a lehetos�geket). Val�di programokn�l a facet f�ggv�nyei a be-
�s
kimeneti hib�k kezel�s�vel egyar�nt foglalkoznak, vagy csak jelentik a hib�kat, a
<< �s >>
muveletekre b�zva azok kezel�s�t.
A Season_io ezen v�ltozata arra t�maszkodott, hogy a sz�rmaztatott oszt�lyok adj�k
meg
a lok�lra jellemzo karakterl�ncokat. Egy m�sik megold�s, hogy a Season_io maga
szerzi
meg ezeket egy, a lok�lhoz kapcsol�d� adatt�rb�l (l�sd �D.4.7). Gyakorlatk�nt
hagytuk annak
kidolgoz�s�t, hogy egyetlen Season_io oszt�lyunk van, amelynek az �vszakokat jelzo

karakterl�ncok a konstruktor param�terek�nt ad�dnak �t (�D.6[2]).


D.3.3. A lok�lok �s jellemzok haszn�lata
A lok�lok elsodlegesen a standard k�nyvt�ron bel�l, az I/O adatfolyamokban
haszn�latosak,
de a locale a helyi saj�toss�gok �br�zol�s�nak enn�l �ltal�nosabb eszk�ze. A
messages
(�D.4.7) p�ld�ul olyan facet, amelynek semmi k�ze a be- �s kimeneti
adatfolyamokhoz.
Az iostream k�nyvt�r esetleges bov�t�sei, sot, a nem adatfolyamokkal dolgoz� be-
�s kimeneti
eszk�z�k is kihaszn�lhatj�k a lok�lok adta lehetos�geket, a felhaszn�l� pedig a
locale
objektumok seg�ts�g�vel tetszoleges m�don rendezheti a helyi saj�toss�gokat.
A lok�lokon �s jellemzok�n alapul� elj�r�sok �ltal�noss�ga r�v�n a felhaszn�l�i
facet-ek
adta lehetos�gek korl�tlanok. A d�tumok, idoz�n�k, telefonsz�mok,
t�rsadalombiztos�t�si
sz�mok (szem�lyi sz�mok), gy�rt�si sz�mok, hom�rs�kletek, �ltal�nos (m�rt�kegys�g,
�rt
�k) p�rok, ir�ny�t�sz�mok, ruham�retek, �s ISBN sz�mok mind megadhat�k facet-k�nt.

Mint minden .eros. szolg�ltat�ssal, a facet-ekkel is �vatosan kell b�nni. Az, hogy
valamit lehet
jellemzok�nt �br�zolni, m�g nem jelenti azt, hogy ez a legjobb megold�s. A
kultur�lis
elt�r�sek �br�zol�s�nak kiv�laszt�sakor a kulcsk�rd�s . mint mindig . az, hogy
milyen neh
�z a k�d meg�r�sa, mennyire k�nnyu a kapott k�dot olvasni, valamint hogy hogyan
befoly
�solj�k a d�nt�sek a kapott program fenntarthat�s�g�t, illetve az I/O muveletek
ido- �s
t�rbeli hat�konys�g�t.
1196 F�ggel�kek �s t�rgymutat�
D.4. Szabv�nyos facet-ek
A standard k�nyvt�r <locale> fej�llom�nya a k�vetkezo facet-eket ny�jtja a
classic() lok�lhoz:
A t�bl�zatban a Ch hely�n char vagy wchar_t t�pus szerepelhet. Ha a felhaszn�l�nak
arra
van sz�ks�ge, hogy a szabv�nyos I/O m�sfajta X karaktert�pust kezeljen, a
megfelelo faceteket
meg kell adnia az X sz�m�ra. A codecvt<X,char,mbstate_t> (�D.4.6) p�ld�ul
sz�ks�ges
lehet az X �s char t�pusok k�z�tti �talak�t�sokhoz. Az mbstate_t t�pus arra val�,
hogy egy
t�bb�jtos karakter�br�zol�s l�ptet�si �llapotait jel�lje (�D.4.6); definici�ja a
<cwchar> �s
a <wchar.h> fej�llom�nyokban tal�lhat�. Tetszoleges X karaktert�pus eset�ben az
mbstate_t-nek a char_traits<X>::state_type felel meg.
D. Helyi saj�toss�gok 1197
Szabv�nyos facet-ek (a classic() lok�lban)
�D.4.1 collate Karakterl�ncok collate<Ch>
�sszehasonl�t�sa
�D.4.2 numeric Sz�mok be- �s kivitele numpunct<Ch>
num_get<Ch>
num_put<Ch>
�D.4.3 monetary P�nz I/O moneypunct<Ch>
moneypunct<Ch,true>
money_get<Ch>
money_put<Ch>
�D.4.4 time Ido I/O time_get<Ch>
time_put<Ch>
�D.4.5 ctype Karakterek oszt�lyoz�sa ctype<Ch>
codecvt<Ch,char,mbstate_t>
�D.4.7 messages �zenet-visszakeres�s messages<Ch>
Kateg�ria Rendeltet�s Facet-ek
A standard k�nyvt�r tov�bbi facet-jei a <locale> fej�llom�nyban a k�vetkezok:
A t�bl�zatban szereplo jellemzok p�ld�nyos�t�sakor a Ch char vagy wchar_t lehet; a
C b�rmilyen
karaktert�pus (�20.1), az International �rt�ke true vagy false, ahol a true azt
jelenti,
hogy a valuta-szimb�lum n�gykarakteres .nemzetk�zi. �br�zol�s�t haszn�ljuk
(�D.4.3.1).
Az mbstate_t t�pus a t�bb�jtos karakter-�br�zol�sok l�ptet�si �llapotait jel�li
(�D.4.6), meghat
�roz�sa a <cwchar> �s a <wchar.h> fej�llom�nyokban tal�lhat�.
Az In �s az Out bemeneti �s kimeneti bej�r�k (iter�torok, �19.1, �19.2.1). Ha a
_put �s _get
jellemzoket ell�tjuk ezekkel a sablonparam�terekkel, olyan facet-eket hozhatunk
l�tre,
amelyek nem szabv�nyos �tmeneti t�rakhoz f�rnek hozz� (�D.4.2.2). Az iostream-ek
�tmeneti
t�rai (pufferei) adatfolyam �tmeneti t�rak, �gy bej�r�ik ostreambuf_iterator-ok
(�19.2.6.1, �D.4.2.2), vagyis a hibakezel�shez rendelkez�s�nkre �ll a failed()
f�ggv�ny.
Az F_byname az F facet-bol sz�rmazik; ugyanazt a fel�letet ny�jtja mint az F, de
hozz�ad
egy konstruktort, amelynek egy lok�lt megnevezo karakterl�nc param�tere van (l�sd
�D.4.1-et). Az F_byname(n�v) jelent�se ugyanaz, mint az F locale(n�v) szerkezet�.
Az elgondol
�s az, hogy a program v�grehajt�si k�rnyezet�ben egy neves�tett lok�lb�l (�D.2.1)
kivessz�k a szabv�nyos facet egy adott v�ltozat�t:
1198 F�ggel�kek �s t�rgymutat�
Szabv�nyos facet-ek
Kateg�ria Rendeltet�s Facet-ek
�D.4.1 collate Karakterl�ncok collate_byname<Ch>
�sszehasonl�t�sa
�D.4.2 numeric Sz�mok be- �s kivitele numpunct_byname<Ch>
num_get<C,In>
num_put<C,Out>
�D.4.3 monetary P�nz I/O moneypunct_byname<Ch,International>
money_get<C,In>
money_put<C,Out>
�D.4.4 time Ido I/O time_put_byname<Ch>
�D.4.5 ctype Karakterek oszt�lyoz�sa ctype_byname<Ch>
�D.4.7 messages �zenet-visszakeres�s messages_byname<Ch>
void f(vector<string>& v, const locale& loc)
{
locale d1(loc, new collate_byname<char>("da")); // d�n karakterl�nc-
�sszehasonl�t�s
// haszn�lata
locale dk(d1, new ctype_byname<char>("da")); // d�n karakteroszt�lyoz�s haszn�lata

sort(v.begin(), v.end(), dk);


// ...
}
Az �j dk lok�l .d�n st�lus�. karakterl�ncokat fog haszn�lni, de megtartja a
sz�mokra vonatkoz
� alap�rtelmezett szab�lyokat. Mivel a facet m�sodik param�tere alap�rtelmez�s
szerint
0, a new muvelettel l�trehozott facet �lettartam�t a lok�l fogja kezelni (�D.3).
A karakterl�nc param�terekkel rendelkezo locale-konstruktorokhoz hasonl�an a
_bynamekonstruktorok
is hozz�f�rnek a program v�grehajt�si k�rnyezet�hez. Ebbol az k�vetkezik,
hogy nagyon lass�ak azokhoz a konstruktorokhoz k�pest, amelyeknek nem kell a
k�rnyezethez
fordulniuk inform�ci��rt. Majdnem mindig gyorsabb, ha l�trehozunk egy lok�lt �s
azut�n f�r�nk hozz� annak jellemzoihez, mintha _byname facet-eket haszn�ln�nk t�bb
helyen
a programban. Ez�rt j� �tlet, ha a facet-et egyszer olvassuk be a k�rnyezetbol,
majd
k�sobb mindig a mem�ri�ban l�vo m�solat�t haszn�ljuk:
locale dk("da"); // a d�n lok�l beolvas�sa (bele�rtve �sszes facet-j�t) egyszer,
// majd a dk lok�l �s jellemzoinek haszn�lata ig�ny szerint
void f(vector<string>& v, const locale& loc)
{
const collate<char>& col = use_facet< collate<char> >(dk);
const collate<char>& ctyp = use_facet< ctype<char> >(dk);
locale d1(loc,col); // d�n karakterl�nc-�sszehasonl�t�s haszn�lata
locale d2(d1,ctyp); // d�n karakteroszt�lyoz�s �s karakterl�nc-
// �sszehasonl�t�s haszn�lata
sort(v.begin(), v.end(), d2);
// ...
}
A kateg�ri�k egyszerubb� teszik a lok�lok szabv�nyos facet-jeinek kezel�s�t.
P�ld�ul ha
adott a dk lok�l, l�trehozhatunk belole egy m�sikat, amely a d�n nyelv
szab�lyainak megfelel
oen (ez az angolhoz k�pest h�rom tov�bbi mag�nhangz�t jelent) olvas be �s hasonl�t

�ssze karakterl�ncokat, de megtartja a C++-ban haszn�latos sz�mform�tumot:


locale dk_us(locale::classic(), dk, collate|ctype); // d�n betuk, amerikai sz�mok
D. Helyi saj�toss�gok 1199
Az egyes szabv�nyos facet-ek bemutat�s�n�l tov�bbi p�ld�kat n�z�nk meg a jellemzok

haszn�lat�ra. A collate (�D.4.1) t�rgyal�sakor p�ld�ul a facet-ek sok k�z�s


szerkezetbeli tulajdons
�ga eloker�l.
Jegyezz�k meg, hogy a szabv�nyos facet-ek gyakran f�ggnek egym�st�l. A num_put
p�ld
�ul a numpunct-ra t�maszkodik. Csak ha az egyes jellemzoket m�r r�szletesen
ismerj�k,
akkor lehet�nk k�pesek azokat sikeresen egy�tt haszn�lni, egyeztetni vagy �j
v�ltozataikat
elk�sz�teni. M�s szavakkal, a �21.7 pontban eml�tett egyszeru muveleteken t�l a
lok�lok
nem arra val�k, hogy a kezdok k�zvetlen�l haszn�lj�k azokat.
A jellemzok megtervez�se gyakran nagyon k�r�lm�nyes. Ennek oka r�szben az, hogy a
jellemz
ok nem rendszerezheto helyi saj�toss�gokat kell, hogy t�kr�zzenek, melyekre
a k�nyvt�r tervezoje nincs befoly�ssal; m�sr�szt pedig az, hogy a C++ standard
k�nyvt�rbeli
eszk�zeinek nagyr�szt �sszeegyeztethetonek kell maradniuk azzal, amit a C standard

k�nyvt�ra �s az egyes platformok szabv�nyai ny�jtanak. A POSIX p�ld�ul olyan


eszk�z�kkel
t�mogatja a lok�lok haszn�lat�t, melyeket a k�nyvt�rak tervezoi nem szabad, hogy
figyelmen
k�v�l hagyjanak.
M�sfelol a lok�lok �s jellemzok �ltal ny�jtott szerkezet nagyon �ltal�nos �s
rugalmas.
A facet-ek b�rmilyen adatot t�rolhatnak �s azokon b�rmilyen muveletet v�gezhetnek.
Ha
az �j facet viselked�s�t a szab�lyok nem korl�tozz�k t�ls�gosan, szerkezete
egyszeru �s
tiszta lehet (�D.3.2).
D.4.1. Karakterl�ncok �sszehasonl�t�sa
A szabv�nyos collate jellemzo Ch t�pus� karakterekbol �ll� t�mb�k
�sszehasonl�t�s�t teszi
lehetov�:
template <class Ch>
class std::collate : public locale::facet {
public:
typedef Ch char_type;
typedef basic_string<Ch> string_type;
explicit collate(size_t r = 0);
int compare(const Ch* b, const Ch* e, const Ch* b2, const Ch* e2) const
{ return do_compare(b,e,b2,e2); }
long hash(const Ch* b, const Ch* e) const { return do_hash(b,e); }
string_type transform(const Ch* b, const Ch* e) const { return
do_transform(b,e); }
1200 F�ggel�kek �s t�rgymutat�
static locale::id id; // facet-azonos�t� objektum (�D.2, �D.3, �D.3.1)
protected:
~collate(); // figyelem: v�dett destruktor
virtual int do_compare(const Ch* b, const Ch* e, const Ch* b2, const Ch* e2)
const;
virtual string_type do_transform(const Ch* b, const Ch* e) const;
virtual long do_hash(const Ch* b, const Ch* e) const;
};
A t�bbi facet-hez hasonl�an a collate is nyilv�nos m�don sz�rmazik a facet
oszt�lyb�l �s
olyan konstruktorral rendelkezik, amelynek egyetlen param�tere azt mondja meg,
hogy
a locale oszt�ly vez�rli-e a jellemzo �lettartam�t (�D.3).
Jegyezz�k meg, hogy a destruktor v�dett (protected). A collate nem k�zvetlen
haszn�latra
val�, ink�bb arra sz�nt�k, hogy minden (sz�rmaztatott) �sszehasonl�t� oszt�ly
alapja legyen
�s a locale kezelje (�D.3). A rendszerfejlesztoknek �s a k�nyvt�rak k�sz�toinek a
karakterl
�ncokat �sszehasonl�t� facet-eket �gy kell meg�rniuk, hogy a collate ny�jtotta
fel�leten kereszt
�l lehessen haszn�lni azokat.
Az alapveto karakterl�nc-�sszehasonl�t�st a compare() f�ggv�ny v�gzi, az adott
collate-re
vonatkoz� szab�lyok szerint; 1-et ad vissza, ha az elso karakterl�nc t�bb
karakterbol �ll,
mint a m�sodik, 0-�t, ha a karakterl�ncok megegyeznek, �s -1-et, ha a m�sodik
karakterl
�nc .nagyobb., mint az elso:
void f(const string& s1, const string& s2, collate<char>& cmp)
{
const char* cs1 = s1.data(); // mivel a compare() muvelet char[] t�mb�n dolgozik
const char* cs2 = s2.data();
switch ( cmp.compare(cs1,cs1+s1.size(), cs2,cs2+s2.size()) )
{
case 0: // a cmp szerint azonos karakterl�ncok
// ...
break;
case -1: // s1 < s2
// ...
break;
case 1: // s1 > s2
// ...
break;
}
}
D. Helyi saj�toss�gok 1201
Vegy�k �szre, hogy a collate tagf�ggv�nyek Ch t�pus� elemekbol �ll� t�mb�ket
hasonl�tanak
�ssze, nem basic_string-eket vagy nulla v�gzod�su C st�lus� karakterl�ncokat,
vagyis
a 0 sz�m�rt�ku Ch k�z�ns�ges karakternek minos�l, nem v�gzod�snek. A compare()
abban
is k�l�nb�zik a strcmp()-tol, hogy pontosan a -1, 0, 1 �rt�keket adja vissza, nem
egyszer
uen 0-�t �s (tetszoleges) pozit�v �s negat�v �rt�keket (�20.4.1).
A standard k�nyvt�rbeli string nem f�gg a lok�lokt�l, azaz a karakterl�ncok
�sszehasonl�-
t�sa az adott nyelvi v�ltozat karakterk�szlete alapj�n t�rt�nik (�C.2). Ezenk�v�l
a szabv�-
nyos string nem biztos�t k�zvetlen m�dot arra, hogy meghat�rozzuk az
�sszehasonl�t�si felt
�telt (20. fejezet). A lok�lt�l f�ggo �sszehasonl�t�shoz a collate kateg�ria
compare()
f�ggv�ny�t haszn�lhatjuk. M�g k�nyelmesebb, ha a f�ggv�nyt a lok�l operator()
oper�tor
�n kereszt�l, k�zvetett m�don h�vjuk meg (�D.2.4):
void f(const string& s1, const string& s2, const char* n)
{
bool b = s1 == s2; // �sszehasonl�t�s a megval�s�t�s karakterk�szlet�nek �rt�kei
szerint
const char* cs1 = s1.data(); // mivel a compare() muvelet char[] t�mb�n dolgozik
const char* cs2 = s2.data();
typedef collate<char> Col;
const Col& glob = use_facet<Col>(locale()); // az �rv�nyes glob�lis lok�lb�l
int i0 = glob.compare(cs1,cs1+s1.size(),cs2,cs2+s2.size());
const Col& my_coll = use_facet<Col>(locale("")); // az elonyben r�szes�tett
lok�lb�l
int i1 = my_coll.compare(cs1,cs1+s1.size(),cs2,cs2+s2.size());
const Col& coll = use_facet<Col>(locale(n)); // az "n" nevu lok�lb�l
int i2 = coll.compare(cs1,cs1+s1.size(),cs2,cs2+s2.size());
int i3 = locale()(s1,s2); // �sszehasonl�t�s az �rv�nyes glob�lis lok�l alapj�n
int i4 = locale("")(s1,s2); // �sszehasonl�t�s az elonyben r�szes�tett lok�l
alapj�n
int i5 = locale(n)(s1,s2); // �sszehasonl�t�s az "n" lok�l alapj�n
// ...
}
Itt i0==i3, i1==i4, �s i2==i5, de k�nnyu olyan eseteket elk�pzelni, ahol i2, i3,
�s i4 �rt�ke
m�s. Vegy�k a k�vetkezo szavakb�l �ll� sorozatot egy n�met sz�t�rb�l:
Dialekt, Di�t, dich, dichten, Dichtung
1202 F�ggel�kek �s t�rgymutat�
A nyelv szab�lyainak megfeleloen a fonevek (�s csak azok) nagy kezdobetusek, de a
rendez
�s nem k�l�nb�zteti meg a kis- �s nagybetuket.
Egy kis- �s nagybetuket megk�l�nb�zteto n�met nyelvu rendez�s minden D-vel kezdodo

sz�t a d el� tenne:


Dialekt, Di�t, Dichtung, dich, dichten
Az � (umlautos a) .egyfajta a.-nak minos�l, �gy a c el� ker�l. A legt�bb
karakterk�szletben
azonban az � sz�m�rt�ke nagyobb a c sz�m�rt�k�n�l, k�vetkez�sk�ppen int(.c.) <
int(.a.),
a sz�m�rt�keken alapul� egyszeru alap�rtelmezett rendez�s pedig a k�vetkezoket
adja:
Dialekt, Dichtung, Di�t, dich, dichten
�rdekes feladat lehet egy olyan f�ggv�nyt �rni, amely a sz�t�rnak megfeleloen
helyesen
rendezi ezt a sorozatot (�D.6[3]).
A hash() f�ggv�ny egy has�t��rt�ket sz�m�t ki (�17.6.2.3), ami mag�t�l �rtetodoen
has�t�t�bl�k l�trehoz�sakor lehet hasznos.
A transform() f�ggv�ny egy olyan karakterl�ncot �ll�t elo, amelyet m�s
karakterl�ncokkal
�sszehasonl�tva ugyanazt az eredm�nyt kapjuk, mint amit a param�ter-
karakterl�nccal val�
�sszehasonl�t�s eredm�nyezne. A transform() c�lja az, hogy optim�lis k�dot
k�sz�thess�nk
az olyan programr�szekbol, ahol egy karakterl�ncot sz�mos m�sikkal hasonl�tunk
�ssze. Ez
akkor hasznos, ha karakterl�ncok halmaz�ban egy vagy t�bb karakterl�ncot
szeretn�nk
megkeresni.
A public compare(), a hash() �s a transform() f�ggv�nyek megval�s�t�s�t a
do_compare(),
do_hash() �s do_transform() nyilv�nos virtu�lis f�ggv�nyek megh�v�sa biztos�tja.
Ezeket
a .do_ f�ggv�nyeket. a sz�rmaztatott oszt�lyokban fel�l lehet �rni. A
k�tf�ggv�nyes megold
�s lehetov� teszi a k�nyvt�r azon k�sz�toj�nek, aki a nem virtu�lis f�ggv�nyeket
�rja, hogy
valamilyen k�z�s szerepet biztos�tson minden h�v�snak, f�ggetlen�l att�l, hogy mit
csin�ln
�nak a felhaszn�l� �ltal megadott do_ f�ggv�nyek.
A virtu�lis f�ggv�nyek haszn�lata megorzi a facet-ek t�bbalak� (polimorfikus)
term�szet�t,
de k�lts�ges lehet. A t�l sok f�ggv�nyh�v�s elker�l�s�hez a locale pontosan
meghat�rozhatja
a haszn�latos jellemzoket �s b�rmennyi �rt�ket a gyors�t�t�rba tehet, amennyire
csak
sz�ks�ge van a hat�kony v�grehajt�shoz (�D.2.2).
D. Helyi saj�toss�gok 1203
A jellemzoket locale::id t�pus� statikus id tagok azonos�tj�k (�D.3). A szabv�nyos
has_facet
�s use_facet f�ggv�nyek az azonos�t�k �s jellemzok k�z�tti �sszef�gg�seken
alapulnak
(�D.3.1). Az azonos fel�letu �s szerepu facet-eknek ugyanazzal az azonos�t�val
kell rendelkezni
�k, �gy a collate<char> �s a collate_byname<char> (�D.4.1.1) azonos�t�ja is
megegyezik.
K�vetkez�sk�ppen k�t facet-nek biztosan k�l�nb�zo az azonos�t�ja, ha (a locale
szempontj
�b�l n�zve) k�l�nb�zo f�ggv�nyeket hajtanak v�gre, �gy ez a helyzet
a numpunct<char> �s a num_put<char> eset�ben is (�D.4.2).
D.4.1.1. Neves�tett Collate
A collate_byname olyan jellemzo, amely a collate azon v�ltozat�t ny�jtja az adott
lok�lnak,
amelyet a konstruktor karakterl�nc-param�tere nevez meg:
template <class Ch>
class std::collate_byname : public collate<Ch> {
public:
typedef basic_string<Ch> string_type;
// l�trehoz�s n�vvel rendelkezo lok�lb�l
explicit collate_byname(const char*, size_t r = 0);
// figyelem: nincs azonos�t� �s nincsenek �j f�ggv�nyek
protected:
~collate_byname(); // figyelem: v�dett destruktor
// a collate<Ch> virtu�lis f�ggv�nyeinek fel�l�r�sa
int do_compare(const Ch* b, const Ch* e, const Ch* b2, const Ch* e2) const;
string_type do_transform(const Ch* b, const Ch* e) const;
long do_hash(const Ch* b, const Ch* e) const;
};
�gy a collate_byname arra haszn�lhat�, hogy kivegy�nk egy collate-et egy, a
program v�grehajt
�si k�rnyezet�ben levo neves�tett lok�lb�l (�D.4). A v�grehajt�si k�rnyezetben
a facet-eket egyszeruen f�jlban, adatk�nt is t�rolhatjuk. Egy kev�sb� rugalmas
megold�s, ha
a jellemzoket programsz�vegk�nt �s adatk�nt �br�zoljuk egy _byname facet-ben.
A collate_byname<char> oszt�ly olyan facet, amelynek nincs saj�t azonos�t�ja
(�D.3). A lok
�lokban a collate_byname<Ch> �s a collate<Ch> felcser�lhetok. Azonos lok�l
eset�ben
a collate �s a collate_byname csak az ut�bbi szerep�ben �s a collate_byname �ltal
felk�n�lt
tov�bbi konstruktorban k�l�nb�zik.
1204 F�ggel�kek �s t�rgymutat�
Jegyezz�k meg, hogy a _byname destruktor v�dett. Ebbol k�vetkezik, hogy lok�lis
(helyi)
v�ltoz�k�nt nem haszn�lhatunk _byname facet-et:
void f()
{
collate_byname<char> my_coll(""); // hiba: a my_coll nem sz�molhat� fel
// ...
}
Ez azt a n�zopontot t�kr�zi, hogy a lok�lok �s jellemzok olyasmik, amiket a
legjobb el�gg
� magas szinten haszn�lni a programban, hogy a program min�l nagyobb r�sz�re
legy�nk
hat�ssal. Erre p�lda a glob�lis lok�l be�ll�t�sa (�D.2.3) vagy egy adatfolyam
megt�lt�se
(�21.6.3, �D.1). Ha sz�ks�ges, egy _byname oszt�lyb�l egy nyilv�nos destruktorral
rendelkez
o oszt�lyt sz�rmaztathatunk �s ebbol az oszt�lyb�l lok�lis v�ltoz�kat hozhatunk
l�tre.
D.4.2. Sz�mok be- �s kivitele
A sz�m-kimenetet a num_put facet kezeli, amely egy adatfolyam �tmeneti t�rba �r
(�21.6.4).
A bemenet kezel�se a num_get dolga; ez is �tmeneti t�rb�l olvas. A num_put �s
num_get
�ltal haszn�lt form�tumot a numpunct jellemzo hat�rozza meg.
D.4.2.1. Sz�mjegy-form�tumok
A be�p�tett t�pusok (mint a bool, az int, �s a double) be- �s kimeneti form�tum�t
a numpunct jellemzo �rja le:
template <class Ch>
class std::numpunct : public locale::facet {
public:
typedef Ch char_type;
typedef basic_string<Ch> string_type;
explicit numpunct(size_t r = 0);
Ch decimal_point() const; // ... a classic() lok�lban
Ch thousands_sep() const; // .,. a classic() lok�lban
string grouping() const; // "" a classic() lok�lban, jelent�se: nincs
csoportos�t�s
string_type truename() const; // "true" a classic() lok�lban
string_type falsename() const; // "false" a classic() lok�lban
D. Helyi saj�toss�gok 1205
static locale::id id; // facet-azonos�t� objektum (�D.2, �D.3, �D.3.1)
protected:
~numpunct();
// virtu�lis "do_" f�ggv�nyek a nyilv�nos f�ggv�nyek sz�m�ra (l�sd �D.4.1)
};
A grouping() �ltal visszaadott karakterl�nc karaktereinek beolvas�sa kis eg�sz
�rt�kek sorozatak
�nt t�rt�nik. Minden sz�m a sz�mjegyek sz�m�t hat�rozza meg egy csoport sz�m�-
ra. A 0. karakter a jobb sz�lso csoportot adja meg (ezek a legkisebb helyi�rt�ku
sz�mjegyek),
az 1. az att�l balra levo csoportot �s �gy tov�bb. �gy a .\004\002\003. egy sz�mot

�r le (pl. 123-45-6789, felt�ve, hogy a .-. az elv�laszt�sra haszn�lt karakter).


Ha sz�ks�ges,
a csoportos�t� minta utols� karaktere ism�telten haszn�lhat�, �gy a .\003.
egyen�rt�ku
a .\003\003\003.-mal. Ahogy az elv�laszt� karakter neve, a thousands_sep() mutatja
is,
a csoportos�t�st leggyakrabban arra haszn�lj�k, hogy a nagy eg�szeket olvashat�bb�
tegy
�k. A grouping() �s thousands_sep() f�ggv�nyek az eg�szek be- �s kimeneti
form�tum�t
is megadj�k, a lebegopontos sz�mok szabv�nyos be- �s kimenet�hez azonban nem haszn
�latosak, �gy nem tudjuk ki�ratni az 1234567.89-et 1,234,567.89-k�nt csup�n
az�ltal,
hogy megadjuk a grouping() �s thousands_sep() f�ggv�nyeket.
A numpunct oszt�lyb�l sz�rmaztat�ssal �j form�tumot adhatunk meg. A My_punct
jellemz
oben p�ld�ul le�rhatjuk, hogy az eg�sz �rt�kek sz�mjegyeit sz�k�z�kkel elv�lasztva
�s
h�rmas�val csoportos�tva, a lebegopontos �rt�keket pedig eur�pai st�lus szerint,
tizedesvessz
ovel elv�lasztva kell ki�rni:
class My_punct : public std::numpunct<char> {
public:
typedef char char_type;
typedef string string_type;
explicit My_punct(size_t r = 0) : std::numpunct<char>(r) { }
protected:
char do_decimal_point() const { return �,�; } // vesszo
char do_thousands_sep() const { return � �; } // sz�k�z
string do_grouping() const { return "\003"; } // 3 sz�mjegyu csoportok
};
void f()
{
cout << "Elso st�lus: " << 12345678 << " *** " << 1234567.8 << �\n�;
locale loc(locale(), new My_punct);
cout.imbue(loc);
cout << "M�sodik st�lus: " << 12345678 << " *** " << 1234567.8 << �\n�;
}
1206 F�ggel�kek �s t�rgymutat�
Ez a k�vetkezo eredm�nyt adja:
Elso st�lus: 12345678 *** 1.23457e+06
M�sodik st�lus: 12 345 678 *** 1,23457e+06
Jegyezz�k meg, hogy az imbue() az adatfolyam�ban m�solatot t�rol param�ter�rol.
K�vetkez
�sk�ppen az adatfolyam akkor is t�maszkodhat egy megt�lt�tt lok�lra, ha annak
eredeti
p�ld�nya m�r nem l�tezik. Ha a bemeneti adatfolyam sz�m�ra be van �ll�tva a
boolalpha
jelzobit (�21.2.2, �21.4.1), a true �s false �rt�keket a truename() �s a
falsename() �ltal
visszaadott karakterl�ncok jel�lhetik, m�s esetben a 0 �s az 1.
A numpunct _byname v�ltozata (�D.4, �D.4.1) is adott:
template <class Ch>
class std::numpunct_byname : public numpunct<Ch> { /* ... */ };
D.4.2.2. Sz�mok ki�r�sa
Az �tmeneti t�rba val� �r�skor (�21.6.4) a kimeneti adatfolyamok (ostream) a
num_put jellemz
ore t�maszkodnak:
template <class Ch, class Out = ostreambuf_iterator<Ch> >
class std::num_put : public locale::facet {
public:
typedef Ch char_type;
typedef Out iter_type;
explicit num_put(size_t r = 0);
// a "v" �rt�k elhelyez�se az "s" adatfolyam �tmeneti t�r�nak "b" poz�ci�j�ra:
Out put(Out b, ios_base& s, Ch fill, bool v) const;
Out put(Out b, ios_base& s, Ch fill, long v) const;
Out put(Out b, ios_base& s, Ch fill, unsigned long v) const;
Out put(Out b, ios_base& s, Ch fill, double v) const;
Out put(Out b, ios_base& s, Ch fill, long double v) const;
Out put(Out b, ios_base& s, Ch fill, const void* v) const;
static locale::id id; // facet-azonos�t� objektum (�D.2, �D.3, �D.3.1)
protected:
~num_put();
// virtu�lis "do_" f�ggv�nyek a nyilv�nos f�ggv�nyek sz�m�ra (l�sd �D.4.1)
};
D. Helyi saj�toss�gok 1207
Az Out kimeneti bej�r� (iter�tor) param�ter azonos�tja, hogy a put() a sz�m�rt�ket
jel�lo karaktereket
hol helyezi el a kimeneti adatfolyam �tmeneti t�r�ban (�21.6.4). A put() �rt�ke az

a bej�r� (iterator), amely egy hellyel az utols� karakter m�g� mutat.


Jegyezz�k meg, hogy a num_put alap�rtelmezett v�ltozata (amelynek bej�r�j�val
ostreambuf_iterator<Ch> t�pus� karakterekhez lehet hozz�f�rni) a szabv�nyos
locale-ek
(�D.4) r�sze. Ha m�s v�ltozatot akarunk haszn�lni, akkor azt magunknak kell
elk�sz�ten�nk:
template<class Ch>
class String_numput : public std::num_put<Ch, typename basic_string<Ch>::iterator>
{
public:
String_numput() : num_put<Ch, typename basic_string<Ch>::iterator>(1) { }
};
void f(int i, string& s, int pos) // "i" form�z�sa "s"-be, a "pos" poz�ci�t�l
kezdve
{
String_numput<char> f;
ios_base& xxx = cout; // a cout form�z�si szab�lyainak haszn�lata
f.put(s.begin()+pos, xxx, � �, i); // "i" form�z�sa "s"-be
}
Az ios_base param�terrel a form�tumr�l �s a lok�lr�l kaphatunk inform�ci�t.
P�ld�ul ha
�res helyeket kell kit�lten�nk, az ios_base param�ter �ltal megadott fill karakter
lesz felhaszn
�lva. Az �tmeneti t�r, amelybe b-n kereszt�l �runk, �ltal�ban ahhoz az ostream-hez

kapcsol�dik, amelynek s a b�zisoszt�lya. Az ios_base objektumokat nem k�nnyu


l�trehozni,
mert a form�tummal kapcsolatban t�bb dolgot is szab�lyoznak �s ezeknek egys�gesnek

kell lenni�k, hogy a kimenet elfogadhat� legyen. K�vetkez�sk�ppen az ios_base


oszt�lynak
nincs nyilv�nos konstruktora (�21.3.3).
A put() f�ggv�nyek szint�n ios_base param�tereket haszn�lnak az adatfolyam
lok�lj�nak lek
�rdez�s�hez. A lok�l hat�rozza meg az elv�laszt� karaktereket (�D.4.2.1), a
logikai �rt�kek
sz�veges �br�zol�s�t �s a Ch-ra val� �talak�t�st. P�ld�ul ha feltessz�k, hogy a
put() f�ggv
�ny ios_base param�tere s, a put() f�ggv�nyben ehhez hasonl� k�dot tal�lhatunk:
const locale& loc = s.getloc();
// ...
wchar_t w = use_facet< ctype<char> >(loc).widen(c); // �talak�t�s char-r�l Ch-ra
// ...
string pnt = use_facet< numpunct<char> >(loc).decimal_point(); //
alap�rtelmez�s: ...
// ...
string flse = use_facet< numpunct<char> >(loc).falsename(); // alap�rtelmez�s:
"false"
1208 F�ggel�kek �s t�rgymutat�
A num_put<char>-hoz hasonl� szabv�nyos facet-eket a szabv�nyos I/O adatfolyam-
f�ggv
�nyek �ltal�ban automatikusan haszn�lj�k, �gy a legt�bb programoz�nak nem is kell
tudnia
r�luk. �rdemes azonban szem�gyre venni, hogy a standard k�nyvt�r f�ggv�nyei hogyan

haszn�lj�k a jellemzoket, mert j�l mutatja, hogyan muk�dnek a be- �s kimeneti


adatfolyamok, illetve a facet-ek. Mint mindig, a standard k�nyvt�r most is �rdekes
programoz
�si elj�r�sokra mutat p�ld�kat.
A num_put felhaszn�l�s�val az ostream k�sz�toje a k�vetkezoket �rhatja:
template<class Ch, class Tr>
ostream& std::basic_ostream<Ch,Tr>::operator<<(double d)
{
sentry guard(*this); // l�sd �21.3.8
if (!guard) return *this;
try {
if (use_facet< num_put<Ch> >(getloc()).put(*this,*this,this->fill(),d).failed())
setstate(badbit);
}
catch (...) {
handle_ioexception(*this);
}
return *this;
}
Itt sok minden t�rt�nik. Az .orszem. (sentry) biztos�tja, hogy minden muvelet
v�grehajt�-
dik (�21.3.8). Az ostream lok�lj�t a getloc() tagf�ggv�ny megh�v�s�val kapjuk meg,
majd
a lok�lb�l a use_facet sablon f�ggv�nnyel (�D.3.1) kiszedj�k a num_put jellemzot.
Miut�n
ezt megtett�k, megh�vjuk a megfelelo put() f�ggv�nyeket az igazi munka
elv�gz�s�hez.
A put() elso k�t param�ter�t k�nnyen megadhatjuk, hiszen az ostream-bol
l�trehozhatjuk
az ostream_buf bej�r�t (�19.2.6), az adatfolyamot pedig automatikusan ios_base
b�zisoszt
�ly�ra alak�thatjuk (�21.2.1).
A put() kimeneti bej�r� param�ter�t adja vissza. A bej�r�t egy basic_ostream-bol
szerzi
meg, �gy annak t�pusa ostreambuf_iterator. K�vetkez�sk�ppen a failed() (�19.2.6.1)
rendelkez
�s�nkre �ll a hibaellenorz�shez �s lehetov� teszi sz�munkra, hogy megfeleloen
be�ll�thassuk
az adatfolyam �llapot�t.
Nem haszn�ltuk a has_facet f�ggv�nyt, mert a szabv�nyos facet-ek (�D.4)
garant�ltan ott
vannak minden lok�lban. Ha ez a garancia nem �ll fenn, bad_cast kiv�tel
kiv�lt�s�ra ker�l
sor (�D.3.1).
D. Helyi saj�toss�gok 1209
A put() a do_put virtu�lis f�ggv�nyt h�vja meg. K�vetkez�sk�ppen lehet, hogy
felhaszn�l�i
k�d hajt�dik v�gre �s az operator<<()-nek fel kell k�sz�lnie arra, hogy a fel�l�rt
do_put()
�ltal kiv�ltott kiv�telt kezelje. Tov�bb� lehet, hogy a num_put nem l�tezik
valamilyen karaktert
�pusra, �gy a use_facet() az std::bad_cast kiv�telt v�lthatja ki (�D.3.1). A
be�p�tett t�-
pusokra, mint amilyen a double, a << viselked�s�t a C++ szabv�ny �rja le.
K�vetkez�sk�ppen
nem az a k�rd�s, hogy a handle_ioexception() f�ggv�nynek mit kell csin�lnia, hanem

az, hogyan csin�lja azt, amit a szabv�ny elo�r. Ha a badbit jelzobit az ostream
kiv�tel �llapot
�ra van �ll�tva (�21.3.6), a kiv�tel tov�bbdob�s�ra ker�l sor, m�s esetben a
kiv�tel kezel
�se az adatfolyam �llapot�nak be�ll�t�s�t �s a v�grehajt�s folytat�s�t jelenti. A
badbit jelzo-
bitet mindk�t esetben az adatfolyam �llapot�ra kell �ll�tani (�21.3.3):
template<class Ch, class Tr>
void handle_ioexception(std::basic_ostream<Ch,Tr>& s) // a catch r�szbol megh�vva
{
if (s.exceptions()&ios_base::badbit) {
try {
s.setstate(ios_base::badbit); } catch(...) { }
throw; // tov�bbdob�s
}
s.setstate(ios_base::badbit); // basic_ios::failure kiv�telt v�lthat ki
}
A try blokk az�rt sz�ks�ges, mert a setstate() basic_ios::failure kiv�telt v�lthat
ki (�21.3.3,
�21.3.6). Ha azonban a badbit a kiv�tel �llapotra �ll�tott, az operator<<()-nek
tov�bb kell
dobnia azt a kiv�telt, amely a handle_ioexception() megh�v�s�t okozta (nem pedig
egyszer
uen basic_ios::failure kiv�telt kell kiv�ltania).
A <<-t �gy kell megval�s�tani a be�p�tett t�pusokra, p�ld�ul a double-ra, hogy
k�zvetlen�l
az adatfolyam �tmeneti t�r�ba �rjunk. Ha a <<-t felhaszn�l�i t�pusra �rjuk meg, az
ebbol ered
o neh�zs�geket �gy ker�lhetj�k el, hogy a felhaszn�l�i t�pusok kimenet�t m�r
megl�vo t�-
pusok kimenet�vel fejezz�k ki (�D.3.2).
D.4.2.3. Sz�mok bevitele
A bemeneti adatfolyamok (istream) a num_get jellemzore t�maszkodnak az �tmeneti
t�rb�l
(�21.6.4) val� olvas�shoz:
template <class Ch, class In = istreambuf_iterator<Ch> >
class std::num_get : public locale::facet {
public:
typedef Ch char_type;
typedef In iter_type;
1210 F�ggel�kek �s t�rgymutat�
explicit num_get(size_t r = 0);
// olvas�s [b:e)-b�l v-be, az s-beli form�z�si szab�lyok haszn�lat�val;
// hibajelz�s az r be�ll�t�s�val:
In get(In b, In e, ios_base& s, ios_base::iostate& r, bool& v) const;
In get(In b, In e, ios_base& s, ios_base::iostate& r, long& v) const;
In get(In b, In e, ios_base& s, ios_base::iostate& r, unsigned short& v) const;
In get(In b, In e, ios_base& s, ios_base::iostate& r, unsigned int& v) const;
In get(In b, In e, ios_base& s, ios_base::iostate& r, unsigned long& v) const;
In get(In b, In e, ios_base& s, ios_base::iostate& r, float& v) const;
In get(In b, In e, ios_base& s, ios_base::iostate& r, double& v) const;
In get(In b, In e, ios_base& s, ios_base::iostate& r, long double& v) const;
In get(In b, In e, ios_base& s, ios_base::iostate& r, void*& v) const;
static locale::id id; // facet-azonos�t� objektum (�D.2, �D.3, �D.3.1)
protected:
~num_get();
// virtu�lis "do_" f�ggv�nyek a nyilv�nos f�ggv�nyek sz�m�ra (l�sd �D.4.1)
};
A num_get szerkezete alapvetoen a num_put-�hoz (�D.4.2.2) hasonl�. Mivel ink�bb
olvas,
mint �r, a get()-nek egy bej�r�p�rra van sz�ks�ge, az olvas�s c�lpontj�t
meghat�roz� param
�ter pedig egy referencia. Az iostate t�pus� r v�ltoz� �gy van be�ll�tva, hogy
t�kr�zze az
adatfolyam �llapot�t. Ha a k�v�nt t�pus� �rt�ket nem lehet beolvasni, az r-ben a
failbit be-
�ll�t�s�ra ker�l sor, ha el�rt�k a bemenet v�g�t, az eofbit-�re. A bemeneti
muveletek az r-t
arra haszn�lj�k, hogy eld�nts�k, hogyan �ll�ts�k be az adatfolyam �llapot�t. Ha
nem t�rt�nt
hiba, a beolvasott �rt�k a v-n kereszt�l �rt�k�l ad�dik; egy�bk�nt a v v�ltozatlan
marad.
Az istream k�sz�toje a k�vetkezoket �rhatja:
template<class Ch, class Tr>
istream& std::basic_istream<Ch,Tr>::operator>>(double& d)
{
sentry guard(*this); // l�sd �21.3.8
if (!guard) return *this;
iostate state = 0; // j�
istreambuf_iterator<Ch> eos;
double dd;
try {
use_facet< num_get<Ch> >(getloc()).get(*this,eos,*this,state,dd);
}
D. Helyi saj�toss�gok 1211
catch (...) {
handle_ioexception(*this); // l�sd �D.4.2.2
return *this;
}
if (state==0 || state==eofbit) d = dd; // d �rt�k�nek be�ll�t�sa csak akkor,
// ha a get() sikerrel j�rt
setstate(state);
return *this;
}
Az istream sz�m�ra megengedett kiv�teleket hiba eset�n a setstate() f�ggv�ny
v�ltja ki
(�21.3.6).
Egy numpunct jellemzot . mint amilyen a my_numpunct a �D.4.2 pontban . megadva nem

szabv�nyos elv�laszt� karaktereket haszn�lva is olvashatunk:


void f()
{
cout << "Elso st�lus: "
int i1;
double d1;
cin >> i1 >> d1; // beolvas�s a szabv�nyos "12345678" forma haszn�lat�val
locale loc(locale::classic(), new My_punct);
cin.imbue(loc);
cout << "M�sodik st�lus: "
int i2;
double d2;
cin >> i1 >> d2; // beolvas�s a "12 345 678" forma haszn�lat�val
}
Ha igaz�n ritk�n haszn�lt sz�mform�tumokat szeretn�nk beolvasni, fel�l kell �rnunk

a do_get() f�ggv�nyt. Megadhatunk p�ld�ul egy num_get facet-et, amely r�mai


sz�mokat
olvas be ( XXI vagy MM, �D.6[15]).
D.4.3. P�nz�rt�kek be- �s kivitele
A p�nz�sszegek form�z�s�nak m�dja az .egyszeru. sz�mok form�z�s�hoz hasonl�t
(�D.4.2), az elobbin�l azonban a kultur�lis elt�r�sek jelentos�ge nagyobb. A
negat�v �sszegeket
(vesztes�g, tartoz�s, mondjuk -1,25) p�ld�ul egyes helyeken pozit�v sz�mokk�nt,
z�-
r�jelben kell felt�ntetni (1,25). Az is elofordulhat, hogy a negat�v �sszegek
felismer�s�nek
megk�nny�t�s�re sz�neket kell haszn�lnunk.
1212 F�ggel�kek �s t�rgymutat�
Nincs szabv�nyos .p�nz t�pus.. Ehelyett kifejezetten a .p�nz. facet-eket kell
haszn�lnunk
az olyan sz�m�rt�kekn�l, amelyekrol tudjuk, hogy p�nz�sszegeket jelentenek:
class Money { // egyszeru t�pus p�nz�sszegek t�rol�s�ra
long int amount;
public:
Money(long int i) : amount(i) { }
operator long int() const { return amount; }
};
// ...
void f(long int i)
{
cout << "�rt�k= " << i << " �sszeg= " << Money(i) << endl;
}
Ezen facet-ek feladata az, hogy jelentosen megk�nny�ts�k az olyan kimeneti
muveletek
meg�r�s�t a Money t�pusra, melyek az �sszeget a helyi szok�soknak megfeleloen
�rj�k ki
(l�sd �D.4.3.2-t). A kimenet a cout lok�lj�t�l f�ggoen v�ltozik:
�rt�k= 1234567 �sszeg= $12345.67
�rt�k= 1234567 �sszeg= 12345,67 DKK
�rt�k= -1234567 �sszeg= $-12345.67
�rt�k= -1234567 �sszeg= -$12345.67
�rt�k= -1234567 �sszeg= (CHF12345,67)
A p�nz�rt�kek eset�ben rendszerint alapveto a legkisebb p�nzegys�gre is kiterjedo
pontoss
�g. K�vetkez�sk�ppen �n azt a szok�st k�vetem, hogy ink�bb a .fill�rek. (penny,
ore, cent
stb.) sz�m�t �br�zolom eg�sz �rt�kekkel, nem a .forintok�t. (font, korona, d�n�r,
eur� stb.).
Ezt a megold�st a money_punct frac_digits() f�ggv�nye t�mogatja (�D.4.3.1). A
.tizedes-elv
�laszt�t. a decimal_point() adja meg.
A money_base jellemzo �ltal le�rt form�tumon alapul� bemenetet �s kimenetet kezelo
f�ggv
�nyeket a money_get �s money_put facet-ek biztos�tj�k.
A be- �s kimeneti form�tum szab�lyoz�s�ra �s a p�nz�rt�kek t�rol�s�ra egy egyszeru

Money t�pust haszn�lhatunk. Az elso esetben a p�nz�sszegek t�rol�s�ra haszn�lt


(m�s) t�-
pusokat ki�r�s elott a Money t�pusra alak�tjuk, a beolvas�st pedig szint�n Money
t�pus� v�ltoz
�kba v�gezz�k, mielott az �rt�keket m�s t�pusra alak�tan�nk. Kevesebb hib�val j�r,
ha
a p�nz�sszegeket k�vetkezetesen a Money t�pusban t�roljuk: �gy nem feledkezhet�nk
meg
arr�l, hogy egy �rt�ket Money t�pusra alak�tsunk, mielott ki�rn�nk �s nem kapunk
bemeneti
hib�kat, ha a lok�lt�l f�ggetlen�l pr�b�lunk p�nz�sszegeket beolvasni. Lehets�ges
azonban,
hogy a Money t�pus bevezet�se kivitelezhetetlen, ha a rendszer nincs felk�sz�tve
r�.
Ilyen esetekben sz�ks�ges a Money-konverzi�kat alkalmazni az olvas� �s �r�
muveletekn�l.
D. Helyi saj�toss�gok 1213
D.4.3.1. A p�nz�rt�kek form�tuma
A p�nz�sszegek megjelen�t�s�t szab�lyoz� moneypunct term�szetesen a k�z�ns�ges
sz�-
mok form�tum�t megad� numpunct facet-re (�D.4.2.1) hasonl�t:
class std::money_base {
public:
enum part { none, space, symbol, sign, value }; // az elrendez�s r�szei
struct pattern { char field[4]; }; // elrendez�s
};
template <class Ch, bool International = false>
class std::moneypunct : public locale::facet, public money_base {
public:
typedef Ch char_type;
typedef basic_string<Ch> string_type;
explicit moneypunct(size_t r = 0);
Ch decimal_point() const; // ... a classic() lok�lban
Ch thousands_sep() const; // .,. a classic() lok�lban
string grouping() const; // "" a classic() lok�lban, jelent�se: nincs
csoportos�t�s
string_type curr_symbol() const; // "$" a classic() lok�lban
string_type positive_sign() const; // "" a classic() lok�lban
string_type negative_sign() const; // "-" a classic() lok�lban
int frac_digits() const; // sz�mjegyek sz�ma a tizedesvesszo ut�n; 2 a classic()
lok�lban
pattern pos_format() const; // { symbol, sign, none, value } a classic() lok�lban
pattern neg_format() const; // { symbol, sign, none, value } a classic() lok�lban
static const bool intl = International; // a "nemzetk�zi" p�nzform�tum haszn�lata
static locale::id id; // facet-azonos�t� objektum (�D.2, �D.3, �D.3.1)
protected:
~moneypunct();
// virtu�lis "do_" f�ggv�nyek a nyilv�nos f�ggv�nyek sz�m�ra (l�sd �D.4.1)
};
A moneypunct szolg�ltat�sait elsosorban a money_put �s money_get jellemzok
k�sz�toinek
sz�nt�k (�D.4.3.2, �D.4.3.3).
A decimal_point(), thousands_sep(), �s grouping() tagok �gy viselkednek, mint a
vel�k
egyen�rt�ku f�ggv�nyek a numpunct facet-ben.
1214 F�ggel�kek �s t�rgymutat�
A curr_symbol(), positive_sign() �s negative_sign() tagok rendre a valutajelet ($,
Y, FrF,
DKr), a pluszjelet �s a m�nuszjelet jel�lo karakterl�ncot adj�k vissza. Ha az
International
sablonparam�ter �rt�ke true volt, az intl tag szint�n true lesz �s a
valutajelek .nemzetk�zi.
�br�zol�sa lesz haszn�latos. A nemzetk�zi �br�zol�s egy n�gy karakterbol �ll�
karakterl�nc:
"USD "
"DKK "
"EUR "
Az utols� karakter �ltal�ban sz�k�z. A h�rom betus valuta-azonos�t�t az ISO-4217
szabv�ny
�rja le. Ha az International �rt�ke false, .helyi. valutajelet . $, L vagy Y .
lehet haszn�lni.
A pos_format() �s neg_format() �ltal visszaadott minta (pattern) n�gy r�szbol
(part) �ll,
amelyek a sz�m�rt�k, a valutajel, az elojel �s az �reshely megjelen�t�s�nek
sorrendj�t adj�k
meg. A leggyakoribb form�tumok ezt a mint�t k�vetik:
+$ 123.45 // { sign, symbol, space, value }, ahol a positive_sign() visszat�r�si
�rt�ke "+"
$+123.45 // { symbol, sign, value, none }, ahol a positive_sign() visszat�r�si
�rt�ke "+"
$123.45 // { symbol, sign, value, none }, ahol a positive_sign() visszat�r�si
�rt�ke ""
$123.45- // { symbol, value, sign, none }
-123.45 DKK // { sign, value, space, symbol }
($123.45) // { sign, symbol, value, none }, ahol a negative_sign() visszat�r�si
�rt�ke "()"
(123.45DKK) // { sign, value, symbol, none }, ahol a negative_sign() visszat�r�si
�rt�ke "()"
A negat�v sz�mok z�r�jeles �br�zol�s�t a negative_sign() f�ggv�ny visszat�r�si
�rt�kek�nt
a () karakterekbol �ll� karakterl�ncot defini�lva biztos�tjuk. Az elojel-
karakterl�nc elso karaktere
oda ker�l, ahol a sign (elojel) tal�lhat� a mint�ban, a marad�k pedig a minta
t�bbi
r�sze ut�n k�vetkezik. Ezt a megold�st leggyakrabban ahhoz a szok�sos p�nz�gyi
jel�l�shez
haszn�lj�k, miszerint a negat�v �sszegeket z�r�jelben t�ntetik fel, de m�sra is
fel lehet
haszn�lni:
-$123.45 // { sign, symbol, value, none }, ahol a negative_sign() visszat�r�si
�rt�ke "-"
*$123.45 silly // { sign, symbol, value, none }, ahol a negative_sign()
// visszat�r�si �rt�ke "* silly"
Az elojel, �rt�k �s szimb�lum (sign, value, symbol) �rt�kek csak egyszer
szerepelhetnek
a mint�ban. A marad�k �rt�k space (�reshely) vagy none (semmi) lehet. Ahol space
szerepel,
oda legal�bb egy �reshely karakternek kell ker�lnie, a none nulla vagy t�bb
�reshely
karaktert jelent (kiv�ve ha a none a minta v�g�n szerepel).
D. Helyi saj�toss�gok 1215
Ezek a szigor� szab�lyok n�h�ny l�tsz�lag �sszeru mint�t is megtiltanak:
pattern pat = { sign, value, none, none }; // hiba: a symbol nincs megadva
A decimal_point() hely�t a frac_digits() f�ggv�ny jel�li ki. A p�nz�sszegeket
�ltal�ban
a legkisebb valutaegys�ggel �br�zolj�k (�D.4.3), ami jellemzoen a fo egys�g
sz�zadr�sze
(p�ld�ul cent �s doll�r), �gy a frac_digits() �rt�ke �ltal�ban 2.
K�vetkezzen egy egyszeru form�tum, facet-k�nt megadva:
class My_money_io : public moneypunct<char,true> {
public:
explicit My_money_io(size_t r = 0) : moneypunct<char,true>(r) { }
char_type do_decimal_point() const { return �.�; }
char_type do_thousands_sep() const { return �,�; }
string do_grouping() const { return "\003\003\003"; }
string_type do_curr_symbol() const { return "USD "; }
string_type do_positive_sign() const { return ""; }
string_type do_negative_sign() const { return "()"; }
int do_frac_digits() const { return 2; } // 2 sz�mjegy a tizedesvesszo ut�n
pattern do_pos_format() const
{
static pattern pat = { sign, symbol, value, none };
return pat;
}
pattern do_neg_format() const
{
static pattern pat = { sign, symbol, value, none };
return pat;
}
};
Ezt a facet-et haszn�ljuk a Money al�bbi be- �s kimeneti muveleteiben is (�D.4.3.2
�s
�D.4.3.3).
A moneypunct _byname v�ltozata (�D.4, �D.4.1) is adott:
template <class Ch, bool Intl = false>
class std::moneypunct_byname : public moneypunct<Ch, Intl> { /* ... */ };
1216 F�ggel�kek �s t�rgymutat�
D.4.3.2. P�nz�rt�kek ki�r�sa
A money_put a moneypunct �ltal meghat�rozott form�tumban �rja ki a p�nz�sszegeket.

Pontosabban, a money_put olyan put() f�ggv�nyeket ny�jt, amelyek megfeleloen


form�-
zott karakter-�br�zol�sokat tesznek egy adatfolyam �tmeneti t�r�ba:
template <class Ch, class Out = ostreambuf_iterator<Ch> >
class std::money_put : public locale::facet {
public:
typedef Ch char_type;
typedef Out iter_type;
typedef basic_string<Ch> string_type;
explicit money_put(size_t r = 0);
// a "v" �rt�k elhelyez�se az �tmeneti t�r "b" poz�ci�j�ra:
Out put(Out b, bool intl, ios_base& s, Ch fill, long double v) const;
Out put(Out b, bool intl, ios_base& s, Ch fill, const string_type& v) const;
static locale::id id; // facet-azonos�t� objektum (�D.2, �D.3, �D.3.1)
protected:
~money_put();
// virtu�lis "do_" f�ggv�nyek a nyilv�nos f�ggv�nyek sz�m�ra (l�sd �D.4.1)
};
A b, s, fill �s v param�terek ugyanarra haszn�latosak, mint a num_put jellemzo
put() f�ggv
�nyeiben (�D.4.3.2.2). Az intl param�ter jelzi, hogy a szabv�nyos
n�gykarakteres .nemzetk
�zi. valutaszimb�lum vagy .helyi. valutajel haszn�latos-e (�D.4.3.1).
Ha adott a money_put jellemzo, a Money oszt�ly sz�m�ra(�D.4.3) kimeneti muveletet
�rhatunk:
ostream& operator<<(ostream& s, Money m)
{
ostream::sentry guard(s); // l�sd �21.3.8
if (!guard) return s;
try {
const money_put<char>& f = use_facet< money_put<char> >(s.getloc());
if (m==static_cast<long double>(m)) { // m long double-k�nt �br�zolhat�
if (f.put(s,true,s,s.fill(),m).failed()) s.setstate(ios_base::badbit);
}
else {
ostringstream v;
v << m; // karakterl�nc-�br�zol�sra alak�t
D. Helyi saj�toss�gok 1217
if (f.put(s,true,s,s.fill(),v.str()).failed()) s.setstate(ios_base::badbit);
}
}
catch (...) {
handle_ioexception(s); // l�sd �D.4.2.2
}
return s;
}
Ha a long double nem el�g pontos a p�nz�rt�k �br�zol�s�hoz, az �rt�ket
karakterl�ncc�
alak�tjuk �s azt �rjuk ki az ilyen param�tert v�r� put() f�ggv�nnyel.
D.4.3.3. P�nz�rt�kek beolvas�sa
A money_get a moneypunct �ltal meghat�rozott form�tumnak megfeleloen olvassa be
a p�nz�sszegeket. Pontosabban, a money_get olyan get() f�ggv�nyeket ny�jt, amelyek

a megfeleloen form�zott karakteres �br�zol�st olvass�k be egy adatfolyam �tmeneti


t�r�b�l:
template <class Ch, class In = istreambuf_iterator<Ch> >
class std::money_get : public locale::facet {
public:
typedef Ch char_type;
typedef In iter_type;
typedef basic_string<Ch> string_type;
explicit money_get(size_t r = 0);
// olvas�s [b:e)-b�l v-be, az s-beli form�z�si szab�lyok haszn�lat�val;
// hibajelz�s az r be�ll�t�s�val:
In get(In b, In e, bool intl, ios_base& s, ios_base::iostate& r, long double& v)
const;
In get(In b, In e, bool intl, ios_base& s, ios_base::iostate& r, string_type& v)
const;
static locale::id id; // facet-azonos�t� objektum (�D.2, �D.3, �D.3.1)
protected:
~money_get();
// virtu�lis "do_" f�ggv�nyek a nyilv�nos f�ggv�nyek sz�m�ra (l�sd �D.4.1)
};
A b, s, fill, �s v param�terek ugyanarra haszn�latosak, mint a num_get jellemzo
get() f�ggv
�nyeiben (�D.4.3.2.2). Az intl param�ter jelzi, hogy a szabv�nyos
n�gykarakteres .nemzetk
�zi. valutaszimb�lum vagy .helyi. valutajel haszn�latos-e (�D.4.3.1).
1218 F�ggel�kek �s t�rgymutat�
Megfelelo money_get �s money_put jellemzop�rral olyan form�ban adhatunk kimenetet,

amelyet hiba �s adatveszt�s n�lk�l lehet visszaolvasni:


int main()
{
Money m;
while (cin>>m) cout << m << "\n";
}
Ez az egyszeru program kimenet�t el kell, hogy fogadja bemenetk�nt is. Sot, ha a
programot
m�sodszor is lefuttatjuk az elso futtat�s eredm�ny�vel, a kimenetnek meg kell
egyeznie
a program eredeti bemenet�vel.
A Money oszt�ly sz�m�ra a k�vetkezo megfelelo bemeneti muvelet lehet:
istream& operator>>(istream& s, Money& m)
{
istream::sentry guard(s); // l�sd �21.3.8
if (guard) try {
ios_base::iostate state = 0; // j�
istreambuf_iterator<char> eos;
string str;
use_facet< money_get<char> >(s.getloc()).get(s,eos,true,state,str);
if (state==0 || state==ios_base::eofbit) { // csak akkor �ll�t be �rt�ket,
// ha a get() sikerrel j�rt
long int i = strtol(str.c_str(),0,0);
if (errno==ERANGE)
state |= ios_base::failbit;
else
m = i; // csak akkor �ll�tja be m �rt�k�t, ha az �talak�t�s long int-re siker�lt
s.setstate(state);
}
}
catch (...) {
handle_ioexception(s); // l�sd �D.4.2.2
}
return s;
}
D. Helyi saj�toss�gok 1219
D.4.4. D�tum �s ido beolvas�sa �s ki�r�sa
Sajnos a C++ standard k�nyvt�ra nem ny�jt megfelelo d�tum t�pust, de a C standard
k�nyvt
�r�b�l alacsonyszintu eszk�z�ket �r�k�lt a d�tumok �s idotartom�nyok kezel�s�hez.
Ezek
a C-beli eszk�z�k szolg�lnak a C++ rendszerf�ggetlen idokezelo eszk�zeinek
alapj�ul.
A k�vetkezokben azt mutatjuk be, hogyan igaz�that� a d�tum �s ido megjelen�t�se a
lok�lhoz,
tov�bb� p�ld�kat adunk arra, hogyan illesztheto be egy felhaszn�l�i t�pus (Date)
az
iostream (21. fejezet) �s locale (�D.2) �ltal ny�jtott szerkezetbe. A Date t�puson
kereszt�l
olyan elj�r�sokkal is megismerked�nk, amelyek seg�thetik az idokezel�st, ha nem
�ll rendelkez
�s�nkre a Date t�pus.
D.4.4.1. �r�k �s idoz�tok
A legt�bb rendszer a legalacsonyabb szinten rendelkezik egy finom idoz�tovel. A
standard
k�nyvt�r a clock() f�ggv�nyt bocs�tja rendelkez�s�nkre, amely megval�s�t�s-f�ggo
clock_t
t�pus� �rt�kkel t�r vissza. A clock() eredm�nye a CLOCK_PER_SEC makr� seg�ts�g�vel
szab
�lyozhat�. Ha nincs hozz�f�r�s�nk megb�zhat� idom�ro eszk�zh�z, akkor �gy
m�rhetj�k
meg egy ciklus idej�t:
int main(int argc, char* argv[]) // �6.1.7
{
int n = atoi(argv[1]); // �20.4.1
clock_t t1 = clock();
if (t1 == clock_t(-1)) { // clock_t(-1) jelent�se: "a clock() nem muk�dik"
cerr << "Sajnos nincs �r�nk.\n";
exit(1);
}
for (int i = 0; i < n; i++) do_something(); // idoz�to ciklus
clock_t t2 = clock();
if (t2 == clock_t(-1)) {
cerr << "T�lcsordul�s.\n";
exit(2);
}
cout << "A do_something() " << n << " alkalommal val� v�grehajt�sa "
<< double(t2-t1)/CLOCKS_PER_SEC << " m�sodpercet vett ig�nybe"
<< " (m�r�si �rz�kenys�g: " << CLOCKS_PER_SEC << " per m�sodperc).\n";
}
1220 F�ggel�kek �s t�rgymutat�
Az oszt�s elott v�grehajtott double(t2-t1) �talak�t�s az�rt sz�ks�ges, mert a
clock_t lehet,
hogy eg�sz t�pus�. Az, hogy a clock() mikor kezd futni, az adott nyelvi
v�ltozatt�l f�gg;
a f�ggv�ny az egyes programr�szek fut�si idej�nek m�r�s�re val�. A clock() �ltal
visszaadott
t1 �s t2 �rt�keket alapul v�ve a double(t2-t1)/CLOCK_PER_SEC a rendszer legjobb
k�-
zel�t�se k�t h�v�s k�zt eltelt idore (m�sodpercben).
Ha az adott feldolgoz�egys�gre nincs megadva a clock() f�ggv�ny vagy ha az ido t�l
hossz�
ahhoz, hogy m�rheto legyen, a clock() a clock_t(-1) �rt�ket adja vissza.
A clock() f�ggv�ny a m�sodperc t�red�k�tol legfeljebb n�h�ny m�sodpercig terjedo
idotartom
�nyok m�r�s�re val�. P�ld�ul ha a clock_t egy 32 bites elojeles eg�sz �s
a CLOCK_PER_SEC �rt�ke 1 000 000, a clock() f�ggv�nnyel az idot 0-t�l valamivel
t�bb mint
2000 m�sodpercig (k�r�lbel�l f�l �r�ig) m�rhetj�k (a m�sodperc milliomod
r�sz�ben).
A programokr�l l�nyegi m�r�seket k�sz�teni nem k�nnyu. A g�pen fut� t�bbi program
jelent
osen befoly�solhatja az adott program fut�si idej�t, neh�z megj�solni a
gyors�t�t�raz�s
�s az utas�t�scs�vek hat�sait �s az algoritmusok nagym�rt�kben f�gghetnek az
adatokt�l is.
Ha meg akarjuk m�rni egy program fut�si idej�t, futtassuk t�bbsz�r �s vegy�k
hib�snak
azokat az eredm�nyeket, amelyek jelentosen elt�rnek a t�bbitol.
A hosszabb idotartom�nyok �s a napt�ri ido kezel�s�re a standard k�nyvt�r a time_t
t�pust
ny�jtja, amely egy idopontot �br�zol; valamint a tm szerkezetet, amely az
idopontokat .r�-
szeikre. bontja:
typedef megval�s�t�s_f�ggo time_t; // megval�s�t�s-f�ggo aritmetikai t�pus
(�4.1.1)
// k�pes idotartom�ny �br�zol�s�ra,
// �ltal�ban 32 bites eg�sz
struct tm {
int tm_sec; // a perc m�sodpercei [0,61]; a 60 �s a 61 "sz�ko-m�sodpercek"
int tm_min; // az �ra percei [0,59]
int tm_hour; // a nap �r�i [0,23]
int tm_mday; // a h�nap napjai [1,31]
int tm_mon; // az �v h�napjai [0,11]; a 0 jelent�se "janu�r" (figyelem: NEM
[1:12])
int tm_year; // �vek 1900 �ta; a 0 jelent�se "1900", a 102-� "2002"
int tm_wday; // napok vas�rnap �ta [0,6]; a 0 jelent�se "vas�rnap"
int tm_yday; // napok janu�r 1 �ta [0,365]; a 0 jelent�se "janu�r 1."
int tm_isdst; // ny�ri idosz�m�t�s jelzo
};
A szabv�ny csak azt biztos�tja, hogy a tm rendelkezik a fenti eml�tett int t�pus�
tagokkal, azt
nem, hogy a tagok ilyen sorrendben szerepelnek vagy hogy nincsenek m�s tagok.
D. Helyi saj�toss�gok 1221
A time_t �s tm t�pusok, valamint a hozz�juk kapcsol�d� szolg�ltat�sok a <ctime> �s

<time.h> fej�llom�nyokban tal�lhat�k:


clock_t clock(); // �rajelek sz�ma a program indul�sa �ta
time_t time(time_t* pt); // �rv�nyes napt�ri ido
double difftime(time_t t2, time_t t1); // t2.t1 m�sodpercben
tm* localtime(const time_t* pt); // *pt �rt�ke helyi ido szerint
tm* gmtime(const time_t* pt); // *pt �rt�ke greenwichi k�z�pido (GMT) szerint,
vagy 0
// (hivatalos neve: Coordinated Universal Time, UTC)
time_t mktime(tm* ptm); // *ptm �rt�ke time_t form�ban, vagy time_t(-1)
char* asctime(const tm* ptm); // *ptm egy C st�lus� karakterl�nccal �br�zolva
// pl. "Sun Sep 16 01:03:52 1973\n"
char* ctime(const time_t* t) { return asctime(localtime(t)); }
Vigy�zzunk: mind a localtime(), mind a gmtime() statikusan lefoglalt objektumra
mutat�
*tm t�pus� �rt�ket ad vissza, vagyis mindk�t f�ggv�ny k�vetkezo megh�v�sa meg
fogja v�ltoztatni
az objektum �rt�k�t. Ez�rt r�gt�n haszn�ljuk fel a visszat�r�si �rt�ket vagy
m�soljuk
a tm-et olyan mem�riahelyre, amit mi fel�gyel�nk. Ugyan�gy az asctime() f�ggv�ny
is
statikusan lefoglalt karaktert�mbre hivatkoz� mutat�t ad vissza.
A tm t�pus legal�bb t�zezer �vnyi d�tumot (ez a legkisebb eg�sz eset�ben
k�r�lbel�l
a [-32000,32000] tartom�ny) k�pes �br�zolni. A time_t azonban �ltal�ban 32 bites
(elojeles)
long int. Ha m�sodperceket sz�molunk, a time_t nem sokkal t�bb, mint 68 �vet tud
�br�-
zolni valamilyen .0. �vtol. mindk�t .ir�nyban.. Az .alap�v. rendszerint 1970, a
hozz� tartoz
� alapido pedig janu�r 1., 0:00 GMT (UTC). Ha a time_t 32 bites elojeles eg�sz,
akkor 2038-
ban futunk ki az .idobol., hacsak nem terjesztj�k ki a time_t-t egy nagyobb eg�sz
t�pusra,
ahogy azt m�r n�h�ny rendszeren meg is tett�k.
A time_t alapvetoen arra val�, hogy a .jelenhez k�zeli idot. �br�zoljuk, ez�rt nem
szabad
elv�rnunk, hogy k�pes legyen az [1902,2038] tartom�nyon k�v�li d�tumokat is
jel�lni. Ami
m�g enn�l is rosszabb, nem minden idokezelo f�ggv�ny kezeli azonos m�don a negat�v

sz�mokat. A .hordozhat�s�g. miatt az olyan �rt�keknek, amelyeket tm-k�nt �s


time_t-k�nt
is �br�zolni kell, az [1920,2038] tartom�nyba kell esni�k. Azoknak, akik az 1970-
tol 2038-ig
terjedo idokereten k�v�li d�tumokat szeretn�nek �br�zolni, tov�bbi elj�r�sokat
kell kidolgozniuk
ahhoz, hogy ezt megtehess�k.
1222 F�ggel�kek �s t�rgymutat�
Ennek egyik k�vetkezm�nye, hogy az mktime() hib�t eredm�nyezhet. Ha az mktime()
param
�ter�t nem lehet time_t-k�nt �br�zolni, a f�ggv�ny a time_t(-1) hibajelz�st adja
vissza.
Ha van egy sok�ig fut� programunk, �gy m�rhetj�k le fut�si idej�t:
int main(int argc, char* argv[]) // �6.1.7
{
time_t t1 = time(0);
do_a_lot(argc,argv);
time_t t2 = time(0);
double d = difftime(t2,t1);
cout << "A do_a_lot() v�grehajt�sa" << d << " m�sodpercig tartott.\n";
}
Ha a time() param�tere nem 0, a f�ggv�ny eredm�nyek�nt kapott ido �rt�k�l ad�dik
a f�ggv�ny time_t t�pusra mutat� param�ter�nek is. Ha a napt�ri ido nem el�rheto
(mondjuk
valamilyen egyedi processzoron), akkor a time_t(-1) �rt�k ad�dik vissza. A mai
d�tumot
a k�vetkezok�ppen pr�b�lhatjuk meg �vatosan meg�llap�tani:
int main()
{
time_t t;
if (time(&t) == time_t(-1)) { // a time_t(.1) jelent�se: "a time() nem muk�dik"
cerr << "Az ido nem �llap�that� meg.\n";
exit(1);
}
tm* gt = gmtime(&t);
cout << gt->tm_mon+1 << '/' << gt->tm_mday << '/' << 1900+gt->tm_year << endl;
}
D.4.4.2. Egy d�tum oszt�ly
Amint a �10.3 pontban eml�tett�k, nem val�sz�nu, hogy egyetlen Date t�pus minden
ig�nyt
ki tud szolg�lni. A d�tum felhaszn�l�sa t�bbf�le megval�s�t�st ig�nyel �s a XIX.
sz�zad elott
a napt�rak nagyban f�ggtek a t�rt�nelem szesz�lyeitol. P�ldak�nt azonban a �10.3-
hoz hasonl
�an k�sz�thet�nk egy Date t�pust, a time_t t�pust felhaszn�lva:
class Date {
public:
enum Month { jan=1, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec };
D. Helyi saj�toss�gok 1223
class Bad_date {};
Date(int dd, Month mm, int yy);
Date();
friend ostream& operator<<(ostream& s, const Date& d);
// ...
private:
time_t d; // szabv�nyos d�tum- �s ido�br�zol�s
};
Date::Date(int dd, Month mm, int yy)
{
tm x = { 0 };
if (dd<0 || 31<dd) throw Bad_date(); // t�legyszerus�tett: l�sd �10.3.1
x.tm_mday = dd;
if (mm<jan || dec<mm) throw Bad_date();
x.tm_mon = mm-1; // a tm_mon 0 alap�
x.tm_year = yy-1900; // a tm_year 1900 alap�
d = mktime(&x);
}
Date::Date()
{
d = time(0); // alap�rtelmezett Date: a mai nap
if (d == time_t(-1)) throw Bad_date();
}
A feladat az, hogy a << �s >> oper�torokat a Date t�pusra lok�lf�ggo m�don
val�s�tsuk
meg.
D.4.4.3. D�tum �s ido ki�r�sa
A num_put facet-hez (�D.4.2) hasonl�an a time_put is put() f�ggv�nyeket ad, hogy
bej�r�-
kon kereszt�l az �tmeneti t�rakba �rhassunk:
template <class Ch, class Out = ostreambuf_iterator<Ch> >
class std::time_put : public locale::facet {
public:
typedef Ch char_type;
typedef Out iter_type;
explicit time_put(size_t r = 0);
1224 F�ggel�kek �s t�rgymutat�
// �r�s az s adatfolyam �tmeneti t�r�ba b-n kereszt�l, az fmt form�tum
haszn�lat�val
Out put(Out b, ios_base& s, Ch fill, const tm* t,
const Ch* fmt_b, const Ch* fmt_e) const;
Out put(Out b, ios_base& s, Ch fill, const tm* t, char fmt, char mod = 0) const
{ return do_put(b,s,fill,t,fmt,mod); }
static locale::id id; // facet-azonos�t� objektum (�D.2, �D.3, �D.3.1)
protected:
~time_put();
virtual Out do_put(Out, ios_base&, Ch, const tm*, char, char) const;
};
A put(b,s,fill,t,fmt_b,fmt_e) a t-ben l�vo d�tumot b-n kereszt�l az s adatfolyam
�tmeneti t�-
r�ba helyezi. A fill karakterek a kit�lt�shez haszn�latosak, ha az sz�ks�ges. A
kimeneti form
�tumot a printf() form�z�hoz hasonl� (fmt_b,fmt_e) form�z�si karakterl�nc (vagy
form�-
tumvez�rlo) hat�rozza meg. A t�nyleges kimenethez a printf()-hez hasonl� (�21.8)
form�tum haszn�latos, ami a k�vetkezo k�l�nleges form�tumvez�rloket
tartalmazhatja:
%a A h�t napj�nak r�vid�tett neve (pl. Szo)
%A A h�t napj�nak teljes neve (pl. Szombat)
%b A h�nap r�vid�tett neve (pl. Feb)
%B A h�nap teljes neve (pl. Febru�r)
%c A d�tum �s ido (pl. Szo Feb 06 21:46:05 1999)
%d A h�nap napja [01,31] (pl. 06)
%H �ra [00,23] (pl. 21)
%I �ra [01,12] (pl. 09)
%j Az �v napja [001,366] (pl. 037)
%m Az �v h�napja [01,12] (pl. 02)
%M Perc [00,59] (pl. 48)
%p D�lelott/d�lut�n (am./pm. . de./du.) jelz�se a 12 �r�s �r�hoz (pl. PM)
%S M�sodperc [00,61] (pl. 48)
%U Az �v hete [00,53] vas�rnappal kezdodoen (pl. 05): az 1. h�t az elso vas
�rnappal kezdodik
%w A h�t napja [0,6]: a 0 jelenti a vas�rnapot (pl. 6)
%W Az �v hete [00,53] h�tfovel kezdodoen (pl. 05): az 1. h�t az elso h�tfovel
kezdodik
%x D�tum (pl. 02/06/99)
%X Ido (pl.21:48:40)
%y �v az �vsz�zad n�lk�l [00,99] (pl. 99)
%Y �v (pl.1999)
%Z Az idoz�na jelz�se (pl. EST), ha az idoz�na ismert
D. Helyi saj�toss�gok 1225
Ezeket az igen r�szletes form�z� szab�lyokat a bov�theto I/O rendszer
param�tereik�nt
haszn�lhatjuk, de mint minden egyedi jel�l�st, ezeket is c�lszerubb (�s
k�nyelmesebb) csak
eredeti feladatuk ell�t�s�ra alkalmazni.
A fenti form�z� utas�t�sokon t�l a legt�bb C++-v�ltozat t�mogatja az olyan
.m�dos�t�kat.
(modifier), mint amilyen a mezosz�less�get (�21.8) meghat�roz� eg�sz sz�m (%10X).
Az ido- �s d�tumform�tumok m�dos�t�i nem k�pezik r�sz�t a C++ szabv�nynak, de
n�h�ny
platformszabv�ny, mint a POSIX, ig�nyelheti azokat. K�vetkez�sk�ppen a m�dos�t�kat
neh
�z elker�lni, m�g akkor is, ha nem t�k�letesen .hordozhat�k..
A <ctime> vagy <time.h> fej�llom�nyban tal�lhat� . az sprintf()-hez (�21.8)
hasonl� .
strftime() f�ggv�ny a kimenetet az ido- �s d�tumform�z� utas�t�sok
felhaszn�l�s�val hozza
l�tre:
size_t strftime(char* s, size_t max, const char* format, const tm* tmp);
A f�ggv�ny legfeljebb max karaktert tesz a *tmp-bol �s a format-b�l a *s-be, a
format form
�z�nak megfeleloen:
int main()
{
const int max = 20; // hanyag: abban b�zik, hogy az strftime()
// soha sem eredm�nyez 20-n�l t�bb karaktert
char buf[max];
time_t t = time(0);
strftime(buf,max,"%A\n",localtime(&t));
cout << buf;
}
A fenti program az alap�rtelmezett classic() lok�lban (�D.2.3) egy szerdai napon
Wednesday-t fog ki�rni, d�n lok�lban onsdag-ot.
Azok a karakterek, melyek nem r�szei a meghat�rozott form�tumnak, mint a p�ld�ban
az
�jsor karakter, egyszeruen bem�sol�dnak az elso (s) param�terbe.
Amikor a put() azonos�t egy f form�tumkaraktert (�s egy nem k�telezo m m�dos�t�t),
megh
�vja a do_put() virtu�lis f�ggv�nyt, hogy az v�gezze el a t�nyleges form�z�st:
do_put(b,s,fill,t,f,m).
1226 F�ggel�kek �s t�rgymutat�
A put(b,s,fill,t,f,m) h�v�s a put() egyszerus�tett form�ja, ahol a
form�tumkarakter (f) �s
a m�dos�t� (m) pontosan meghat�rozott. Ez�rt a
const char fmt[] = "%10X";
put(b, s, fill, t, fmt, fmt+sizeof(fmt));
h�v�st a k�vetkezo alakra lehet r�vid�teni:
put(b, s, fill, t, �X�, 10);
Ha egy form�tum t�bb�jtos karaktereket tartalmaz, annak az alap�rtelmezett
�llapotban
(�D.4.6) kell kezdodnie �s v�gzodnie.
A put() f�ggv�nyt felhaszn�lhatjuk arra is, hogy a Date sz�m�ra lok�lt�l f�ggo
kimeneti mu-
veletet adjunk meg:
ostream& operator<<(ostream& s, const Date& d)
{
ostream::sentry guard(s); // l�sd �21.3.8
if (!guard) return s;
tm* tmp = localtime(&d.d);
try {
if (use_facet< time_put<char> >(s.getloc()).put(s,s,s.fill(),tmp,�x�).failed())
s.setstate(ios_base::failbit);
}
catch (...) {
handle_ioexception(s); // l�sd �D.4.2.2
}
return s;
}
Mivel nincs szabv�nyos Date t�pus, nem l�tezik alap�rtelmezett form�tum a d�tumok
be- �s
kivitel�re. Itt �gy hat�roztam meg a %x form�tumot, hogy form�z�k�nt az .x.
karaktert adtam
�t. Mivel a get_time() f�ggv�ny (�D.4.4.4) alap�rtelmezett form�tuma a %x,
val�sz�nu-
leg ez �ll legk�zelebb a szabv�nyhoz. A �D.4.4.5 pontban p�ld�t is l�thatunk arra,
hogyan
haszn�lhatunk m�s form�tumokat.
D. Helyi saj�toss�gok 1227
D.4.4.4. D�tum �s ido beolvas�sa
Mint mindig, a bemenet .tr�kk�sebb., mint a kimenet. Amikor �rt�k ki�r�s�ra �runk
k�dot,
gyakran k�l�nb�zo form�tumok k�z�l v�laszthatunk. A beolvas�sn�l emellett a
hib�kkal is
foglalkoznunk kell �s n�ha sz�m�tanunk kell arra, hogy sz�mos form�tum lehets�ges.

A d�tum �s ido beolvas�s�t a time_get jellemzon kereszt�l kezelj�k. Az alap�tlet


az, hogy
egy lok�l time_get facet-je el tudja olvasni a time_put �ltal l�trehozott idoket
�s d�tumokat.
Szabv�nyos d�tum- �s idot�pusok azonban nincsenek, ez�rt a programoz� egy locale-t

haszn�lhat arra, hogy a kimenetet k�l�nf�le form�tumoknak megfeleloen hozza l�tre.


A k�-
vetkezo �br�zol�sokat p�ld�ul mind l�tre lehet hozni egyetlen kimeneti
utas�t�ssal, �gy,
hogy a time_put jellemzot (�D.4.4.5) k�l�nb�zo lok�lokb�l haszn�ljuk:
January 15th 1999
Thursday 15th January 1999
15 Jan 1999AD
Thurs 15/1/99
A C++ szabv�ny arra biztat, hogy a time_get elk�sz�t�s�n�l �gy fogadjuk el a
d�tum- �s ido-
form�tumokat, ahogy azt a POSIX �s m�s szabv�nyok elo�rj�k. A probl�ma az, hogy
neh�z
szabv�nyos�tani a d�tum �s ido beolvas�s�nak b�rmilyen m�dj�t, amely egy adott
kult�r�-
ban szab�lyos. B�lcsebb k�s�rletezni �s megn�zni, mit ny�jt egy adott locale
(�D.6[8]). Ha
egy form�tum nem elfogadott, a programoz� m�sik, megfelelo time_get facet-et
k�sz�thet.
Az ido beolvas�s�ra haszn�lt szabv�nyos time_get a time_base oszt�lyb�l sz�rmazik:

class std::time_base {
public:
enum dateorder {
no_order, // nincs sorrend, esetleg t�bb elem is van (pl. a h�t napja)
dmy, // nap, h�nap, �v sorrend
mdy, // h�nap, nap, �v sorrend
ymd, // �v, h�nap, nap sorrend
ydm // �v, nap, h�nap sorrend
};
};
Ezt a felsorol�st arra haszn�lhatjuk, hogy egyszerus�ts�k a d�tumform�tumok
elemz�s�t.
1228 F�ggel�kek �s t�rgymutat�
A num_get -hez hasonl�an a time_get is egy bemeneti bej�r�p�ron kereszt�l f�r
hozz� �tmeneti
t�r�hoz:
template <class Ch, class In = istreambuf_iterator<Ch> >
class time_get : public locale::facet, public time_base {
public:
typedef Ch char_type;
typedef In iter_type;
explicit time_get(size_t r = 0);
dateorder date_order() const { return do_date_order(); }
// olvas�s [b:e)-b�l d-be, az s-beli form�z�si szab�lyok haszn�lat�val; hibajelz�s
az r
// be�ll�t�s�val:
In get_time(In b, In e, ios_base& s, ios_base::iostate& r, tm* d) const;
In get_date(In b, In e, ios_base& s, ios_base::iostate& r, tm* d) const;
In get_year(In b, In e, ios_base& s, ios_base::iostate& r, tm* d) const;
In get_weekday(In b, In e, ios_base& s, ios_base::iostate& r, tm* d) const;
In get_monthname(In b, In e, ios_base& s, ios_base::iostate& r, tm* d) const;
static locale::id id; // facet-azonos�t� objektum (�D.2, �D.3, �D.3.1)
protected:
~time_get();
// virtu�lis "do_" f�ggv�nyek a nyilv�nos f�ggv�nyek sz�m�ra (l�sd �D.4.1)
};
A get_time() a do_get_time() f�ggv�nyt h�vja meg. Az alap�rtelmezett get_time() a
%X form
�tum (�D.4.4) felhaszn�l�s�val �gy olvassa be az idot, ahogy a lok�l time_put()
f�ggv�-
nye l�trehozza azt. Ugyan�gy a get_date() f�ggv�ny a do_get_date()-et h�vja meg �s
az alap-
�rtelmezett get_time() a %x form�tum felhaszn�l�s�val (�D.4.4) a lok�l time_put()
f�ggv�ny�nek eredm�nye szerint olvas.
A Date t�pusok legegyszerubb bemeneti muvelete valami ilyesmi:
istream& operator>>(istream& s, Date& d)
{
istream::sentry guard(s); // l�sd �21.3.8
if (!guard) return s;
ios_base::iostate res = 0;
tm x = { 0 };
istreambuf_iterator<char,char_traits<char> > end;
D. Helyi saj�toss�gok 1229
try {
use_facet< time_get<char> >(s.getloc()).get_date(s,end,s,res,&x);
if (res==0 || res==ios_base::eofbit)
d = Date(x.tm_mday,Date::Month(x.tm_mon+1),x.tm_year+1900);
else
s.setstate(res);
}
catch (...) {
handle_ioexception(s); // l�sd �D.4.2.2
}
return s;
}
A get_date(s,end,s,res,&x) h�v�s az istream-rol val� k�t automatikus �talak�t�son
alapul: az
elso s param�ter egy istreambuf_iterator l�trehoz�s�ra haszn�latos, a harmadik
param�terk
�nt szereplo s pedig az istream b�zisoszt�ly�ra, az ios_base-re alakul �t.
A fenti bemeneti muvelet azon d�tumok eset�ben muk�dik helyesen, amelyek a time_t
t�-
pussal �br�zolhat�k.
Egy egyszeru pr�ba a k�vetkezo lenne:
int main()
try {
Date today;
cout << today << endl; // �r�s %x form�tummal
Date d(12, Date::may, 1998);
cout << d << endl;
Date dd;
while (cin >> dd) cout << dd << endl; // az %x form�tummal l�trehozott
// d�tumok olvas�sa
}
catch (Date::Bad_date) {
cout << "Rossz d�tum: a program kil�p.\n";
}
A put_time _byname v�ltozata (�D.4, �D.4.1) szint�n adott:
template <class Ch, class Out = ostreambuf_iterator<Ch> >
class std::time_put_byname : public time_put<Ch,Out> { /* ... */ };
1230 F�ggel�kek �s t�rgymutat�
D.4.4.5. Egy rugalmasabb Date oszt�ly
Ha megpr�b�ln�nk felhaszn�lni a �D.4.4.2 pontb�l a Date oszt�lyt a �D.4.4.3-ban �s

�D.4.4.4-ben szereplo be- �s kimenettel, hamarosan korl�tokba �tk�zn�nk:


1. A Date csak olyan d�tumokat tud kezelni, amelyek a time_t t�pussal �br�zolhat
�k: ez �ltal�ban az [1970,2038] tartom�nyt jelenti.
2. A Date csak a szabv�nyos form�tumban fogadja el a d�tumokat . b�rmilyen legyen
is az.
3. A Date-n�l a bemeneti hib�k jelz�se elfogadhatatlan.
4. A Date csak char t�pus� adatfolyamokat t�mogat, nem tetszoleges karakter
t�pus�akat.
Egy hasznosabb bemeneti muvelet a d�tumok sz�lesebb tartom�ny�t fogadn� el,
felismerne
n�h�ny gyakori form�tumot �s megb�zhat�an jelenten� a hib�kat valamilyen j�l
haszn�lhat
� form�ban. Ahhoz, hogy ezt el�rj�k, el kell t�rn�nk a time_t �br�zol�st�l:
class Date {
public:
enum Month { jan=1, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec };
struct Bad_date {
const char* why;
Bad_date(const char* p) : why(p) { }
};
Date(int dd, Month mm, int yy, int day_of_week = 0);
Date();
void make_tm(tm* t) const; // a Date tm �br�zol�s�t *t-be teszi
time_t make_time_t() const; // a Date time_t �br�zol�s�val t�r vissza
int year() const { return y; }
Month month() const { return m; }
int day() const { return d; }
// ...
private:
char d;
Month m;
int y;
};
Itt az egyszerus�g kedv��rt a (d,m,y) �br�zol�shoz (�10.2) t�rt�nk vissza.
D. Helyi saj�toss�gok 1231
A konstruktort �gy adhatjuk meg:
Date::Date(int dd, Month mm, int yy, int day_of_week)
: d(dd), m(mm), y(yy)
{
if (d==0 && m==Month(0) && y==0) return; // Date(0,0,0) a "null d�tum"
if (mm<jan || dec<mm) throw Bad_date("rossz a h�nap");
if (dd<1 || 31<dd) // j�csk�n leegyszerus�tve; l�sd �10.3.1
throw Bad_date("rossz a h�nap napja");
if (day_of_week && day_in_week(yy,mm,dd)!=day_of_week)
throw Bad_date("rossz a h�t napja");
}
Date::Date() : d(0), m(0), y(0) { } // egy "null d�tum"
A day_in_week() kisz�m�t�sa nem k�nnyu �s nem kapcsol�dik a lok�lokhoz, ez�rt
kihagytam.
Ha sz�ks�g�nk van r�, rendszer�nkben biztosan megtal�lhatjuk valahol.
Az �sszehasonl�t� muveletek mindig hasznosak az olyan t�pusok eset�ben, mint a
Date:
bool operator==(const Date& x, const Date& y)
{
return x.year()==y.year() && x.month()==y.month() && x.day()==y.day();
}
bool operator!=(const Date& x, const Date& y)
{
return !(x==y);
}
Mivel elt�rt�nk a szabv�nyos tm �s time_t form�tumokt�l, sz�ks�g�nk van konverzi�s

f�ggv�nyekre is, amelyek egy�tt tudnak muk�dni azokkal a programokkal, amelyek


ezeket
a t�pusokat v�rj�k el:
void Date::make_tm(tm* p) const // a d�tum *p-be helyez�se
{
tm x = { 0 };
*p = x;
p->tm_year = y-1900;
p->tm_mday = d;
p->tm_mon = m-1;
}
time_t Date::make_time_t() const
{
if (y<1970 || 2038<y) // t�legyszerus�tett
1232 F�ggel�kek �s t�rgymutat�
throw Bad_date("A d�tum a time_t tartom�ny�n k�v�l esik.");
tm x;
make_tm(&x);
return mktime(&x);
}
D.4.4.6. D�tumform�tumok megad�sa
A C++ nem hat�rozza meg a d�tumok ki�r�s�nak szabv�nyos form�tum�t (a %x k�zel�ti
meg
a legjobban; �D.4.4.3), de m�g ha l�tezne is ilyen, val�sz�nuleg szeretn�nk m�s
form�tumokat
is haszn�lni. Ezt �gy tehetj�k meg, hogy meghat�rozunk egy .alap�rtelmezett
form�tumot
. �s lehetos�get adunk annak m�dos�t�s�ra:
class Date_format {
static char fmt[]; // alap�rtelmezett form�tum
const char* curr; // az �ppen �rv�nyes form�tum
const char* curr_end;
public:
Date_format() : curr(fmt), curr_end(fmt+strlen(fmt)) { }
const char* begin() const { return curr; }
const char* end() const { return curr_end; }
void set(const char* p, const char* q) { curr=p; curr_end=q; }
void set(const char* p) { curr=p; curr_end=curr+strlen(p); }
static const char* default_fmt() { return fmt; }
};
const char Date_format<char>::fmt[] = "%A, %B %d, %Y"; // pl. Friday, February 5,
1999
Date_format date_fmt;
Hogy az strftime() form�tumot (�D.4.4.3) haszn�lhassuk, tart�zkodtam att�l, hogy
a Date_format oszt�lyt a haszn�lt karaktert�pussal param�terezzem. Ebbol
k�vetkezik, hogy
ez a megold�s csak olyan d�tumjel�l�st enged meg, amelynek form�tum�t ki lehet
fejezni
a char[] t�pussal. Ezenk�v�l felhaszn�ltam egy glob�lis form�tum-objektumot is
(date_fmt),
az alap�rtelmezett d�tumform�tum megad�s�hoz. Mivel a date_fmt �rt�k�t meg lehet
v�ltoztatni,
a Date form�z�s�hoz rendelkez�s�nkre �ll egy . meglehetosen nyers . m�dszer,
hasonl
�an ahhoz, ahogy a global() lok�lt (�D.2.3) lehet haszn�lni a form�z�sra.
D. Helyi saj�toss�gok 1233
Sokkal �ltal�nosabb megold�s, ha l�trehozzuk a Date_in �s Date_out facet-eket az
adatfolyamb
�l t�rt�no olvas�s �s �r�s vez�rl�s�hez. Ezt a megk�zel�t�st a �D.4.4.7 pontban
mutatjuk
be. Ha adott a Date_format, a Date::operator<<()-t �gy �rhatjuk meg:
template<class Ch, class Tr>
basic_ostream<Ch,Tr>& operator<<(basic_ostream<Ch,Tr>& s, const Date& d)
// �r�s felhaszn�l�i form�tummal
{
typename basic_ostream<Ch,Tr>::sentry guard(s); // l�sd �21.3.8
if (!guard) return s;
tm t;
d.make_tm(&t);
try {
const time_put<Ch>& f = use_facet< time_put<Ch> >(s.getloc());
if (f.put(s,s,s.fill(),&t,date_fmt.begin(),date_fmt.end()).failed())
s.setstate(ios_base::failbit);
}
catch (...) {
handle_ioexception(s); // l�sd �D.4.2.2
}
return s;
}
A has_facet f�ggv�nnyel ellenorizhetn�nk, hogy az s lok�lja rendelkezik-e a
time_put<Ch>
jellemzovel, itt azonban egyszerubb �gy kezelni a probl�m�t, hogy minden kiv�telt
elkapunk,
amit a use_facet kiv�lt.
�me egy egyszeru tesztprogram, ami a kimenet form�tum�t a date_fmt-n kereszt�l
vez�rli:
int main()
try {
while (cin >> dd && dd != Date()) cout << dd << endl; // �r�s az alap�rtelmezett
// date_fmt haszn�lat�val
date_fmt.set("%Y/%m/%d");
while (cin >> dd && dd != Date()) cout << dd << endl; // �r�s az "%Y/%m/%d"
// haszn�lat�val
}
catch (Date::Bad_date e) {
cout << "Rossz d�tum: " << e.why << endl;
}
1234 F�ggel�kek �s t�rgymutat�
D.4.4.7. Bemeneti facet-ek d�tumokhoz
Mint mindig, a bemenet kezel�se kicsit nehezebb, mint a kimenet�. M�gis, mivel
a get_date() jav�tott a fel�leten az alacsonyszintu bemenethez �s mert a �D.4.4.4
pontban
a Date t�pushoz megadott operator>>() nem f�rt hozz� k�zvetlen m�don a Date
�br�zol�-
s�hoz, az operator>>()-t v�ltozatlanul haszn�lhatjuk. �me az operator>>() sablon
f�ggv�nyk
�nt meg�rt v�ltozata:
template<class Ch, class Tr>
istream<Ch,Tr>& operator>>(istream<Ch,Tr>& s, Date& d)
{
typename istream<Ch,Tr>::sentry guard(s);
if (guard) try {
ios_base::iostate res = 0;
tm x = { 0 };
istreambuf_iterator<Ch,Tr> end;
use_facet< time_get<Ch> >(s.getloc()).get_date(s,end,s,res,&x);
if (res==0 || res==ios_base::eofbit)
d = Date(x.tm_mday,Date::Month(x.tm_mon+1),x.tm_year+1900,x.tm_wday);
else
s.setstate(res);
}
catch (...) {
handle_ioexception(s); // l�sd �D.4.2.2
}
return s;
}
Ez a bemeneti muvelet az istream time_get jellemzoj�nek get_date() f�ggv�ny�t
h�vja meg,
�gy a bemenet �j, rugalmasabb form�j�t adhatjuk meg, �gy, hogy sz�rmaztat�ssal egy
�j
facet-et k�sz�t�nk a time_get-bol:
template<class Ch, class In = istreambuf_iterator<Ch> >
class Date_in : public std::time_get<Ch,In> {
public:
Date_in(size_t r = 0) : std::time_get<Ch>(r) { }
protected:
In do_get_date(In b, In e, ios_base& s, ios_base::iostate& r, tm* tmp) const;
private:
enum Vtype { novalue, unknown, dayofweek, month };
In getval(In b, In e, ios_base& s, ios_base::iostate& r, int* v, Vtype* res)
const;
};
D. Helyi saj�toss�gok 1235
A getval() f�ggv�nynek egy �vet, egy h�napot, a h�nap napj�t �s a h�t egy napj�t
kell beolvasnia
(ez ut�bbi nem k�telezo), az eredm�nyt pedig egy tm szerkezetbe kell tennie.
A h�napok �s a h�t napjainak nevei a lok�lt�l f�ggnek, k�vetkez�sk�ppen nem
eml�thetj
�k meg azokat k�zvetlen�l a bemeneti f�ggv�nyben. Ehelyett a h�napokat �s napokat
�gy
ismerj�k fel, hogy megh�vjuk azokat a f�ggv�nyeket, amelyeket a time_get ad erre a
c�lra:
a get_monthname() �s get_weekday() f�ggv�nyeket (�D.4.4.4).
Az �v, a h�nap napja �s val�sz�nuleg a h�nap is eg�szk�nt van �br�zolva. Sajnos
egy sz�m
nem jelzi, hogy egy h�nap napj�t jel�li-e vagy valami eg�szen m�st. A 7 p�ld�ul
jel�lhet j�-
liust, egy h�nap 7. napj�t vagy �ppen a 2007-es �vet is. A time_get date_order()
f�ggv�ny�-
nek val�di c�lja az, hogy feloldja az eff�le t�bb�rtelmus�geket.
A Date_in �rt�keket olvas be, oszt�lyozza azokat, majd a date_order() f�ggv�nnyel
megn�-
zi, a be�rt adatok �rtelmesek-e (illetve .hogyan �rtelmesek.). A t�nyleges
olvas�st az adatfolyam
�tmeneti t�r�b�l, illetve a kezdeti oszt�lyoz�st a priv�t getval() f�ggv�ny v�gzi:

template<class Ch, class In>


In Date_in<Ch,In>::getval(In b,In e,ios_base& s,ios_base::iostate& r,int* v,Vtype*
res)
const
// A Date r�sz�nek olvas�sa: sz�m, a h�t napja vagy h�nap. �reshelyek �s �r�sjelek
�tl�p�se.
{
const ctype<Ch>& ct = use_facet< ctype<Ch> >(s.getloc()); // a ctype le�r�s�t
// l�sd �D.4.5.-ben
Ch c;
*res = novalue; // nem tal�lt �rt�ket
for (;;) { // �reshelyek �s �r�sjelek �tl�p�se
if (b == e) return e;
c = *b;
if (!(ct.is(ctype_base::space,c) || ct.is(ctype_base::punct,c))) break;
++b;
}
if (ct.is(ctype_base::digit,c)) { // eg�sz olvas�sa a numpunct figyelmen k�v�l
hagy�s�val
int i = 0;
do { // tetszoleges karakterk�szlet sz�mjegy�nek decim�lis �rt�kk� alak�t�sa
static char const digits[] = "0123456789";
i = i*10 + find(digits,digits+10,ct.narrow(c,' '))-digits;
c = *++b;
} while (ct.is(ctype_base::digit,c));
*v = i;
1236 F�ggel�kek �s t�rgymutat�
*res = unknown; // egy eg�sz, de nem tudjuk, mit �br�zol
return b;
}
if (ct.is(ctype_base::alpha,c)) { // h�nap nev�nek vagy a h�t napj�nak keres�se
basic_string<Ch> str;
while (ct.is(ctype_base::alpha,c)) { // karakterek olvas�sa karakterl�ncba
str += c;
if (++b == e) break;
c = *b;
}
tm t;
basic_stringstream<Ch> ss(str);
typedef istreambuf_iterator<Ch> SI; // bej�r�t�pus az ss �tmeneti t�r�hoz
get_monthname(ss.rdbuf(),SI(),s,r,&t); // olvas�s mem�riabeli adatfolyam
// �tmeneti t�r�b�l
if ((r&(ios_base::badbit|ios_base::failbit))==0) {
*v= t.tm_mon;
*res = month;
return b;
}
r = 0; // az adatfolyam-�llapot t�rl�se a m�sodik olvas�s elott
get_weekday(ss.rdbuf(),SI(),s,r,&t); // olvas�s mem�riabeli adatfolyam
// �tmeneti t�r�b�l
if ((r&(ios_base::badbit|ios_base::failbit))==0) {
*v = t.tm_wday;
*res = dayofweek;
return b;
}
}
r |= ios_base::failbit;
return b;
}
Itt a .tr�kk�s. r�sz a h�t napjainak �s a h�napoknak a megk�l�nb�ztet�se. Mivel
bemeneti
bej�r�kon kereszt�l olvasunk, nem olvashatjuk be [b,e)-t k�tszer, elosz�r egy
h�napot,
m�sodszor pedig egy napot keresve. M�sfelol nem tudjuk megk�l�nb�ztetni a
h�napokat
sem a napokt�l, ha egyszerre csak egy karaktert olvasunk be, mert csak
a get_monthname() �s a get_weekday() f�ggv�nyek tudj�k, hogy az adott lok�lban a
h�napok
�s a h�t napjainak nevei mely karaktersorozatokb�l �p�lnek fel. Azt a megold�st
v�-
lasztottam, hogy az alfabetikus karakterekbol �ll� sorozatokat beolvastam egy
karakterl�ncba,
ebbol egy stringstream-et k�sz�tettem, majd ism�telten olvastam az adatfolyam
streambuf-j�b�l.
D. Helyi saj�toss�gok 1237
A hibajelzo rendszer k�zvetlen�l haszn�lja az olyan �llapotbiteket, mint az
ios_base::badbit.
Ez az�rt sz�ks�ges, mert az adatfolyam �llapot�t kezelo k�nyelmesebb f�ggv�nyeket,
mint
a clear() �s a setstate(), a basic_ios oszt�ly hat�rozza meg, nem pedig annak
b�zisoszt�lya,
az ios_base (�21.3.3). Ha sz�ks�ges, a >> oper�tor felhaszn�lja a get_date() �ltal
jelentett hib
�kat, hogy vissza�ll�tsa a bemeneti adatfolyam �llapot�t.
Ha a getval() adott, elosz�r beolvashatjuk az �rt�keket, majd k�sobb megn�zhetj�k,
hogy
�rtelmesek-e. A dateorder() szerepe d�nto lehet:
template<class Ch, class In>
In Date_in<Ch,In>::do_get_date(In b, In e, ios_base& s, ios_base::iostate& r, tm*
tmp) const
// a "h�t napja" (nem k�telezo), melyet md, dmy, mdy, vagy ydm form�tum k�vet
{
int val[3]; // nap, h�nap, �s �v �rt�kek sz�m�ra
Vtype res[3] = { novalue }; // �rt�koszt�lyoz�shoz
for (int i=0; b!=e && i<3; ++i) { // nap, h�nap, �v beolvas�sa
b = getval(b,e,s,r,&val[i],&res[i]);
if (r) return b; // hopp�: hiba
if (res[i]==novalue) { // nem tudjuk befejezni a d�tumot
r |= ios_base::badbit;
return b;
}
if (res[i]==dayofweek) {
tmp->tm_wday = val[i];
--i; // hopp�: nem nap, h�nap, vagy �v
}
}
time_base::dateorder order = dateorder(); // most megpr�b�lunk r�j�nni
// a beolvasott adat jelent�s�re
if (res[0] == month) { // mdy form�tum vagy hiba
// ...
}
else if (res[1] == month) { // dmy vagy ymd vagy hiba
tmp->tm_mon = val[1];
switch (order)
{
case dmy:
tmp->tm_mday = val[0];
tmp->tm_year = val[2];
break;
case ymd:
tmp->tm_year = val[0];
tmp->tm_mday = val[1];
1238 F�ggel�kek �s t�rgymutat�
break;
default:
r |= ios_base::badbit;
return b;
}
}
else if (res[2] == month) { // ydm vagy hiba
// ...
}
else { // megb�zunk a dateorder-ben vagy hiba
// ...
}
tmp->tm_year -= 1900; // az alap�v igaz�t�sa a tm-hez
return b;
}
Azokat a k�dr�szleteket, amelyek nem j�rulnak hozz� a lok�lok, d�tumok �s a
bemenet kezel
�s�nek meg�rt�s�hez, kihagytam. A jobb �s �ltal�nosabb d�tumform�tumok beolvas�s�-

ra alkalmas f�ggv�nyek meg�r�s�t feladatk�nt tuztem ki (�D.6[9-10]).


�me egy egyszeru tesztprogram:
int main()
try {
cin.imbue(loc(locale(), new Date_in)); // d�tumok olvas�sa a Date_in haszn�lat�val

while (cin >> dd && dd != Date()) cout << dd << endl;


}
catch (Date::Bad_date e) {
cout << "Rossz d�tum: " << e.why << endl;
}
Vegy�k �szre, hogy a do_get_date() �rtelmetlen d�tumokat is elfogad, mint amilyen
a
Thursday October 7, 1998
�s az
1999/Feb/31
Az �v, h�nap, nap �s (nem k�telezoen) a h�t napja egys�gess�g�nek ellenorz�se a
Date
konstruktor�ban t�rt�nik. A Date oszt�lynak kell tudnia, mi alkot helyes d�tumot,
a Date_in
oszt�llyal pedig nem kell megosztania ezt a tud�st.
D. Helyi saj�toss�gok 1239
Meg lehetne oldani azt is, hogy a get_val() vagy a get_date() f�ggv�nyek pr�b�lj�k
kital�lni
a sz�m�rt�kek jelent�s�t. P�ld�ul a
12 May 1922
vil�gos, hogy nem a 12-es �v 1922. napja. Azaz .gyan�thatn�nk., hogy egy olyan
sz�m�rt�k,
ami nem lehet a megadott h�nap napja, biztosan �vet jel�l. Az ilyen feltev�sek
bizonyos
esetekben hasznosak lehetnek, de nem j� �tlet ezeket �ltal�nosabb k�rnyezetben
haszn�lni.
P�ld�ul a
12 May 15
a 12., 15., 1912.,1915., 2012., vagy 2015. �vben jel�lhet egy d�tumot. N�ha jobb
megk�zel
�t�s, ha kieg�sz�tj�k a jel�l�st valamivel, ami seg�t az �vek �s napok
megk�l�nb�ztet�s�-
ben. Az angolban a 1st �s 15th p�ld�ul biztosan egy h�nap napjait jel�lik.
Ugyan�gy
a 751BC-t �s az 1453AD-t (i.e.751 �s i.sz.1453) nyilv�nval�an �vk�nt lehetne
azonos�tani.
D.4.5. Karakterek oszt�lyoz�sa
Amikor a bemenetrol karaktereket olvasunk be, gyakran van sz�ks�g arra, hogy
oszt�lyozzuk
azokat, hogy �rtelmezhess�k, mit is olvastunk. Egy sz�m beolvas�s�hoz p�ld�ul egy
bemeneti elj�r�snak tudnia kell, hogy a sz�mjegyeket mely karakterek jel�lik. A
�6.1.2 pontban
is bemutattuk a szabv�nyos karakteroszt�lyoz� f�ggv�nyek egy felhaszn�l�s�t a
bemenet
elemz�s�re.
Term�szetesen a karakterek oszt�lyoz�sa f�gg az �ppen haszn�latos �b�c�tol. Ez�rt
rendelkez
�s�nkre �ll a ctype jellemzo, amely az adott lok�lban a karakterek oszt�lyoz�s�t
�br�zolja.
A karakteroszt�lyokat a mask felsorol� t�pus hat�rozza meg:
class std::ctype_base {
public:
enum mask { // a t�nyleges �rt�kek megval�s�t�sf�ggoek
space = 1, // �reshely (a "C" lok�lban . ., .\n., .\t., ...)
print = 1<<1, // nyomtathat� karakterek
cntrl = 1<<2, // vez�rlokarakterek
upper = 1<<3, // nagybetuk
lower = 1<<4, // kisbetuk
alpha = 1<<5, // alfabetikus karakterek
digit = 1<<6, // decim�lis sz�mjegyek
punct = 1<<7, // �r�sjelek
1240 F�ggel�kek �s t�rgymutat�
xdigit = 1<<8, // hexadecim�lis sz�mjegyek
alnum=alpha|digit, // alfanumerikus karakterek
graph=alnum|punct
};
};
A mask nem f�gg egyetlen karaktert�pust�l sem, k�vetkez�sk�ppen a felsorol�s egy
(nem
sablon) b�zisoszt�lyban tal�lhat�.
Vil�gos, hogy a mask a hagyom�nyos C �s C++-beli oszt�lyoz�st t�kr�zi (�20.4.1).
Elt�ro karakterk
�szletek eset�ben azonban a k�l�nb�zo karakter�rt�kek k�l�nb�zo oszt�lyokba esnek.

Az ASCII karakterk�szletben p�ld�ul a 125 eg�sz �rt�k a .}. karaktert jel�li, ami
az �r�sjelekhez
(punct) tartozik, a d�n karakterk�szletben viszont az .a. mag�nhangz�t, amit egy
d�n locale-ben az alpha oszt�lyba kell sorolni.
Az oszt�lyoz�st .maszknak. nevezik, mert a kis karakterk�szletek hagyom�nyos �s
hat�-
kony oszt�lyoz�sa egy t�bl�val t�rt�nik, amelyben minden bejegyz�s az
oszt�ly(oka)t �br�-
zol� biteket t�rolja:
table[�a�] == lower|alpha|xdigit
table[�1�] == digit
table[� �] == space
Ha a fenti adott, a table[c]&m nem nulla, ha a c karakter az m oszt�lyba tartozik
(.c egy m.),
egy�bk�nt pedig 0.
A ctype defin�ci�ja �gy fest:
template <class Ch>
class std::ctype : public locale::facet, public ctype_base {
public:
typedef Ch char_type;
explicit ctype(size_t r = 0);
bool is(mask m, Ch c) const; // "c" az "m" oszt�lyba tartozik?
// minden [b:e)-beli Ch oszt�lyoz�sa, az eredm�ny a v-be ker�l
const Ch* is(const Ch* b, const Ch* e, mask* v) const;
const Ch* scan_is(mask m, const Ch* b, const Ch* e) const; // m keres�se
const Ch* scan_not(mask m, const Ch* b, const Ch* e) const; // nem m keres�se
D. Helyi saj�toss�gok 1241
Ch toupper(Ch c) const;
const Ch* toupper(Ch* b, const Ch* e) const; // [b:e) �talak�t�sa
Ch tolower(Ch c) const;
const Ch* tolower(Ch* b, const Ch* e) const;
Ch widen(char c) const;
const char* widen(const char* b, const char* e, Ch* b2) const;
char narrow(Ch c, char def) const;
const Ch* narrow(const Ch* b, const Ch* e, char def, char* b2) const;
static locale::id id; // facet-azonos�t� objektum (�D.2, �D.3, �D.3.1)
protected:
~ctype();
// virtu�lis "do_" f�ggv�nyek a nyilv�nos f�ggv�nyek sz�m�ra (l�sd �D.4.1)
};
Az is(c,m) h�v�ssal vizsg�lhatjuk meg, hogy a c karakter az m oszt�lyba tartozik-
e:
int count_spaces(const string& s, const locale& loc)
{
const ctype<char>& ct = use_facet< ctype<char> >(loc);
int i = 0;
for(string::const_iterator p = s.begin(); p != s.end(); ++p)
if (ct.is(ctype_base::space,*p)) ++i; // �reshely a ct meghat�roz�sa alapj�n
return i;
}
Az is() f�ggv�nnyel azt is megn�zhetj�k, hogy egy karakter adott oszt�lyok
valamelyik�be
tartozik-e:
ct.is(ctype_base::space|ctype_base::punct,c); // c �reshely vagy �r�sjel ct
alapj�n?
Az is(b,e,v) h�v�s a [b,e)-ben szereplo minden karakter oszt�ly�t eld�nti �s a
megfelelo poz
�ci�ra helyezi azokat a v t�mbben.
A scan_is(m,b,e) egy mutat�t ad vissza a [b,e)-ben l�vo elso olyan karakterre,
amely az m
oszt�lyba tartozik. Ha egyetlen karakter sem tartozik az m oszt�lyba, a f�ggv�ny
az e-t adja
vissza. Mint mindig a szabv�nyos facet-ek eset�ben, a nyilv�nos tagf�ggv�ny
saj�t .do_.
virtu�lis f�ggv�ny�t h�vja meg. Egy egyszeru v�ltozat a k�vetkezo lenne:
1242 F�ggel�kek �s t�rgymutat�
template <class Ch>
const Ch* std::ctype<Ch>::do_scan_is(mask m, const Ch* b, const Ch* e) const
{
while (b!=e && !is(m,*b)) ++b;
return b;
}
A scan_not(m,b,e) a [b,e)-ben l�vo elso olyan karakterre ad vissza mutat�t, amely
nem tartozik
az m oszt�lyba. Ha minden karakter az m oszt�lyba tartozik, a f�ggv�ny az e-t adja

vissza.
A toupper(c) a c nagybetus v�ltozat�t adja vissza, ha az l�tezik a haszn�latban
l�vo karakterk
�szletben; k�l�nben pedig mag�t a c-t.
A toupper(b,e) a [b,e) tartom�nyban minden karaktert nagybetusre alak�t �s az e-t
adja
vissza. Ennek egy egyszeru megval�s�t�sa a k�vetkezo lehet:
template <class Ch>
const Ch* std::ctype<Ch>::to_upper(Ch* b, const Ch* e)
{
for ( ; b!=e; ++b) *b = toupper(*b);
return e;
}
A tolower() f�ggv�nyek hasonl�ak a toupper()-hez, azzal az elt�r�ssel, hogy
kisbetusre alak
�tanak.
A widen(c) a c karaktert a neki megfelelo Ch t�pus� �rt�kre alak�tja. Ha a Ch
karakterk�szlete
t�bb c-nek megfelelo karaktert ny�jt, a szabv�ny .a legegyszerubb �sszeru
�talak�t�s.
alkalmaz�s�t �rja elo. P�ld�ul a
wcout << use_facet< ctype<wchar_t> >(wcout.getloc()).widen('e');
az e karakternek a wcout lok�lban l�vo �sszeru megfeleloj�t fogja ki�rni.
A k�l�nb�zo karakter�br�zol�sok, mint az ASCII �s az EBCDIC k�z�tti �talak�t�st
szint�n el
lehet v�gezni a widen() f�ggv�nnyel. P�ld�ul tegy�k fel, hogy l�tezik az ebcdic
lok�l:
char EBCDIC_e = use_facet< ctype<char> >(ebcdic).widen('e');
A widen(b,e,v) h�v�s a [b,e) tartom�nyban l�vo minden karakter .sz�les�tett.
v�ltozat�t helyezi
a megfelelo poz�ci�ra a v t�mbben.
D. Helyi saj�toss�gok 1243
A narrow(ch,def) egy char t�pus� �rt�ket ad a Ch t�pus� ch karakternek. Itt is
a .legegyszer
ubb �sszeru �talak�t�st. kell alkalmazni. Ha nem l�tezik megfelelo char t�pus�
�rt�k,
a f�ggv�ny a def-et adja vissza.
A narrow(b,e,v) h�v�s a [b,e) tartom�nyban l�vo minden karakter .leszuk�tett.
v�ltozat�t helyezi
a megfelelo poz�ci�ra a v t�mbben.
Az �ltal�nos elgondol�s az, hogy a narrow() a nagyobb karakterk�szletet alak�tja
egy kisebbre,
m�g a widen() ennek ellenkezoj�t v�gzi. Egy kisebb karakterk�szletben szereplo c
karakter eset�ben elv�rn�nk a k�vetkezot:
c == narrow(widen(c), 0) // nem garant�lt
Ez akkor igaz, ha a c �ltal �br�zolt karakternek csak egyetlen jel�l�se van a
.kisebbik. karakterk
�szletben, ez azonban nem biztos. Ha a char t�pussal �br�zolt karakterek nem k�-
pezik r�szhalmaz�t azoknak, amelyeket a nagyobb (Ch) karakterk�szlet �br�zol,
rendelleness
�gekre �s probl�m�kra sz�m�thatunk a karaktereket �ltal�noss�gban kezelo
programokban.
A nagyobb karakterk�szletben l�vo ch karakterre ugyan�gy elv�rn�nk az al�bbit:
widen(narrow(ch,def)) == ch || widen(narrow(ch,def)) == widen(def) // nem
garant�lt
Ez gyakran teljes�l, de a nagyobb karakterk�szletben t�bb �rt�kkel jel�lt
karakterek eset�-
ben nem mindig biztos�that�, hogy csak egyszer legyenek �br�zolva a kisebbik
k�szletben.
Egy sz�mjegynek (pl. a 7-nek) p�ld�ul gyakran t�bb elt�ro �br�zol�sa l�tezik egy
nagy karakterk
�szletben. Ennek jellemzoen az az oka, hogy egy nagy karakterk�szletnek �ltal�ban
sz�mos hagyom�nyos karakterk�szlet-r�szhalmaza van �s a kisebb karakterk�szletek
karaktereib
ol m�sodp�ld�nyok l�teznek, hogy megk�nny�ts�k az �talak�t�st.
Az alap karakterk�szletben (�C.3.3) szereplo minden karakterre biztos�tott a
k�vetkezo:
widen(narrow(ch_lit,0)) == ch_lit
P�ld�ul:
widen(narrow(�x�)) == �x�
1244 F�ggel�kek �s t�rgymutat�
A narrow() �s widen() f�ggv�nyek minden�tt figyelembe veszik a karakterek
oszt�lyoz�-
s�t, ahol lehets�ges. P�ld�ul ha is(alpha,c) igaz, akkor az
is(alpha,narrow(c,.a.)) �s az
is(alpha,widen(c)) is igaz lesz ott, ahol az alpha �rv�nyes maszk a haszn�latban
l�vo lok�lra
n�zve.
A ctype facet-et . k�l�n�sen a narrow() �s widen() f�ggv�nyeket . �ltal�ban arra
haszn�ljuk,
hogy olyan k�dot �rjunk, amely tetszoleges karakterk�szleten v�gzi a be- �s
kimenet,
illetve a karakterl�ncok kezel�s�t; azaz, hogy az ilyen k�dot �ltal�noss� tegy�k a
karakterk
�szletek szempontj�b�l. Ebbol k�vetkezik, hogy az iostream-megval�s�t�sok
alapvetoen
f�ggnek ezektol az eszk�z�ktol. A felhaszn�l�nak legt�bbsz�r nem kell k�zvetlen�l
haszn
�lnia a ctype jellemzot, ha az <iostream>-re �s a <string>-re t�maszkodik.
A ctype _byname v�ltozata (�D.4, �D.4.1) szint�n adott:
template <class Ch> class std::ctype_byname : public ctype<Ch> { /* ... */ };
D.4.5.1. K�nyelmet szolg�l� fel�letek
A ctype facet-et leggyakrabban arra haszn�ljuk, hogy lek�rdezz�k, hogy egy
karakter egy
adott oszt�lyba tartozik-e. K�vetkez�sk�ppen erre a c�lra a k�vetkezo f�ggv�nyek
adottak:
template <class Ch> bool isspace(Ch c, const locale& loc);
template <class Ch> bool isprint(Ch c, const locale& loc);
template <class Ch> bool iscntrl(Ch c, const locale& loc);
template <class Ch> bool isupper(Ch c, const locale& loc);
template <class Ch> bool islower(Ch c, const locale& loc);
template <class Ch> bool isalpha(Ch c, const locale& loc);
template <class Ch> bool isdigit(Ch c, const locale& loc);
template <class Ch> bool ispunct(Ch c, const locale& loc);
template <class Ch> bool isxdigit(Ch c, const locale& loc);
template <class Ch> bool isalnum(Ch c, const locale& loc);
template <class Ch> bool isgraph(Ch c, const locale& loc);
A fenti f�ggv�nyek a use_facet-et haszn�lj�k:
template <class Ch>
inline bool isspace(Ch c, const locale& loc)
{
return use_facet< ctype<Ch> >(loc).is(space, c);
}
D. Helyi saj�toss�gok 1245
Ezen f�ggv�nyek egyparam�teru v�ltozatai (�20.4.2) az aktu�lis C glob�lis
lok�lhoz, nem
a C++ glob�lis lok�lj�hoz, a locale()-hez k�sz�ltek. Azokat a ritka eseteket
kiv�ve, amikor
a C �s a C++ glob�lis lok�l k�l�nb�zik (�D.2.3), ezeket a v�ltozatokat �gy
tekinthetj�k,
mintha a k�tparam�teru v�ltozatokat a locale()-re alkalmaztuk volna:
inline int isspace(int i)
{
return isspace(i, locale()); // majdnem
}
D.4.6. Karakterk�d-�talak�t�sok
A f�jlban t�rolt karakterek �br�zol�sa n�ha k�l�nb�zik ugyanazoknak a
karaktereknek az
elsodleges mem�ri�ban k�v�natos �br�zol�s�t�l. A jap�n karaktereket p�ld�ul
gyakran
olyan f�jlokban t�rolj�k, amelyekben .l�ptet�sek. jelzik, hogy az adott
karaktersorozat
a n�gy legelterjedtebb karakterk�szlet (kandzsi, katakana, hiragana �s romadzsi)
k�z�l melyikhez
tartozik. Ez kiss� esetlen megold�s, mert minden b�jt jelent�se a .l�ptet�si
�llapott
�l. f�gg, de mem�ri�t takar�that meg, mert csak egy kandzsi karakter �br�zol�sa
ig�nyel
egy b�jtn�l t�bbet. Az elsodleges mem�ri�ban ezek a karakterek k�nnyebben
kezelhetok,
ha t�bb�jtos karakterk�nt �br�zoltak, ahol minden karakter m�rete megegyezik. Az
ilyen
karakterek (p�ld�ul a Unicode karakterek) �ltal�ban sz�les karakterekben vannak
elhelyezve
(wchar_t; �4.3). Mindezek miatt a codecvt facet eszk�z�ket ny�jt a karakterek
egyik �br
�zol�sr�l a m�sikra val� �talak�t�s�ra; mik�zben azokat olvassuk vagy �rjuk:
1246 F�ggel�kek �s t�rgymutat�
�br�zol�s lemezen:
�br�zol�s az elsodleges mem�ri�ban:
A codecvt �ltal fel�gyelt I/O �talak�t�sok
JIS
Unicode
Ez a k�d�talak�t� rendszer el�g �ltal�nos ahhoz, hogy a karakter�br�zol�sok k�z�tt
tetszo-
leges �talak�t�st tegyen lehetov�, �gy a bemeneti adatfolyamok �ltal haszn�lt
locale be�ll�t�-
s�val olyan programot �rhatunk, amely (char, wchar_t vagy m�s t�pusban t�rolt)
alkalmas
belso karakter�br�zol�st haszn�l �s t�bbf�le karakter-adatfolyam �br�zol�st
elfogad bemenetk
�nt. A m�sik lehetos�g az lenne, hogy mag�t a programot m�dos�tjuk vagy a
beolvasott
�s ki�rt f�jlok form�tum�t alak�tjuk oda-vissza.
A codecvt a k�l�nb�zo karakterk�szletek k�z�tti �talak�t�sra akkor ad lehetos�get,
amikor
a karaktert az adatfolyam �tmeneti t�ra �s egy k�lso t�r k�z�tt mozgatjuk:
class std::codecvt_base {
public:
enum result { ok, partial, error, noconv }; // eredm�nyjelzo
};
template <class I, class E, class State>
class std::codecvt : public locale::facet, public codecvt_base {
public:
typedef I intern_type;
typedef E extern_type;
typedef State state_type;
explicit codecvt(size_t r = 0);
result in(State&, const E* from, const E* from_end, const E*& from_next, //
olvas�s
I* to, I* to_end, I*& to_next) const;
result out(State&, const I* from, const I* from_end, const I*& from_next, // �r�s
E* to, E* to_end, E*& to_next) const;
result unshift(State&, E* to, E* to_end, E*& to_next) const; // karaktersorozat
v�ge
int encoding() const throw(); // alapveto k�dol�si tulajdons�gok
bool always_noconv() const throw(); // mehet az I/O k�d�talak�t�s n�lk�l?
int length(const State&, const E* from, const E* from_end, size_t max) const;
int max_length() const throw(); // a lehets�ges legnagyobb length()
static locale::id id; // facet-azonos�t� objektum (�D.2, �D.3, �D.3.1)
protected:
~codecvt();
// virtu�lis "do_" f�ggv�nyek a nyilv�nos f�ggv�nyek sz�m�ra (l�sd �D.4.1)
};
D. Helyi saj�toss�gok 1247
A codecvt facet-et a basic_filebuf (�21.5) karakterek olvas�s�hoz �s �r�s�hoz
haszn�lja �s az
adatfolyam lok�lj�b�l olvassa ki (�21.7.1).
A State sablonparam�ter az �ppen �talak�tott adatfolyam l�ptet�si �llapot�nak
t�rol�s�ra
szolg�l� t�pus. Ha specializ�ci�t k�sz�t�nk belole, a State-et a k�l�nb�zo
�talak�t�sok azonos
�t�s�ra is felhaszn�lhatjuk. Ez ut�bbi az�rt hasznos, mert �gy t�bbfajta
karakterk�dol�shoz
(karakterk�szlethez) tartoz� karaktereket lehet ugyanolyan t�pus� objektumokban
t�rolni:
class JISstate { /* .. */ };
p = new codecvt<wchar_t,char,mbstate_t>; // szabv�nyos char-r�l sz�les karakterre
q = new codecvt<wchar_t,char,JISstate>; // JIS-rol sz�les karakterre
A k�l�nb�zo State param�terek n�lk�l a facet nem tudn� meg�llap�tani, melyik
k�dol�st t�-
telezze fel egy adott char adatfolyamra. A rendszer szabv�nyos �talak�t�s�t a char
�s
a wchar_t t�pusok k�z�tt a <cwchar> vagy <wchar.h> fej�llom�nyban l�vo mbstate_t
t�pus
�rja le.
Sz�rmaztatott oszt�lyk�nt, n�vvel azonos�tva �j codecvt-t is l�trehozhatunk:
class JIScvt : public codecvt<wchar_t,char,mbstate_t> { /* ... */ };
Az in(s,from,from_end,from_next,to,to_end,to_next) h�v�s minden karaktert beolvas
a [from,from_next) tartom�nyb�l �s megpr�b�lja �talak�tani azokat. Ha egy
karakterrel v�gzett,
akkor azt �j alakj�ban a [to,to_end) tartom�ny megfelelo hely�re �rja; ha
�talak�t�sra
nem ker�l sor, a f�ggv�ny ezen a ponton meg�ll. A visszat�r�skor az in() a
from_next-ben
az utols� beolvasott karakter ut�ni poz�ci�t, a to_next-ben pedig az utols� �rott
karakter ut�-
ni poz�ci�t t�rolja. Az in() �ltal visszaadott result �rt�k jelzi, hogy a f�ggv�ny
mennyire tudta
elv�gezni a munk�t:
ok: A [from,from_end) tartom�nyban minden karakter �talak�t�sra ker�lt.
partial: A [from,from_end) tartom�nyban nem minden karakter ker�lt �talak�t�sra.
error: Az out() olyan karakterrel tal�lkozott, amit nem tudott �talak�tani.
noconv: Nem volt sz�ks�g �talak�t�sra.
A partial (r�szleges) �talak�t�s nem biztos, hogy hiba. Elk�pzelheto, hogy t�bb
karaktert
kell beolvasni, mielott egy t�bb�jtos karakter teljes lesz �s ki lehet �rni,
esetleg a kimeneti
�tmeneti t�rat kell ki�r�teni, hogy helyet csin�ljunk a tov�bbi karaktereknek.
1248 F�ggel�kek �s t�rgymutat�
A bemeneti karaktersorozat �llapot�t az in() megh�v�s�nak kezdet�n a State t�pus�
s param
�ter jelzi. Ennek akkor van jelentos�ge, ha a k�lso karakter�br�zol�s l�ptet�si
�llapotokat
haszn�l. Jegyezz�k meg, hogy az s (nem konstans) referencia param�ter: a h�v�s
v�g�n
a bemeneti sorozat l�ptet�s�nek �llapot�t t�rolja, ami lehetov� teszi, hogy a
programoz�
kezelhesse a r�szleges �talak�t�sokat �s hossz� sorozatokat is �talak�thasson az
in() t�bbsz
�ri megh�v�s�val. Az out(s,from,from_end,from_next,to,to_end,to_next) ugyan�gy
alak
�tja �t a [from,from_end)-et a belso �br�zol�sr�l a k�lsore, ahogy az in() a k�lso
�br�zol
�st a belsore.
A karakterfolyamoknak .semleges. (.nem l�ptetett.) �llapotban kell kezdodni�k �s
v�gz
odni�k. Ez az �llapot �ltal�ban a State(). Az unshift(s,to,to_end,to_next) h�v�s
megn�zi az
s-t �s a [to,to_end)-be annyi karaktert tesz, amennyire sz�ks�g van ahhoz, hogy a
karaktersorozatot
vissza�ll�tsa a nem l�ptetett �llapotba. Az unshift() eredm�nye �s a to_next
felhaszn
�l�si m�dja az out() f�ggv�ny�vel azonos.
A length(s,from,from_end,max) azoknak a karaktereknek a sz�m�t adja vissza,
amelyeket
az in() �t tudott alak�tani a [from,from_end)-bol.
Az encoding() visszat�r�si �rt�kei a k�vetkezok lehetnek:
-1, ha a k�lso karakterk�szlet k�dol�sa �llapotot (p�ld�ul l�ptetett �s nem
l�ptetett
karaktersorozatokat) haszn�l,
0, ha a k�dol�s az egyes karakterek �br�zol�s�ra k�l�nb�zo sz�m� b�jtot haszn�l
(p�ld�ul egy b�jtban egy bitet annak a jel�l�s�re, hogy egy vagy k�t b�jtos-e
a karakter �br�zol�sa.),
n, ha a k�lso karakterk�szlet minden karakter�nek �br�zol�sa pontosan n b�jtos.
Az always_noconv() h�v�s true-t ad vissza, ha a belso �s a k�lso karakterk�szletek
k�z�tt
nincs sz�ks�g �talak�t�sra, k�l�nben pedig false-t. Vil�gos, hogy az
always_noconv()==true
megnyitja a lehetos�get az adott nyelvi v�ltozat sz�m�ra, hogy a leheto
leghat�konyabb
megval�s�t�st ny�jtsa; az�ltal, hogy egy�ltal�n nem h�vja meg az �talak�t�
f�ggv�nyeket.
A max_length() h�v�s azt a legnagyobb �rt�ket adja vissza, amit a length()
visszaadhat egy
adott �rv�nyes param�terhalmazra.
A bemenet nagybetusre alak�t�sa a legegyszerubb k�d�talak�t�s. Annyira egyszeru,
amennyire csak egy codecvt lehet, m�gis ell�tja a feladat�t:
class Cvt_to_upper : public codecvt<char,char,mbstate_t> { // nagybetuss� alak�t�s

explicit Cvt_to_upper(size_t r = 0) : codecvt(r) { }


D. Helyi saj�toss�gok 1249
protected:
// k�lso �br�zol�s olvas�sa, belso �br�zol�s �r�sa:
result do_in(State& s, const char* from, const char* from_end, const char*&
from_next,
char* to, char* to_end, char*& to_next) const;
// belso �br�zol�s olvas�sa, k�lso �br�zol�s �r�sa:
result do_out(State& s, const char* from, const char* from_end, const char*&
from_next,
char* to, char* to_end, char*& to_next) const
{
return codecvt<char,char,mbstate_t>::do_out
(s,from,from_end,from_next,to,to_end,to_next);
}
result do_unshift(State&, E* to, E* to_end, E*& to_next) const { return ok; }
int do_encoding() const throw() { return 1; }
bool do_always_noconv() const throw() { return false; }
int do_length(const State&, const E* from, const E* from_end, size_t max) const;
int do_max_length() const throw(); // a lehets�ges legnagyobb length()
};
codecvt<char,char,mbstate_t>::result
Cvt_to_upper::do_in(State& s, const char* from, const char* from_end,
const char*& from_next, char* to, char* to_end, char*& to_next) const
{
// ... �D.6[16] ...
}
int main() // egyszeru teszt
{
locale ulocale(locale(), new Cvt_to_upper);
cin.imbue(ulocale);
while (cin>>ch) cout << ch;
}
A codecvt _byname v�ltozata (�D.4, �D.4.1) is adott:
template <class I, class E, class State>
class std::codecvt_byname : public codecvt<I,E,State> { /* ... */ };
1250 F�ggel�kek �s t�rgymutat�
D.4.7. �zenetek
Term�szetesen minden felhaszn�l� a saj�t anyanyelv�t szereti haszn�lni, amikor
.t�rsalog.
a programmal, a lok�lt�l f�ggo �zenetek kifejez�s�re azonban nem tudunk szabv�nyos
elj
�r�st biztos�tani. A k�nyvt�r csup�n egyszeru eszk�z�ket ny�jt ahhoz, hogy
lok�lf�ggo karakterl
�nc-halmazokat t�rolhassunk, melyekbol egyszeru �zeneteket (message) hozhatunk
l�tre. A messages oszt�ly alapj�ban v�ve egy igen egyszeru, csak olvashat�
adatb�zist �r le:
class std::messages_base {
public:
typedef int catalog; // katal�gus-azonos�t� t�pus
};
template <class Ch>
class std::messages : public locale::facet, public messages_base {
public:
typedef Ch char_type;
typedef basic_string<Ch> string_type;
explicit messages(size_t r = 0);
catalog open(const basic_string<char>& fn, const locale&) const;
string_type get(catalog c, int set, int msgid, const string_type& d) const;
void close(catalog c) const;
static locale::id id; // facet-azonos�t� objektum (�D.2, �D.3, �D.3.1)
protected:
~messages();
// virtu�lis "do_" f�ggv�nyek a nyilv�nos f�ggv�nyek sz�m�ra (l�sd �D.4.1)
};
Az open(s,loc) h�v�s megnyitja az s nevu .�zenetkatal�gust. a loc lok�lban. A
katal�gus egy
megval�s�t�st�l f�ggoen elrendezett karakterl�nc-halmaz, amelyhez a
messages::get() f�ggv
�nnyel f�rhet�nk hozz�. Ha az s nevu katal�gust nem lehet megnyitni, az open()
negat�v
�rt�ket ad vissza. A katal�gust meg kell nyitni a get() elso haszn�lata elott.
A close(cat) h�v�s bez�rja a cat �ltal azonos�tott katal�gust �s minden vele
kapcsolatos ero-
forr�st felszabad�t.
A get(cat,set,id,.foo.) a (set,id)-vel azonos�tott �zenetet keresi meg a cat
katal�gusban. Ha
megtal�lja a karakterl�ncot, akkor a get() ezzel t�r vissza; ha nem, az
alap�rtelmezett karakterl
�nccal (itt ez a.foo.).
D. Helyi saj�toss�gok 1251
�me egy p�lda a messages facet-re, ahol az �zenetkatal�gus .�zenetek. halmaz�b�l
�ll�
vektor, az .�zenet. pedig egy karakterl�nc:
struct Set {
vector<string> msgs;
};
struct Cat {
vector<Set> sets;
};
class My_messages : public messages<char> {
vector<Cat>& catalogs;
public:
explicit My_messages(size_t = 0) : catalogs(*new vector<Cat>) { }
catalog do_open(const string& s, const locale& loc) const; // az s katal�gus
megnyit�sa
string do_get(catalog c, int s, int m, const string&) const; // az (s,m) �zenet
// megszerz�se c-bol
void do_close(catalog cat) const
{
if (catalogs.size()<=cat) catalogs.erase(catalogs.begin()+cat);
}
~My_messages() { delete &catalogs; }
};
A messages minden tagf�ggv�nye const, �gy a katal�gus adatszerkezete (a
vector<Set>)
a facet-en k�v�l t�rol�dik.
Az �zeneteket egy katal�gus, azon bel�l egy halmaz, majd a halmazon bel�l egy
�zenetkarakterl
�nc megad�s�val jel�lhetj�k ki. Egy karakterl�ncot param�terk�nt adunk meg; ezt
a f�ggv�ny alap�rtelmezett visszat�r�si �rt�kk�nt haszn�lja, ha nem tal�lja az
�zenetet a
katal�gusban:
string My_messages::do_get(catalog cat, int set, int msg, const string& def) const

{
if (catalogs.size()<=cat) return def;
Cat& c = catalogs[cat];
if (c.sets.size()<=set) return def;
Set& s = c.sets[set];
if (s.msgs.size()<=msg) return def;
return s.msgs[msg];
}
1252 F�ggel�kek �s t�rgymutat�
A katal�gus megnyit�sakor a lemezrol egy sz�veges �br�zol�st olvasunk egy Cat
szerkezetbe.
Itt olyan �br�zol�st v�lasztottam, ami k�nnyen olvashat�: a <<< �s >>> jelek egy
halmazt
hat�rolnak, az �zenetek pedig sz�vegsorok:
messages<char>::catalog My_messages::do_open(const string& n, const locale& loc)
const
{
string nn = n + locale().name();
ifstream f(nn.c_str());
if (!f) return -1;
catalogs.push_back(Cat()); // a katal�gus mem�ri�ba helyez�se
Cat& c = catalogs.back();
string s;
while (f>>s && s=="<<<") { // halmaz olvas�sa
c.sets.push_back(Set());
Set& ss = c.sets.back();
while (getline(f,s) && s != ">>>") ss.msgs.push_back(s); // �zenetek beolvas�sa
}
return catalogs.size()-1;
}
�me egy egyszeru felhaszn�l�s:
int main()
{
if (!has_facet< My_messages >(locale())) {
cerr << "A " << locale().name() << "lok�lban nincs messages facet.\n";
exit(1);
}
const messages<char>& m = use_facet< My_messages >(locale());
extern string message_directory; // itt tartom az �zeneteimet
int cat = m.open(message_directory,locale());
if (cat<0) {
cerr << "Nincs katal�gus.\n";
exit(1);
}
cout << m.get(cat,0,0,"Megint t�ves!") << endl;
cout << m.get(cat,1,2,"Megint t�ves!") << endl;
cout << m.get(cat,1,3,"Megint t�ves!") << endl;
cout << m.get(cat,3,0,"Megint t�ves!") << endl;
}
D. Helyi saj�toss�gok 1253
Ha a katal�gus
<<<
hell�
viszl�t
>>>
<<<
igen
nem
tal�n
>>>
a program a k�vetkezot �rja ki:
hell�
tal�n
Megint t�ves!
Megint t�ves!
D.4.7.1. M�s facet-ekben l�vo �zenetek haszn�lata
Azon t�l, hogy a felhaszn�l�kkal val� kapcsolattart�sra alkalmas lok�lf�ggo
karakterl�ncokat
t�rolnak, az �zenetek arra is felhaszn�lhat�k, hogy m�s facet-ek sz�m�ra
t�roljanak karakterl
�ncokat. A Season_io jellemzot (�D.3.2) p�ld�ul �gy is meg�rhattuk volna:
class Season_io : public locale::facet {
const messages<char>&m; // �zenetk�nyvt�r
int cat; // �zenetkatal�gus
public:
class Missing_messages { };
Season_io(int i = 0)
: locale::facet(i),
m(use_facet<Season_messages>(locale())),
cat(m.open(message_directory,locale()))
{ if (cat<0) throw Missing_messages(); }
~Season_io() { } // lehetov� teszi a Season_io objektumok felsz�mol�s�t (�D.3)
const string& to_str(Season x) const; // x �br�zol�sa karakterl�nccal
bool from_str(const string& s, Season& x) const; // az s-nek megfelelo
// Season objektumot x-be helyezi
1254 F�ggel�kek �s t�rgymutat�
static locale::id id; // facet-azonos�t� objektum (�D.2, �D.3, �D.3.1)
};
locale::id Season_io::id; // az azonos�t� objektum meghat�roz�sa
const string& Season_io::to_str(Season x) const
{
return m->get(cat, x, "Nincs ilyen �vszak");
}
bool Season_io::from_str(const string& s, Season& x) const
{
for (int i = Season::spring; i<=Season::winter; i++)
if (m->get(cat, i, "Nincs ilyen �vszak") == s) {
x = Season(i);
return true;
}
return false;
}
Ez az �zenetekre �p�lo megold�s abban k�l�nb�zik az eredetitol (�D.3.2), hogy a
Season
karakterl�ncok halmaz�t egy adott lok�lhoz meg�r� programoz�nak a karakterl�ncokat

hozz� kell tudnia adni egy messages k�nyvt�rhoz. Ezt az teheti meg k�nnyen, aki �j
lok�lt
ad a v�grehajt�si k�rnyezethez. M�gis, mivel a messages csak olvashat� fel�letet
ny�jt, az
�vszakok egy �jabb halmaz�nak megad�sa a rendszerprogramoz�k hat�sk�r�n k�v�l
esik.
A messages _byname v�ltozata (�D.4, �D.4.1) is adott:
template <class Ch>
class std::messages_byname : public messages<Ch> { /* ... */ };
D.5. Tan�csok
[1] Sz�m�tsunk r�, hogy a felhaszn�l�kkal k�zvetlen�l t�rsalg� programokat �s
rendszereket t�bb orsz�gban is haszn�lni fogj�k. �D.1.
[2] Ne t�telezz�k fel, hogy mindenki ugyanazt a karakterk�szletet haszn�lja, amit
mi. �D.4.1.
[3] Ha a bemenet �s kimenet f�gg a helyi saj�toss�gokt�l, lok�lokat haszn�ljuk �s
ne alkalmi k�dot �rjunk. �D.1.
[4] Ker�lj�k a lok�lnevek be�gyaz�s�t a programsz�vegbe. �D.2.1.
D. Helyi saj�toss�gok 1255
[5] Haszn�ljuk a leheto legkevesebb glob�lis form�z�st. �D.2.3, �D.4.4.7.
[6] R�szes�ts�k elonyben a lok�lhoz igazod� karakterl�nc-�sszehasonl�t�sokat �s -
rendez�seket. �D.2.4, �D.4.1.
[7] A facet-ek legyenek nem m�dos�that�k. �D.2.2, �D.3.
[8] Csak kev�s helyen v�ltoztassuk meg a lok�lt egy programban. �D.2.3.
[9] Hagyjuk, hogy a lok�l szab�lyozza a facet-ek �lettartam�t. �D.3.
[10] Amikor lok�lf�ggo I/O f�ggv�nyeket �runk, ne felejts�k el kezelni a
felhaszn�-
l�i (fel�l�rt) f�ggv�nyek okozta kiv�teleket. �D.4.2.2.
[11] A p�nz�rt�kek t�rol�s�ra haszn�ljunk egy egyszeru Money t�pust. �D.4.3.
[12] Haszn�ljunk egyszeru felhaszn�l�i t�pusokat az olyan �rt�kek t�rol�s�ra,
amelyek
lok�lt�l f�ggo I/O-t ig�nyelnek (�s ne a be�p�tett t�pusok �rt�keit alak�tsuk
oda-vissza). �D.4.3.
[13] Ne higgy�nk az ido�rt�keknek, am�g nincs valamilyen j� m�dszer�nk arra,
hogy belesz�m�tsuk az �sszes lehets�ges m�dos�t� t�nyezot. �D.4.4.1.
[14] Legy�nk tiszt�ban a time_t t�pus korl�taival. �D.4.4.1, �D.4.4.5.
[15] Haszn�ljunk olyan d�tumbeviteli elj�r�st, amely t�bbf�le form�tumot is
elfogad.
�D.4.4.5.
[16] R�szes�ts�k elonyben az olyan karakteroszt�lyoz� f�ggv�nyeket, amelyekben
a lok�l kifejezetten megadott. �D.4.5, �D.4.5.1.
D.6. Gyakorlatok
1. (*2,5) K�sz�ts�k el a Season_io-t (�D.3.2) az amerikai angolt�l elt�ro nyelvre.

2. (*2) Hozzunk l�tre egy Season_io oszt�lyt (�D.3.2), amelynek konstruktora nevek

halmaz�t veszi param�terk�nt, hogy a k�l�nb�zo lok�lokban l�vo �vszakok


neveit ezen oszt�ly objektumaik�nt lehessen �br�zolni.
3. (*3) �rjunk egy collate<char>::compare f�ggv�nyt, amely �b�c�sorrendet �ll�t
fel. Lehetoleg olyan nyelvre k�sz�ts�k el, mint a n�met, a francia vagy a magyar,
mert ezek �b�c�je az angoln�l t�bb betut tartalmaz.
4. (*2) �rjunk egy programot, ami logikai �rt�keket sz�mokk�nt, angol szavakk�nt
�s egy tetszoleges nyelv szavaik�nt olvas be �s �r ki.
5. (*2,5) Hat�rozzuk meg a Time t�pust a pontos ido �br�zol�s�ra. Hat�rozzuk
meg a Date_and_time t�pust is, a Time �s valamilyen Date t�pus felhaszn�l�s�-
val. Fejts�k ki ennek a megk�zel�t�snek a �D.4.4. pontban szereplo Date t�pussal
szembeni elonyeit �s h�tr�nyait. �rjuk meg a Time �s a Date_and_time t�pusok
lok�lf�ggo be- �s kimeneti elj�r�sait.
1256 F�ggel�kek �s t�rgymutat�
6. (*2,5) Tervezz�nk meg �s k�sz�ts�nk el egy .postai ir�ny�t�sz�m. facet-et.
�rjuk
meg legal�bb k�t, elt�ro c�mz�si szok�sokat haszn�l� orsz�gra.
7. (*2,5) K�sz�ts�nk egy .telefonsz�m. facet-et. �rjuk meg legal�bb k�t, elt�ro
telefonsz
�m-form�t (p�ld�ul (973) 360-8000 �s 1223 343000) haszn�l� orsz�gra.
8. (*2,5) Pr�b�ljuk meg kital�lni, milyen be- �s kimeneti form�tumokat haszn�l
C++-v�ltozatunk a d�tumokhoz.
9. (*2,5) �rjunk olyan get_time() f�ggv�nyt, amely megpr�b�lja kital�lni a
t�bb�rtelm
u d�tumok . p�ld�ul a 12/05/1995 . jelent�s�t, de elutas�t minden vagy
majdnem minden hib�t. Hat�rozzuk meg pontosan, melyik .tal�lgat�st. fogadjuk
el �s gondoljuk �t a hib�k val�sz�nus�g�t.
10. (*2) �rjunk olyan get_time() f�ggv�nyt, ami t�bbfajta bemeneti form�tumot
fogad
el, mint a �D.4.4.5 pontban szereplo v�ltozat.
11. (*2) K�sz�ts�nk list�t a rendszer�nk �ltal t�mogatott lok�lokr�l.
12. (*2,5) Tal�ljuk meg, rendszer�nk hol t�rolja a neves�tett lok�lokat. Ha van
hozz
�f�r�s�nk a rendszer azon r�sz�hez, ahol a lok�lok t�rol�dnak, k�sz�ts�nk egy
�j, n�vvel rendelkezo locale-t. Legy�nk �vatosak, nehogy t�nkretegy�k a m�r
l�tezo locale-eket.
13. (*2) Hasonl�tsuk �ssze a Season_io k�t megval�s�t�s�t (�D.3.2 �s �D.4.7.1).
14. (*2) �rjuk meg, �s tesztelj�k le a Date_out facet-et, ami Date-eket �r ki
a konstruktor�nak megadott param�ter �ltal meghat�rozott form�ban. Fejts�k ki
ennek a megk�zel�t�snek az elonyeit �s h�tr�nyait a date_fmt �ltal ny�jtott glob
�lis adatform�tummal (�D.4.4.6) szemben.
15. (*2,5) �rjuk meg a r�mai sz�mok (p�ld�ul XI �s MDCLII) be- �s kimeneti
elj�r�sait.
16. (*2,5) K�sz�ts�k el �s ellenorizz�k a Cvt_to_upper-t (�D.4.6).
17. (*2,5) �llap�tsuk meg a k�vetkezok �tlagos k�lts�g�t a clock() f�ggv�ny
felhaszn
�l�s�val: (1) f�ggv�nyh�v�s, (2) virtu�lis f�ggv�nyh�v�s, (3) egy char beolvas�-
sa, (4) egy 1 sz�mjegyu int beolvas�sa, (5) egy 5 sz�mjegyu int beolvas�sa (6)
egy 5 sz�mjegyu double, (7) egy 1 karakteres string, (8) egy 5 karakteres string,
�s (9) egy 40 karakteres string beolvas�sa.
18. (*6,5) Tanuljunk meg egy m�sik term�szetes nyelvet.
D. Helyi saj�toss�gok 1257
Kiv�telbiztoss�g a standard k�nyvt�rban
.Minden �gy muk�dik, ahogy
elv�rjuk . felt�ve, hogy
elv�r�saink helyesek..
(Hyman Rosen)
Kiv�telbiztoss�g . Kiv�telbiztos elj�r�sok . Eroforr�sok �br�zol�sa . �rt�kad�s .
push_back() . Konstruktorok �s invari�nsok . A szabv�nyos t�rol�k szolg�ltat�sai .
Elemek
beilleszt�se �s elt�vol�t�sa . Garanci�k �s kompromisszumok . swap() . A kezdeti
�rt
�kad�s �s a bej�r�k . Hivatkoz�s elemekre . Predik�tumok . Karakterl�ncok,
adatfolyamok,
algoritmusok, a valarray �s a complex . A C standard k�nyvt�ra . Javaslatok
a k�nyvt�rak felhaszn�l�i sz�m�ra . Tan�csok . Gyakorlatok
E.1. Bevezet�s
A standard k�nyvt�r f�ggv�nyei gyakran olyan f�ggv�nyeket h�vnak meg, melyeket a
felhaszn
�l� ad meg ak�r f�ggv�ny-, ak�r sablonparam�terek form�j�ban. Term�szetesen ezek
a felhaszn�l�i elj�r�sok n�ha kiv�teleket v�ltanak ki. Egyes f�ggv�nyek (p�ld�ul a
mem�-
riafoglal� elj�r�sok) �nmagukban is k�pesek kiv�tel kiv�lt�s�ra:
E
void f(vector<X>& v, const X& g)
{
v[2] = g; // X t�pus �rt�kad�sa kiv�telt v�lthat ki
v.push_back(g); // vector<X> mem�riafoglal�ja kiv�telt v�lthat ki
sort(v.begin(), v.end()); // X "kisebb mint" oper�tora kiv�telt v�lthat ki
vector<X> u = v; // X m�sol� konstruktora kiv�telt v�lthat ki
// ...
// u itt semmis�l meg: biztos�tanunk kell, hogy X destruktora helyesen muk�dj�n
}
Mi t�rt�nik, ha az �rt�kad�s kiv�telt v�lt ki, mik�zben a g �rt�k�t pr�b�ljuk
lem�solni? A v
ezut�n egy �rv�nytelen elemet fog tartalmazni? Mi t�rt�nik, ha az a konstruktor,
amit
a v.push_back() haszn�l a g lem�sol�s�hoz, std::bad_alloc kiv�telt v�lt ki?
Megv�ltozik az
elemek sz�ma? Beker�lhet �rv�nytelen elem a t�rol�ba? Mi t�rt�nik, ha az X oszt�ly
.kisebb,
mint. oper�tora eredm�nyez kiv�telt a rendez�s k�zben? Az elemek ezut�n r�szben
rendezettekk
� v�lnak? Elk�pzelheto, hogy a rendezo elj�r�s elt�vol�t egy elemet a t�rol�b�l �s

egy hiba miatt nem teszi vissza?


A fenti p�ld�ban szereplo �sszes kiv�tel-lehetos�g megtal�l�sa az �E.8.[1] feladat
c�lja, ezen
f�ggel�k� az, hogy elmagyar�zzuk, hogyan illik viselkednie a fenti programnak az
�sszes
megfeleloen meghat�rozott X t�pus eset�ben (bele�rtve azt az esetet is, amikor az
X kiv�teleket
v�lthat ki). Term�szetesen a f�ggel�k nagy r�sz�ben azt fogjuk tiszt�zni, mit is
nevez�nk
helyes viselked�snek, illetve megfeleloen meghat�rozottnak a kiv�telekkel
kapcsolatban.
A f�ggel�kben a k�vetkezokkel foglalkozunk:
1. Megvizsg�ljuk, hogyan adhat meg a felhaszn�l� olyan t�pusokat, amelyek
megfelelnek
a standard k�nyvt�r elv�r�sainak.
2. R�gz�tj�k, milyen garanci�kat biztos�t a standard k�nyvt�r.
3. Megn�zz�k, milyen elv�r�sokat �ll�t a standard k�nyvt�r a felhaszn�l� �ltal
megadott programr�szekkel szemben.
4. Bemutatunk n�h�ny hat�kony m�dszert, mellyel kiv�telbiztos �s hat�kony t�rol
�kat k�sz�thet�nk.
5. Megeml�tj�k a kiv�telbiztos programoz�s n�h�ny �ltal�nos szab�ly�t.
A kiv�telbiztoss�g vizsg�lata �rtelemszeruen a legrosszabb esetben tapasztalhat�
viselked
�ssel foglalkozik. Hol jelentheti egy kiv�tel a legt�bb probl�m�t? Hogyan tudja a
standard
k�nyvt�r megv�deni mag�t �s a felhaszn�l�t a lehets�ges probl�m�kt�l? Hogyan
seg�thet
a felhaszn�l� a probl�m�k elker�l�s�ben? Ne hagyjuk, hogy az itt bemutatott
kiv�tel-
1260 F�ggel�kek �s t�rgymutat�
kezel�si m�dszerek elfeledtess�k vel�nk, hogy a kiv�telek kiv�lt�sa a legjobb
m�dszer a hib
�k jelz�s�re (�14.1, �14.9). Az elveket, a m�dszereket �s a standard k�nyvt�r
szolg�ltat�sait
a k�vetkezo rendszerben t�rgyaljuk:
�E.2. Ebben a pontban a kiv�telbiztoss�g fogalm�t vizsg�ljuk meg.
�E.3. Itt m�dszereket mutatunk arra, hogyan �rhatunk hat�kony, kiv�telbiztos
t�rol�kat �s muveleteket.
�E.4. Ebben a r�szben k�rvonalazzuk a standard k�nyvt�r t�rol�i �s muveletei
�ltal biztos�tott garanci�kat.
�E.5. Itt �sszefoglaljuk a kiv�telbiztoss�g probl�m�j�t a standard k�nyvt�r nem
t�rol�kkal foglalkoz� r�sz�ben.
�E.6. V�g�l �jb�l �ttekintj�k a kiv�telbiztoss�g k�rd�s�t a standard k�nyvt�r
felhaszn�l�inak szemsz�g�bol.
Szok�s szerint a standard k�nyvt�r p�ld�kat mutat azokra a probl�mat�pusokra,
amelyekre
egy alkalmaz�s fejleszt�sekor oda kell figyeln�nk. A standard k�nyvt�rban a
kiv�telbiztoss
�g megval�s�t�s�ra alkalmazott elj�r�sok sz�mos m�s ter�leten is felhaszn�lhat�k.
E.2. Kiv�telbiztoss�g
Egy objektumon v�grehajtott muveletet akkor nevez�nk kiv�telbiztosnak, ha a
muvelet az
objektumot akkor is �rv�nyes �llapotban hagyja, ha kiv�tel kiv�lt�s�val �rt v�get.
Ez az �rv
�nyes �llapot lehet egy hiba�llapot is, amit esetleg csak teljes �jb�li
l�trehoz�ssal lehet
megsz�ntetni, de mindenk�ppen pontosan meghat�rozottnak kell lennie, hogy az
objektumhoz
logikus hibakezelo elj�r�st adhassunk meg. A kiv�telkezelo p�ld�ul t�r�lheti az
objektumot,
kijav�thatja azt, megpr�b�lkozhat a muvelet egy m�sik v�ltozat�val vagy megpr�-
b�lhat egyszeruen tov�bbhaladni a hiba figyelmen k�v�l hagy�s�val.
M�s szavakkal, az objektum rendelkezni fog egy invari�nssal (�llapotbiztos�t�, nem
v�ltoz
� �llapot �24.3.7.1), melyet konstruktorai �ll�tanak elo, �s minden tov�bbi
muveletnek meg
tartania az �ltala le�rt �llapotot, m�g akkor is, ha kiv�telek k�vetkeztek be. A
v�gso rendrak
�st a destruktorok v�gzik el. Minden muveletnek figyelnie kell arra, hogy a
kiv�telek kiv
�lt�sa elott vissza�ll�ts�k az invari�nst, hogy az objektum �rv�nyes �llapotban
l�pjen ki
a muveletbol. Term�szetesen nagy val�sz�nus�ggel ez az �rv�nyes �llapot nem az az
�llapot
lesz, amire az alkalmaz�snak �ppen sz�ks�ge lenne. Egy karakterl�nc egy kiv�tel
k�-
vetkezt�ben p�ld�ul �ress� v�lhat, egy t�rol� pedig rendezetlen maradhat. Teh�t
a .kijav�-
E. Kiv�telbiztoss�g a standard k�nyvt�rban 1261
t�s. csak azt jelenti, hogy az objektumnak olyan �rt�ket adunk, ami elfogadhat�bb
a program
sz�m�ra, mint az, amit a f�lbeszakadt muvelet benne hagyott. A standard k�nyvt�r
szempontj�b�l a leg�rdekesebb objektumok a t�rol�k.
Az al�bbiakban azt vizsg�ljuk meg, milyen felt�telek mellett nevezhetj�k a
szabv�nyos t�-
rol�kat feldolgoz� muveleteket kiv�telbiztosnak. Elvileg mind�ssze k�t egyszeru
megk�zel
�t�s k�z�l v�laszthatunk:
1. .Nincs biztos�t�s.: Ha kiv�tel l�p fel, a muvelet �ltal haszn�lt valamennyi
t�rol�t
.val�sz�nuleg s�r�ltnek. t�telezz�k fel.
2. .Eros biztos�t�s.: Ha kiv�tel l�p fel, minden t�rol� pontosan abba az �llapotba
ker
�l vissza, mint amiben a standard k�nyvt�r muvelet�nek megkezd�se elott volt.
Sajnos ez a k�t megold�s annyira egyszeru, hogy igaz�n nem is alkalmazhat�. Az
elso az�rt
elfogadhatatlan, mert ha ezen megold�s mellett egy t�rol�muvelet kiv�telt v�lt ki,
a t�rol�t
t�bbet nem �rhetj�k el, sot m�g nem is t�r�lhetj�k an�lk�l, hogy fut�si ideju
hib�kt�l k�ne
rettegn�nk. A m�sodik lehetos�g az�rt nem haszn�lhat�, mert ekkor a vissza�ll�t�s
megval
�s�t�s�nak k�lts�gei a standard k�nyvt�r minden muvelet�ben jelentkezn�nek.
A probl�ma megold�s�ra a C++ standard k�nyvt�ra kiv�telbiztos�t�si szinteket
k�n�l, melyek
a helyes program k�sz�t�s�nek terheit megosztj�k a standard k�nyvt�r megval�s�t�i
�s
felhaszn�l�i k�z�tt:
3a Alapbiztos�t�s az �sszes muveletre: A standard k�nyvt�r alapveto invari�nsai
mindenk�ppen fennmaradnak �s semmilyen eroforr�s (p�ld�ul mem�riatartom
�ny) nem maradhat lefoglalt.
3b Eros biztos�t�s a legfontosabb muveletekhez: Az alapbiztos�t�son t�l, a muvelet

vagy sikeresen v�grehajt�sra ker�l, vagy semmilyen v�ltoz�st nem eredm�nyez.


Ilyen szintu biztos�t�s csak a k�nyvt�r legfontosabb muveleteit illeti meg, p�ld�-

ul a push_back(),a list oszt�lyban az egyelemu insert(), illetve az


uninitialized_copy() f�ggv�nyeket (�E.3.1, �E.4.1).
3c .Nncs kiv�tel. biztos�t�s bizonyos muveletekre Az alapbiztos�t�s mellett n�h�ny

muvelet egy�ltal�n nem v�lthat ki kiv�teleket. Ez a t�pus� biztos�t�s csak n�-


h�ny egyszeru muveletre val�s�that� meg, p�ld�ul a swap() vagy a pop_back()
f�ggv�nyre (�E.4.1).
Az alapbiztos�t�s �s az eros biztos�t�s is felt�telezi, hogy a felhaszn�l� �ltal
megadott muveletek
(p�ld�ul az �rt�kad�sok �s a swap() f�ggv�nyek) nem hagyj�k a t�rol� elemeit �rv
�nytelen �llapotban �s minden �ltaluk lefoglalt eroforr�st felszabad�tanak.
Ezenk�v�l
a destruktoroknak nem szabad kiv�telt kiv�ltaniuk. P�ld�ul vizsg�ljuk meg az
al�bbi oszt�-
lyokat (�25.7):
1262 F�ggel�kek �s t�rgymutat�
template<class T> class Safe {
T* p; // p egy T t�pus�, new-val lefoglalt objektumra mutat
public:
Safe() : p(new T) { }
~Safe() { delete p; }
Safe& operator=(const Safe& a) { *p = *a.p; return *this; }
// ...
};
template<class T> class Unsafe { // hanyag �s vesz�lyes k�d
T* p; // egy T-re mutat
public:
Unsafe(T* pp) : p(pp) { }
~Unsafe() { if (!p->destructible()) throw E(); delete p; }
Unsafe& operator=(const Unsafe& a)
{
p->~T(); // a r�gi �rt�k t�rl�se (�10.4.11)
new(p) T(a.p); // T l�trehoz�sa *p-ben a.p alapj�n (�10.4.11)
return *this;
}
// ...
};
void f(vector< Safe<Some_type> >&vg, vector< Unsafe<Some_type> >&vb)
{
vg.at(1) = Safe<Some_type>();
vb.at(1) = Unsafe<Some_type>(new Some_type);
// ...
}
Ebben a p�ld�ban a Safe oszt�ly l�trehoz�sa csak akkor sikeres, ha a T oszt�ly is
sikeresen
l�trej�n. Egy T objektum l�trehoz�sa meghi�sulhat az�rt, mert nem siker�l a
mem�riafoglal
�s (ilyenkor std::bad_alloc kiv�tel jelentkezik), vagy az�rt, mert a T
konstruktora b�rmilyen
okb�l kiv�telt v�lt ki. Ettol f�ggetlen�l, egy sikeresen l�trehozott Safe eset�ben
a p egy
hib�tlan T objektumra mutat, m�g ha a konstruktor sikertelen, sem T, sem Safe
objektum
nem j�n l�tre. Ugyan�gy kiv�telt v�lthat ki a T �rt�kad� muvelete is; ekkor a Safe
�rt�kad�
muvelete (a C++ muk�d�s�nek megfeleloen) tov�bbdobja a kiv�telt. Mindez nem jelent

probl�m�t mindaddig, am�g a T �rt�kad� oper�tora saj�t operandus�t megfelelo


�llapotban
hagyja. Teh�t a Safe k�vetelm�nyeinknek megfeleloen muk�dik, �gy a standard
k�nyvt�r
muveletei Safe objektumokra alkalmazva logikus �s megfeleloen meghat�rozott
eredm�nyt
fognak adni.
E. Kiv�telbiztoss�g a standard k�nyvt�rban 1263
Ezzel szemben az Unsafe() konstruktort figyelmetlen�l �rtuk meg (pontosabban
figyelmesen
�gy �rtuk meg, hogy a helytelen form�t bemutassa). Egy Unsafe objektum l�trehoz�sa

sohasem fog meghi�sulni. Ehelyett az objektumot haszn�l� muveletekre (p�ld�ul az


�rt�kad
�sra �s a megsemmis�t�sre) b�zzuk, hogy t�rodjenek saj�t bel�t�suk szerint az
�sszes lehets
�ges probl�m�val. Az �rt�kad�s meghi�sulhat �gy, hogy a T m�sol� konstruktora
kiv�lt
egy kiv�telt. Ilyenkor a T t�pus� objektumot nem meghat�rozott �llapotban hagyjuk,
hiszen
a *p r�gi �rt�k�t t�r�lt�k, de nem helyettes�tett�k �rv�nyes �rt�kkel. Az ilyen
muk�d�s k�-
vetkezm�nyei �ltal�ban megj�solhatatlanok. Az Unsafe destruktora tartalmaz egy
rem�nytelen
pr�b�lkoz�st az �rv�nytelen megsemmis�t�s elker�l�s�re, egy kiv�tel megh�v�sa egy
m�sik kiv�tel kezel�se k�zben azonban a terminate() (�14.7) megh�v�s�t
eredm�nyezi, m�g
a standard k�nyvt�r elv�rja, hogy a destruktor szab�lyosan visszat�rjen az
objektum t�rl�se
ut�n. A standard k�nyvt�r nem k�sz�lt fel �s nem is tud felk�sz�lni arra, hogy
garanci�kat
adjon olyan felhaszn�l�i objektumokra, melyek nem megfeleloen muk�dnek. A
kiv�telkezel
�s szempontj�b�l a Safe �s az Unsafe abban k�l�nb�zik, hogy a Safe a konstruktort
haszn
�lja az invari�ns (�24.3.7.1) l�trehoz�s�hoz, ami lehetov� teszi, hogy muveleteit
egyszeru-
en �s biztons�gosan val�s�tsuk meg. Ha az �llapotbiztos�t� felt�tel nem el�g�theto
ki,
kiv�telt kapunk, mielott m�g az �rv�nytelen objektum l�trej�nne. Ugyanakkor az
Unsafe
nem rendelkezik �rtelmes invari�nssal �s a k�l�n�ll� muveletek mindenf�le
kiv�teleket v�ltanak
ki, an�lk�l, hogy egy .k�zponti. hibakezelo elj�r�s rendelkez�s�kre �llna.
Term�szetesen
ez gyakran vezet a standard k�nyvt�r (�sszeru) felt�telez�seinek megs�rt�s�hez. Az

Unsafe eset�ben p�ld�ul �rv�nytelen elemek maradhatnak egy t�rol�ban, miut�n


a T::operator=() egy kiv�telt v�ltott ki, �s a destruktor is eredm�nyezhet
kiv�teleket.
A standard k�nyvt�r biztos�t�sainak viszonya a rossz viselked�su felhaszn�l�i
muveletekhez
ugyanolyan, mint a nyelv biztos�t�sainak viszonya a t�pusrendszer szab�lyait
megs�rto
muveletekhez. Ha egy alapmuveletet nem meghat�rozott szab�lyai szerint haszn�lunk,
az
eredm�ny nem meghat�rozhat� lesz. Ha egy vector elemeinek destruktora kiv�telt
v�lt ki,
ugyan�gy nincs jogunk logikus viselked�st elv�rni, mint amikor egy kezdo�rt�kk�nt
v�letlensz�mmal felt�lt�tt mutat�val szeretn�nk adatokat el�rni:
class Bomb {
public:
// ...
~Bomb() { throw Trouble(); }
};
vector<Bomb> b(10); // nem meghat�rozhat� viselked�shez vezet
void f()
{
int* p = reinterpret_cast<int*>(rand()); // nem meghat�rozhat� viselked�shez vezet

*p = 7;
}
1264 F�ggel�kek �s t�rgymutat�
De n�zz�k a dolgok j� oldal�t: ha betartjuk a nyelv �s a standard k�nyvt�r
alapveto szab�-
lyait, a k�nyvt�r j�l fog viselkedni �gy is, ha kiv�teleket v�ltunk ki.
Amellett, hogy rendelkez�s�nkre �ll a tiszta kiv�telbiztoss�g, szeretj�k elker�lni
az eroforr
�sokban elofordul� .lyukakat.; azaz egy olyan muveletnek, amely kiv�telt v�lt ki,
nem el�g
az operandusait meghat�rozott �llapotban hagynia, biztos�tania kell azt is, hogy
minden
ig�nyelt eroforr�s valamikor felszabaduljon. Egy kiv�tel kiv�lt�s�nak hely�n
p�ld�ul minden
kor�bban lefoglalt mem�riater�letet fel kell szabad�tanunk vagy azokat valamilyen
objektumhoz
kell k�tn�nk, hogy k�sobb a mem�ria szab�lyosan felszabad�that� legyen.
A standard k�nyvt�r biztos�tja, hogy nem lesznek eroforr�s-lyukak, ha azok a
felhaszn�l�i
muveletek, melyeket a k�nyvt�r haszn�l, maguk sem hoznak l�tre ilyeneket:
void leak(bool abort)
{
vector<int> v(10); // nincs mem�ria-elsziv�rg�s
vector<int>* p = new vector<int>(10); // mem�ria-elsziv�rg�s lehets�ges
auto_ptr< vector<int> > q(new vector<int>(10)); // nincs mem�ria-elsziv�rg�s
(�14.4.2)
if (abort) throw Up();
// ...
delete p;
}
Ha kiv�tel k�vetkezik be, a v vector �s a q �ltal mutatott vector helyesen lesz
t�r�lve, �gy
minden �ltaluk lefoglalt eroforr�s felszabadul. Ezzel szemben a p �ltal mutatott
vector objektumot
nem v�dj�k a kiv�telektol, �gy az nem fog t�rlodni. Ha a k�dr�szletet biztons�goss
� akarjuk tenni, vagy magunknak kell felszabad�tani a p �ltal mutatott ter�letet a
kiv�tel kiv
�lt�sa elott, vagy biztos�tanunk kell, hogy valamilyen objektum . p�ld�ul egy
auto_ptr
(�14.4.2) . birtokolja azt �s szab�lyosan felszabad�tsa akkor is, ha kiv�tel
k�vetkezett be.
Figyelj�k meg, hogy a nyelv szab�lyai a r�szleges l�trehoz�ssal, illetve
megsemmis�t�ssel
kapcsolatban biztos�tj�k, hogy a r�szobjektumok �s az adattagok l�trehoz�sakor
bek�vetkez
o kiv�teleket a standard k�nyvt�r elj�r�sai minden k�l�n erofesz�t�s n�lk�l
helyesen kezelj
�k (�14.4.1). Ez minden kiv�telekkel kapcsolatos elj�r�s eset�ben nagyon fontos
alapelv.
Gondoljunk arra is, hogy nem a mem�ria az egyetlen olyan eroforr�s, amelyben
lyukak fordulhatnak
elo. A megnyitott f�jlok, z�rol�sok, h�l�zati kapcsolatok �s a sz�lak is olyan
rendszereroforr�sok, melyeket egy f�ggv�nynek fel kell szabad�tania vagy �t kell
adnia valamely
objektumnak egy kiv�tel kiv�lt�sa elott.
E. Kiv�telbiztoss�g a standard k�nyvt�rban 1265
E.3. A kiv�telbiztoss�got megval�s�t� elj�r�sok
A standard k�nyvt�r . szok�s szerint . bemutatja azokat a probl�m�kat, amelyek sok
m�s
helyzetben is elofordulhatnak �s ezekre olyan megold�st ad, ami sz�les k�rben
felhaszn�lhat
�. A kiv�telbiztos programok �r�s�nak alapveto eszk�zei a k�vetkezok:
1. A try blokk (�8.3.1)
2. A .kezdeti �rt�kad�s az eroforr�s megszerz�s�vel. elj�r�s (�14.4)
A k�vetendo �ltal�nos elvek:
3. Soha ne .dobjunk ki. adatokat �gy, hogy nem tudjuk pontosan, mi ker�l
a hely�kre.
4. Az objektumokat mindig �rv�nyes �llapotban hagyjuk, amikor kiv�telt v�ltunk ki.

Ha betartjuk ezeket a szab�lyokat, minden hib�t megfeleloen kezelhet�nk. Ezen


elvek k�-
vet�se a gyakorlatban az�rt jelent probl�m�t, mert m�g a leg�rtalmatlanabbnak tuno
elj�r�-
sok (p�ld�ul a <, az = vagy a sort()) is kiv�lthatnak kiv�teleket. Annak
meg�llap�t�s�hoz,
hogy egy programban mit kell megvizsg�lnunk, nagy tapasztalatra van sz�ks�g.
Ha k�nyvt�rat �runk, c�lszeru az eros kiv�telbiztoss�got (�E.2) c�lul kituzn�nk �s
mindenhol
meg kell val�s�tanunk az alapbiztos�t�st. Programok �r�sakor a kiv�telbiztoss�g
kev�sb
� fontos szempont. P�ld�ul, amikor egy egyszeru adatfeldolgoz� programot k�sz�t�nk
saj
�t magunknak, �ltal�ban nem baj, ha a program egyszeruen befejezodik, amikor a
virtu�lis
mem�ria valamilyen hiba miatt elfogy. Ugyanakkor a helyess�g �s az alapveto
kiv�telbiztoss
�g szorosan kapcsol�dik egym�shoz.
Az alapveto kiv�telbiztoss�g megval�s�t�s�ra szolg�l� elj�r�sok . p�ld�ul az
�llapotbiztos�-
t�k megad�sa �s fenntart�sa (�24.3.7.1) . nagyon hasonl�tanak azokhoz, melyek
seg�ts�g�-
vel kicsi �s helyesen muk�do programokat hozhatunk l�tre. Ebbol k�vetkezik, hogy
az
alapveto kiv�telbiztoss�g (az alapbiztos�t�s; �E.2) . vagy ak�r az eros biztos�t�s
. megval�-
s�t�sa csup�n jelent�ktelen teljes�tm�nyroml�ssal j�r. L�sd: �E.8[17]
Az al�bbiakban a vector szabv�nyos t�rol� (�16.3) egy megval�s�t�s�t adjuk meg,
hogy bemutassuk,
milyen feladatokat kell megoldanunk az ide�lis kiv�telbiztoss�g megval�s�t�s�-
hoz �s hol �rdemes alaposabb fel�gyeletet biztos�tanunk.
1266 F�ggel�kek �s t�rgymutat�
E.3.1. Egy egyszeru vektor
A vector (�16.3) leggyakoribb megval�s�t�s�ban h�rom mutat� (vagy az ezzel
egyen�rt�ku
mutat�.eltol�s p�r) szerepel: egy az elso elemre, egy az utols� ut�ni elemre �s
egy az utols
� ut�ni lefoglalt helyre hivatkozik (�17.1.3):
L�ssuk, mire van sz�ks�g�nk a vector deklar�ci�j�ban, ha csak a kiv�telbiztoss�g
�s az ero-
forr�s-lyukak elker�l�se szempontj�b�l vizsg�ljuk az oszt�lyt:
template<class T, class A = allocator<T> >
class vector {
private:
T* v; // a lefoglalt ter�let eleje
T* space; // az elemsorozat v�ge, bov�t�s sz�m�ra tartal�kolt ter�let kezdete
T* last; // a lefoglalt ter�let v�ge
A alloc; // mem�riafoglal�
public:
explicit vector(size_type n, const T& val = T(), const A& = A());
vector(const vector& a); // m�sol� konstruktor
vector& operator=(const vector& a); // m�sol� �rt�kad�s
~vector();
size_type size() const { return space-v; }
size_type capacity() const { return last-v; }
void push_back(const T&);
// ...
};
E. Kiv�telbiztoss�g a standard k�nyvt�rban 1267
vector: first
space
last
elemek tartal�k hely
Vizsg�ljunk elosz�r egy meggondolatlan konstruktor-megval�s�t�st:
template<class T, class A>
vector<T,A>::vector(size_type n, const T& val, const A& a) // vigy�zat: na�v
megval�s�t�s
: alloc(a) // mem�riafoglal� m�sol�sa
{
v = alloc.allocate(n); // mem�ria lefoglal�sa az elemek sz�m�ra (�19.4.1)
space = last = v+n;
for (T* p = v; p!=last; ++p) a.construct(p,val); // val l�trehoz� m�sol�sa *p-be
(�19.4.1)
}
Itt h�rom helyen keletkezhet kiv�tel:
1. Az allocate() f�ggv�ny kiv�telt v�lthat ki, ha nincs elegendo mem�ria.
2. A mem�riafoglal� (allok�tor) m�sol� konstruktora is eredm�nyezhet kiv�telt.
3. A T elemt�pus m�sol� konstruktora is kiv�lthat kiv�telt, ha nem tudja lem�solni

a val �rt�ket.
Egyik esetben sem j�n l�tre �j objektum, teh�t a vector konstruktora sem fut le
(�14.4.1).
Ha az allocate() v�grehajt�sa sikertelen, a throw m�r akkor kil�p a
konstruktorb�l, amikor
m�g semmilyen eroforr�st nem foglaltunk le, �gy ezzel minden rendben.
Ha a T m�sol� konstruktora eredm�nyez hib�t, m�r lefoglaltunk valamennyi mem�ri�t,
�gy
azt fel kell szabad�tanunk, ha el akarjuk ker�lni a mem�ria-elsziv�rg�st. Az
igaz�n nagy
probl�m�t az jelenti, hogy a T m�sol� konstruktora esetleg akkor v�lt ki kiv�telt,
amikor
m�r n�h�ny objektumot sikeresen l�trehozott, de m�g nem az �sszeset.
Ezen probl�ma kezel�s�hez nyilv�n kell tartanunk, hogy eddig mely elemeket hoztuk
l�tre,
�s amikor hiba k�vetkezik be, ezeket (�s csak ezeket) t�r�ln�nk kell:
template<class T, class A>
vector<T,A>::vector(size_type n, const T& val, const A& a) // j�l kidolgozott
megval�s�t�s
: alloc(a) // mem�riafoglal� m�sol�sa
{
v = alloc.allocate(n); // mem�ria lefoglal�sa az elemek sz�m�ra
iterator p;
try {
iterator end = v+n;
for (p=v; p!=end; ++p) alloc.construct(p,val); // elemek l�trehoz�sa (�19.4.1)
last = space = p;
}
1268 F�ggel�kek �s t�rgymutat�
catch (...) {
for (iterator q = v; q!=p; ++q) alloc.destroy(q); // l�trehozott elemek
megsemmis�t�se
alloc.deallocate(v,n); // mem�ria felszabad�t�sa
throw; // tov�bbdob�s
}
}
A pluszk�lts�g ez esetben is csak a try blokk k�lts�ge. Egy j� C++-v�ltozatban ez
elhanyagolhat
� a mem�riafoglal�shoz �s az elemek kezdeti �rt�kad�s�hoz k�pest. Ahol a try blokk

k�lts�ge magas, esetleg beilleszthetj�k az if(n) vizsg�latot a try el�, ezzel az


�res vektort k�-
l�n esetk�nt kezelhetj�k.
A konstruktor nagy r�sz�t az uninitialized_fill() f�ggv�ny kiv�telbiztos
megval�s�t�sa t�lti ki:
template<class For, class T>
void uninitialized_fill(For beg, For end, const T& x)
{
For p;
try {
for (p=beg; p!=end; ++p)
new(static_cast<void*>(&*p)) T(x); // x l�trehoz� m�sol�sa *p-ben (�10.4.11)
}
catch (...) { // a l�trehozott elemek t�rl�se �s tov�bbdob�s:
for (For q = beg; q!=p; ++q) (&*q)->~T(); // (�10.4.11)
throw;
}
}
A furcsa &*p kifejez�sre az�rt volt sz�ks�g, hogy a nem mutat� bej�r�kat
(iter�torokat) is
kezelhess�k. Ilyenkor ahhoz, hogy mutat�t kapjunk, a hivatkoz�ssal meghat�rozott
elem
c�m�t kell venn�nk. A void* �talak�t�s biztos�tja, hogy a standard k�nyvt�r
elhelyezo f�ggv
�ny�t haszn�ljuk (�19.4.5), nem a felhaszn�l� �ltal a T* t�pusra megadott operator
new()
f�ggv�nyt. Ez az elj�r�s olyan alacsony szinten muk�dik, ahol a teljes
�ltal�noss�got m�r
el�g neh�z biztos�tani.
Szerencs�re nem kell �jra�rnunk az uninitialized_fill() f�ggv�nyt, mert a standard
k�nyvt
�r biztos�tja hozz� a megk�v�nt eros biztos�t�st (�E.2). Gyakran elengedhetetlen ,
hogy
olyan kezdo�rt�k-ad� muvelet �lljon rendelkez�s�nkre, amely vagy minden elemet
hib�tlanul
t�lt fel kezdo�rt�kkel, vagy . hiba eset�n . egy�ltal�n nem ad vissza elemeket.
�ppen
ez�rt a standard k�nyvt�rban szereplo uninitialized_fill(), uninitialized_fill_n()
�s
uninitialized_copy() f�ggv�ny (�19.4.4) biztos�tja ezt az eros kiv�telbiztoss�got
(�E.4.4).
E. Kiv�telbiztoss�g a standard k�nyvt�rban 1269
Figyelj�k meg, hogy az uninitialized_fill() nem v�dekezik az elemek destruktora
vagy
a bej�r�muveletek �ltal kiv�ltott kiv�telek ellen (�E.4.4), ez ugyanis
elviselhetetlen�l nagy
k�lts�get jelentene (l�sd �E.8[16-17]).
Az uninitialized_fill() nagyon sokf�le sorozatra alkalmazhat�, ez�rt csak elore
halad� bej
�r�kat vesz �t (�19.2.1), amivel viszont nem tudja garant�lni, hogy az elemeket
l�trehoz�-
sukkal ford�tott sorrendben t�rli.
Az uninitialized_fill() felhaszn�l�s�val az al�bbiakat �rhatjuk:
template<class T, class A>
vector<T,A>::vector(size_type n, const T& val, const A& a) // zavaros megval�s�t�s

:alloc(a) // mem�riafoglal� m�sol�sa


{
v = alloc.allocate(n); // mem�ria lefoglal�sa az elemek sz�m�ra
try {
uninitialized_fill(v,v+n,val); // elemek m�sol�sa
space = last = v+n;
}
catch (...) {
alloc.deallocate(v,n); // mem�ria felszabad�t�sa
throw; // tov�bbdob�s
}
}
Ennek ellen�re ezt a programot nem nevezhetj�k sz�pnek. A k�vetkezokben
bemutatjuk,
hogyan tehetj�k a programot sokkal egyszerubb�.
Figyelj�k meg, hogy a konstruktor �jra kiv�ltja azt a kiv�telt, amit elkapott. A
c�l az, hogy
a vector oszt�lyt .�tl�tsz�v�. tegy�k a kiv�telek elott, mert �gy a felhaszn�l�
pontosan meg-
�llap�thatja a hiba ok�t. A standard k�nyvt�r �sszes t�rol�ja rendelkezik ezzel a
tulajdons
�ggal. A kiv�telekkel szembeni �tl�tsz�s�g gyakran a legjobb lehetos�g a sablonok
�s a hasonl
� .v�kony. r�tegek sz�m�ra. Ez ellent�tben �ll a programrendszerek nagyobb
r�szeinek (.moduljainak.) ir�nyvonal�val, hiszen ezeknek �ltal�ban �n�ll�an kell
kezelni-
�k minden hib�t. Pontosabban, az ilyen modulok k�sz�toinek fel kell tudniuk
sorolni az
�sszes kiv�telt, amit a modul kiv�lthat. Ennek megval�s�t�s�hoz vagy a kiv�telek
csoportos
�t�s�ra (�14.2), vagy az alacsonyszintu elj�r�sok �s a modul saj�t kiv�teleinek
�sszekapcsol
�s�ra (�14.6.3), esetleg a kiv�telek meghat�roz�s�ra (�14.6) van sz�ks�g.
1270 F�ggel�kek �s t�rgymutat�
E.3.2. A mem�ria �br�zol�sa
A tapasztalatok bebizony�tott�k, hogy helyes, kiv�telbiztos programok k�sz�t�se
try blokkok
seg�ts�g�vel bonyolultabb ann�l, mint amit egy �tlagos programoz� m�g elfogad.
Val�j�ban
feleslegesen bonyolult, hiszen van egy m�sik lehetos�g: a .kezdeti �rt�kad�s az
eroforr�s
megszerz�s�vel. (�14.4), melynek seg�ts�g�vel cs�kkenthetj�k azon programsorok
sz�m�t,
melyek egy .st�lusos. program megval�s�t�s�hoz sz�ks�gesek. Eset�nkben a
legfontosabb
eroforr�s, amire a vector oszt�lynak sz�ks�ge van, egy�rtelmuen a mem�ria, melyben
az
elemeket t�roljuk. Ha bevezet�nk egy seg�doszt�lyt, amely a vector �ltal haszn�lt
mem�ri-
�t �br�zolja, leegyszerus�thetj�k programunkat �s cs�kkenthetj�k annak es�ly�t,
hogy v�-
letlen�l elfelejtj�k felszabad�tani a mem�ri�t.
template<class T, class A = allocator<T> >
struct vector_base {
A alloc; // mem�riafoglal�
T* v; // a lefoglalt ter�let eleje
T* space; // az elemsorozat v�ge, bov�t�s sz�m�ra tartal�kolt ter�let kezdete
T* last; // a lefoglalt ter�let v�ge
vector_base(const A& a, typename A::size_type n)
: alloc(a), v(a.allocate(n)), space(v+n), last(v+n) { }
~vector_base() { alloc.deallocate(v,last-v); }
};
Am�g a v �s a last mutat� helyes, a vector_base objektum megsemmis�theto. A
vector_base
oszt�ly a T t�pus sz�m�ra lefoglalt mem�ri�t kezeli �s nem T t�pus� objektumokat,
ez�rt miel
ott egy vector_base objektumot t�rl�nk, minden ennek seg�ts�g�vel l�trehozott
objektumot
is t�r�ln�nk kell.
Term�szetesen mag�t a vector_base oszt�lyt is �gy kell meg�rni, hogy ha kiv�tel
k�vetkezik
be (a mem�riafoglal� m�sol� konstruktor�ban vagy az allocate() f�ggv�nyben), ne
j�jj�n
l�tre vector_base objektum, �gy mem�ria-elsziv�rg�s sem k�vetkezik be.
A vector_base felhaszn�l�s�val a vector oszt�lyt a k�vetkezok�ppen hat�rozhatjuk
meg:
template<class T, class A = allocator<T> >
class vector : private vector_base<T,A> {
void destroy_elements() { for (T* p = v; p!=space; ++p) p->~T(); } // �10.4.11
public:
explicit vector(size_type n, const T& val = T(), const A& = A());
E. Kiv�telbiztoss�g a standard k�nyvt�rban 1271
vector(const vector& a); // m�sol� konstruktor
vector& operator=(const vector& a); // m�sol� �rt�kad�s
~vector() { destroy_elements(); }
size_type size() const { return space-v; }
size_type capacity() const { return last-v; }
void push_back(const T&);
// ...
};
A vector destruktora az �sszes elemre egym�s ut�n megh�vja a T t�pus destruktor�t.
Ebbol
k�vetkezik, hogy ha egy elem destruktora kiv�telt v�lt ki, a vector destruktora
sem tud hib
�tlanul lefutni. Ez igen nagy probl�m�t okoz, ha egy m�sik kiv�tel miatt
kezdem�nyezett
.verem-visszateker�s. k�zben k�vetkezik be, hiszen ekkor a terminate() f�ggv�ny
fut le
(�14.7). Ha a destruktor kiv�telt v�lt ki, �ltal�ban eroforr�s-lyukak keletkeznek
�s azok az
elj�r�sok, melyeket szab�lyos viselked�su objektumokhoz fejlesztettek ki,
megj�solhatatlanul
fognak muk�dni. Nem igaz�n van haszn�lhat� megold�s a destruktorokban keletkezo
kiv�telek kezel�s�re, ez�rt a k�nyvt�r semmilyen biztos�t�st nem v�llal, ha az
elemek ilyen
viselked�suek lehetnek (�E.4).
A konstruktort az al�bbi egyszeru form�ban adhatjuk meg:
template<class T, class A>
vector<T,A>::vector(size_type n, const T& val, const A& a)
: vector_base<T,A>(a,n) // ter�let lefoglal�sa n elem sz�m�ra
{
uninitialized_fill(v,v+n,val); // elemek m�sol�sa
}
A m�sol� konstruktor mind�ssze abban k�l�nb�zik ettol, hogy az
uninitialized_fill() helyett
az uninitialized_copy() f�ggv�nyt haszn�lja:
template<class T, class A>
vector<T,A>::vector(const vector<T,A>& a)
: vector_base<T,A>(a.alloc,a.size())
{
uninitialized_copy(a.begin(),a.end(),v);
}
1272 F�ggel�kek �s t�rgymutat�
Figyelj�k meg, hogy az ilyen st�lus� konstruktor kihaszn�lja a nyelvnek azon
alapszab�ly�t,
hogy ha a konstruktorban kiv�tel keletkezik, azokra a r�szobjektumokra (�s
alapobjektumokra),
melyek sikeresen l�trej�ttek, a destruktor is szab�lyosan lefut (�14.4.1). Az
uninitialized_fill() �s testv�rei (�E.4.4) ugyanilyen szolg�ltat�st ny�jtanak a
f�lig l�trehozott
sorozatok eset�ben.
E.3.3. �rt�kad�s
Szok�s szerint az �rt�kad�s abban k�l�nb�zik a l�trehoz�st�l, hogy a kor�bbi
�rt�kekre is
figyeln�nk kell. Vizsg�ljuk meg az al�bbi megval�s�t�st:
template<class T, class A>
vector<T,A>& vector<T,A>::operator=(const vector& a) // eros biztos�t�st ad (�E.2)

{
vector_base<T,A> b(alloc,a.size()); // mem�ria lefoglal�sa
uninitialized_copy(a.begin(),a.end(),b.v); // elemek m�sol�sa
destroy_elements();
alloc.deallocate(v,last-v); // a r�gi mem�riater�let felszabad�t�sa
vector_base::operator=(b); // �br�zol�s elhelyez�se
b.v = 0; // felszabad�t�s megeloz�se
return *this;
}
Ez az �rt�kad�s sz�p �s kiv�telbiztos is, de t�l sok mindent ism�tel meg a
konstruktorb�l �s
a destruktorb�l. Ennek elker�l�s�re a k�vetkezo elj�r�st �rhatjuk:
template<class T, class A>
vector<T,A>& vector<T,A>::operator=(const vector& a) // eros biztos�t�st ad (�E.2)

{
vector temp(a); // "a" m�sol�sa
swap< vector_base<T,A> >(*this,temp); // �br�zol�sok felcser�l�se
return *this;
}
A r�gi elemeket a temp destruktora t�rli, az �ltaluk lefoglalt ter�letet pedig a
temp v�ltoz�
vector_base objektum�nak destruktora szabad�tja fel.
A k�t v�ltozat teljes�tm�nye szinte teljesen egyenlo. Val�j�ban csak k�t k�l�nb�zo
form�ban
adjuk meg ugyanazokat a muveleteket. A m�sodik megval�s�t�s viszont r�videbb �s
nem ism
�tli a vector oszt�ly egy�b f�ggv�nyeiben m�r szereplo k�dr�szleteket, �gy az
�rt�kad�s
ezen v�ltozata kevesebb hibalehetos�get tartalmaz �s egyszerubb rendben tartani
is.
E. Kiv�telbiztoss�g a standard k�nyvt�rban 1273
Figyelj�k meg, hogy az �n�rt�kad�s szok�sos vizsg�lata hi�nyzik az elj�r�sb�l
(�10.4.4):
if (this == &a) return *this;
Ezek az �rt�kad� muveletek elosz�r l�trehoznak egy m�solatot, majd lecser�lik az
elemeket.
Ez a megold�s automatikusan kezeli az �n�rt�kad�s probl�m�j�t. �gy d�nt�ttem, hogy

a ritk�n elofordul� �n�rt�kad�s k�l�n vizsg�lata nem j�r annyi haszonnal, hogy
�rdemes legyen
ezzel lass�tani az �ltal�nos esetet, amikor egy m�sik vector objektumot adunk
�rt�k�l.
Mindk�t esetben k�t, esetleg jelentos optimaliz�l�si lehetos�g hi�nyzik:
1. Ha az �rt�ket kap� vektor m�rete el�g nagy ahhoz, hogy az �rt�k�l adott vektort

t�rolja, nincs sz�ks�g �j mem�ria lefoglal�s�ra.


2. Az elemek k�z�tti �rt�kad�s hat�konyabb lehet, mint egy elem t�rl�se, majd
k�l�n l�trehoz�sa.
Ha ezeket a jav�t�sokat is be�p�tj�k, a k�vetkezo eredm�nyt kapjuk:
template<class T, class A>
vector<T,A>& vector<T,A>::operator=(const vector& a) // optimaliz�lt,
alapbiztos�t�s (�E.2)
{
if (capacity() < a.size()) { // �j vektor�br�zol�s sz�m�ra ter�let lefoglal�sa
vector temp(a); // "a" m�sol�sa
swap< vector_base<T,A> >(*this,temp); // az �br�zol�sok felcser�l�se
return *this;
}
if (this == &a) return *this; // v�delem az �n�rt�kad�s ellen (�10.4.4)
// a r�gi elemek �rt�kad�sa
size_type sz = size();
size_type asz = a.size();
alloc = a.get_allocator(); // mem�riafoglal� m�sol�sa
if (asz<=sz) {
copy(a.begin(),a.begin()+asz,v);
for (T* p = v+asz; p!=space; ++p) p->~T(); // felesleges elemek felsz�mol�sa
(�10.4.11)
}
else {
copy(a.begin(),a.begin()+sz,v);
uninitialized_copy(a.begin()+sz,a.end(),space); // tov�bbi elemek l�trehoz�sa
}
space = v+asz;
return *this;
}
1274 F�ggel�kek �s t�rgymutat�
Ezek az optimaliz�ci�k nem val�s�that�k meg b�ntetlen�l. A copy() elj�r�s nem
ny�jt eros
kiv�telbiztos�t�st, mert nem garant�lja, hogy a c�l v�ltozatlan marad, ha m�sol�s
k�zben kiv
�tel k�vetkezik be. Teh�t ha a T::operator=() kiv�telt v�lt ki a copy() muvelet
k�zben, elo-
fordulhat, hogy az �rt�ket kap� vektor megv�ltozik, de nem lesz az �rt�k�l adott
vektor
pontos m�solata. Lehets�ges p�ld�ul, hogy az elso �t elemet siker�l lem�solni az
�rt�k�l
adott vektorb�l, de a t�bbi v�ltozatlan marad, sot ak�r az is elk�pzelheto, hogy
egy elem
(az, amelyiket �ppen m�soltuk, amikor a T::operator=() kiv�telt v�ltott ki) olyan
�rt�ket fog
tartalmazni, amely nem egyezik meg sem az eredetivel, sem a m�soland�val. Azt
az�rt elmondhatjuk,
hogy ha a T::operator=() �rv�nyes �llapotban hagyja operandus�t egy kiv�tel
kiv�lt�sakor is, a teljes vector is �rv�nyes �llapotban marad, b�r nem abban az
�llapotban,
amit szerett�nk volna.
A fentiekben a mem�riafoglal�t is �rt�kad�ssal m�soltuk le. Val�j�ban a
mem�riafoglal�kt
�l nem mindig k�vetelj�k meg, hogy rendelkezzenek �rt�kad�ssal (�19.4.3, l�sd
m�g:�E.8[9]).
A standard k�nyvt�r vector �rt�kad�s�nak legut�bbi megval�s�t�sa gyeng�bb
kiv�telbiztoss
�got, de nagyobb hat�konys�got biztos�t. Csak az alapbiztos�t�st ny�jtja, ami
megfelel
a legt�bb programoz� kiv�telbiztoss�gr�l alkotott fogalm�nak, de nem �ll
rendelkez�s�nkre
eros biztos�t�s (�E.2). Ha olyan �rt�kad�sra van sz�ks�g�nk, amely kiv�tel
fell�ptekor
a vector-t v�ltozatlanul hagyja, olyan k�nyvt�r-megval�s�t�st kell haszn�lnunk,
amely eros
biztos�t�st ny�jt az ilyen helyzetekben is vagy saj�t magunknak kell meg�rni az
�rt�kad�
muveletet:
template<class T, class A>
void safe_assign(vector<T,A>& a, const vector<T,A>& b) // "mag�t�l �rtendo" a = b
{
vector<T,A> temp(a.get_allocator());
temp.reserve(b.size());
for (typename vector<T,A>::iterator p = b.begin(); p!=b.end(); ++p)
temp.push_back(*p);
swap(a,temp);
}
Ha nincs elegendo mem�ria ahhoz, hogy l�trehozzuk a temp v�ltoz�t b.size() elem
sz�m�-
ra, az std:bad_alloc kiv�telt v�ltjuk ki, mielott b�rmilyen v�ltoztat�st v�gezn�nk
az a vektoron.
Ehhez hasonl�an, ha a push_back() v�grehajt�sa nem siker�l, az a akkor is
�rintetlen
marad, hiszen minden push_back() muveletet a temp objektumon hajtunk v�gre az a
helyett.
Ezzel a megold�ssal azt is biztos�tjuk, hogy felszabaduljon a temp minden eleme,
amit
a push_back() seg�ts�g�vel l�trehoztunk, mielott a hib�t okoz� kiv�telt �jra
kiv�ltan�nk.
E. Kiv�telbiztoss�g a standard k�nyvt�rban 1275
A swap() nem m�solja a vektorok elemeit, csup�n lecser�li a vector adattagjait,
�gy
a vector_base objektumot is. Ennek k�vetkezt�ben a swap() akkor sem v�lthat ki
kiv�telt,
ha az elemek muveletei k�pesek erre (�E.4.3). A safe_assign() nem k�sz�t
felesleges m�solatokat
az elemekrol, teh�t el�g hat�kony tud lenni.
Szok�s szerint vannak m�s lehetos�gek is a nyilv�nval� megval�s�t�s mellett,
p�ld�ul r�b�zhatjuk
mag�ra a k�nyvt�rra, hogy az elemeket az ideiglenes vektorba m�solja:
template<class T, class A>
void safe_assign(vector<T,A>& a, const vector<T,A>& b) // egyszeru a = b
{
vector<T,A> temp(b); // b elemeinek m�sol�sa az ideiglenes v�ltoz�ba
swap(a,temp);
}
Sot, egyszeru �rt�k szerinti param�ter�tad�st (�7.2) is haszn�lhatunk:
template<class T, class A>
void safe_assign(vector<T,A>& a, vector<T,A> b) // egyszeru a = b
// (figyelem: b �rt�k szerint �tadva)
{
swap(a,b);
}
A safe_assign() ez ut�bbi k�t v�ltozata a vector mem�riafoglal�j�t nem m�solja le,
ami megengedett
optimaliz�ci� (l�sd �19.4.3).
E.3.4. A push_back()
A kiv�telbiztoss�g szemsz�g�bol n�zve a push_back() nagyon hasonl�t az �rt�kad�sra
abban,
hogy nem szabad a vector objektumot megv�ltoztatnunk, ha az �j elem beilleszt�se
valamilyen
probl�m�ba �tk�zik:
template< class T, class A>
void vector<T,A>::push_back(const T& x)
{
if (space == last) { // nincs t�bb hely; �thelyez�s
vector_base b(alloc,size()?2*size():2); // a lefoglal�s megkettoz�se
uninitialized_copy(v,space,b.v);
new(b.space) T(x); // x m�solat�nak *b.space-be helyez�se (�10.4.11)
++b.space;
destroy_elements();
1276 F�ggel�kek �s t�rgymutat�
swap<vector_base<T,A> >(b,*this); // az �br�zol�sok felcser�l�se
return;
}
new(space) T(x); // x m�solat�nak *space-be helyez�se (�10.4.11)
++space;
}
Term�szetesen, a *space kezdeti �rt�kad�s�ra szolg�l� m�sol� konstruktor v�lthat
ki kiv�-
telt. Ha ez t�rt�nik, a vector v�ltozatlan marad �s a space �rt�k�t sem n�velj�k
meg. Ilyenkor
a vektor elemeit sem kell �thelyezn�nk a mem�ri�ban, teh�t az eddigi bej�r�k is
�rv
�nyben maradnak. �gy ez a megval�s�t�s eros biztos�t�st ad: ha egy mem�riafoglal�
vagy
egy felhaszn�l�i elj�r�s kiv�telt v�lt ki, a vector nem v�ltozik meg. A standard
k�nyvt�r ilyen
biztos�t�st ny�jt a push_back() f�ggv�nyhez (�E.4.1).
Figyelj�k meg, hogy az elj�r�sban nincs egyetlen try blokk sem (att�l eltekintve,
ami az
uninitialized_copy() f�ggv�nyben, rejtve szerepel). A m�dos�t�st a muveletek
sorrendj�-
nek pontos megv�laszt�s�val hajtjuk v�gre, �gy ha kiv�tel keletkezik, a vektor
�rt�ke nem
v�ltozik meg.
Ez a megk�zel�t�s . miszerint az utas�t�sok sorrendje adja a kiv�telbiztoss�got .
�s a .kezdeti
�rt�kad�s az eroforr�s megszerz�s�vel. (�14.4) alkalmaz�sa eleg�nsabb �s
hat�konyabb
megold�st k�n�l, mint a hib�k kifejezett kezel�se try blokkok seg�ts�g�vel. Ha
utas�-
t�sainkat szerencs�tlen sorrendben �rjuk le, sokkal t�bb kiv�telbiztoss�gi
probl�m�val kell
megk�zden�nk, mint a kiv�telkezelo elj�r�sok elhagy�sa mellett. A sorrend
meghat�roz�-
sakor az alapszab�ly az, hogy ne semmis�ts�nk meg inform�ci�t, mielott az azt
helyettes�to
adatokat l�tre nem hoztuk �s nem biztos�tottuk, hogy azokat kiv�telek vesz�lye
n�lk�l �t�rhassuk
a hely�kre.
A kiv�telkezel�s egyik k�vetkezm�nye, hogy a program v�grehajt�sa sor�n a vez�rl�s
meglep
o helyekre ker�lhet. Az olyan egyszeru, helyi vez�rl�ssel rendelkezo
f�ggv�nyekben,
mint az operator=(), a safe_assign() vagy a push_back(), meglepet�sek ritk�bban
fordulnak
elo. Ha r�n�z�nk egy k�dr�szletre, viszonylag egyszeruen meg�llap�thatjuk, hogy
egy adott
sor v�lthat-e ki kiv�telt �s mi lesz annak k�vetkezm�nye. A nagyobb f�ggv�nyekben,
melyekben
bonyolult vez�rl�si szerkezeteket (p�ld�ul bonyolult felt�teles utas�t�sokat �s
egym
�sba �gyazott ciklusokat) haszn�lunk, az ilyen k�rd�sekre neh�z v�laszt adni. A
try blokkok
alkalmaz�sa a helyi vez�rl�st m�g tov�bb bonyol�tja, �gy �jabb kevered�seket �s
hib�kat eredm�nyezhet (�14.4). Azt hiszem, az utas�t�srendez�s �s a .kezdeti
�rt�kad�s az
eroforr�s megszerz�s�vel. hat�konys�ga a nagyobb m�retu try blokkokkal szemben
�ppen
a helyi vez�rl�s egyszerus�t�s�ben rejlik. Egyszerubben fogalmazva, a .st�lusos.
programokat
egyszerubb meg�rteni �s egyszerubb helyesen meg�rni.
E. Kiv�telbiztoss�g a standard k�nyvt�rban 1277
Gondoljunk r�, hogy az itt szereplo vector csak a kiv�telek �ltal okozott
probl�m�k �s az
ezen probl�m�k megold�s�ra kidolgozott elj�r�sok bemutat�s�ra szolg�l. A szabv�ny
nem
k�veteli meg, hogy minden megval�s�t�s pontosan �gy n�zzen ki, ahogy itt
bemutatjuk.
A szabv�ny �ltal biztos�tott garanci�kat az �E.4. pontban t�rgyaljuk.
E.3.5. Konstruktorok �s invari�nsok
A kiv�telbiztoss�g szemsz�g�bol n�zve a vector t�bbi muvelete vagy ugyan�gy
viselkedik,
mint az eddig bemutatottak (mivel hasonl� m�don foglalnak le �s szabad�tanak fel
eroforr
�sokat), vagy megval�s�t�suk egyszeru (mert nem v�geznek olyan tev�kenys�get,
amelyben
az �rv�nyes �llapot fenntart�sa probl�m�t okozhatna). A legt�bb oszt�lyban ezek
a .trivi
�lis. f�ggv�nyek jelentik a d�nto t�bbs�get. Az ilyen elj�r�sok bonyolults�ga
elsosorban
att�l f�gg, hogy a konstruktor milyen muk�d�si k�rnyezetet biztos�t sz�mukra.
M�sk�ppen
fogalmazva, az �ltal�nos tagf�ggv�nyek bonyolults�ga elsosorban a j�
oszt�lyinvari�ns
megv�laszt�s�n m�lik (�24.3.7.1). Az egyszeru vektormuveletek vizsg�lat�val
meg�rthetj�k,
mitol lesz j� egy oszt�lyinvari�ns �s hogyan kell meg�rnunk a konstruktorokat
ahhoz, hogy
ezeket az invari�nsokat biztos�ts�k.
Az olyan muveleteket, mint a vektorok indexel�se (�16.3.3) az�rt k�nnyu
megval�s�tani,
mert erosen �p�tenek arra az invari�nsra, amit a konstruktor hoz l�tre �s az
eroforr�sokat
lefoglal�, illetve felszabad�t� f�ggv�nyek tartanak fenn. Az indexelo muvelet
p�ld�ul hivatkozhat
a v t�mbre, amely az elemeket t�rolja:
template< class T, class A>
T& vector<T,A>::operator[](size_type i)
{
return v[i];
}
Nagyon fontos �s alapveto szab�ly, hogy a konstruktornak kell lefoglalnia az
eroforr�sokat
�s biztos�tania kell egy egyszeru invari�nst. Ahhoz, hogy ennek fontoss�g�t
meg�rts�k, n�zz
�k meg a vector_base defin�ci�j�nak al�bbi v�ltozat�t:
template<class T, class A = allocator<T> > // a konstruktor esetlen haszn�lata
class vector_base {
public:
A alloc; // mem�riafoglal�
T* v; // a lefoglalt ter�let eleje
T* space; // az elemsorozat v�ge, bov�t�s sz�m�ra tartal�kolt ter�let kezdete
T* last; // a lefoglalt ter�let v�ge
1278 F�ggel�kek �s t�rgymutat�
vector_base(const A& a, typename A::size_type n) : alloc(a), v(0), space(0),
last(0)
{
v = alloc.allocate(n);
space = last = v+n;
}
~vector_base() { if (v) alloc.deallocate(v,last-v); }
};
Itt a vector_base objektumot k�t l�p�sben hozzuk l�tre. Elosz�r egy .biztons�gi
�llapotot.
alak�tunk ki, amely a v, a space �s a last v�ltoz�t 0-ra �ll�tja, �s csak ezut�n
pr�b�lunk mem
�ri�t foglalni. Ez arra az indokolatlan f�lelemre vezetheto vissza, hogy az elemek
lefoglal
�sa k�zben keletkezo kiv�telek miatt f�lig l�trej�tt objektumot hozhatunk l�tre. A
f�lelem
az�rt indokolatlan, mert ilyen objektumot egy�ltal�n nem hozhatunk l�tre. A
szab�lyok,
melyek a statikus, automatikus, illetve tagobjektumok �s a standard k�nyvt�r
t�rol�inak
elemeire vonatkoznak, megakad�lyozz�k ezt. Azokban a szabv�ny elotti k�nyvt�rakban

azonban, melyek a t�rol�kban elhelyezo new oper�tort (�10.4.11) haszn�ltak


(haszn�lnak)
az objektumok l�trehoz�s�ra �s nem foglalkoztak (foglalkoznak) a
kiv�telbiztoss�ggal, ez
elofordulhatott (elofordulhat). A megr�gz�tt szok�sokon neh�z v�ltoztatni.
Figyelj�k meg, hogy a biztons�gosabb program elo�ll�t�s�ra ir�nyul� pr�b�lkoz�s
tov�bb
bonyol�tja az oszt�lyinvari�nst: nem lehet�nk biztosak abban, hogy a v egy l�tezo,
lefoglalt
mem�riater�letre mutat, mert szerepelhet benne a 0 �rt�k is. Ez a hiba azonnal
megbosszulja
mag�t. A standard k�nyvt�r nem k�veteli meg a mem�riafoglal�kt�l, hogy egy 0
�rt�ket
tartalmaz� mutat�t biztons�gosan szabad�tsanak fel (�19.4.1). A mem�riafoglal�k
ebben elt
�rnek a delete muvelettol (�6.2.6). Ebbol k�vetkezik, hogy a destruktorban k�l�n
ellenorz
�st kell v�gezn�nk. Ezenk�v�l minden elemnek kezdo�rt�ket adunk �s csak k�sobb
�rtelmes
�rt�ket. Ezen k�lts�gek egy olyan elemt�pus eset�ben lehetnek jelentosek, ahol az
�rt�kad�s bonyolult, p�ld�ul a string vagy a list oszt�lyn�l.
A k�tl�p�ses l�trehoz�s nem szokatlan megold�s. Gyakran olyan form�ban jelenik
meg,
hogy a konstruktor csak egy .egyszeru �s biztons�gos. kezdeti �rt�kad�st v�gez,
mellyel az
objektum t�r�lheto �llapotba ker�l. A val�di kezdeti �rt�kad�st egy init()
f�ggv�ny v�gzi
el, melyet a felhaszn�l�nak k�l�n meg kell h�vnia:
template<class T> // r�gies (szabv�ny �s kiv�telkezel�s elotti) st�lus
class vector_base {
public:
T* v; // a lefoglalt ter�let eleje
T* space; // az elemsorozat v�ge, bov�t�s sz�m�ra tartal�kolt ter�let kezdete
T* last; // a lefoglalt ter�let v�ge
E. Kiv�telbiztoss�g a standard k�nyvt�rban 1279
vector_base() : v(0), space(0), last(0) { }
~vector_base() { free(v); }
bool init(size_t n) // igazat ad vissza, ha a kezdeti �rt�kad�s siker�lt
{
if (v = (T*)malloc(sizeof(T)*n)) {
uninitialized_fill(v,v+n,T());
space = last = v+n;
return true;
}
return false;
}
};
Ezen st�lus l�that� elonyei a k�vetkezok:
1. A konstruktor nem v�lthat ki kiv�telt �s az init() seg�ts�g�vel megval�s�tott
kezdeti
�rt�kad�s sikeress�g�t a .szok�sos. m�dszerekkel (azaz nem kiv�telekkel)
ellenorizhetj�k.
2. �rv�nyes �llapot �ll rendelkez�s�nkre, melyet b�rmely muvelet komoly probl�-
ma eset�n is biztos�tani tud.
3. Az eroforr�sok lefoglal�s�t mindaddig halaszthatjuk, am�g t�nylegesen sz�ks�-
g�nk nincs kezdo�rt�kkel rendelkezo objektumokra.
A k�vetkezo r�szfejezetekben ezeket a szempontokat vizsg�ljuk meg �s bemutatjuk,
hogy
a k�tl�p�ses l�trehoz�s mi�rt nem biztos�tja az elv�rt elony�ket, amellett, hogy
m�s probl�-
m�kat is felvet.
E.3.5.1. Az init() f�ggv�ny haszn�lata
Az elso pont (az init() elj�r�s haszn�lata a konstruktor helyett) val�j�ban nem is
elony.
A konstruktorok �s kiv�telek haszn�lata sokkal �ltal�nosabb �s rendezettebb
megold�s az
eroforr�s-lefoglal�si hib�k �s a kezdeti �rt�kad�ssal kapcsolatos probl�m�k
kezel�s�re
(�14.1, �14.4). Ez a st�lus a kiv�telek n�lk�li C++ maradv�nya.
Ha a k�t st�lusban ugyanolyan figyelmesen �runk meg egy programot, azt
tapasztalhatjuk,
hogy k�t, szinte teljesen egyen�rt�ku eredm�nyt kapunk. Az egyik:
int f1(int n)
{
vector<X> v;
// ...
1280 F�ggel�kek �s t�rgymutat�
if (v.init(n)) {
// "v" n elem vektora
}
else {
// a probl�ma kezel�se
}
}
M�g m�sik v�ltozat:
int f2(int n)
try {
vector v<X> v(n);
// ...
// "v" n elem vektora
}
catch (...) {
// a probl�ma kezel�se
}
A k�l�n init() f�ggv�ny haszn�lata viszont .lehetos�get. ad az al�bbi hib�k
elk�vet�s�re:
1. Elfelejtj�k megh�vni az init() f�ggv�nyt (�10.2.3).
2. Elfelejtj�k megvizsg�lni, hogy az init() sikerrel j�rt-e.
3. Elfelejtj�k, hogy az init() kiv�teleket v�lthat ki.
4. Haszn�lni kezd�nk egy objektumot, mielott megh�vn�nk az init() elj�r�st.
A vector<T>::init() defin�ci�ja a [3] pontra mutat p�ld�t.
Egy j� C++-v�ltozatban az f2() egy kicsit gyorsabb is, mint az f1(), mert az
�ltal�nos esetben
nem v�gez ellenorz�st.
E.3.5.2. Alap�rtelmezett �rv�nyes �llapot
A m�sodik pont (miszerint egy k�nnyen elo�ll�that�, .alap�rtelmezett. �rv�nyes
�llapot �ll
rendelkez�s�nkre) �ltal�ban t�nyleg elony, de a vector eset�ben ez felesleges
k�lts�geket
jelent, ugyanis elk�pzelheto olyan vector_base, ahol v==0 �s a vector
megval�s�t�s�nak
mindenhol v�dekeznie kell ez ellen:
template< class T>
T& vector<T>::operator[](size_t i)
{
E. Kiv�telbiztoss�g a standard k�nyvt�rban 1281
if (v) return v[i];
// hibakezel�s
}
Ha megengedj�k a v==0 �llapotot, a tartom�ny-ellenorz�s n�lk�li indexel�s
ugyanolyan
lass� lesz, mint az ellenorz�tt hozz�f�r�s:
template< class T>
T& vector<T>::at(size_t i)
{
if (i<v.size()) return v[i];
throw out_of_range("vector index");
}
Itt alapj�ban v�ve annyi t�rt�nt, hogy a vector_base eredeti invari�ns�t
t�lbonyol�tottuk, azzal,
hogy bevezett�k a v==0 lehetos�get. Ennek k�vetkezt�ben a vector eredeti
invari�ns�t
is ugyan�gy kellett m�dos�tanunk, teh�t a vector �s a vector_base minden elj�r�s�t
bonyolultabban
kell megfogalmaznunk. Ez sz�mtalan hiba forr�sa lehet, p�ld�ul nehezebb lesz
a k�d m�dos�t�sa �s a program lassabban fog futni. Gondoljunk arra, hogy a modern
ki�p�-
t�su sz�m�t�g�pekn�l a felt�teles utas�t�sok meglepoen k�lts�gesek lehetnek. Ha
fontos
a hat�konys�g, a kulcsmuveletek . p�ld�ul a vektorindexel�s . felt�teles
utas�t�sok n�lk�-
li megval�s�t�sa elsorendu k�vetelm�ny lehet.
�rdekes m�don, m�r a vector_base eredeti meghat�roz�sa is biztos�t egy k�nnyen
l�trehozhat
� �rv�nyes �llapotot. Csak akkor l�tezhet egy vector_base objektum, ha a kezdeti
helyfoglal
�s sikeres volt. Ebbol k�vetkezik, hogy a vector �r�j�nak biztos�tania kell egy
.v�szkij
�rat. f�ggv�nyt, p�ld�ul a k�vetkezo form�ban:
template< class T, class A>
void vector<T,A>::emergency_exit()
{
space = v; // *this m�ret�nek 0-ra �ll�t�sa
throw Total_failure();
}
Ez a megold�s t�ls�gosan drasztikus, mert nem h�vja meg az elemek destruktorait �s
nem
szabad�tja fel a vector_base objektumban az elemek �ltal elfoglalt ter�letet.
R�viden fogalmazva,
nem ny�jt alapbiztos�t�st (�E.2). Ha figyel�nk a v �s a space adattag tartalm�ra
�s az
elemek destruktoraira, elker�lhetj�k az eroforr�s-lyukak kialakul�s�t:
template< class T, class A>
void vector<T,A>::emergency_exit()
{
1282 F�ggel�kek �s t�rgymutat�
destroy_elements(); // takar�t�s
throw Total_failure();
}
Figyelj�k meg, hogy a szabv�nyos vector olyan egyszeru szerkezet, amely a leheto
legkisebbre
cs�kkenti a k�tl�p�ses l�trehoz�s miatt jelentkezo probl�m�k lehetos�g�t. Az
init()
f�ggv�ny szinte egyen�rt�ku a resize() elj�r�ssal, a v==0 lehetos�get pedig a
legt�bb esetben
a size()==0 vizsg�lat elv�gz�s�vel is kezelhetj�k. A k�tl�p�ses l�trehoz�s eddig
bemutatott
negat�v hat�sai m�g erosebben jelentkeznek, ha programunkban szerepel egy olyan
oszt�ly, amelynek jelentos eroforr�sokra . p�ld�ul h�l�zati kapcsolatra vagy k�lso
�llom�-
nyokra . van sz�ks�ge. Ezek az oszt�lyok ritk�n k�pezik egy olyan keretrendszer
r�sz�t,
amely fel�gyeli haszn�latukat �s megval�s�t�sukat, olyan form�ban, ahogy a
standard
k�nyvt�r k�vetelm�nyei fel�gyelik a vector haszn�lat�t. A probl�m�k sz�ma m�g
tov�bb
n�vekszik, ha az alkalmaz�s c�ljai �s a megval�s�t�sukhoz sz�ks�ges eroforr�sok
kapcsolata
bonyolult. Nagyon kev�s olyan oszt�ly van, amely annyira k�zvetlen�l kapcsol�dik
a rendszer eroforr�saihoz, mint a vector.
Az egyszeru .biztons�gos �llapot. l�tez�s�nek elve alapj�ban v�ve nagyon hasznos.
Ha egy
objektumot nem tudunk �rv�nyes �llapotba �ll�tani an�lk�l, hogy kiv�telektol
kellene tartanunk
a muvelet befejez�se elott, val�ban probl�m�ink lehetnek. A .biztons�gos
�llapotnak
. viszont az oszt�ly szerep�hez term�szetesen kell kapcsol�dnia, nem eroltetett
m�don,
az oszt�ly invari�ns�t bonyol�tva.
E.3.5.3. Az eroforr�s-lefoglal�s k�sleltet�se
A m�sodik ponthoz hasonl�an (�E.3.5.2) a harmadik is egy j� �tlet rossz
megval�s�t�sa, ami
nyeres�g helyett ink�bb vesztes�get eredm�nyez. A legt�bb esetben . k�l�n�sen az
olyan
t�rol�kban, mint a vector . az eroforr�s-lefoglal�s k�sleltet�s�nek legjobb m�dja
a programoz
� sz�m�ra az, hogy mag�t az objektumot hozza l�tre, amikor sz�ks�ge van r�. N�zz�k

meg p�ld�ul a vector objektum al�bbi felhaszn�l�s�t:


void f(int n)
{
vector<X> v(n); // n darab alap�rtelmezett X t�pus� objektum l�trehoz�sa
// ...
v[3] = X(99); // v[3] igazi "kezdeti �rt�kad�sa"
// ...
}
E. Kiv�telbiztoss�g a standard k�nyvt�rban 1283
Nagy pazarl�s egy X t�pus� objektumot csak az�rt l�trehozni, mert valamikor,
k�sobb �rt�-
ket fogunk adni neki. K�l�n�sen nagy a vesztes�g, ha az X oszt�lyra az �rt�kad�s
k�lts�ges
muvelet. Ez�rt az X k�tl�p�ses l�trehoz�sa elony�snek tunhet. Az X maga is lehet
egy
vector, ez�rt a vector k�tl�p�ses l�trehoz�s�t�l az �res vektorok l�trehoz�si
k�lts�geinek
cs�kkent�s�t rem�lhetj�k, az alap�rtelmezett (�res) vektorok l�trehoz�sa azonban
m�r
egy�bk�nt is el�g hat�kony, ez�rt felesleges a megval�s�t�st azzal bonyol�tanunk,
hogy az
�res vektort k�l�n esetk�nt kezelj�k. �ltal�nosabban fogalmazva, a felesleges
kezdeti �rt
�kad�sok elker�l�s�re ritk�n jelent t�k�letes megold�st az, hogy a konstruktorb�l
kiemelj
�k az �sszetettebb kezdeti �rt�kad�sokat:
void f2(int n)
{
vector<X> v; // �res vektor l�trehoz�sa
// ...
v.push_back(X(99)); // elemek l�trehoz�sa, amikor sz�ks�ges
// ...
}
�sszefoglalva: a k�tl�p�ses l�trehoz�s sokkal bonyolultabb oszt�lyinvari�nshoz �s
�ltal�-
ban kev�sb� eleg�ns, t�bb hibalehetos�get tartalmaz� �s nehezebben kezelheto
programhoz
vezet. Ez�rt a nyelv �ltal t�mogatott .konstruktor elv. jobban haszn�lhat�, mint
az
.init() f�ggv�nyes megold�s". Teh�t az eroforr�sokat mindig a konstruktorban
foglaljuk le,
ha a k�sleltetett eroforr�s-lefoglal�st nem teszi k�telezov� maga az oszt�ly
term�szete.
E.4. A szabv�nyos t�rol�k garanci�i
Ha a k�nyvt�r valamelyik muvelete �nmaga v�lt ki kiv�telt, akkor biztos�tani tudja
. �s biztos
�tja is ., hogy az �ltala haszn�lt objektumok �rv�nyes �llapotban maradnak. A
vector eset
�ben p�ld�ul az at() f�ggv�ny (�16.3.3) k�pes kiv�ltani egy out_of_range kiv�telt,
ez azonban
nem jelent probl�m�t a vektor kiv�telbiztoss�ga szempontj�b�l. Az at() f�ggv�ny
meg�r�j�nak nem jelent probl�m�t, hogy a vektort �rv�nyes �llapotba �ll�tsa a
kiv�tel kiv�lt
�sa elott. Probl�m�k csak akkor jelentkeznek . a k�nyvt�r megval�s�t�i, a k�nyvt�r
felhaszn
�l�i, illetve azok sz�m�ra, akik megpr�b�lj�k meg�rteni a programot ., amikor
felhaszn
�l�i elj�r�sok v�ltanak ki kiv�telt.
A standard k�nyvt�r t�rol�i alapbiztos�t�st ny�jtanak (�E.2): a k�nyvt�r alap
invari�nsai
mindig megmaradnak �s ha a felhaszn�l� a k�vetelm�nyeknek megfeleloen j�r el, nem
keletkeznek
eroforr�s-lyukak sem. A felhaszn�l�i elj�r�sokt�l azt k�vetelj�k meg, hogy ne
1284 F�ggel�kek �s t�rgymutat�
hagyj�k a t�rol�k elemeit �rv�nytelen �llapotban �s a destruktorok ne v�ltsanak ki
kiv�telt.
Az elj�r�sokon most azokat a f�ggv�nyeket �rtj�k, melyeket a standard k�nyvt�r
megval�-
s�t�s�ban felhaszn�lunk, teh�t a konstruktorokat, az �rt�kad�sokat, a
destruktorokat, illetve
a bej�r�k muveleteit (�E.4.4).
A programoz� ezeket a muveleteket k�nnyen meg�rhatja a k�nyvt�r elv�r�sainak
megfelel
oen. A k�vetelm�nyeket �ltal�ban akkor is kiel�g�tik elj�r�saink, ha nem tudatosan
figyel
�nk r�juk. A k�vetkezo t�pusok biztosan kiel�g�tik a standard k�nyvt�r
k�vetelm�nyeit
a t�rol�k elemt�pusaira vonatkoz�an:
1. A be�p�tett t�pusok, k�zt�k a mutat�k
2. Azok a t�pusok, melyek nem tartalmaznak felhaszn�l�i muveleteket
3. Az olyan muveletekkel rendelkezo oszt�lyok, melyek nem v�ltanak ki kiv�teleket
�s nem hagyj�k operandusaikat �rv�nytelen �llapotban
4. Azok az oszt�lyok, melyek destruktora nem v�lt ki kiv�telt, �s amelyekn�l
k�nnyen ellenorizheto, hogy a standard k�nyvt�r �ltal haszn�lt elj�r�sok (a
konstruktorok, az �rt�kad�sok, a <, az == �s a swap() f�ggv�ny) nem hagyj�k
operandusaikat �rv�nytelen �llapotban
Azt is ellenorizn�nk kell minden esetben, hogy a muveletek ne hozzanak l�tre
eroforr�slyukakat:
void f(Circle* pc, Triangle* pt, vector<Shape*>& v2)
{
vector<Shape*> v(10); // vektor l�trehoz�sa vagy bad_alloc kiv�tel kiv�lt�sa
v[3] = pc; // nem v�lt ki kiv�telt
v.insert(v.begin()+4,pt); // vagy besz�rja a pt elemet, vagy nincs hat�sa v-re
v2.erase(v2.begin()+3); // vagy t�rli v2[3]-t, vagy nincs hat�sa v2-re
v2 = v; // vagy �tm�solja v-t, vagy nincs hat�sa v2-re
// ...
}
Amikor az f() fut�sa v�get �r, v szab�lyosan t�rlodni fog, m�g v2 �rv�nyes
�llapotban lesz.
A fenti r�szlet nem mutatja, ki felel a pc �s a pt t�rl�s��rt. Ha f() a felelos,
akkor vagy el kell
kapnia a kiv�teleket �s �gy kezelni a sz�ks�ges t�rl�seket, vagy a mutat�kat
lok�lis auto_ptr
v�ltoz�khoz kell k�tnie.
Enn�l �rdekesebb k�rd�s, mikor ad a k�nyvt�r eros biztos�t�st, azaz mely muveletek
mu-
k�dnek �gy, hogy vagy sikeresen futnak le, vagy semmilyen v�ltoztat�st nem
hajtanak v�gre
operandusaikon.
E. Kiv�telbiztoss�g a standard k�nyvt�rban 1285
P�ld�ul:
void f(vector<X>& vx)
{
vx.insert(vx.begin()+4,X(7)); // elem hozz�ad�sa
}
�ltal�ban az X muveletei �s a vector<X> oszt�ly mem�riafoglal�ja v�lthat ki
kiv�telt. Mit
mondhatunk a vx elemeirol, ha az f() f�ggv�ny fut�sa kiv�tel k�vetkezt�ben szakad
meg?
Az alapbiztos�t�s garant�lja, hogy eroforr�s-lyukak nem keletkeznek �s a vx elemei
�rv�-
nyes �llapotban maradnak. De pontosan milyen elemekrol van sz�? Elk�pzelheto, hogy
egy
elem az�rt t�rlodik, mert az insert() csak �gy tudja az alapbiztos�t�s
k�vetelm�nyeit vissza-
�ll�tani? Gyakran nem el�g annyit tudnunk, hogy a t�rol� j� �llapotban van,
pontosan tudni
akarjuk azt is, milyen �llapotr�l van sz�. A kiv�tel kezel�se ut�n �ltal�ban
tiszt�ban szeretn
�nk lenni azzal, hogy milyen elemek szerepelnek a vektorban, mert ellenkezo
esetben
komolyabb hibakezel�st kellene v�gezn�nk.
E.4.1. Elemek besz�r�sa �s t�rl�se
Az elemek besz�r�sa egy t�rol�ba, illetve az elemek t�rl�se onnan nyilv�nval�
p�ld�ja azon
muveleteknek, melyek a t�rol�t megj�solhatatlan �llapotban hagyhatn�k egy kiv�tel
bek�-
vetkez�sekor. Ennek oka legink�bb az, hogy a besz�r�s �s a t�rl�s sor�n sok olyan
muveletet
hajtunk v�gre, amely kiv�telt v�lthat ki:
1. �j �rt�ket m�solunk a t�rol�ba.
2. A t�rol�b�l elt�vol�tott elemet meg is kell semmis�ten�nk.
3. Az �j elem t�rol�s�hoz n�ha mem�ri�t is kell foglalnunk.
4. A vector �s a deque elemeit n�ha �j helyre kell �thelyezn�nk.
5. Az asszociat�v t�rol�k �sszehasonl�t� elj�r�sokat alkalmaznak az elemekre.
6. Sok besz�r�s �s t�rl�s eset�ben bej�r� muveleteket is v�gre kell hajtanunk.
Ezek a muveletek mind okozhatnak kiv�teleket, ezt semmilyen biztos�t�s (�E.2) nem
akad
�lyozza meg. Ahhoz, hogy ezekre az esetekre valamilyen biztos�t�st ny�jtsunk,
elviselhetetlen
�l k�lts�ges elj�r�sokra lenne sz�ks�g. Ennek ellen�re a k�nyvt�r v�di mag�t . �s
a felhaszn�l�kat . a t�bbi, felhaszn�l�i f�ggv�ny kiv�teleitol.
Amikor l�ncolt adatszerkezeteken v�gz�nk muveleteket (p�ld�ul egy list-en vagy
map-en),
�gy sz�rhatunk be �s t�vol�thatunk el elemeket, hogy a t�rol� t�bbi elem�re nem
vagyunk
1286 F�ggel�kek �s t�rgymutat�
hat�ssal. Ugyanez nem val�s�that� meg az olyan t�rol�kban, ahol t�bb elem sz�m�ra
egyetlen,
folytonos mem�riater�letet foglalunk le (p�ld�ul a vector �s a deque eset�ben).
Ilyenkor
az elemeket n�ha �j helyre kell mozgatnunk.
Az alapbiztos�t�son t�l a standard k�nyvt�r eros biztos�t�st is ny�jt n�h�ny olyan
muvelethez,
amely elemeket sz�r be vagy t�r�l. Mivel a l�ncolt adatszerkezetekkel
megval�s�that�
t�rol�k ebbol a szempontb�l jelentosen elt�rnek az elemek t�rol�s�hoz folytonos
mem�riater
�letet haszn�l�kt�l, a standard k�nyvt�r teljesen m�s garanci�kat ad a k�l�nb�zo
t�rol�fajt�khoz:
1. Garanci�k a vector (�16.3) �s a deque (�17.2.3) oszt�lyra:
. Ha egy push_back() vagy egy push_front() muvelet okoz kiv�telt, akkor az
nem v�ltoztatja meg operandusait.
. Ha egy insert() utas�t�s v�lt ki kiv�telt �s azt nem egy elem m�sol�
konstruktora vagy �rt�kad� muvelete okozta, akkor az sem v�ltoztat
operandusain.
. Az erase() muvelet csak akkor v�lt ki kiv�telt, ha azt az elemek m�sol�
konstruktora vagy �rt�kad� muvelete okozza.
. A pop_back() �s a pop_front() nem okoz kiv�telt.
2. A list (�17.2.2) garanci�i:
. Ha egy push_back() vagy push_front() muvelet v�lt ki kiv�telt, akkor a f�ggv
�ny hat�stalan.
. Ha az insert() okoz kiv�telt, akkor az nem v�ltoztatja meg operandusait.
. Az erase(), a pop_back(), a pop_front(), a splice() �s a reverse() sohasem v�lt
ki kiv�telt.
. Ha a predik�tumok �s az �sszehasonl�t� f�ggv�nyek nem okoznak kiv�telt,
akkor a list oszt�ly remove(), remove_if(), unique(), sort() �s merge() elj�r�-
sai sem v�lthatnak ki kiv�telt.
3. Garanci�k asszociat�v t�rol�kra (�17.4):
. Ha egy elem besz�r�sa k�zben az insert() kiv�telt v�lt ki, akkor a f�ggv�ny
hat�stalan.
. Az erase() nem okozhat kiv�telt.
Jegyezz�k meg, hogy ha eros biztos�t�s �ll rendelkez�s�nkre egy t�rol� valamelyik
muvelet
�ben, akkor minden bej�r�, az elemekre hivatkoz� �sszes mutat� �s hivatkoz�s
(referencia)
�rv�nyes marad kiv�tel bek�vetkez�se eset�n is.
A szab�lyokat egy t�bl�zatban foglalhatjuk �ssze:
E. Kiv�telbiztoss�g a standard k�nyvt�rban 1287
1288 F�ggel�kek �s t�rgymutat�
A t�rol�muveletek garanci�i
vector deque list map
clear() nem lehet kiv�tel nem lehet kiv�tel nem lehet kiv�tel nem lehet kiv�tel
(m�sol�s) (m�sol�s)
erase() nem lehet kiv�tel nem lehet kiv�tel nem lehet kiv�tel nem lehet kiv�tel
(m�sol�s) (m�sol�s)
1 elemu insert() eros eros eros eros
(m�sol�s) (m�sol�s)
N elemu insert() eros eros eros alap
(m�sol�s) (m�sol�s)
merge() .. .. nem lehet kiv�tel ..
(�sszehasonl�t�s)
push_back() eros eros eros ..
push_front() .. eros eros ..
pop_back() nem lehet kiv�tel nem lehet kiv�tel nem lehet kiv�tel ..
pop_front() .. nem lehet kiv�tel nem lehet kiv�tel ..
remove() .. .. nem lehet kiv�tel ..
(�sszehasonl�t�s)
remove_if() .. .. nem lehet kiv�tel ..
(predik�tum)
reverse() .. .. nem lehet kiv�tel ..
splice() .. .. nem lehet kiv�tel ..
swap() nem lehet kiv�tel nem lehet kiv�tel nem lehet kiv�tel nem lehet kiv�tel
(�sszehasonl�t�s
m�sol�sa)
unique() .. .. nem lehet kiv�tel ..
(�sszehasonl�t�s)
A t�bl�zat elemeinek jelent�se:
alap A muvelet csak alapbiztos�t�st ny�jt (�E.2).
eros A muvelet eros biztos�t�st ny�jt (�E.2).
nem lehet kiv�tel A muvelet nem v�lthat ki kiv�telt (�E.2).
.. A muvelet ebben a t�rol�ban nem szerepel tagf�ggv�nyk�nt.
Ahol a biztos�t�s megk�veteli, hogy a felhaszn�l� �ltal megadott bizonyos
muveletek ne
v�ltsanak ki kiv�telt, ott a biztos�t�s alatt z�r�jelben felt�ntett�k, milyen
muveletekre kell figyeln
�nk. Ezek a k�vetelm�nyek pontosan megegyeznek a t�bl�zat elott, sz�vegesen
megfogalmazott
felt�telekkel.
A swap() f�ggv�nyek abban k�l�nb�znek a t�bbi elj�r�st�l, hogy nem tagf�ggv�nyek.
A clear() f�ggv�nyre vonatkoz� garancia az erase() biztos�t�s�b�l k�vetkezik.
(�16.3.6)
A t�bl�zatban az alapbiztos�t�son t�li szolg�ltat�sokat t�ntett�k fel, teh�t nem
szerepelnek
azok az elj�r�sok (p�ld�ul a reverse() vagy a unique() a vector oszt�lyra), melyek
tov�bbi
biztos�t�s n�lk�l val�s�tanak meg valamilyen algoritmust az �sszes sorozatra.
A .majdnem-t�rol�. basic_string (�17.5, �20.3) minden muvelet�re garant�lja az
alapbiztos�-
t�st (�E.5.1). A szabv�ny azt is biztos�tja, hogy a basic_string oszt�ly erase()
�s swap() elj�r�-
sa nem okoz kiv�telt, az insert() �s a push_back() f�ggv�nyre pedig eros
biztos�t�st kapunk.
Az eros biztos�t�st ny�jt� elj�r�sokban amellett, hogy a t�rol� v�ltozatlan marad,
az �sszes
bej�r�, mutat� �s referencia is �rv�nyes marad:
void update(map<string,X>& m, map<string,X>::iterator current)
{
X x;
string s;
while (cin>>s>>x)
try {
current = m.insert(current,make_pair(s,x));
}
catch(...) {
// itt a "current" m�g mindig az aktu�lis elemet jel�li
}
}
E. Kiv�telbiztoss�g a standard k�nyvt�rban 1289
E.4.2. Garanci�k �s kompromisszumok
Az alapbiztos�t�son t�li szolg�ltat�sok �sszevisszas�gai a megval�s�t�si
lehetos�gekkel magyar
�zhat�k. A programoz�k azt szeretn�k legink�bb, hogy mindenhol eros biztos�t�s
�lljon
rendelkez�s�kre a leheto legkevesebb korl�toz�s mellett, de ugyanakkor azt is
elv�rj�k,
hogy a standard k�nyvt�r minden muvelete optim�lisan hat�kony legyen. Mindk�t
elv�r�s
jogos, de sok muvelet eset�ben lehetetlen egym�ssal p�rhuzamosan megval�s�tani.
Ahhoz,
hogy jobban megvil�g�tsuk az elker�lhetetlen kompromisszumokat, megvizsg�ljuk,
milyen
m�dokon lehet egy vagy t�bb elemet felvenni egy list�ba, vektorba vagy map-be.
N�zz�k elosz�r, hogy egy elemet hogyan vihet�nk be egy list�ba vagy egy vektorba.
Szok
�s szerint, a push_back() ny�jtja a legegyszerubb lehetos�get:
void f(list<X>& lst, vector<X>& vec, const X& x)
{
try {
lst.push_back(x); // hozz�ad�s a list�hoz
}
catch (...) {
// lst v�ltozatlan
return;
}
try {
vec.push_back(x); // hozz�ad�s a vektorhoz
}
catch (...) {
// vec v�ltozatlan
return;
}
// lst �s vec egy-egy x �rt�ku �j elemmel rendelkezik
}
Az eros biztos�t�s megval�s�t�sa ez esetben egyszeru �s .olcs�.. Az elj�r�s az�rt
is hasznos,
mert teljesen kiv�telbiztos megold�st ad az elemek felv�tel�re. A push_back()
azonban
asszociat�v t�rol�kra nem meghat�rozott: a map oszt�lyban nincs back(). Egy
asszociat�v t�-
rol� eset�ben az utols� elemet a rendez�s hat�rozza meg, nem a poz�ci�.
Az insert() f�ggv�ny garanci�i m�r kicsit bonyolultabbak. A gondot az jelenti,
hogy az
insert() muveletnek gyakran kell egy elemet a t�rol� .k�zep�n. elhelyeznie.
L�ncolt adatszerkezetekn
�l ez nem jelent probl�m�t, teh�t a list �s a map egyszeruen megval�s�that�,
a vector eset�ben azonban elore lefoglalt ter�let �ll rendelkez�s�nkre, a
vector<X>::insert()
f�ggv�ny egy �tlagos megval�s�t�sa pedig a besz�r�si pont ut�ni elemeket
�thelyezi, hogy
helyet csin�ljon az �j elem sz�m�ra. Ez az optim�lis megold�s, de arra nincs
egyszeru m�d-
1290 F�ggel�kek �s t�rgymutat�
szer, hogy a vektort vissza�ll�tsuk eredeti �llapot�ba, ha valamelyik elem m�sol�
�rt�kad�-
sa vagy m�sol� konstruktora kiv�telt v�lt ki (l�sd �E.8[10-11]), ez�rt a vector
azzal a felt�tellel
ad biztos�t�sokat, hogy az elemek m�sol� konstruktora nem v�lt ki kiv�telt. A list
�s
a map oszt�lynak nincs sz�ks�ge ilyen korl�toz�sra, ezek k�nnyed�n be tudj�k
illeszteni az
�j elemet a sz�ks�ges m�sol�sok elv�gz�se ut�n.
P�ldak�ppen t�telezz�k fel, hogy az X m�sol� konstruktora �s m�sol� �rt�kad�sa egy

X::cannot_copy kiv�telt v�lt ki, ha valamilyen okb�l nem siker�l l�trehoznia a


m�solatot:
void f(list<X>& lst, vector<X>& vec, map<string,X>& m, const X& x, const string&
s)
{
try {
lst.insert(lst.begin(),x); // hozz�ad�s a list�hoz
}
catch (...) {
// lst v�ltozatlan
return;
}
try {
vec.insert(vec.begin(),x); // hozz�ad�s a vektorhoz
}
catch (X::cannot_copy) {
// hopp�: vec vagy rendelkezik, vagy nem rendelkezik �j elemmel
return;
}
catch (...) {
// vec v�ltozatlan
return;
}
try {
m.insert(make_pair(s,x)); // hozz�ad�s az asszociat�v t�mbh�z
}
catch (...) {
// m v�ltozatlan
return;
}
// lst �s vec egy-egy x �rt�ku �j elemmel rendelkezik
// m egy �j (s,x) �rt�ku elemmel rendelkezik
}
Ha X::cannot_copy kiv�telt kapunk, nem tudhatjuk, hogy az �j elem beker�lt-e a vec
t�rol
�ba. Ha siker�lt beilleszteni az elemet, az �rv�nyes �llapotban lesz, de pontos
�rt�k�t nem
ismerj�k. Az is elk�pzelheto, hogy egy X::cannot_copy kiv�tel ut�n n�h�ny elem
.titokza-
E. Kiv�telbiztoss�g a standard k�nyvt�rban 1291
tosan. megkettozodik (l�sd �E.8[11]), m�sik megval�s�t�st alkalmazva pedig a
vektor v�g�n
l�vo elemek tunhetnek el, mert csak �gy lehet biztos�tani, hogy a t�rol� �rv�nyes
�llapotban
maradjon �s ne szerepeljenek benne �rv�nytelen elemek.
Sajnos az eros biztos�t�s megval�s�t�sa a vector oszt�ly insert() f�ggv�nye
eset�ben lehetetlen,
ha megengedj�k, hogy az elemek m�sol� konstruktora kiv�telt v�ltson ki. Ha egy
vektorban
teljesen meg akarn�nk v�deni magunkat az elemek �thelyez�se k�zben keletkezo
kiv�telektol, a k�lts�gek elviselhetetlen�l megnon�nek az egyszeru,
alapbiztos�t�st ny�jt�
megold�shoz k�pest.
Sajnos nem ritk�k az olyan elemt�pusok, melyek m�sol� konstruktora kiv�telt
eredm�nyezhet.
M�r a standard k�nyvt�rban is tal�lhatunk p�ld�t: a vector<string>, a vector<
vector<double> > �s a map<string, int> is ilyen.
A list �s a vector t�rol� ugyanolyan biztos�t�st ad az insert() egyelemu �s
t�bbelemu v�ltozat
�hoz, mert azok megval�s�t�si m�dja azonos. A map viszont eros biztos�t�st ad az
egyelem
u besz�r�shoz, m�g a t�bbelemuh�z csak alapbiztos�t�st. Az egyelemu insert() a map

eset�ben k�nnyen elk�sz�theto eros biztos�t�ssal, a t�bbelemu v�ltozat egyetlen


logikus
megval�s�t�si m�dja azonban a map eset�ben az, hogy az �j elemeket egym�s ut�n
sz�rjuk
be, �s ehhez m�r nagyon neh�z lenne eros garanci�kat adni. A gondot itt az
jelenti, hogy
nincs egyszeru visszal�p�si lehetos�g (nem tudunk kor�bbi sikeres besz�r�sokat
visszavonni),
ha valamelyik elem besz�r�sa nem siker�l.
Ha olyan t�bbelemu besz�r� muveletre van sz�ks�g�nk, amely eros biztos�t�st ad,
azaz
vagy minden elemet hib�tlanul beilleszt, vagy egy�ltal�n nem v�ltoztatja meg a
t�rol�t, legegyszer
ubben �gy val�s�thatjuk meg, hogy egy teljesen �j t�rol�t k�sz�t�nk, majd ennek
sikeres
l�trehoz�sa ut�n egy swap() muveletet alkalmazunk:
template<class C, class Iter>
void safe_insert(C& c, typename C::const_iterator i, Iter begin, Iter end)
{
C tmp(c.begin(),i); // az el�l levo elemek m�sol�sa ideiglenes v�ltoz�ba
copy(begin,end,inserter(tmp,tmp.end())); // �j elemek m�sol�sa
copy(i,c.end(),inserter(tmp,tmp.end())); // a z�r� elemek m�sol�sa
swap(c,tmp);
}
Szok�s szerint, ez a f�ggv�ny is hib�san viselkedhet, ha az elemek destruktora
kiv�telt v�lt
ki, ha viszont az elemek m�sol� konstruktora okoz hib�t, a param�terben megadott
t�rol�
v�ltozatlan marad.
1292 F�ggel�kek �s t�rgymutat�
E.4.3. A swap()
A m�sol� konstruktorokhoz �s �rt�kad�sokhoz hasonl�an a swap() elj�r�sok is nagyon
fontos
szerepet j�tszanak sok szabv�nyos algoritmusban �s k�zvetlen�l is gyakran
haszn�lj�k
a felhaszn�l�k. A sort() �s a stable_sort() p�ld�ul �ltal�ban a swap()
seg�ts�g�vel rendezi �t
az elemeket. Teh�t ha a swap() kiv�telt v�lt ki, mik�zben a t�rol�ban szereplo
�rt�keket
cser�lgeti, akkor a t�rol� elemei a csere helyett vagy v�ltozatlanok maradnak,
vagy megkett
ozodnek.
Vizsg�ljuk meg a standard k�nyvt�r swap() f�ggv�ny�nek al�bbi, egyszeru
megval�s�t�s�t
(�18.6.8):
template<class T> void swap(T& a, T& b)
{
T tmp = a;
a = b;
b = tmp;
}
Erre teljes�l, hogy a swap() csak akkor eredm�nyezhet kiv�telt, ha azt az elemek
m�sol�
konstruktora vagy m�sol� �rt�kad�sa v�ltja ki.
Az asszociat�v t�rol�kt�l eltekintve a szabv�nyos t�rol�k biztos�tj�k, hogy a
swap() f�ggv
�ny ne v�ltson ki kiv�teleket. A t�rol�kban �ltal�ban �gy is meg tudjuk val�s�tani
a swap()
f�ggv�nyt, hogy csak az adatszerkezeteket cser�lj�k fel, melyek mutat�k�nt
szolg�lnak
a t�nyleges elemekhez (�13.5, �17.1.3). Mivel �gy magukat az elemeket nem kell
mozgatnunk,
azok konstruktor�ra vagy �rt�kad� muvelet�re nincs sz�ks�g�nk, teh�t azok nem
kapnak lehetos�get kiv�tel kiv�lt�s�ra. Ezenk�v�l a szabv�ny biztos�tja, hogy a
k�nyvt�r
swap() f�ggv�nye nem tesz �rv�nytelenn� egyetlen hivatkoz�st, mutat�t �s bej�r�t
sem
azok k�z�l, melyek a felcser�lt t�rol�k elemeire hivatkoznak. Ennek k�vetkezt�ben
kiv�telek
egyetlen ponton l�phetnek fel: az asszociat�v t�rol�k �sszehasonl�t�
objektumaiban,
melyeket az adatszerkezet le�r�j�nak r�szek�nt kell m�solnunk. Teh�t az egyetlen
kiv�tel,
amit a szabv�nyos t�rol�k swap() elj�r�sa eredm�nyezhet, az �sszehasonl�t�
objektum m�-
sol� konstruktor�b�l vagy �rt�kad� muvelet�bol sz�rmazik (�17.1.4.1). Szerencs�re
az
�sszehasonl�t� objektumoknak �ltal�ban annyira egyszeru m�sol� muveleteik vannak,
hogy nincs lehetos�g�k kiv�tel kiv�lt�s�ra.
A felhaszn�l�i swap() f�ggv�nyek viszonylag egyszeruen ny�jthatnak ugyanilyen
biztos�t�-
sokat, ha gondolunk r�, hogy .mutat�kkal. �br�zolt adatok eset�ben elegendo csak a
mutat
�kat felcser�ln�nk, ahelyett, hogy lassan �s prec�zen lem�soln�nk a mutat�k �ltal
kijel�lt
t�nyleges adatokat (�13.5, �16.3.9, �17.1.3).
E. Kiv�telbiztoss�g a standard k�nyvt�rban 1293
E.4.4. A kezdeti �rt�kad�s �s a bej�r�k
Az elemek sz�m�ra val� mem�riafoglal�s �s a mem�riater�letek kezdeti �rt�kad�sa
alapvet
o r�sze minden t�rol�nak (�E.3). Ebbol k�vetkezik, hogy a fel nem t�lt�tt
(elok�sz�tetlen)
mem�riater�leten objektumot l�trehoz� szabv�nyos elj�r�sok . az
uninitialized_fill(), az
uninitialized_fill_n() �s az uninitialized_copy() (�19.4.4) . semmik�ppen sem
hagyhatnak
l�trehozott objektumokat a mem�ri�ban, ha kiv�telt v�ltanak ki. Ezek az
algoritmusok eros
biztos�t�st val�s�tanak meg (�E.2), amihez gyakran kell elemeket t�r�lni, teh�t az
a k�vetelm
�ny, miszerint a destruktoroknak tilos kiv�telt kiv�ltaniuk, elengedhetetlen
ezekn�l
a f�ggv�nyekn�l is (l�sd �E.8[14]). Ezenk�v�l azoknak a bej�r�knak is megfeleloen
kell viselkedni
�k, melyeket param�terk�nt adunk �t ezeknek az elj�r�soknak. Teh�t �rv�nyes bej
�r�knak kell lenni�k, �rv�nyes sorozatokra kell hivatkozniuk, �s a bej�r�
muveleteknek
(p�ld�ul a ++, a != vagy a * oper�tornak) nem szabad kiv�telt kiv�ltaniuk, ha
�rv�nyes bej
�r�kra alkalmazzuk azokat.
A bej�r�k (iter�torok) olyan objektumok, melyeket a szabv�nyos algoritmusok �s a
szabv�-
nyos t�rol�k muveletei szabadon lem�solhatnak, teh�t ezek m�sol� konstruktora �s
m�sol
� �rt�kad�sa nem eredm�nyezhet kiv�telt. A szabv�ny garant�lja, hogy a szabv�nyos
t�rol
�k �ltal visszaadott bej�r�k m�sol� konstruktora �s m�sol� �rt�kad�sa nem v�lt ki
kiv�telt,
�gy a vector<T>::begin() �ltal visszaadott bej�r�t p�ld�ul nyugodtan
lem�solhatjuk, nem kell
kiv�teltol tartanunk.
Figyelj�nk r�, hogy a bej�r�kra alkalmazott ++ vagy -- muvelet eredm�nyezhet
kiv�telt. P�ld
�ul egy istreambuf_iterator (�19.2.6) egy bemenethib�t (logikusan) egy kiv�tel
kiv�lt�s�-
val jelezhet, egy tartom�nyellenorz�tt bej�r� pedig teljesen szab�lyosan jelezheti
kiv�tellel
azt, hogy megpr�b�ltunk kil�pni a megengedett tartom�nyb�l (�19.3). Akkor azonban
nem
eredm�nyezhetnek kiv�telt, ha a bej�r�t �gy ir�ny�tjuk �t egy sorozat egyik
elem�rol a m�-
sikra, hogy k�zben a ++ vagy a -- egyetlen szab�ly�t sem s�rtj�k meg. Teh�t az
uninitialized_fill(), az uninitialized_fill_n() �s az uninitialized_copy()
felt�telezi, hogy
a bej�r�kra alkalmazott ++ �s -- muvelet nem okoz kiv�telt. Ha ezt m�gis
megteszik, a szabv
�ny megfogalmaz�sa szerint ezek nem is igaz�n bej�r�k, vagy az �ltaluk megadott
.sorozat
. nem �rtelmezheto sorozatk�nt. Most is igaz, hogy a szabv�ny nem k�pes megv�deni
a felhaszn�l�t a saj�t maga �ltal okozott nem meghat�rozhat� viselked�stol (�E.2).

E.4.5. Hivatkoz�sok elemekre


Ha elemre hivatkoz� mutat�t, referenci�t vagy bej�r�t adunk �t egy elj�r�snak, az
t�nkreteheti
a list�t azzal, hogy az adott elemet �rv�nytelenn� teszi:
1294 F�ggel�kek �s t�rgymutat�
void f(const X& x)
{
list<X> lst;
lst.push_back(x);
list<X>::iterator i = lst.begin();
*i = x; // x list�ba m�sol�sa
// ...
}
Ha az x v�ltoz�ban �rv�nytelen �rt�k szerepel, a list destruktora nem k�pes
hib�tlanul megsemmis
�teni az lst objektumot:
struct X {
int* p;
X() { p = new int; }
~X() { delete p; }
// ...
};
void malicious()
{
X x;
x.p = reinterpret_cast<int*>(7); // hib�s x
f(x); // idoz�tett bomba
}
Az f() v�grehajt�s�nak befejezt�vel megh�v�dik a list<X> destruktora, amely
viszont megh
�vja az X destruktor�t egy �rv�nytelen �rt�kre. Ha megpr�b�ljuk a delete p
parancsot v�grehajtani
egy olyan p �rt�kre, amely nem 0 �s nem is l�tezo X t�pus� �rt�kre mutat, az eredm
�ny nem meghat�rozhat� lesz �s ak�r a rendszer azonnali �sszeoml�s�t okozhatja.
Egy
m�sik lehetos�g, hogy a mem�ria �rv�nytelen �llapotba ker�l, ami sokkal k�sobb, a
program
olyan r�sz�ben okoz .megmagyar�zhatatlan. hib�kat, amely teljesen f�ggetlen a
t�nyleges
probl�m�t�l.
Ez a hibalehetos�g nem g�tolja meg a programoz�kat abban, hogy referenci�kat �s
bej�r�-
kat haszn�ljanak a t�rol�k elemeinek kezel�s�re, hiszen mindenk�ppen ez az egyik
legegyszer
ubb �s leghat�konyabb m�dszer az ilyen feladatok elv�gz�s�hez. Mindenesetre
�rdemes
k�l�n�sen elovigy�zatosnak lenn�nk a t�rol�k elemeire val� hivatkoz�sokkal
kapcsolatban. Ha egy t�rol� �ps�ge vesz�lybe ker�lhet, �rdemes a kev�sb�
gyakorlott felhaszn
�l�k sz�m�ra biztons�gosabb, ellenorz�tt v�ltozatokat is k�sz�ten�nk, p�ld�ul
megadhatunk
egy olyan elj�r�st, amely ellenorzi, hogy az �j elem �rv�nyes-e, mielott besz�rja
azt
a .fontos. t�rol�ba. Term�szetesen ilyen ellenorz�seket csak akkor v�gezhet�nk, ha
pontosan
ismerj�k a t�rol�ban t�rolt elemek t�pus�t.
E. Kiv�telbiztoss�g a standard k�nyvt�rban 1295
�ltal�ban, ha egy t�rol� valamelyik eleme �rv�nytelenn� v�lik, a t�rol�ra
alkalmazott minden
tov�bbi muvelet hib�kat eredm�nyezhet. Ez nem csak a t�rol�k saj�tja: b�rmely
objektum,
amely valamilyen szempontb�l hib�s �llapotba ker�l, a k�sobbiekben b�rmikor
okozhat
probl�m�kat.
E.4.6. Predik�tumok
Sz�mos szabv�nyos algoritmus �s t�rol� haszn�l olyan predik�tumokat, melyeket a
felhaszn
�l�k adhatnak meg. Az asszociat�v t�rol�k eset�ben ezek k�l�n�sen fontos szerepet
t�ltenek
be: az elemek keres�se �s besz�r�sa is ezen alapul.
A szabv�nyos t�rol�k muveletei �ltal haszn�lt predik�tumok is okozhatnak
kiv�teleket, �s
ha ez bek�vetkezik, a standard k�nyvt�r muveletei legal�bb alapbiztos�t�st
ny�jtanak, de
sok esetben (p�ld�ul az egyelemu insert() muveletn�l) eros biztos�t�s �ll
rendelkez�s�nkre
(�E.4.1). Ha egy t�rol�j�n v�gzett muvelet k�zben egy predik�tum kiv�telt v�lt ki,
elk�pzelhet
o, hogy az ott t�rolt elemek nem pontosan azok lesznek, amelyeket szeretn�nk, de
mindenk�ppen �rv�nyes elemek. P�ld�ul ha az == okoz kiv�telt a list::unique()
(�17.2.2.3)
muvelet v�grehajt�sa k�zben, nem v�rhatjuk el, hogy minden �rt�kism�tlod�s
eltunj�n.
A felhaszn�l� mind�ssze annyit felt�telezhet, hogy a list�ban szereplo �rt�kek
�rv�nyesek
maradnak (l�sd �E.5.3).
Szerencs�re a predik�tumok ritk�n csin�lnak olyasmit, ami kiv�telt eredm�nyezhet.
Ennek
ellen�re a felhaszn�l�i <, ==, �s != predik�tumokat figyelembe kell venn�nk,
amikor kiv�-
telbiztoss�gr�l besz�l�nk.
Az asszociat�v t�rol�k �sszehasonl�t� objektumair�l a swap() muvelet v�grehajt�sa
sor�n
m�solat k�sz�l (�E.4.3), ez�rt �rdemes biztos�tanunk, hogy azon predik�tumok
m�sol� mu-
veletei, melyeket felhaszn�lhatunk �sszehasonl�t� objektumokk�nt, ne v�lthassanak
ki
kiv�telt.
E.5. A standard k�nyvt�r tov�bbi r�szei
A kiv�telbiztoss�g legfontosabb c�lja, hogy fenntartsuk az objektumok �ps�g�t �s
k�vetkezetess
�g�t, azaz az �n�ll� objektumok alap-invari�nsa mindig igaz maradjon �s az
egym�ssal
kapcsolatban �ll� objektumok se s�r�ljenek. A standard k�nyvt�r szemsz�g�bol n�zve

1296 F�ggel�kek �s t�rgymutat�


a kiv�telbiztoss�g fenntart�sa a t�rol�k eset�ben a legbonyolultabb. Ha a
kiv�telbiztoss�gra
�sszpontos�tunk, a standard k�nyvt�r t�bbi r�sze nem t�l �rdekes, de a
kiv�telbiztoss�g
szempontj�b�l a be�p�tett t�mb is egy t�rol�, melyet felelotlen muveletekkel
k�nnyen
t�nkretehet�nk.
A standard k�nyvt�r f�ggv�nyei �ltal�ban csak olyan kiv�teleket v�lthatnak ki,
melyeket
meghat�roznak vagy amelyeket az �ltaluk megh�vott felhaszn�l�i muveletek
eredm�nyezhetnek.
Emellett azok az elj�r�sok, melyek (k�zvetve vagy k�zvetlen�l) mem�ri�t foglalnak
le, a mem�ria elfogy�s�t kiv�tellel jelezhetik (�ltal�ban az std::bad_alloc
kiv�tellel).
E.5.1. Karakterl�ncok
A string objektumokon v�gzett muveletek sokf�le kiv�telt okozhatnak, a
basic_string viszont
karaktereit a char_traits (�20.2) oszt�ly �ltal biztos�tott f�ggv�nyekkel kezeli
�s ezeknek
nem szabad kiv�telt okozniuk. A standard k�nyvt�r char_traits objektumai nem
v�ltanak
ki kiv�teleket, �s ha egy felhaszn�l�i char_traits valamelyik elj�r�sa eredm�nyez
ilyet,
az�rt a standard k�nyvt�r semmilyen feleloss�get nem v�llal. K�l�n�sen fontos,
hogy
a basic_string oszt�lyban elemk�nt (karakterk�nt) haszn�lt t�pus nem rendelkezhet
felhaszn
�l�i m�sol� konstruktorral �s �rt�kad�ssal, mert �gy nagyon sok kiv�tel-
lehetos�gtol szabadulunk
meg.
A basic_string nagyon hasonl�t a szabv�nyos t�rol�kra (�17.5, �20.3), elemei
val�j�ban egy
egyszeru sorozatot alkotnak, melyet a basic_string<Ch,Tr,A>::iterator vagy
a basic_string<Ch,Tr,A>::const_iterator objektumokkal �rhet�nk el. Ennek
k�vetkezt�ben
a string alapbiztos�t�st (�E.2) ad �s az erase(), az insert(), a push_back() �s a
swap() (�E.4.1)
f�ggv�ny garanci�i a basic_string oszt�ly eset�ben is �rv�nyesek.
A basic_string<Ch,Tr,A>::push_back() p�ld�ul eros biztos�t�st ny�jt.
E.5.2. Adatfolyamok
Ha egy adatfolyamot megfeleloen �ll�tunk be, annak f�ggv�nyei az
�llapotv�ltoz�sokat kiv
�telekkel jelzik (�21.3.6). Ezek jelent�se pontosan meghat�rozott �s nem okoznak
kiv�telbiztoss�gi probl�m�kat. Ha egy felhaszn�l�i operator<<() vagy operator>>()
elj�r�s
okoz kiv�telt, az �gy jelenhet meg a programoz� sz�m�ra, mintha azt az iostream
k�nyvt�r
okozta volna. Ennek ellen�re ezek a kiv�telek nem hatnak az adatfolyam �llapot�ra
(�21.3.3). Az adatfolyam k�sobbi muveletei esetleg nem tal�lj�k meg az �ltaluk
v�rt adatokat
. mert egy kor�bbi muvelet kiv�telt v�ltott ki a szab�lyos befejezod�s helyett .,
de ma-
E. Kiv�telbiztoss�g a standard k�nyvt�rban 1297
ga az adatfolyam nem v�lik �rv�nytelenn�. Szok�s szerint az I/O probl�m�k ut�n
sz�ks�g
lehet a clear() f�ggv�ny megh�v�s�ra, mielott tov�bbi �r�st vagy olvas�st
kezdem�nyezn�nk
(�21.3.3, �21.3.5).
A basic_string oszt�lyhoz hasonl�an az iostream is egy char_traits objektumra
hivatkozik
a karakterkezel�s megval�s�t�s�hoz (�20.2.1, �E.5.1), teh�t felt�telezheti, hogy a
karaktereken
v�gzett muveletek nem okoznak kiv�telt, illetve semmilyen biztos�t�st nem kell
adnia,
ha a felhaszn�l� megs�rti ezt a kik�t�st.
Ahhoz, hogy a standard k�nyvt�r kelloen hat�kony optimaliz�l�st alkalmazhasson,
felt�telezz
�k, hogy a locale (�D.2) �s a facet (�D.3) objektumok sem okozhatnak kiv�telt. Ha
m�gis
�gy muk�dnek, akkor az azokat haszn�l� adatfolyamok �rv�nytelenn� v�lhatnak. Ennek

ellen�re a leggyakoribb ilyen kiv�tel . az std::bad_cast a use_facet (�D.3.1)


f�ggv�nyben .
csak olyan, felhaszn�l� �ltal �rt programr�szletekben fordul elo, melyek
f�ggetlenek a szabv
�nyos adatfolyamokt�l, �gy a legrosszabb esetben is csak a ki�r�s f�lbeszakad�s�t
vagy hib
�s beolvas�st eredm�nyez, az adatfolyam (legyen az ak�r istream, ak�r ostream)
�rv�nyes
marad.
E.5.3. Algoritmusok
Eltekintve az uninitialized_copy(), az uninitialized_fill() �s az
uninitialized_fill_n() f�ggv
�nytol (�E.4.4) a standard k�nyvt�r az algoritmusokhoz alapbiztos�t�st (�E.2) ad.
Ez azt jelenti,
hogy ha a felhaszn�l� �ltal megadott objektumok a k�vetelm�nyeknek megfeleloen
viselkednek, az algoritmusok fenntartj�k a standard k�nyvt�r invari�nsait �s
elker�lik az
eroforr�s-lyukakat. A nem meghat�rozott viselked�s elker�l�se �rdek�ben a
felhaszn�l�i
muveleteknek mindig �rv�nyes �llapotban kell hagyniuk param�tereiket �s
a destruktoroknak nem szabad kiv�teleket kiv�ltaniuk.
Az algoritmusok maguk nem okoznak kiv�teleket, ehelyett visszat�r�si �rt�k�k�n
kereszt
�l jelzik a probl�m�kat. A kereso algoritmusok p�ld�ul t�bbnyire a sorozat v�g�t
adj�k
vissza annak jelz�s�re, hogy nem tal�lt�k meg a keresett elemet (�18.2). Teh�t a
szabv�nyos
algoritmusokban keletkezo kiv�telek val�j�ban mindig egy felhaszn�l�i elj�r�sb�l
sz�rmaznak.
Ez azt jelenti, hogy a kiv�tel vagy az egyik elemen v�gzett muvelet . predik�tum
(�18.4), �rt�kad�s vagy swap() . k�zben j�tt l�tre, vagy egy mem�riafoglal�
(�19.4) okozta.
Ha egy ilyen muvelet kiv�telt okoz, az algoritmusok azonnal befejezik muk�d�s�ket
�s az
algoritmust elind�t� f�ggv�ny feladata lesz, hogy a kiv�telt kezelje. N�h�ny
algoritmus eset
�ben elofordulhat, hogy a kiv�tel akkor k�vetkezik be, amikor a t�rol� �llapota a
felhaszn
�l� szempontj�b�l elfogadhatatlan. N�h�ny rendezo elj�r�s p�ld�ul az elemeket
ideigle-
1298 F�ggel�kek �s t�rgymutat�
nesen egy �tmeneti t�rba m�solja �s k�sobb innen teszi azokat vissza az eredeti
t�rol�ba.
Egy ilyen sort() elj�r�s esetleg sikeresen kim�solja az elemeket a t�rol�b�l (azt
tervezve,
hogy hamarosan a megfelelo sorrendben �rja azokat vissza), helyesen v�gzi el a
t�rl�st is,
de ezut�n azonnal kiv�tel k�vetkezik be. A felhaszn�l� szempontj�b�l a t�rol�
teljesen
megsemmis�l, ennek ellen�re minden elem �rv�nyes �llapotban van, teh�t az
alapbiztos�-
t�s megval�s�t�sa egyszeru feladat.
Gondoljunk r�, hogy a szabv�nyos algoritmusok a sorozatokat bej�r�kon kereszt�l
�rik el,
sohasem k�zvetlen�l a t�rol�kon dolgoznak, hanem azok elemein. A t�ny, hogy ezek
az algoritmusok
soha nem k�zvetlen�l vesznek fel elemeket egy t�rol�ba vagy t�r�lnek elemeket
onnan, leegyszerus�ti annak vizsg�lat�t, hogy egy kiv�telnek milyen k�vetkezm�nyei
lehetnek.
Ha egy adatszerkezetet csak konstans bej�r�kon, mutat�kon vagy referenci�kon
(p�ld�ul const Rec*) kereszt�l �rhet�nk el, �ltal�ban nagyon egyszeruen
ellenorizhetj�k,
hogy a kiv�telek muvelnek-e valamilyen vesz�lyes dolgot.
E.5.4. A valarray �s a complex
A sz�mkezelo f�ggv�nyek sem okoznak kifejezetten kiv�teleket (22. fejezet), de a
valarray
oszt�lynak mem�ri�t kell foglalnia, �gy haszn�latakor elofordulhat std::bad_alloc
kiv�tel.
Ezenk�v�l a valarray �s a complex kaphat olyan elemt�pust is (skal�rokat), amely
kiv�teleket
v�lthat ki. Szok�s szerint a szabv�ny alapbiztos�t�st (�E.2) ny�jt, de a kiv�telek
�ltal megszakadt
sz�m�t�sok eredm�ny�rol semmit sem felt�telezhet�nk.
A basic_string oszt�lyhoz hasonl�an (�E.5.1) a valarray �s a complex is
felt�telezheti, hogy
a sablonparam�ter�ben megadott t�pus nem rendelkezik felhaszn�l�i m�sol�
muveletekkel,
teh�t egyszeruen, b�jtonk�nt m�solhat�. A standard k�nyvt�r numerikus t�pusainak
t�bbs�ge a sebess�gre optimaliz�lt, �gy felt�telezi, hogy elemt�pusai nem okoznak
kiv�teleket.
E.5.5. A C standard k�nyvt�ra
A standard k�nyvt�r kiv�tel-meghat�roz�s n�lk�li muveletei az adott C++-
v�ltozatt�l f�ggo-
en v�lthatnak ki kiv�teleket, a C standard k�nyvt�r�nak f�ggv�nyein�l azonban
biztosak lehet
�nk abban, hogy csak akkor okoznak kiv�teleket, ha a nekik param�terk�nt �tadott
elj
�r�sok kiv�telt okoznak, hiszen v�geredm�nyben ezeket a f�ggv�nyeket C programok
is
haszn�lj�k �s a C-ben nincsenek kiv�telek. Egy sz�p megval�s�t�s a szabv�nyos C
f�ggv�-
nyeket �res kiv�tel-meghat�roz�ssal adhatja meg (throw()), ezzel lehetos�get adhat
a ford
�t�nak jobb k�d elo�ll�t�s�ra.
E. Kiv�telbiztoss�g a standard k�nyvt�rban 1299
Az olyan f�ggv�nyek, mint a qsort() vagy a bsearch(), egy f�ggv�nyre hivatkoz�
mutat�t
vesznek �t param�terk�nt, �gy okozhatnak kiv�telt, ha param�ter�k k�pes erre. Az
alapbiztos
�t�s (�E.2) ezekre a f�ggv�nyekre is kiterjed.
E.6. Javaslatok a k�nyvt�r felhaszn�l�i sz�m�ra
A standard k�nyvt�r vizsg�latakor a kiv�telbiztoss�gra �gy tekinthet�nk, mint egy
probl�-
mamentes�to eszk�zre, amely sok mindentol megv�d minket, ha nem okozunk saj�t
magunknak
kellemetlens�geket. A k�nyvt�r mindaddig helyesen fog muk�dni, am�g a felhaszn
�l�i elj�r�sok teljes�tik az alapk�vetelm�nyeket (�E.2). A szabv�nyos t�rol�k
muveletei
�ltal kiv�ltott kiv�telek t�bbnyire nem okoznak mem�ria-elsziv�rg�st �s a t�rol�t
�rv�nyes
�llapotban hagyj�k. Teh�t a k�nyvt�r haszn�l�inak a legfontosabb k�rd�s a
k�vetkezo: hogyan
hat�rozzuk meg saj�t t�pusainkat ahhoz, hogy elker�lj�k a kisz�m�thatatlan
viselked
�st �s a mem�ria-lyukak keletkez�s�t?
Az alapszab�lyok a k�vetkezok:
1. Amikor egy objektumot friss�t�nk, soha ne m�dos�tsuk az eredeti �br�zol�st
addig,
am�g az �j �rt�ket teljesen l�tre nem hoztuk �s nem biztos�tottuk, hogy kiv
�tel vesz�lye n�lk�l le tudjuk cser�lni az �rt�ket. P�ldak�ppen n�zz�k meg
a vector::operator=(), a safe_assign() vagy a vector::push_back() f�ggv�ny megval
�s�t�s�t az �E.3 pontban.
2. Mielott kiv�telt v�ltunk ki, szabad�tsunk fel minden olyan lefoglalt
eroforr�st,
amelyet nem k�t�tt�nk (m�s) objektumhoz.
2a A .kezdeti �rt�kad�s az eroforr�s megszerz�s�vel. m�dszer (�14.4) �s
a nyelv szab�lyai, melyek szerint a r�szben l�trehozott objektumok olyan
m�rt�kben t�rlodnek, amennyire l�trej�ttek (�14.4.1), nagyban eloseg�tik ezt
a c�lt. P�ldak�ppen n�zz�k meg a leak() f�ggv�nyt. (�E.2).
2b Az uninitialized_copy() �s testv�rei automatikus eroforr�s-felszabad�t�st
tesznek lehetov�, ha egy objektumhalmaz l�trehoz�sa nem siker�l (�E.4.4).
3. Mielott kiv�telt v�ltunk ki, ellenorizz�k, hogy minden operandus �rv�nyes
�llapotban
van-e, azaz minden objektumot olyan �llapotban kell hagynunk, hogy
az k�sobb szab�lyosan el�rheto �s t�r�lheto legyen an�lk�l, hogy nem meghat
�rozhat� eredm�nyeket kapn�nk �s a destruktornak kiv�telt kellene kiv�ltania.
P�ldak�ppen a vector �rt�kad�s�t eml�thetj�k (�E.3.2).
1300 F�ggel�kek �s t�rgymutat�
3a A konstruktorok abban is elt�rnek az �tlagos elj�r�sokt�l, hogy ha ezekben
keletkezik kiv�tel, nem j�n l�tre objektum, amelyet k�sobb t�r�ln�nk kellene.
Ebbol k�vetkezik, hogy ha egy konstruktorban kell kiv�telt kiv�ltanunk,
akkor nem kell invari�nst helyre�ll�tanunk, de minden eroforr�st fel kell szabad
�tanunk, amit a konstruktor megszakad�sa elott lefoglaltunk.
3b A destruktorok abban k�l�nb�znek a t�bbi muvelettol, hogy ha itt kiv�tel
keletkezik, szinte biztosan elrontunk valamilyen invari�nst �s ak�r
a terminate() f�ggv�ny azonnali megh�v�s�t is eloid�zhetj�k.
A gyakorlatban ezeket a szab�lyokat meglepoen neh�z betartani. Ennek legfobb oka
az,
hogy a kiv�telek gyakran ott k�vetkeznek be, ahol egy�ltal�n nem v�rjuk azokat.
Egy j� p�lda
erre az std::bad_alloc. B�rmely f�ggv�ny okozhatja ezt a kiv�telt, amely k�zvetve
vagy
k�zvetlen�l haszn�lja a new oper�tort vagy egy allocator objektumot mem�ria
lefoglal�s�-
hoz. Bizonyos programokban ezt a hib�t elker�lhetj�k, ha nem ig�nyl�nk a
lehets�gesn�l
t�bb mem�ri�t, az olyan programok eset�ben azonban, amelyek el�g sok�ig futnak
vagy jelent
os mennyis�gu adatot kell feldolgozniuk, fel kell k�sz�ln�nk a legk�l�nb�zobb
hib�kra
az eroforr�s-foglal�sokkal kapcsolatban. Ez azt jelenti, hogy felt�telezn�nk kell,
hogy minden
f�ggv�ny k�pes b�rmely kiv�tel kiv�lt�s�ra, am�g m�st nem bizony�tottunk r�juk.
A meglepet�sek elker�l�s�nek egyik m�dja az, hogy csak olyan elemekbol �p�t�nk
t�rol�-
kat, melyek nem haszn�lnak kiv�teleket (p�ld�ul mutat�kb�l vagy egyszeru, konkr�t
t�pusokb
�l) vagy l�ncolt t�rol�kat (p�ld�ul list) haszn�lunk, melyek eros biztos�t�st
ny�jtanak
(�E.4). A m�sik, ellent�tes megk�zel�t�s, hogy elsosorban az olyan muveletekre
sz�m�tunk,
melyek eros biztos�t�st ny�jtanak (p�ld�ul a push_back()). Ezek vagy sikeresen
befejezodnek,
vagy egy�ltal�n nincs hat�suk (�E.2), de �nmagukban nem elegendoek az
eroforr�slyukak
elker�l�s�re �s csak rendezetlen, pesszimista hibakezel�st �s helyre�ll�t�st
tesznek
lehetov�. A vector<T*> p�ld�ul t�pusbiztos, ha a T t�puson v�gzett muveletek nem
okoznak
kiv�teleket, de ha kiv�tel k�vetkezik be a vector objektumban �s nem gondoskodunk
valahol
a mutatott objektumok t�rl�s�rol, azonnal mem�ria-lyukak keletkeznek. Ebbol
k�vetkezik,
hogy be kell vezetn�nk egy Handle oszt�lyt, amely mindig elv�gzi a sz�ks�ges
felszabad
�t�sokat (�25.7), �s az egyszeru vector<T*> helyett a vector< Handle<T> >
szerkezetet
kell haszn�lnunk. Ez a megold�s az eg�sz programot rugalmasabb� teszi.
Amikor �j programot k�sz�t�nk, lehetos�g�nk van arra, hogy �tgondoltabb
megk�zel�t�st
tal�ljunk �s biztos�tsuk, hogy eroforr�sainkat olyan oszt�lyokkal �br�zoljuk,
melyek invari-
�nsa alapbiztos�t�st ny�jt (�E.2). Egy ilyen rendszerben lehetos�g ny�lik arra,
hogy kiv�-
lasszuk a l�tfontoss�g� objektumokat �s ezek muveleteihez visszag�rget�si
m�dszereket alkalmazzunk
(azaz eros biztos�t�st adhatunk . n�h�ny egyedi felt�tel mellett).
E. Kiv�telbiztoss�g a standard k�nyvt�rban 1301
A legt�bb program tartalmaz olyan adatszerkezeteket �s programr�szeket, melyeket a
kiv�-
telbiztoss�gra nem gondolva �rtak meg. Ha sz�ks�g van r�, ezek a r�szek egy
kiv�telbiztos
keretbe �gyazhat�k. Az egyik lehetos�g, hogy biztos�tjuk, hogy kiv�telek ne
k�vetkezzenek
be (ez t�rt�nt a C standard k�nyvt�r�val, �E.5.5), a m�sik megold�s pedig az, hogy
fel�letoszt
�lyokat haszn�lunk, melyekben a kiv�telek viselked�se �s az eroforr�sok kezel�se
pontosan
meghat�rozhat�.
Amikor olyan �j t�pusokat tervez�nk, amelyek kiv�telbiztos k�rnyezetben futnak
majd, k�-
l�n figyelmet kell szenteln�nk azoknak az elj�r�soknak, melyeket a standard
k�nyvt�r
haszn�lni fog: a konstruktoroknak, a destruktoroknak, az �rt�kad�soknak,
�sszehasonl�t�-
soknak, swap f�ggv�nyeknek, a predik�tumk�nt haszn�lt f�ggv�nyeknek �s a bej�r�kat
kezel
o elj�r�soknak. Ezt legk�nnyebben �gy val�s�thatjuk meg, hogy egy j�
oszt�lyinvari�nst
hat�rozunk meg, amelyet minden konstruktor k�nnyed�n biztos�that. N�ha �gy kell
megtervezn
�nk az oszt�lyinvari�nst, hogy az objektumoknak legyen egy olyan �llapota, melyben

egyszeruen t�r�lhetok, ha egy muvelet .kellemetlen. helyen �tk�zik hib�ba. Ide�lis

esetben ez az �llapot nem egy mesters�gesen megadott �rt�k, amit csak a


kiv�telkezel�s miatt
kellett bevezetni, hanem az oszt�ly term�szet�bol k�vetkezo �llapot (�E.3.5).
Amikor kiv�telbiztoss�ggal foglalkozunk, a fo hangs�lyt az objektumok �rv�nyes
�llapotainak
(invari�nsainak) meghat�roz�s�ra �s az eroforr�sok megfelelo felszabad�t�s�ra kell
helyezn
�nk. Ez�rt nagyon fontos, hogy az eroforr�sokat k�zvetlen�l oszt�lyokkal
�br�zoljuk.
A vector_base (�E.3.2) ennek egyszeru p�ld�ja. Az ilyen eroforr�s-oszt�lyok
konstruktora alacsonyszint
u eroforr�sokat foglal le (p�ld�ul egy mem�riatartom�nyt a vector_base eset�ben),
�s invari�nsokat �ll�t be (p�ld�ul a mutat�kat a megfelelo helyekre �ll�tja a
vector_base oszt
�lyban). Ezen oszt�lyok destruktora egyszeruen felszabad�tja a lefoglalt
eroforr�st. A r�szleges
l�trehoz�s szab�lyai (�14.4.1) �s a .kezdeti �rt�kad�s az eroforr�s
lefoglal�s�val. m�dszer
(�14.4) alkalmaz�sa lehetov� teszi, hogy az eroforr�sokat �gy kezelj�k.
Egy j�l meg�rt konstruktor minden objektum eset�ben be�ll�tja a megfelelo
invari�nst
(�24.3.7.1), teh�t a konstruktor olyan �rt�ket ad az objektumnak, amely lehetov�
teszi, hogy
a tov�bbi muveleteket egyszeruen meg tudjuk �rni �s sikeresen v�gre tudjuk
hajtani. Ebbol
k�vetkezik, hogy a konstruktoroknak gyakran kell eroforr�st lefoglalniuk. Ha ezt
nem tudj
�k elv�gezni, kiv�telt v�lthatnak ki, �gy az objektum l�trehoz�sa elott
foglalkozhatunk a jelentkez
o probl�m�kkal. Ezt a megk�zel�t�st a nyelv �s a standard k�nyvt�r k�zvetlen�l t�-
mogatja (�E.3.5).
Az a k�vetelm�ny, hogy az eroforr�sokat fel kell szabad�tanunk �s az operandusokat
�rv�-
nyes �llapotban kell hagynunk a kiv�tel kiv�lt�sa elott, azt jelenti, hogy a
kiv�telkezel�s terheit
megosztjuk a kiv�telt kiv�lt� f�ggv�ny, a h�v�si l�ncban levo f�ggv�nyek �s a
kiv�telt
t�nylegesen kezelo elj�r�s k�z�tt. Egy kiv�tel kiv�lt�sa nem azt a hibakezel�si
st�lust jelen-
1302 F�ggel�kek �s t�rgymutat�
ti, hogy .hagyjuk az eg�szet valaki m�sra.. Minden f�ggv�nynek, amely kiv�telt
v�lt ki vagy
ad tov�bb, k�teless�ge felszabad�tani azokat az eroforr�sokat, melyek hat�sk�r�be
tartoznak,
operandusait pedig megfelelo �rt�kre kell �ll�tania. Ha az elj�r�sok ezt a
feladatot nem
k�pesek v�grehajtani, a kiv�telkezelo nemigen tehet m�st, minthogy megpr�b�lja
.sz�pen.
befejezni a program muk�d�s�t.
E.7. Tan�csok
[1] Legy�nk tiszt�ban azzal, milyen szintu kiv�telbiztoss�gra van sz�ks�g�nk.
�E.2.
[2] A kiv�telbiztoss�gnak egy teljes k�ru hibatur�si strat�gia r�sz�nek kell
lennie.
�E.2.
[3] Az alapbiztos�t�st minden oszt�lyhoz �rdemes megval�s�tani, azaz az
invari�nsokat
mindig tartsuk meg �s az eroforr�s-lyukakat mindig ker�lj�k el. �E.2,
�E.3.2, �E.4.
[4] Ahol lehetos�g �s sz�ks�g van r�, val�s�tsunk meg eros biztos�t�st, azaz egy
muvelet vagy sikeresen hajt�djon v�gre, vagy minden operandus�t hagyja
v�ltozatlanul.
�E.2, �E.3.
[5] Destruktorokban ne fordulhasson elo kiv�tel. �E.2, �E.3.2, �E.4.
[6] Ne v�ltson ki kiv�telt egy �rv�nyes sorozatban mozg� bej�r�. �E.4.1, �E.4.4.
[7] A kiv�telbiztoss�g foglalja mag�ban az �n�ll� muveletek alapos vizsg�lat�t.
�E.3.
[8] A sablon oszt�lyokat �gy tervezz�k meg, hogy azok .�tl�tsz�ak. legyenek a kiv
�telek sz�m�ra. �E.3.1.
[9] Az init() f�ggv�ny helyett haszn�ljunk konstruktort az eroforr�sok
lefoglal�s�-
hoz. �E.3.5.
[10] Adjunk meg invari�nst minden oszt�lyhoz, hogy ezzel pontosan meghat�rozzuk
�rv�nyes �llapotaikat. �E.2, �E.6.
[11] Gyozodj�nk meg r�la, hogy objektumaink mindig �rv�nyes �llapotba �ll�that�k
an�lk�l, hogy kiv�telektol kellene tartanunk. �E.3.2, �E.6.
[12] Az invari�nsok mindig legyenek egyszeruek. �E.3.5.
[13] Kiv�tel kiv�lt�sa elott minden objektumot �ll�tsunk �rv�nyes �llapotba. �E.2,

�E.6.
[14] Ker�lj�k el az eroforr�s-lyukakat. �E.2, �E.3.1, �E.6.
[15] Az eroforr�sokat k�zvetlen�l �br�zoljuk. �E.3.2, �E.6.
[16] Gondoljunk r�, hogy a swap() f�ggv�ny gyakran haszn�lhat� az elemek m�sol
�sa helyett. �E.3.3.
E. Kiv�telbiztoss�g a standard k�nyvt�rban 1303
[17] Ha lehetos�g van r�, a try blokkok haszn�lata helyett a muveletek
sorrendj�nek
j� megv�laszt�s�val kezelj�k a probl�m�kat. �E.3.4.
[18] Ne t�r�lj�k a .r�gi. inform�ci�kat addig, am�g a helyettes�to adatok nem
v�lnak
biztons�gosan el�rhetov�. �E.3.3, �E.6.
[19] Haszn�ljuk a .kezdeti �rt�kad�s az eroforr�s megszerz�s�vel. m�dszert. �E.3,
�E.3.2, �E.6.
[20] Vizsg�ljuk meg, hogy asszociat�v t�rol�inkban az �sszehasonl�t� muveletek m�-

solhat�k-e. �E.3.3.
[21] Keress�k meg a l�tfontoss�g� adatszerkezeteket �s ezekhez adjunk meg olyan
muveleteket, melyek eros biztos�t�st adnak. �E.6.
E.8. Gyakorlatok
1. (*1) Soroljuk fel az �sszes kiv�telt, amely elofordulhat az �E.1 pont f()
f�ggv�ny�ben.
2. (*1) V�laszoljunk az �E.1 pontban, a p�lda ut�n szereplo k�rd�sekre.
3. (*1) K�sz�ts�nk egy Tester oszt�lyt, amely idonk�nt a legalapvetobb
muveletekben
okoz kiv�telt, p�ld�ul a m�sol� konstruktorban. A Tester oszt�ly seg�ts�g�-
vel pr�b�ljuk ki saj�t standard k�nyvt�runk t�rol�it.
4. (*1) Keress�k meg a hib�t az �E.3.1 pontban szereplo vector konstruktor�nak
rendezetlen v�ltozat�ban �s �rjunk programot, amely t�nkreteszi az oszt�lyt.
Aj�nl�s: elosz�r �rjuk meg a vector destruktor�t.
5. (*2) K�sz�ts�nk egyszeru list�t, amely alapbiztos�t�st ny�jt. �llap�tsuk meg
nagyon
pontosan, milyen k�vetelm�nyeket kell a felhaszn�l�nak teljes�tenie a biztos
�t�s megval�s�t�s�hoz.
6. (*3) K�sz�ts�nk egyszeru list�t, amely eros biztos�t�st ny�jt. Alaposan
ellenorizz
�k az oszt�ly muk�d�s�t. Indokoljuk meg, mi�rt tartjuk ezt a megold�st biztons
�gosabbnak.
7. (*2.5)�rjuk �jra a �11.12 String oszt�ly�t �gy, hogy ugyanolyan biztons�gos
legyen,
mint a szabv�nyos t�rol�k.
8. (*2) Hasonl�tsuk �ssze a vector oszt�lyban meghat�rozott �rt�kad�s �s
a safe_assign() f�ggv�ny k�l�nb�zo v�ltozatait a fut�si ido szempontj�b�l.
(�E.3.3)
9. (*1.5) M�soljunk le egy mem�riafoglal�t az �rt�kad� oper�tor haszn�lata n�lk�l
(hiszen az operator=() megval�s�t�s�hoz erre van sz�ks�g�nk az �E.3.3
pontban).
1304 F�ggel�kek �s t�rgymutat�
10. (*2) �rjunk a vector oszt�lyhoz alapbiztos�t�ssal egy egyelemu �s egy
t�bbelemu
erase(), illetve insert() f�ggv�nyt.�E.3.2.
11. (*2) �rjunk a vector oszt�lyhoz eros biztos�t�ssal egy egyelemu �s egy
t�bbelemu
erase(), illetve insert() f�ggv�nyt (�E.3.2). Hasonl�tsuk �ssze ezen f�ggv�nyek
k�lts�g�t �s bonyolults�g�t az elozo feladatban szereplo f�ggv�nyek�vel.
12. (*2) K�sz�ts�nk egy safe_insert() f�ggv�nyt (�E.4.2), amely egy l�tezo vector
objektumba
sz�r be elemet (nem pedig egy ideiglenes v�ltoz�t m�sol le). Milyen
kik�t�seket kell tenn�nk a muveletekre?
13. (*2.5) Hasonl�tsuk �ssze m�ret, bonyolults�g �s hat�konys�g szempontj�b�l
a 12. �s a 13. feladatban szereplo safe_insert() f�ggv�nyt az �E.4.2 pontban
bemutatott
safe_insert() f�ggv�nnyel.
14. (*2.5) �rjunk egy jobb (gyorsabb �s egyszerubb) safe_insert() f�ggv�nyt,
kifejezetten
asszociat�v t�rol�khoz. Haszn�ljuk a traits elj�r�st egy olyan safe_insert()
megval�s�t�s�hoz, amely automatikusan kiv�lasztja az adott t�rol�hoz optim�lis
megval�s�t�st. Aj�nl�s: �19.2.3.
15. (*2.5) Pr�b�ljuk meg�rni az uninitialized_fill() f�ggv�nyt (�19.4.4, �E.3.1)
�gy,
hogy az megfeleloen kezelje a kiv�teleket kiv�lt� destruktorokat is. Lehets�ges
ez? Ha igen, milyen �ron? Ha nem, mi�rt nem?
16. (*2.5) Keress�nk egy t�rol�t egy olyan k�nyvt�rban, amely nem tartozik a szabv
�nyhoz. N�zz�k �t dokument�ci�j�t �s �llap�tsuk meg, milyen kiv�telbiztoss�gi
lehetos�gek �llnak rendelkez�s�nkre. V�gezz�nk n�h�ny tesztet, hogy meg�llap
�tsuk, mennyire rugalmas a t�rol� a mem�riafoglal�sb�l vagy a felhaszn�l� �ltal
megadott programr�szekbol sz�rmaz� kiv�telekkel szemben. Hasonl�tsuk �ssze
a tapasztaltakat a standard k�nyvt�r megfelelo t�rol�j�nak szolg�ltat�saival.
17. (*3) Pr�b�ljuk optimaliz�lni az �E.3 pontban szereplo vector oszt�lyt a
kiv�telek
lehetos�g�nek figyelmen k�v�l hagy�s�val. P�ld�ul t�r�lj�nk minden try blokkot.
Hasonl�tsuk �ssze az �gy kapott v�ltozat hat�konys�g�t a standard k�nyvt�r
vector oszt�ly�nak hat�konys�g�val. Hasonl�tsuk �ssze a k�t v�ltozatot m�ret �s
bonyolults�g szempontj�b�l is.
18. (*1) Adjunk meg invari�nst a vector oszt�ly (�E.3) sz�m�ra �gy, hogy megengedj
�k, illetve megtiltjuk a v==0 esetet (�E.3.5).
19. (*2.5) N�zz�k v�gig egy vector oszt�ly megval�s�t�s�nak forr�sk�dj�t. Milyen
biztos�t�s �ll rendelkez�s�nkre az �rt�kad�sban, a t�bbelemu insert() utas�t�sban
�s a resize() f�ggv�nyben?
20. (*3) �rjuk meg a hash_map (�17.6) olyan v�ltozat�t, amely ugyanolyan biztons�-

gos, mint a szabv�nyos t�rol�k.


E. Kiv�telbiztoss�g a standard k�nyvt�rban 1305

Vous aimerez peut-être aussi