Académique Documents
Professionnel Documents
Culture Documents
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�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-
programon bel�l . vagyis az egy megold�sban szereplo k�l�nb�zo elemek k�zti pontos
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
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
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.
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
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:
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
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
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 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�-
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
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
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).
�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.
(�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
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
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
// �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
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, ©, &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
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
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:
ki, melyiket kaptuk el. Ne felejts�k el azt az esetet, amikor a kiv�telt a kiv�lt�
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
[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,
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.
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
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
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
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-
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
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
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
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,
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-
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
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
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
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:
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�
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
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
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
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
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
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
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
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
�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:
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
�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
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
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
// 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:
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.
// �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
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
// 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
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�-
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
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
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
{
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
// 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
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).
// �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
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
// 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
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
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
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
}
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.
�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
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
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.
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,
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,
�s �br�zoljunk egy locale objektum le�r�sa szerint. Tal�ljuk meg saj�t rendszer�nk
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
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
�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)
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
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
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
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.
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
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
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
(�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
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).
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
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�-
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.
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
�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
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
�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
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-
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
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�-
�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 .
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
}
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�-
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
(�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 */
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 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�-
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
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�:
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,
// ...
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
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
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
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
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
{
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
*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.
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
{
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
�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�-