Darmowy fragment publikacji:
Tytuł oryginału: The C++ Programming Language, 4th Edition
Tłumaczenie: Łukasz Piwko
ISBN: 978-83-246-8530-1
Authorized translation from the English language edition, entitled:
THE C++ PROGRAMMING LANGUAGE, FOURTH EDITION;
ISBN 0321563840; by Bjarne Stroustrup; published by Pearson Education, Inc, publishing as Addison
Wesley.
Copyright © 2013 by Pearson Education.
All rights reserved. No part of this book may by reproduced or transmitted in any form or by any
means, electronic or mechanical, including photocopying, recording or by any information storage
retrieval system, without permission from Pearson Education, Inc.
Polish language edition published by HELION S.A. Copyright © 2014.
Wszelkie prawa zastrzeżone. Nieautoryzowane rozpowszechnianie całości
lub fragmentu niniejszej publikacji w jakiejkolwiek postaci jest zabronione. Wykonywanie kopii
metodą kserograficzną, fotograficzną, a także kopiowanie książki na nośniku filmowym,
magnetycznym lub innym powoduje naruszenie praw autorskich niniejszej publikacji.
Wszystkie znaki występujące w tekście są zastrzeżonymi znakami firmowymi bądź towarowymi ich
właścicieli.
Autor oraz Wydawnictwo HELION dołożyli wszelkich starań, by zawarte
w tej książce informacje były kompletne i rzetelne. Nie biorą jednak żadnej odpowiedzialności ani za
ich wykorzystanie, ani za związane z tym ewentualne naruszenie praw patentowych lub autorskich.
Autor oraz Wydawnictwo HELION nie ponoszą również żadnej odpowiedzialności za ewentualne
szkody wynikłe z wykorzystania informacji zawartych w książce.
Wydawnictwo HELION
ul. Kościuszki 1c, 44-100 GLIWICE
tel. 32 231 22 19, 32 230 98 63
e-mail: helion@helion.pl
WWW: http://helion.pl (księgarnia internetowa, katalog książek)
Drogi Czytelniku!
Jeżeli chcesz ocenić tę książkę, zajrzyj pod adres
http://helion.pl/user/opinie/jcppkw
Możesz tam wpisać swoje uwagi, spostrzeżenia, recenzję.
Printed in Poland.
• Kup książkę
• Poleć książkę
• Oceń książkę
• Księgarnia internetowa
• Lubię to! » Nasza społeczność
Przedmowa
Przedmowa do wydania trzeciego
Przedmowa do wydania drugiego
Przedmowa do wydania pierwszego
CZ(cid:125)(cid:165)(cid:109) I. WPROWADZENIE
Rozdzia(cid:239) 1. Uwagi do czytelnika
1.1. Struktura ksi(cid:200)(cid:285)ki
1.1.1. Wprowadzenie
1.1.2. Podstawowe narz(cid:218)dzia
1.1.3. Techniki abstrakcji
1.1.4. Biblioteka standardowa
1.1.5. Przyk(cid:239)ady i odwo(cid:239)ania
1.2. Projekt j(cid:218)zyka C++
1.2.1. Styl programowania
1.2.2. Kontrola typów
1.2.3. Zgodno(cid:258)(cid:202) z j(cid:218)zykiem C
1.2.4. J(cid:218)zyk, biblioteki i systemy
1.3. Nauka j(cid:218)zyka C++
1.3.1. Programowanie w j(cid:218)zyku C++
1.3.2. Rady dla programistów C++
1.3.3. Rady dla programistów C
1.3.4. Rady dla programistów j(cid:218)zyka Java
1.4. Historia
1.4.1. O(cid:258) czasu
1.4.2. Pierwsze lata
1.4.3. Standard z 1998 r.
1.4.4. Standard z 2011 r.
1.4.5. Do czego jest u(cid:285)ywany j(cid:218)zyk C++
1.5. Rady
1.6. Literatura
Spis tre(cid:258)ci
23
27
29
31
33
35
35
36
36
37
39
40
41
43
46
47
48
50
52
53
53
54
55
56
57
59
62
65
67
68
Kup książkęPoleć książkę4
Spis tre(cid:258)ci
Rozdzia(cid:239) 2. Kurs j(cid:218)zyka C++. Podstawy
2.1. Wprowadzenie
2.2. Podstawy
2.2.1. Witaj, (cid:258)wiecie!
2.2.2. Typy, zmienne i arytmetyka
2.2.3. Sta(cid:239)e
2.2.4. Testy i p(cid:218)tle
2.2.5. Wska(cid:283)niki, tablice i p(cid:218)tle
2.3. Typy zdefiniowane przez u(cid:285)ytkownika
2.3.1. Struktury
2.3.2. Klasy
2.3.3. Wyliczenia
2.4. Modu(cid:239)owo(cid:258)(cid:202)
2.4.1. Osobna kompilacja
2.4.2. Przestrzenie nazw
2.4.3. Obs(cid:239)uga b(cid:239)(cid:218)dów
2.5. Pos(cid:239)owie
2.6. Rady
Rozdzia(cid:239) 3. Kurs j(cid:218)zyka C++. Techniki abstrakcji
3.1. Wprowadzenie
3.2. Klasy
3.2.1. Typy konkretne
3.2.2. Typy abstrakcyjne
3.2.3. Funkcje wirtualne
3.2.4. Hierarchie klas
3.3. Kopiowanie i przenoszenie
3.3.1. Kopiowanie kontenerów
3.3.2. Przenoszenie kontenerów
3.3.3. Zarz(cid:200)dzanie zasobami
3.3.4. T(cid:239)umienie operacji
3.4. Szablony
3.4.1. Typy parametryzowane
3.4.2. Szablony funkcji
3.4.3. Obiekty funkcyjne
3.4.4. Zmienne szablony
3.4.5. Aliasy
3.5. Rady
Rozdzia(cid:239) 4. Kurs j(cid:218)zyka C++. Kontenery i algorytmy
4.1. Biblioteki
4.1.1. Przegl(cid:200)d biblioteki standardowej
4.1.2. Nag(cid:239)ówki i przestrze(cid:241) nazw biblioteki standardowej
4.2. (cid:146)a(cid:241)cuchy
4.3. Strumienie wej(cid:258)cia i wyj(cid:258)cia
4.3.1. Wyj(cid:258)cie
4.3.2. Wej(cid:258)cie
4.3.3. Wej(cid:258)cie i wyj(cid:258)cie typów zdefiniowanych przez u(cid:285)ytkownika
73
73
74
75
76
78
79
80
82
83
84
86
87
88
89
90
93
93
95
95
96
96
101
103
104
108
108
110
112
113
113
114
115
116
118
119
120
121
121
122
123
124
126
126
127
128
Kup książkęPoleć książkęSpis tre(cid:258)ci
4.4. Kontenery
4.4.1. vector
4.4.2. list
4.4.3. map
4.4.4. unordered_map
4.4.5. Przegl(cid:200)d kontenerów
4.5. Algorytmy
4.5.1. U(cid:285)ywanie iteratorów
4.5.2. Typy iteratorów
4.5.3. Iteratory strumieni
4.5.4. Predykaty
4.5.5. Przegl(cid:200)d algorytmów
4.5.6. Algorytmy kontenerowe
4.6. Rady
Rozdzia(cid:239) 5. Kurs j(cid:218)zyka C++. Wspó(cid:239)bie(cid:285)no(cid:258)(cid:202) i narz(cid:218)dzia
5.1. Wprowadzenie
5.2. Zarz(cid:200)dzanie zasobami
5.2.1. unique_ptr i shared_ptr
5.3. Wspó(cid:239)bie(cid:285)no(cid:258)(cid:202)
5.3.1. Zadania i w(cid:200)tki
5.3.2. Przekazywanie argumentów
5.3.3. Zwracanie wyników
5.3.4. Wspólne u(cid:285)ywanie danych
5.3.5. Komunikacja mi(cid:218)dzy zadaniami
5.4. Drobne, ale przydatne narz(cid:218)dzia
5.4.1. Czas
5.4.2. Funkcje typowe
5.4.3. pair i tuple
5.5. Wyra(cid:285)enia regularne
5.6. Matematyka
5.6.1. Funkcje i algorytmy matematyczne
5.6.2. Liczby zespolone
5.6.3. Liczby losowe
5.6.4. Arytmetyka wektorów
5.6.5. Limity liczbowe
5.7. Rady
CZ(cid:125)(cid:165)(cid:109) II. PODSTAWOWE NARZ(cid:125)DZIA
Rozdzia(cid:239) 6. Typy i deklaracje
6.1. Standard ISO j(cid:218)zyka C++
6.1.1. Implementacje
6.1.2. Podstawowy (cid:283)ród(cid:239)owy zestaw znaków
6.2. Typy
6.2.1. Typy podstawowe
6.2.2. Typ logiczny
6.2.3. Typy znakowe
6.2.4. Typy ca(cid:239)kowitoliczbowe
6.2.5. Typy zmiennoprzecinkowe
5
129
130
133
134
135
135
137
138
140
140
142
143
143
144
145
145
146
146
148
149
150
150
151
154
157
157
158
160
161
162
162
163
163
165
165
166
167
169
169
171
171
172
172
173
174
179
181
Kup książkęPoleć książkę6
Spis tre(cid:258)ci
6.2.6. Przedrostki i przyrostki
6.2.7. void
6.2.8. Rozmiary
6.2.9. Wyrównanie
6.3. Deklaracje
6.3.1. Struktura deklaracji
6.3.2. Deklarowanie po kilka nazw
6.3.3. Nazwy
6.3.4. Zakres dost(cid:218)pno(cid:258)ci
6.3.5. Inicjacja
6.3.6. Dedukowanie typu: auto i decltype()
6.4. Obiekty i warto(cid:258)ci
6.4.1. Warto(cid:258)ci lewo- i prawostronne
6.4.2. Cykl istnienia obiektów
6.5. Aliasy typów
6.6. Rady
Rozdzia(cid:239) 7. Wska(cid:283)niki, tablice i referencje
7.1. Wprowadzenie
7.2. Wska(cid:283)niki
7.2.1. void*
7.2.2. nullptr
7.3. Tablice
7.3.1. Inicjatory tablic
7.3.2. Litera(cid:239)y (cid:239)a(cid:241)cuchowe
7.4. Wska(cid:283)niki do tablic
7.4.1. Przegl(cid:200)danie tablic
7.4.2. Tablice wielowymiarowe
7.4.3. Przekazywanie tablic
7.5. Wska(cid:283)niki i const
7.6. Wska(cid:283)niki i w(cid:239)asno(cid:258)(cid:202)
7.7. Referencje
7.7.1. Referencje lewostronne
7.7.2. Referencje prawostronne
7.7.3. Referencje do referencji
7.7.4. Wska(cid:283)niki i referencje
7.8. Rady
Rozdzia(cid:239) 8. Struktury, unie i wyliczenia
8.1. Wprowadzenie
8.2. Struktury
8.2.1. Uk(cid:239)ad struktur
8.2.2. Nazwy struktur
8.2.3. Struktury a klasy
8.2.4. Struktury a tablice
8.2.5. Ekwiwalencja typów
8.2.6. Stare zwyk(cid:239)e dane
8.2.7. Pola
182
183
183
185
186
188
189
189
191
194
197
200
200
201
202
203
205
205
205
206
207
208
209
210
213
214
217
217
220
221
222
224
227
229
230
232
233
233
234
235
236
237
239
241
241
244
Kup książkęPoleć książkęSpis tre(cid:258)ci
8.3. Unie
8.3.1. Unie a klasy
8.3.2. Anonimowe unie
8.4. Wyliczenia
8.4.1. Klasy wyliczeniowe
8.4.2. Zwyk(cid:239)e wyliczenia
8.4.3. Wyliczenia anonimowe
8.5. Rady
Rozdzia(cid:239) 9. Instrukcje
9.1. Wprowadzenie
9.2. Zestawienie instrukcji
9.3. Deklaracje jako instrukcje
9.4. Instrukcje wyboru
9.4.1. Instrukcje if
9.4.2. Instrukcje switch
9.4.3. Deklaracje w warunkach
9.5. Instrukcje iteracyjne
9.5.1. Zakresowe instrukcje for
9.5.2. Instrukcje for
9.5.3. Instrukcje while
9.5.4. Instrukcje do
9.5.5. Ko(cid:241)czenie p(cid:218)tli
9.6. Instrukcje goto
9.7. Komentarze i wci(cid:218)cia
9.8. Rady
Rozdzia(cid:239) 10. Wyra(cid:285)enia
10.1. Wprowadzenie
10.2. Kalkulator
10.2.1. Parser
10.2.2. Wej(cid:258)cie
10.2.3. Wej(cid:258)cie niskopoziomowe
10.2.4. Obs(cid:239)uga b(cid:239)(cid:218)dów
10.2.5. Sterownik
10.2.6. Nag(cid:239)ówki
10.2.7. Argumenty wiersza polece(cid:241)
10.2.8. Uwaga na temat stylu
10.3. Zestawienie operatorów
10.3.1. Wyniki
10.3.2. Kolejno(cid:258)(cid:202) wykonywania dzia(cid:239)a(cid:241)
10.3.3. Priorytety operatorów
10.3.4. Obiekty tymczasowe
10.4. Wyra(cid:285)enia sta(cid:239)e
10.4.1. Sta(cid:239)e symboliczne
10.4.2. const w wyra(cid:285)eniach sta(cid:239)ych
10.4.3. Typy litera(cid:239)owe
10.4.4. Argumenty referencyjne
10.4.5. Wyra(cid:285)enia sta(cid:239)e adresowe
7
244
246
247
249
250
253
254
255
257
257
258
259
260
260
261
264
264
265
266
267
267
268
269
269
271
273
273
273
274
278
282
283
284
284
285
286
287
291
292
292
293
295
297
297
297
298
299
Kup książkęPoleć książkę8
Spis tre(cid:258)ci
10.5. Niejawna konwersja typów
10.5.1. Promocje
10.5.2. Konwersje
10.5.3. Typowe konwersje arytmetyczne
10.6. Rady
Rozdzia(cid:239) 11. Operacje wyboru
11.1. Ró(cid:285)ne operatory
11.1.1. Operatory logiczne
11.1.2. Bitowe operatory logiczne
11.1.3. Wyra(cid:285)enia warunkowe
11.1.4. Inkrementacja i dekrementacja
11.2. Pami(cid:218)(cid:202) wolna
11.2.1. Zarz(cid:200)dzanie pami(cid:218)ci(cid:200)
11.2.2. Tablice
11.2.3. Sprawdzanie dost(cid:218)pno(cid:258)ci miejsca w pami(cid:218)ci
11.2.4. Przeci(cid:200)(cid:285)anie operatora new
11.3. Listy
11.3.1. Model implementacji
11.3.2. Listy kwalifikowane
11.3.3. Listy niekwalifikowane
11.4. Wyra(cid:285)enia lambda
11.4.1. Model implementacji
11.4.2. Alternatywy dla lambd
11.4.3. Lista zmiennych
11.4.4. Wywo(cid:239)ywanie i zwracanie warto(cid:258)ci
11.4.5. Typ lambdy
11.5. Jawna konwersja typów
11.5.1. Konstrukcja
11.5.2. Rzutowania nazwane
11.5.3. Rzutowanie w stylu j(cid:218)zyka C
11.5.4. Rzutowanie w stylu funkcyjnym
11.6. Rady
Rozdzia(cid:239) 12. Funkcje
12.1. Deklarowanie funkcji
12.1.1. Dlaczego funkcje
12.1.2. Sk(cid:239)adniki deklaracji funkcji
12.1.3. Definiowanie funkcji
12.1.4. Zwracanie warto(cid:258)ci
12.1.5. Funkcje inline
12.1.6. Funkcje constexpr
12.1.7. Funkcje [[noreturn]]
12.1.8. Zmienne lokalne
12.2. Przekazywanie argumentów
12.2.1. Argumenty referencyjne
12.2.2. Argumenty tablicowe
12.2.3. Argumenty listowe
12.2.4. Nieokre(cid:258)lona liczba argumentów
12.2.5. Argumenty domy(cid:258)lne
299
300
300
303
304
305
305
305
306
307
307
309
311
313
314
315
318
318
319
320
322
322
323
325
329
329
330
331
333
334
334
335
337
337
338
338
339
340
342
343
346
346
347
348
350
351
353
356
Kup książkęPoleć książkęSpis tre(cid:258)ci
12.3. Przeci(cid:200)(cid:285)anie funkcji
12.3.1. Automatyczne wybieranie przeci(cid:200)(cid:285)onych funkcji
12.3.2. Przeci(cid:200)(cid:285)anie a typ zwrotny
12.3.3. Przeci(cid:200)(cid:285)anie a zakres
12.3.4. Wybieranie przeci(cid:200)(cid:285)onych funkcji z wieloma argumentami
12.3.5. R(cid:218)czne wybieranie przeci(cid:200)(cid:285)onej funkcji
12.4. Warunki wst(cid:218)pne i ko(cid:241)cowe
12.5. Wska(cid:283)nik do funkcji
12.6. Makra
12.6.1. Kompilacja warunkowa
12.6.2. Makra predefiniowane
12.6.3. Pragmy
12.7. Rady
Rozdzia(cid:239) 13. Obs(cid:239)uga wyj(cid:200)tków
13.1. Obs(cid:239)uga b(cid:239)(cid:218)dów
13.1.1. Wyj(cid:200)tki
13.1.2. Tradycyjna obs(cid:239)uga b(cid:239)(cid:218)dów
13.1.3. Niedba(cid:239)a obs(cid:239)uga b(cid:239)(cid:218)dów
13.1.4. Alternatywne spojrzenie na wyj(cid:200)tki
13.1.5. Kiedy nie mo(cid:285)na u(cid:285)ywa(cid:202) wyj(cid:200)tków
13.1.6. Hierarchiczna obs(cid:239)uga b(cid:239)(cid:218)dów
13.1.7. Wyj(cid:200)tki a wydajno(cid:258)(cid:202)
13.2. Gwarancje wyj(cid:200)tków
13.3. Zarz(cid:200)dzanie zasobami
13.3.1. Finalizacja
13.4. Egzekwowanie przestrzegania niezmienników
13.5. Zg(cid:239)aszanie i przechwytywanie wyj(cid:200)tków
13.5.1. Zg(cid:239)aszanie wyj(cid:200)tków
13.5.2. Przechwytywanie wyj(cid:200)tków
13.5.3. Wyj(cid:200)tki a w(cid:200)tki
13.6. Implementacja wektora
13.6.1. Prosty wektor
13.6.2. Jawna reprezentacja pami(cid:218)ci
13.6.3. Przypisywanie
13.6.4. Zmienianie rozmiaru
13.7. Rady
Rozdzia(cid:239) 14. Przestrzenie nazw
14.1. Kwestie dotycz(cid:200)ce kompozycji
14.2. Przestrzenie nazw
14.2.1. Bezpo(cid:258)rednia kwalifikacja
14.2.2. Deklaracje using
14.2.3. Dyrektywy using
14.2.4. Wyszukiwanie wg argumentów
14.2.5. Przestrzenie nazw s(cid:200) otwarte
14.3. Modularyzacja i interfejsy
14.3.1. Przestrzenie nazw i modu(cid:239)y
14.3.2. Implementacje
14.3.3. Interfejsy i implementacje
9
358
358
360
360
361
362
362
364
368
370
371
372
372
373
373
374
376
377
378
379
380
381
383
385
388
389
394
394
397
404
405
405
409
411
413
416
419
419
420
422
423
424
425
427
428
430
431
433
Kup książkęPoleć książkę10
Spis tre(cid:258)ci
14.4. Sk(cid:239)adanie przy u(cid:285)yciu przestrzeni nazw
14.4.1. Wygoda a bezpiecze(cid:241)stwo
14.4.2. Aliasy przestrzeni nazw
14.4.3. Sk(cid:239)adanie przestrzeni nazw
14.4.4. Sk(cid:239)adanie i wybieranie
14.4.5. Przestrzenie nazw a przeci(cid:200)(cid:285)anie
14.4.6. Wersjonowanie
14.4.7. Zagnie(cid:285)d(cid:285)anie przestrzeni nazw
14.4.8. Anonimowe przestrzenie nazw
14.4.9. Nag(cid:239)ówki j(cid:218)zyka C
14.5. Rady
Rozdzia(cid:239) 15. Pliki (cid:283)ród(cid:239)owe i programy
15.1. Rozdzielna kompilacja
15.2. Konsolidacja
15.2.1. Nazwy lokalne w plikach
15.2.2. Pliki nag(cid:239)ówkowe
15.2.3. Regu(cid:239)a jednej definicji
15.2.4. Nag(cid:239)ówki z biblioteki standardowej
15.2.5. Konsolidacja z kodem w innym j(cid:218)zyku
15.2.6. Konsolidacja a wska(cid:283)niki do funkcji
15.3. U(cid:285)ywanie plików nag(cid:239)ówkowych
15.3.1. Organizacja z jednym nag(cid:239)ówkiem
15.3.2. Organizacja z wieloma nag(cid:239)ówkami
15.3.3. Stra(cid:285)nicy do(cid:239)(cid:200)czania
15.4. Programy
15.4.1. Inicjacja zmiennych nielokalnych
15.4.2. Inicjacja i wspó(cid:239)bie(cid:285)no(cid:258)(cid:202)
15.4.3. Zamykanie programu
15.5. Rady
CZ(cid:125)(cid:165)(cid:109) III. TECHNIKI ABSTRAKCJI
Rozdzia(cid:239) 16. Klasy
16.1. Wprowadzenie
16.2. Podstawowe wiadomo(cid:258)ci o klasach
16.2.1. Funkcje sk(cid:239)adowe
16.2.2. Kopiowanie domy(cid:258)lne
16.2.3. Kontrola dost(cid:218)pu
16.2.4. Klasy i struktury
16.2.5. Konstruktory
16.2.6. Konstruktory explicit
16.2.7. Inicjatory wewn(cid:200)trzklasowe
16.2.8. Wewn(cid:200)trzklasowe definicje funkcji
16.2.9. Zmienno(cid:258)(cid:202)
16.2.10. S(cid:239)owo kluczowe this
16.2.11. Dost(cid:218)p do sk(cid:239)adowych
16.2.12. Sk(cid:239)adowe statyczne
16.2.13. Typy sk(cid:239)adowe
435
435
436
436
438
439
441
443
444
444
445
447
447
448
451
451
453
455
456
458
459
459
463
467
468
469
470
470
472
473
475
475
476
477
478
479
480
481
483
485
486
487
490
491
492
494
Kup książkęPoleć książkęSpis tre(cid:258)ci
16.3. Klasy konkretne
16.3.1. Funkcje sk(cid:239)adowe
16.3.2. Funkcje pomocnicze
16.3.3. Przeci(cid:200)(cid:285)anie operatorów
16.3.4. Znaczenie klas konkretnych
16.4. Rady
Rozdzia(cid:239) 17. Tworzenie, kasowanie, kopiowanie i przenoszenie
17.1. Wprowadzenie
17.2. Konstruktory i destruktory
17.2.1. Konstruktory i niezmienniki
17.2.2. Destruktory i zasoby
17.2.3. Destruktory klas bazowych i sk(cid:239)adowych klas
17.2.4. Wywo(cid:239)ywanie konstruktorów i destruktorów
17.2.5. Destruktory wirtualne
17.3. Inicjacja obiektów klas
17.3.1. Inicjacja bez konstruktorów
17.3.2. Inicjacja przy u(cid:285)yciu konstruktorów
17.3.3. Konstruktory domy(cid:258)lne
17.3.4. Konstruktory z list(cid:200) inicjacyjn(cid:200)
17.4. Inicjacja sk(cid:239)adowych i bazy
17.4.1. Inicjacja sk(cid:239)adowych
17.4.2. Inicjatory bazy
17.4.3. Delegowanie konstruktorów
17.4.4. Inicjatory wewn(cid:200)trzklasowe
17.4.5. Inicjacja sk(cid:239)adowych statycznych
17.5. Kopiowanie i przenoszenie
17.5.1. Kopiowanie
17.5.2. Przenoszenie
17.6. Generowanie domy(cid:258)lnych operacji
17.6.1. Jawne operacje domy(cid:258)lne
17.6.2. Operacje domy(cid:258)lne
17.6.3. U(cid:285)ywanie operacji domy(cid:258)lnych
17.6.4. Usuwanie funkcji
17.7. Rady
Rozdzia(cid:239) 18. Przeci(cid:200)(cid:285)anie operatorów
18.1. Wprowadzenie
18.2. Funkcje operatorowe
18.2.1. Operatory dwu- i jednoargumentowe
18.2.2. Predefiniowane znaczenie operatorów
18.2.3. Operatory i typy zdefiniowane przez u(cid:285)ytkownika
18.2.4. Przekazywanie obiektów
18.2.5. Operatory w przestrzeniach nazw
18.3. Typ reprezentuj(cid:200)cy liczby zespolone
18.3.1. Operatory sk(cid:239)adowe i zewn(cid:218)trzne
18.3.2. Arytmetyka mieszana
18.3.3. Konwersje
18.3.4. Litera(cid:239)y
18.3.5. Funkcje dost(cid:218)powe
18.3.6. Funkcje pomocnicze
11
495
498
500
502
503
504
505
505
507
508
509
510
511
512
513
513
515
517
519
524
524
525
526
527
529
530
530
537
541
541
542
543
547
548
551
551
553
554
555
555
556
557
559
559
560
561
564
565
565
Kup książkęPoleć książkę12
Spis tre(cid:258)ci
18.4. Konwersja typów
18.4.1. Operatory konwersji
18.4.2. Operatory konwersji explicit
18.4.3. Niejednoznaczno(cid:258)ci
18.5. Rady
Rozdzia(cid:239) 19. Operatory specjalne
19.1. Wprowadzenie
19.2. Operatory specjalne
19.2.1. Indeksowanie
19.2.2. Wywo(cid:239)ywanie funkcji
19.2.3. Dereferencja
19.2.4. Inkrementacja i dekrementacja
19.2.5. Alokacja i dezalokacja
19.2.6. Litera(cid:239)y zdefiniowane przez u(cid:285)ytkownika
19.3. Klasa String
19.3.1. Podstawowe operacje
19.3.2. Dost(cid:218)p do znaków
19.3.3. Reprezentacja
19.3.4. Funkcje sk(cid:239)adowe
19.3.5. Funkcje pomocnicze
19.3.6. Sposoby u(cid:285)ycia
19.4. Przyjaciele
19.4.1. Znajdowanie przyjació(cid:239)
19.4.2. Przyjaciele i sk(cid:239)adowe
19.5. Rady
Rozdzia(cid:239) 20. Derywacja klas
20.1. Wprowadzenie
20.2. Klasy pochodne
20.2.1. Funkcje sk(cid:239)adowe
20.2.2. Konstruktory i destruktory
20.3. Hierarchie klas
20.3.1. Pola typów
20.3.2. Funkcje wirtualne
20.3.3. Bezpo(cid:258)rednia kwalifikacja
20.3.4. Kontrola przes(cid:239)aniania
20.3.5. U(cid:285)ywanie sk(cid:239)adowych klasy bazowej
20.3.6. Rozlu(cid:283)nienie zasady dotycz(cid:200)cej typów zwrotnych
20.4. Klasy abstrakcyjne
20.5. Kontrola dost(cid:218)pu
20.5.1. Sk(cid:239)adowe chronione
20.5.2. Dost(cid:218)p do klas bazowych
20.5.3. Deklaracje using i kontrola dost(cid:218)pu
20.6. Wska(cid:283)niki do sk(cid:239)adowych
20.6.1. Wska(cid:283)niki do funkcji sk(cid:239)adowych
20.6.2. Wska(cid:283)niki do danych sk(cid:239)adowych
20.6.3. Sk(cid:239)adowe bazy i klasy pochodnej
20.7. Rady
567
567
569
569
571
573
573
573
573
574
576
578
580
581
584
585
585
586
589
591
593
594
596
597
598
599
599
600
602
604
604
605
607
610
610
614
617
619
621
624
625
627
627
628
630
631
631
Kup książkęPoleć książkęSpis tre(cid:258)ci
Rozdzia(cid:239) 21. Hierarchie klas
21.1. Wprowadzenie
21.2. Projektowanie hierarchii klas
21.2.1. Dziedziczenie implementacji
21.2.2. Dziedziczenie interfejsu
21.2.3. Alternatywne implementacje
21.2.4. Lokalizowanie tworzenia obiektu
21.3. Wielodziedziczenie
21.3.1. Wiele interfejsów
21.3.2. Wiele klas implementacyjnych
21.3.3. Rozstrzyganie niejednoznaczno(cid:258)ci
21.3.4. Wielokrotne u(cid:285)ycie klasy bazowej
21.3.5. Wirtualne klasy bazowe
21.3.6. Bazy wirtualne a replikowane
21.4. Rady
Rozdzia(cid:239) 22. Informacje o typach w czasie dzia(cid:239)ania programu
22.1. Wprowadzenie
22.2. Poruszanie si(cid:218) w obr(cid:218)bie hierarchii klas
22.2.1. Rzutowanie dynamiczne
22.2.2. Wielodziedziczenie
22.2.3. Rzutowanie statyczne i dynamiczne
22.2.4. Odzyskiwanie interfejsu
22.3. Podwójny polimorfizm i wizytatorzy
22.3.1. Podwójny polimorfizm
22.3.2. Wizytatorzy
22.4. Konstrukcja i destrukcja
22.5. Identyfikacja typów
22.5.1. Rozszerzone informacje o typie
22.6. Poprawne i niepoprawne u(cid:285)ywanie RTTI
22.7. Rady
Rozdzia(cid:239) 23. Szablony
23.1. Wprowadzenie i przegl(cid:200)d
23.2. Prosty szablon (cid:239)a(cid:241)cucha
23.2.1. Definiowanie szablonu
23.2.2. Konkretyzacja szablonu
23.3. Kontrola typów
23.3.1. Ekwiwalencja typów
23.3.2. Wykrywanie b(cid:239)(cid:218)dów
23.4. Sk(cid:239)adowe szablonu klasy
23.4.1. Dane sk(cid:239)adowe
23.4.2. Funkcje sk(cid:239)adowe
23.4.3. Aliasy typów sk(cid:239)adowych
23.4.4. Sk(cid:239)adowe statyczne
23.4.5. Typy sk(cid:239)adowe
23.4.6. Szablony sk(cid:239)adowe
23.4.7. Przyjaciele
13
633
633
633
634
637
639
642
644
644
644
646
649
651
655
658
659
659
660
661
664
665
667
670
671
673
675
675
677
678
680
681
681
684
685
687
688
689
690
691
691
692
692
692
693
694
698
Kup książkęPoleć książkę14
Spis tre(cid:258)ci
23.5. Szablony funkcji
23.5.1. Argumenty szablonu funkcji
23.5.2. Dedukcja argumentów szablonu funkcji
23.5.3. Przeci(cid:200)(cid:285)anie szablonów funkcji
23.6. Aliasy szablonów
23.7. Organizacja kodu (cid:283)ród(cid:239)owego
23.7.1. Konsolidacja
23.8. Rady
Rozdzia(cid:239) 24. Programowanie ogólne
24.1. Wprowadzenie
24.2. Algorytmy i uogólnianie
24.3. Koncepcje
24.3.1. Odkrywanie koncepcji
24.3.2. Koncepcje i ograniczenia
24.4. Konkretyzacja koncepcji
24.4.1. Aksjomaty
24.4.2. Koncepcje wieloargumentowe
24.4.3. Koncepcje warto(cid:258)ci
24.4.4. Sprawdzanie ogranicze(cid:241)
24.4.5. Sprawdzanie definicji szablonu
24.5. Rady
Rozdzia(cid:239) 25. Specjalizacja
25.1. Wprowadzenie
25.2. Argumenty i parametry szablonu
25.2.1. Typy jako argumenty
25.2.2. Warto(cid:258)ci jako argumenty
25.2.3. Operacje jako argumenty
25.2.4. Szablony jako argumenty
25.2.5. Domy(cid:258)lne argumenty szablonów
25.3. Specjalizacja
25.3.1. Specjalizacja interfejsu
25.3.2. Szablon podstawowy
25.3.3. Porz(cid:200)dek specjalizacji
25.3.4. Specjalizacja szablonu funkcji
25.4. Rady
Rozdzia(cid:239) 26. Konkretyzacja
26.1. Wprowadzenie
26.2. Konkretyzacja szablonu
26.2.1. Kiedy konkretyzacja jest potrzebna
26.2.2. R(cid:218)czne sterowanie konkretyzacj(cid:200)
26.3. Wi(cid:200)zanie nazw
26.3.1. Nazwy zale(cid:285)ne
26.3.2. Wi(cid:200)zanie w miejscu definicji
26.3.3. Wi(cid:200)zanie w miejscu konkretyzacji
26.3.4. Wiele miejsc konkretyzacji
699
701
702
704
708
709
711
712
713
713
714
718
718
722
724
727
728
729
730
731
733
735
735
736
736
738
739
742
742
744
747
748
750
750
753
755
755
756
757
758
759
761
762
763
766
Kup książkęPoleć książkęSpis tre(cid:258)ci
26.3.5. Szablony i przestrzenie nazw
26.3.6. Nadmiernie agresywne wyszukiwanie wg argumentów
26.3.7. Nazwy z klas bazowych
26.4. Rady
Rozdzia(cid:239) 27. Hierarchie szablonów
27.1. Wprowadzenie
27.2. Parametryzacja i hierarchia
27.2.1. Typy generowane
27.2.2. Konwersje szablonów
27.3. Hierarchie szablonów klas
27.3.1. Szablony jako interfejsy
27.4. Parametry szablonowe jako klasy bazowe
27.4.1. Sk(cid:239)adanie struktur danych
27.4.2. Linearyzacja hierarchii klas
27.5. Rady
Rozdzia(cid:239) 28. Metaprogramowanie
28.1. Wprowadzenie
28.2. Funkcje typowe
28.2.1. Aliasy typów
28.2.2. Predykaty typów
28.2.3. Wybieranie funkcji
28.2.4. Cechy
28.3. Struktury steruj(cid:200)ce
28.3.1. Wybieranie
28.3.2. Iteracja i rekurencja
28.3.3. Kiedy stosowa(cid:202) metaprogramowanie
28.4. Definicja warunkowa
28.4.1. U(cid:285)ywanie Enable_if
28.4.2. Implementacja Enable_if
28.4.3. Enable_if i koncepcje
28.4.4. Dodatkowe przyk(cid:239)ady u(cid:285)ycia Enable_if
28.5. Lista czasu kompilacji
28.5.1. Prosta funkcja wyj(cid:258)ciowa
28.5.2. Dost(cid:218)p do elementów
28.5.3. make_tuple
28.6. Szablony zmienne
28.6.1. Bezpieczna typowo funkcja printf()
28.6.2. Szczegó(cid:239)y techniczne
28.6.3. Przekazywanie
28.6.4. Typ tuple z biblioteki standardowej
28.7. Przyk(cid:239)ad z jednostkami uk(cid:239)adu SI
28.7.1. Jednostki
28.7.2. Wielko(cid:258)ci
28.7.3. Litera(cid:239)y jednostkowe
28.7.4. Funkcje pomocnicze
28.8. Rady
15
767
768
770
772
773
773
774
776
778
779
780
781
781
785
790
791
791
794
796
798
799
800
802
802
805
806
807
809
811
811
812
814
816
818
820
821
821
824
825
827
830
830
831
833
834
836
Kup książkęPoleć książkę16
Spis tre(cid:258)ci
Rozdzia(cid:239) 29. Projekt macierzy
29.1. Wprowadzenie
29.1.1. Podstawowe zastosowania macierzy
29.1.2. Wymagania dotycz(cid:200)ce macierzy
29.2. Szablon macierzy
29.2.1. Konstrukcja i przypisywanie
29.2.2. Indeksowanie i ci(cid:218)cie
29.3. Operacje arytmetyczne na macierzach
29.3.1. Operacje skalarne
29.3.2. Dodawanie
29.3.3. Mno(cid:285)enie
29.4. Implementacja macierzy
29.4.1. Wycinki
29.4.2. Wycinki macierzy
29.4.3. Matrix_ref
29.4.4. Inicjacja listy macierzy
29.4.5. Dost(cid:218)p do macierzy
29.4.6. Macierz zerowymiarowa
29.5. Rozwi(cid:200)zywanie równa(cid:241) liniowych
29.5.1. Klasyczna eliminacja Gaussa
29.5.2. Znajdowanie elementu centralnego
29.5.3. Testowanie
29.5.4. Po(cid:239)(cid:200)czone operacje
29.6. Rady
CZ(cid:125)(cid:165)(cid:109) IV. BIBLIOTEKA STANDARDOWA
Rozdzia(cid:239) 30. Przegl(cid:200)d zawarto(cid:258)ci biblioteki standardowej
30.1. Wprowadzenie
30.1.1. Narz(cid:218)dzia biblioteki standardowej
30.1.2. Kryteria projektowe
30.1.3. Styl opisu
30.2. Nag(cid:239)ówki
30.3. Wsparcie dla j(cid:218)zyka
30.3.1. Wsparcie dla list inicjacyjnych
30.3.2. Wsparcie dla zakresowej p(cid:218)tli for
30.4. Obs(cid:239)uga b(cid:239)(cid:218)dów
30.4.1. Wyj(cid:200)tki
30.4.2. Asercje
30.4.3. system_error
30.5. Rady
Rozdzia(cid:239) 31. Kontenery STL
31.1. Wprowadzenie
31.2. Przegl(cid:200)d kontenerów
31.2.1. Reprezentacja kontenera
31.2.2. Wymagania dotycz(cid:200)ce elementów
837
837
838
840
841
842
843
845
846
847
848
850
850
850
852
853
855
857
858
859
860
861
862
864
865
867
867
868
869
870
871
875
876
876
877
877
882
882
892
893
893
893
896
898
Kup książkęPoleć książkęSpis tre(cid:258)ci
31.3. Przegl(cid:200)d operacji
31.3.1. Typy sk(cid:239)adowe
31.3.2. Konstruktory, destruktory i przypisania
31.3.3. Rozmiar i pojemno(cid:258)(cid:202)
31.3.4. Iteratory
31.3.5. Dost(cid:218)p do elementów
31.3.6. Operacje stosowe
31.3.7. Operacje listowe
31.3.8. Inne operacje
31.4. Kontenery
31.4.1. vector
31.4.2. Listy
31.4.3. Kontenery asocjacyjne
31.5. Adaptacje kontenerów
31.5.1. Stos
31.5.2. Kolejka
31.5.3. Kolejka priorytetowa
31.6. Rady
Rozdzia(cid:239) 32. Algorytmy STL
32.1. Wprowadzenie
32.2. Algorytmy
32.2.1. Sekwencje
32.3. Argumenty zasad
32.3.1. Z(cid:239)o(cid:285)ono(cid:258)(cid:202)
32.4. Algorytmy nie modyfikuj(cid:200)ce sekwencji
32.4.1. for_each()
32.4.2. Predykaty sekwencji
32.4.3. count()
32.4.4. find()
32.4.5. equal() i mismatch()
32.4.6. search()
32.5. Algorytmy modyfikuj(cid:200)ce sekwencje
32.5.1. copy()
32.5.2. unique()
32.5.3. remove() i replace()
32.5.4. rotate(), random_shuffle() oraz partition()
32.5.5. Permutacje
32.5.6. fill()
32.5.7. swap()
32.6. Sortowanie i wyszukiwanie
32.6.1. Wyszukiwanie binarne
32.6.2. merge()
32.6.3. Algorytmy dzia(cid:239)aj(cid:200)ce na zbiorach
32.6.4. Sterty
32.6.5. lexicographical_compare()
32.7. Element minimalny i maksymalny
32.8. Rady
17
901
904
904
906
907
908
908
909
910
910
911
915
917
929
929
931
931
932
935
935
935
936
938
939
940
940
940
940
941
942
942
943
944
945
946
947
948
948
949
950
952
954
954
955
956
957
958
Kup książkęPoleć książkę18
Spis tre(cid:258)ci
Rozdzia(cid:239) 33. Iteratory STL
33.1. Wprowadzenie
33.1.1. Model iteratorów
33.1.2. Kategorie iteratorów
33.1.3. Cechy iteratorów
33.1.4. Operacje iteratorów
33.2. Adaptacje iteratorów
33.2.1. Iterator odwrotny
33.2.2. Iteratory wstawiaj(cid:200)ce
33.2.3. Iteratory przenosz(cid:200)ce
33.3. Zakresowe funkcje dost(cid:218)powe
33.4. Obiekty funkcyjne
33.5. Adaptacje funkcji
33.5.1. bind()
33.5.2. mem_fn()
33.5.3. function
33.6. Rady
Rozdzia(cid:239) 34. Pami(cid:218)(cid:202) i zasoby
34.1. Wprowadzenie
34.2. „Prawie kontenery”
34.2.1. array
34.2.2. bitset
34.2.3. vector bool
34.2.4. Krotki
34.3. Wska(cid:283)niki do zarz(cid:200)dzania pami(cid:218)ci(cid:200)
34.3.1. unique_ptr
34.3.2. shared_ptr
34.3.3. weak_ptr
34.4. Alokatory
34.4.1. Alokator domy(cid:258)lny
34.4.2. Cechy alokatorów
34.4.3. Cechy wska(cid:283)ników
34.4.4. Alokatory zakresowe
34.5. Interfejs od(cid:258)miecacza
34.6. Pami(cid:218)(cid:202) niezainicjowana
34.6.1. Bufory tymczasowe
34.6.2. raw_storage_iterator
34.7. Rady
Rozdzia(cid:239) 35. Narz(cid:218)dzia pomocnicze
35.1. Wprowadzenie
35.2. Czas
35.2.1. duration
35.2.2. time_point
35.2.3. Zegary
35.2.4. Cechy czasu
35.3. Dzia(cid:239)ania arytmetyczne na liczbach wymiernych w czasie kompilacji
959
959
959
961
962
964
965
966
968
969
970
971
972
972
974
974
976
977
977
977
978
981
985
986
990
990
993
996
998
1000
1001
1002
1003
1004
1007
1007
1008
1009
1011
1011
1011
1012
1015
1017
1018
1019
Kup książkęPoleć książkęSpis tre(cid:258)ci
35.4. Funkcje typowe
35.4.1. Cechy typów
35.4.2. Generatory typów
35.5. Drobne narz(cid:218)dzia
35.5.1. move() i forward()
35.5.2. swap()
35.5.3. Operatory relacyjne
35.5.4. Porównywanie i mieszanie type_info
35.6. Rady
Rozdzia(cid:239) 36. (cid:146)a(cid:241)cuchy
36.1. Wprowadzenie
36.2. Klasyfikacja znaków
36.2.1. Funkcje klasyfikacji
36.2.2. Cechy znaków
36.3. (cid:146)a(cid:241)cuchy
36.3.1. Typ string a (cid:239)a(cid:241)cuchy w stylu C
36.3.2. Konstruktory
36.3.3. Operacje podstawowe
36.3.4. (cid:146)a(cid:241)cuchowe wej(cid:258)cie i wyj(cid:258)cie
36.3.5. Konwersje numeryczne
36.3.6. Operacje w stylu biblioteki STL
36.3.7. Rodzina funkcji find
36.3.8. Pod(cid:239)a(cid:241)cuchy
36.4. Rady
Rozdzia(cid:239) 37. Wyra(cid:285)enia regularne
37.1. Wyra(cid:285)enia regularne
37.1.1. Notacja wyra(cid:285)e(cid:241) regularnych
37.2. regex
37.2.1. Wyniki dopasowywania
37.2.2. Formatowanie
37.3. Funkcje wyra(cid:285)e(cid:241) regularnych
37.3.1. regex_match()
37.3.2. regex_search()
37.3.3. regex_replace()
37.4. Iteratory wyra(cid:285)e(cid:241) regularnych
37.4.1. regex_iterator
37.4.2. regex_token_iterator
37.5. regex_traits
37.6. Rady
Rozdzia(cid:239) 38. Strumienie wej(cid:258)cia i wyj(cid:258)cia
38.1. Wprowadzenie
38.2. Hierarchia strumieni wej(cid:258)cia i wyj(cid:258)cia
38.2.1. Strumienie plikowe
38.2.2. Strumienie (cid:239)a(cid:241)cuchowe
38.3. Obs(cid:239)uga b(cid:239)(cid:218)dów
19
1020
1020
1025
1030
1030
1031
1031
1032
1033
1035
1035
1035
1035
1036
1038
1039
1040
1042
1044
1044
1046
1048
1049
1050
1053
1053
1054
1059
1061
1063
1064
1064
1066
1067
1068
1068
1070
1072
1073
1075
1075
1077
1078
1079
1081
Kup książkęPoleć książkę20
Spis tre(cid:258)ci
38.4. Operacje wej(cid:258)cia i wyj(cid:258)cia
38.4.1. Operacje wej(cid:258)ciowe
38.4.2. Operacje wyj(cid:258)ciowe
38.4.3. Manipulatory
38.4.4. Stan strumienia
38.4.5. Formatowanie
38.5. Iteratory strumieniowe
38.6. Buforowanie
38.6.1. Strumienie wyj(cid:258)ciowe i bufory
38.6.2. Strumienie wej(cid:258)ciowe i bufory
38.6.3. Iteratory buforów
38.7. Rady
Rozdzia(cid:239) 39. Lokalizacje
39.1. Ró(cid:285)nice kulturowe
39.2. Klasa locale
39.2.1. Lokalizacje nazwane
39.2.2. Porównywanie (cid:239)a(cid:241)cuchów
39.3. Klasa facet
39.3.1. Dost(cid:218)p do faset w lokalizacji
39.3.2. Definiowanie prostej fasety
39.3.3. Zastosowania lokalizacji i faset
39.4. Standardowe fasety
39.4.1. Porównywanie (cid:239)a(cid:241)cuchów
39.4.2. Formatowanie liczb
39.4.3. Formatowanie kwot pieni(cid:218)(cid:285)nych
39.4.4. Formatowanie daty i godziny
39.4.5. Klasyfikacja znaków
39.4.6. Konwersja kodów znaków
39.4.7. Wiadomo(cid:258)ci
39.5. Interfejsy pomocnicze
39.5.1. Klasyfikacja znaków
39.5.2. Konwersje znaków
39.5.3. Konwersje (cid:239)a(cid:241)cuchów
39.5.4. Buforowanie konwersji
39.6. Rady
Rozdzia(cid:239) 40. Liczby
40.1. Wprowadzenie
40.2. Granice liczbowe
40.2.1. Makra ograniczaj(cid:200)ce
40.3. Standardowe funkcje matematyczne
40.4. Liczby zespolone
40.5. Tablica numeryczna valarray
40.5.1. Konstruktory i przypisania
40.5.2. Indeksowanie
40.5.3. Operacje
40.5.4. Wycinki
40.5.5. slice_array
40.5.6. Uogólnione wycinki
1082
1083
1086
1088
1089
1094
1101
1102
1105
1106
1107
1109
1111
1111
1114
1116
1120
1120
1121
1122
1125
1125
1127
1131
1136
1141
1144
1147
1151
1155
1155
1156
1156
1157
1158
1159
1159
1160
1162
1163
1164
1166
1166
1168
1169
1172
1174
1175
Kup książkęPoleć książkęSpis tre(cid:258)ci
40.6. Uogólnione algorytmy numeryczne
40.6.1. Algorytm accumulate()
40.6.2. Algorytm inner_product()
40.6.3. Algorytmy partial_sum() i adjacent_difference()
40.6.4. Algorytm iota()
40.7. Liczby losowe
40.7.1. Mechanizmy
40.7.2. Urz(cid:200)dzenie losowe
40.7.3. Rozk(cid:239)ady
40.7.4. Losowanie liczb w stylu C
40.8. Rady
Rozdzia(cid:239) 41. Wspó(cid:239)bie(cid:285)no(cid:258)(cid:202)
41.1. Wprowadzenie
41.2. Model pami(cid:218)ci
41.2.1. Lokalizacje pami(cid:218)ci
41.2.2. Zmienianie kolejno(cid:258)ci instrukcji
41.2.3. Porz(cid:200)dek pami(cid:218)ci
41.2.4. Wy(cid:258)cigi do danych
41.3. Konstrukcje atomowe
41.3.1. Typy atomowe
41.3.2. Flagi i bariery
41.4. S(cid:239)owo kluczowe volatile
41.5. Rady
Rozdzia(cid:239) 42. W(cid:200)tki i zadania
42.1. Wprowadzenie
42.2. W(cid:200)tki
42.2.1. To(cid:285)samo(cid:258)(cid:202)
42.2.2. Konstrukcja
42.2.3. Destrukcja
42.2.4. Funkcja join()
42.2.5. Funkcja detach()
42.2.6. Przestrze(cid:241) nazw this_thread
42.2.7. Likwidowanie w(cid:200)tku
42.2.8. Dane lokalne w(cid:200)tku
42.3. Unikanie wy(cid:258)cigów do danych
42.3.1. Muteksy
42.3.2. Wiele blokad
42.3.3. Funkcja call_once()
42.3.4. Zmienne warunkowe
42.4. Wspó(cid:239)bie(cid:285)no(cid:258)(cid:202) zadaniowa
42.4.1. Typy future i promise
42.4.2. Typ promise
42.4.3. Typ packaged_task
42.4.4. Typ future
42.4.5. Typ shared_future
42.4.6. Funkcja async()
42.4.7. Przyk(cid:239)ad równoleg(cid:239)ej funkcji find()
42.5. Rady
21
1176
1177
1177
1178
1179
1180
1182
1184
1185
1189
1189
1191
1191
1193
1194
1195
1196
1197
1198
1201
1205
1207
1207
1209
1209
1210
1211
1212
1213
1214
1215
1217
1218
1218
1220
1220
1228
1230
1231
1235
1236
1237
1238
1241
1244
1245
1247
1251
Kup książkęPoleć książkę22
Spis tre(cid:258)ci
Rozdzia(cid:239) 43. Biblioteka standardowa C
43.1. Wprowadzenie
43.2. Pliki
43.3. Rodzina printf()
43.4. (cid:146)a(cid:241)cuchy w stylu C
43.5. Pami(cid:218)(cid:202)
43.6. Data i godzina
43.7. Itd.
43.8. Rady
Rozdzia(cid:239) 44. Zgodno(cid:258)(cid:202)
44.1. Wprowadzenie
44.2. Rozszerzenia C++11
44.2.1. Narz(cid:218)dzia j(cid:218)zykowe
44.2.2. Sk(cid:239)adniki biblioteki standardowej
44.2.3. Elementy wycofywane
44.2.4. Praca ze starszymi implementacjami C++
44.3. Zgodno(cid:258)(cid:202) C i C++
44.3.1. C i C++ to rodze(cid:241)stwo
44.3.2. „Ciche” ró(cid:285)nice
44.3.3. Kod C nie b(cid:218)d(cid:200)cy kodem C++
44.3.4. Kod C++ nie b(cid:218)d(cid:200)cy kodem C
44.4. Rady
Skorowidz
1253
1253
1253
1254
1259
1260
1261
1264
1266
1267
1267
1268
1268
1269
1270
1271
1271
1271
1273
1274
1277
1279
1281
Kup książkęPoleć książkę10
Wyra(cid:285)enia
Programowanie jest jak seks:
mo(cid:285)e dawa(cid:202) konkretne wyniki,
ale nie po to si(cid:218) to robi
— przeprosiny dla Richarda Feynmana
(cid:120) Wprowadzenie
(cid:120) Kalkulator
Parser; Wej(cid:258)cie; Wej(cid:258)cie niskopoziomowe; Obs(cid:239)uga b(cid:239)(cid:218)dów; Sterownik; Nag(cid:239)ówki;
Argumenty wiersza polece(cid:241); Uwaga na temat stylu
(cid:120) Zestawienie operatorów
Wyniki; Kolejno(cid:258)(cid:202) wykonywania dzia(cid:239)a(cid:241); Kolejno(cid:258)(cid:202) wykonywania operatorów; Obiekty
tymczasowe
(cid:120) Wyra(cid:285)enia sta(cid:239)e
Sta(cid:239)e symboliczne; const w wyra(cid:285)eniach sta(cid:239)ych; Typy litera(cid:239)owe; Argumenty referen-
cyjne; Wyra(cid:285)enia sta(cid:239)e adresowe
(cid:120) Niejawna konwersja typów
Promocje; Konwersje; Typowe konwersje arytmetyczne
(cid:120) Rady
10.1. Wprowadzenie
W tym rozdziale znajduje si(cid:218) szczegó(cid:239)owy opis w(cid:239)a(cid:258)ciwo(cid:258)ci wyra(cid:285)e(cid:241). W j(cid:218)zyku C++ wyra(cid:285)e-
niem jest przypisanie, wywo(cid:239)anie funkcji, utworzenie obiektu, jak równie(cid:285) wiele innych ope-
racji wykraczaj(cid:200)cych daleko poza konwencjonalne obliczanie wyra(cid:285)e(cid:241) arytmetycznych. Aby
pokaza(cid:202), w jaki sposób u(cid:285)ywa si(cid:218) wyra(cid:285)e(cid:241), a tak(cid:285)e przedstawi(cid:202) je w odpowiednim kontek(cid:258)cie,
opisa(cid:239)em budow(cid:218) niewielkiego programu — prostego kalkulatora. Dalej przedstawi(cid:239)em ze-
stawienie operatorów oraz zwi(cid:218)(cid:283)le opisa(cid:239)em sposób ich dzia(cid:239)ania dla typów wbudowanych.
Operatory wymagaj(cid:200)ce bardziej szczegó(cid:239)owego omówienia s(cid:200) opisane w rozdziale 11.
10.2. Kalkulator
Wyobra(cid:283) sobie prosty kalkulator s(cid:239)u(cid:285)(cid:200)cy do wykonywania czterech podstawowych dzia(cid:239)a(cid:241)
arytmetycznych reprezentowanych przez operatory infiksowe dzia(cid:239)aj(cid:200)ce na liczbach zmien-
noprzecinkowych. Na przyk(cid:239)ad dla poni(cid:285)szych danych:
Kup książkęPoleć książkę274
r = 2.5
area = pi*r*r
Rozdzia(cid:239) 10 • Wyra(cid:285)enia
(warto(cid:258)(cid:202) pi jest zdefiniowana standardowo) program ten zwróci taki wynik:
2.5
19.635
2.5 to wynik dla pierwszej linijki danych wej(cid:258)ciowych, a 19.635 to wynik dla drugiej.
Cztery g(cid:239)ówne elementy budowy kalkulatora to: parser, funkcja przyjmowania danych, ta-
blica symboli oraz sterownik. W istocie jest to miniaturowy kompilator, w którym parser wy-
konuje analiz(cid:218) sk(cid:239)adniow(cid:200), funkcja wej(cid:258)ciowa pobiera dane i wykonuje analiz(cid:218) leksykaln(cid:200), ta-
blica symboli przechowuje informacje sta(cid:239)e, a sterownik obs(cid:239)uguje inicjacj(cid:218), wyj(cid:258)cie i b(cid:239)(cid:218)dy.
Kalkulator ten mo(cid:285)na by by(cid:239)o wzbogaci(cid:202) o wiele dodatkowych funkcji, ale jego kod i tak ju(cid:285)
jest d(cid:239)ugi, a takie dodatki w (cid:285)aden sposób nie przyczyni(cid:239)yby si(cid:218) do lepszego poznania sposobu
u(cid:285)ywania j(cid:218)zyka C++.
10.2.1. Parser
Poni(cid:285)ej znajduje si(cid:218) gramatyka j(cid:218)zyka rozpoznawanego przez parser:
program:
end // end oznacza koniec danych wej(cid:258)ciowych
expr_list end
expr_list:
expression print // print jest znakiem nowego wiersza lub (cid:258)rednikiem
expression print expr_list
expression:
expression + term
expression (cid:344) term
term
term:
term / primary
term*primary
primary
primar y:
number // number jest litera(cid:239)em zmiennoprzecinkowym
name // name jest identyfikatorem
name = expression
(cid:344) primar y
( expression )
Innymi s(cid:239)owy, program jest sekwencj(cid:200) wyra(cid:285)e(cid:241) oddzielonych (cid:258)rednikami. Podstawowymi jed-
nostkami wyra(cid:285)enia s(cid:200) liczby, nazwy i operatory *, /, +, - (zarówno jedno-, jak i dwuargumen-
towy) oraz = (przypisanie). Nazw nie trzeba deklarowa(cid:202) przed u(cid:285)yciem.
Rodzaj analizy, który stosuj(cid:218), nazywa si(cid:218) zst(cid:218)powaniem rekurencyjnym (ang. recursive
descent). Jest to popularna i prosta technika przetwarzania kodu od góry do do(cid:239)u. W j(cid:218)zykach
programowania takich jak C++, w których wywo(cid:239)ania funkcji s(cid:200) wzgl(cid:218)dnie ma(cid:239)o kosztowne,
metoda ta jest dodatkowo bardzo wydajna. Dla ka(cid:285)dej produkcji w gramatyce istnieje funkcja
wywo(cid:239)uj(cid:200)ca inne funkcje. Symbole terminalne (np. end, number, + i -) s(cid:200) rozpoznawane przez
Kup książkęPoleć książkę10.2. Kalkulator
275
analizator leksykalny, a symbole nieterminalne rozpoznaj(cid:200) funkcj(cid:218) analizy leksykalnej: expr(),
term() i prim(). Gdy oba argumenty wyra(cid:285)enia lub podwyra(cid:285)enia s(cid:200) znane, nast(cid:218)puje obliczenie
warto(cid:258)ci. W prawdziwym kompilatorze móg(cid:239)by to by(cid:202) moment wygenerowania kodu.
Do obs(cid:239)ugi danych wej(cid:258)ciowych wykorzystywana jest klasa Token_stream zawieraj(cid:200)ca ope-
racje wczytywania znaków oraz sk(cid:239)adania z nich tokenów. Innymi s(cid:239)owy, klasa Token_stream
zamienia strumienie znaków, takie jak 123.45, w tokeny (Token). Tokeny to pary {rodzaj-tokenu,
warto(cid:258)(cid:202)}, jak np. {number,123.45}, gdzie litera(cid:239) 123.45 jest zamieniony na warto(cid:258)(cid:202) zmiennoprze-
cinkow(cid:200). G(cid:239)ówne cz(cid:218)(cid:258)ci parsera musz(cid:200) tylko zna(cid:202) nazw(cid:218) strumienia tokenów (Token_stream),
ts, oraz móc pobra(cid:202) z niego tokeny. W celu wczytania kolejnego tokenu wywo(cid:239)ywana jest funkcja
ts.get(). Aby pobra(cid:202) ostatnio wczytany (bie(cid:285)(cid:200)cy) token, wywo(cid:239)ywana jest funkcja ts.current().
Dodatkow(cid:200) funkcj(cid:200) klasy Token_stream jest ukrywanie prawdziwego (cid:283)ród(cid:239)a znaków. Zoba-
czysz, (cid:285)e mog(cid:200) one pochodzi(cid:202) wprost od u(cid:285)ytkownika wpisuj(cid:200)cego je za pomoc(cid:200) klawiatury
do strumienia cin, z wiersza polece(cid:241) lub z jakiego(cid:258) innego strumienia wej(cid:258)ciowego (10.2.7).
Definicja tokenu jest nast(cid:218)puj(cid:200)ca:
enum class Kind : char {
name, number, end,
plus= + , minus= (cid:344) , mul= * , div= / , print= ; , assign= = , lp= ( , rp= )
};
struct Token {
Kind kind;
string string_value;
double number_value;
};
Reprezentowanie ka(cid:285)dego tokenu przez warto(cid:258)(cid:202) ca(cid:239)kowitoliczbow(cid:200) jego znaku jest wygod-
nym i wydajnym rozwi(cid:200)zaniem oraz mo(cid:285)e by(cid:202) pomocne dla programistów u(cid:285)ywaj(cid:200)cych de-
bugera. Metoda ta dzia(cid:239)a, pod warunkiem (cid:285)e (cid:285)aden znak pojawiaj(cid:200)cy si(cid:218) na wej(cid:258)ciu nie ma
warto(cid:258)ci u(cid:285)ytej jako enumerator — a (cid:285)aden znany mi zestaw znaków nie zawiera (cid:285)adnego
drukowalnego znaku w postaci jednocyfrowej liczby ca(cid:239)kowitej.
Interfejs klasy Token_stream wygl(cid:200)da tak:
class Token_stream {
public:
Token get(); // wczytuje i zwraca nast(cid:218)pny token
const Token current(); // ostatnio wczytany token
//...
};
Implementacja jest przedstawiona w sekcji 10.2.2.
Ka(cid:285)da funkcja parsera pobiera argument typu bool (6.2.2), o nazwie get, wskazuj(cid:200)cy, czy
konieczne jest wywo(cid:239)anie funkcji Token_stream::get() w celu pobrania nast(cid:218)pnego tokenu.
Ka(cid:285)da funkcja parsera oblicza warto(cid:258)(cid:202) „swojego” wyra(cid:285)enia i j(cid:200) zwraca. Funkcja expr() obs(cid:239)uguje
dodawanie i odejmowanie. Zawiera jedn(cid:200) p(cid:218)tl(cid:218) znajduj(cid:200)c(cid:200) wyrazy do dodania lub odj(cid:218)cia:
double expr(bool get) // dodaje i odejmuje
{
double left = term(get);
for (;;) { // wieczno(cid:258)(cid:202)
switch (ts.current().kind) {
case Kind::plus:
Kup książkęPoleć książkę276
Rozdzia(cid:239) 10 • Wyra(cid:285)enia
left += term(true);
break;
case Kind::minus:
left (cid:344)= term(true);
break;
default:
return left;
}
}
}
Funkcja ta sama niewiele robi. Jak typowa wysokopoziomowa funkcja w ka(cid:285)dym wi(cid:218)kszym
programie ogranicza si(cid:218) do wywo(cid:239)ywania innych funkcji.
Instrukcja switch (2.2.4, 9.4.2) porównuje swój warunek, który jest wpisany w nawiasie za
s(cid:239)owem kluczowym switch, ze zbiorem sta(cid:239)ych. Instrukcje break s(cid:239)u(cid:285)(cid:200) do wychodzenia z in-
strukcji switch. Je(cid:258)li porównywana warto(cid:258)(cid:202) nie pasuje do (cid:285)adnej z klauzul case, wybierana jest
klauzula default. Programista nie musi definiowa(cid:202) tej klauzuli.
Zwró(cid:202) uwag(cid:218), (cid:285)e wyra(cid:285)enia takie jak 2-3+4 s(cid:200) zgodnie z gramatyk(cid:200) obliczane jako (2-3)+4.
Ta dziwna instrukcja for(;;) to p(cid:218)tla niesko(cid:241)czona (9.5). Alternatywnie mo(cid:285)na te(cid:285) u(cid:285)ywa(cid:202)
p(cid:218)tli while(true) w tym samym celu. Wykonanie instrukcji switch jest powtarzane, dopóki
nie pojawi si(cid:218) co(cid:258) innego ni(cid:285) + lub -, w którym to przypadku nast(cid:218)puje przej(cid:258)cie do klauzuli
default i wykonanie instrukcji return.
Operatory += i -= s(cid:239)u(cid:285)(cid:200) do obs(cid:239)ugi dodawania i odejmowania. Zamiast nich mo(cid:285)na by by(cid:239)o
bez znaczenia dla dzia(cid:239)ania programu u(cid:285)y(cid:202) wyra(cid:285)e(cid:241) left=left+term(true) i left=left(cid:344)term(true).
Jednak wyra(cid:285)enia left+=term(true) i left(cid:344)=term(true) nie do(cid:258)(cid:202), (cid:285)e s(cid:200) krótsze, to na dodatek
bardziej bezpo(cid:258)rednio odzwierciedlaj(cid:200) zamiar programisty. Ka(cid:285)dy operator przypisania jest
osobnym tokenem leksykalnym, a wi(cid:218)c a + = 1; jest b(cid:239)(cid:218)dem sk(cid:239)adniowym z powodu spacji
mi(cid:218)dzy operatorami + i =.
W j(cid:218)zyku C++ dla operatorów binarnych dost(cid:218)pne s(cid:200) operatory przypisania:
+ (cid:344) * / | ˆ
Mo(cid:285)na wi(cid:218)c u(cid:285)ywa(cid:202) nast(cid:218)puj(cid:200)cych operatorów przypisania:
= += (cid:344)= *= /= = = |= ˆ= = =
Operator oznacza reszt(cid:218) z dzielenia. Operatory , | oraz ^ to bitowe operacje logiczne i, lub
oraz lub wykluczaj(cid:200)ce. Operatory i to operacje przesuni(cid:218)cia w lewo i prawo. Zestawienie
operatorów i opis ich dzia(cid:239)ania znajduje si(cid:218) w podrozdziale 10.3. Dla binarnego operatora @
zastosowanego do argumentów typu wbudowanego wyra(cid:285)enie x@=y oznacza x=x@y, z tym (cid:285)e
warto(cid:258)(cid:202) x jest obliczana tylko raz.
Funkcja term() obs(cid:239)uguje mno(cid:285)enie i dzielenie w taki sam sposób jak expr() dodawanie
i odejmowanie:
double term(bool get) // mno(cid:285)y i dzieli
{
double left = prim(get);
for (;;) {
switch (ts.current().kind) {
case Kind::mul:
left*= prim(true);
break;
Kup książkęPoleć książkę10.2. Kalkulator
277
case Kind::div:
if (auto d = prim(true)) {
left /= d;
break;
}
return error( Dzielenie przez 0 );
default:
return left;
}
}
}
Wynik dzielenia przez zero jest niezdefiniowany i najcz(cid:218)(cid:258)ciej operacja taka ma katastrofalne
skutki. Dlatego przed wykonaniem dzielenia sprawdzamy, czy dzielnik nie jest zerem, i w razie
potrzeby wywo(cid:239)ujemy funkcj(cid:218) error(). Jej opis znajduje si(cid:218) w sekcji 10.2.4.
Zmienna d zosta(cid:239)a wprowadzona do programu dok(cid:239)adnie w miejscu, w którym jest po-
trzebna, i od razu jest zainicjowana. Zakres dost(cid:218)pno(cid:258)ci nazwy wprowadzonej w warunku
obejmuje instrukcj(cid:218) kontrolowan(cid:200) przez ten warunek, a powsta(cid:239)a warto(cid:258)(cid:202) jest warto(cid:258)ci(cid:200) tego
warunku (9.4.3). W konsekwencji dzielenie i przypisanie left/=d s(cid:200) wykonywane tylko wtedy,
gdy d nie równa si(cid:218) zero.
Funkcja prim() obs(cid:239)uguj(cid:200)ca wyra(cid:285)enia pierwotne jest podobna do funkcji expr() i term(), ale
w odró(cid:285)nieniu od nich znajduje si(cid:218) na nieco ni(cid:285)szym poziomie hierarchii wywo(cid:239)a(cid:241) i wyko-
nuje troch(cid:218) realnej pracy oraz nie zawiera p(cid:218)tli:
double prim(bool get) // obs(cid:239)uguje wyra(cid:285)enia pierwotne
{
if (get) ts.get(); // wczytuje nast(cid:218)pny token
switch (ts.current().kind) {
case Kind::number: // sta(cid:239)a zmiennoprzecinkowa
{ double v = ts.current().number_value;
ts.g et();
return v;
}
case Kind::name:
{ double v = table[ts.current().string_value]; // znajduje odpowiednik
if (ts.get().kind == Kind::assign) v = expr(true); // znaleziono operator =: przypisanie
return v;
}
case Kind::minus: // jednoargumentowy minus
return (cid:344)prim(true);
case Kind::lp:
{ auto e = expr(true);
if (ts.current().kind != Kind::rp) return error( Oczekiwano ) );
ts.get(); // zjada )
return e;
}
default:
return error( Oczekiwano wyra(cid:285)enia pierwotnego );
}
}
Kup książkęPoleć książkę278
Rozdzia(cid:239) 10 • Wyra(cid:285)enia
Gdy zostanie znaleziony Token b(cid:218)d(cid:200)cy liczb(cid:200) (tzn. litera(cid:239)em ca(cid:239)kowitoliczbowym lub zmien-
noprzecinkowym), jego warto(cid:258)(cid:202) jest umieszczana w sk(cid:239)adowej number_value. Analogicznie,
gdy zostanie napotkany Token b(cid:218)d(cid:200)cy nazw(cid:200) (name) — jakakolwiek jest jej definicja; zobacz
10.2.2 i 10.2.3 — jego warto(cid:258)(cid:202) jest umieszczana w sk(cid:239)adowej string_value.
Zwró(cid:202) uwag(cid:218), (cid:285)e funkcja prim() zawsze wczytuje o jeden token wi(cid:218)cej, ni(cid:285) potrzebuje do
analizy swojego wyra(cid:285)enia pierwotnego. Powodem tego jest fakt, (cid:285)e musi to robi(cid:202) w niektó-
rych przypadkach (aby np. sprawdzi(cid:202), czy do nazwy jest co(cid:258) przypisywane), wi(cid:218)c dla zacho-
wania spójno(cid:258)ci robi to zawsze. W przypadkach, w których funkcja parsera ma tylko przej(cid:258)(cid:202)
do nast(cid:218)pnego tokenu, nie musi u(cid:285)ywa(cid:202) warto(cid:258)ci zwrotnej funkcji ts.get(). Nie ma problemu,
bo wynik mo(cid:285)na pobra(cid:202) z ts.current(). Gdyby przeszkadza(cid:239)o mi ignorowanie warto(cid:258)ci zwrot-
nej funkcji get(), to albo doda(cid:239)bym funkcj(cid:218) read(), która tylko by aktualizowa(cid:239)a current()
bez zwracania warto(cid:258)ci, albo jawnie „wyrzuca(cid:239)bym” wynik: void(ts.get()).
Zanim kalkulator w jakikolwiek sposób u(cid:285)yje nazwy, najpierw musi sprawdzi(cid:202), czy jest co(cid:258)
do niej przypisywane, czy te(cid:285) jest ona tylko odczytywana. W obu przypadkach trzeba si(cid:218)gn(cid:200)(cid:202)
do tablicy symboli. Tablica ta jest map(cid:200) (4.4.3, 31.4.3):
map string,double table;
To znaczy, (cid:285)e mapa table jest indeksowana typem string, dla którego zwracane s(cid:200) warto(cid:258)ci
typu double. Je(cid:258)li na przyk(cid:239)ad u(cid:285)ytkownik wpisze:
radius = 6378.388;
kalkulator dojdzie do klauzuli case Kind::name i wykona:
double v = table[ radius ];
// ... expr() oblicza warto(cid:258)(cid:202) do przypisania...
v = 6378.388;
Referencja v jest u(cid:285)yta jako uchwyt do warto(cid:258)ci double zwi(cid:200)zanej z radius, podczas gdy funk-
cja expr() oblicza warto(cid:258)(cid:202) 6378.388 ze znaków wej(cid:258)ciowych.
W rozdzia(cid:239)ach 14. i 15. znajduj(cid:200) si(cid:218) wskazówki na temat organizacji programu jako zbioru
modu(cid:239)ów. Ale w tym kalkulatorze deklaracje mo(cid:285)na uporz(cid:200)dkowa(cid:202) tak, (cid:285)e (z jednym wyj(cid:200)t-
kiem) ka(cid:285)da wyst(cid:200)pi tylko raz, przed samym jej u(cid:285)yciem. Wyj(cid:200)tkiem jest funkcja expr(), która
wywo(cid:239)uje funkcj(cid:218) term(), która wywo(cid:239)uje funkcj(cid:218) prim(), która z kolei wywo(cid:239)uje funkcj(cid:218) expr().
Ten kr(cid:200)g wywo(cid:239)a(cid:241) trzeba jako(cid:258) rozerwa(cid:202). Mo(cid:285)na na przyk(cid:239)ad umie(cid:258)ci(cid:202) deklaracj(cid:218):
double expr(bool);
przed definicj(cid:200) funkcji prim().
10.2.2. Wej(cid:258)cie
Mechanizm wczytywania danych wej(cid:258)ciowych to cz(cid:218)sto najbardziej skomplikowana cz(cid:218)(cid:258)(cid:202) pro-
gramu, bo trzeba wzi(cid:200)(cid:202) pod uwag(cid:218) humory, przyzwyczajenia i rozmaite b(cid:239)(cid:218)dy pope(cid:239)niane przez
ludzi. Próby zmuszenia u(cid:285)ytkownika do zachowywania si(cid:218) w sposób bardziej odpowiadaj(cid:200)cy
maszynie s(cid:200) zwykle (s(cid:239)usznie) uwa(cid:285)ane za niegrzeczne. Zadaniem niskopoziomowej proce-
dury wej(cid:258)ciowej jest wczytanie znaków i z(cid:239)o(cid:285)enie z nich tokenów, którymi nast(cid:218)pnie pos(cid:239)u-
guj(cid:200) si(cid:218) procedury dzia(cid:239)aj(cid:200)ce na wy(cid:285)szym poziomie. W opisywanym programie niskopozio-
mowa procedura obs(cid:239)ugi wej(cid:258)cia nazywa si(cid:218) td.get(). Pisanie takich funkcji nie jest cz(cid:218)stym
zadaniem, bo wiele systemów zawiera standardowe funkcje tego rodzaju.
Najpierw jednak musimy zobaczy(cid:202) kompletny kod klasy Token_stream:
Kup książkęPoleć książkę10.2. Kalkulator
279
class Token_stream {
public:
Token_stream(istream s) : ip{ s}, owns{false} { }
Token_stream(istream*p) : ip{p}, owns{true} { }
˜Token_stream() { close(); }
Token get(); // wczytuje token i go zwraca
Token current(); // ostatnio wczytany token
void set_input(istream s) { close(); ip = s; owns=false; }
void set_input(istream*p) { close(); ip = p; owns = true; }
private:
void close() { if (owns) delete ip; }
istream*ip; // wska(cid:283)nik do strumienia wej(cid:258)ciowego
bool owns; // czy Token_stream jest w(cid:239)a(cid:258)cicielem strumienia istream?
Token ct {Kind::end} ; // bie(cid:285)(cid:200)cy token
};
Obiekt klasy Token_stream inicjujemy strumieniem wej(cid:258)ciowym (4.3.2, rozdzia(cid:239) 38.), z którego
pobierane s(cid:200) znaki. Klasa Token_stream jest zaimplementowana w taki sposób, (cid:285)e staje si(cid:218) w(cid:239)a(cid:258)ci-
cielem (i ostatecznie te(cid:285) niszczycielem — 3.2.1.2, 11.2) strumienia istream przekazanego jako
wska(cid:283)nik, ale nie strumienia istream przekazanego jako referencja. W tak prostym programie
mo(cid:285)e nie trzeba stosowa(cid:202) a(cid:285) tak wyszukanego rozwi(cid:200)zania, ale jest to bardzo przydatna i ogól-
na technika wykorzystywana do budowy klas przechowuj(cid:200)cych wska(cid:283)niki do zasobów, które
kiedy(cid:258) trzeba usun(cid:200)(cid:202).
Klasa Token_stream zawiera trzy warto(cid:258)ci: wska(cid:283)nik do swojego strumienia wej(cid:258)ciowego (ip),
warto(cid:258)(cid:202) logiczn(cid:200) (owns) okre(cid:258)laj(cid:200)c(cid:200) w(cid:239)asno(cid:258)(cid:202) strumienia wej(cid:258)ciowego oraz bie(cid:285)(cid:200)cy token (ct).
Zmiennej cp nada(cid:239)em warto(cid:258)(cid:202) domy(cid:258)ln(cid:200), bo wydawa(cid:239)o mi si(cid:218), (cid:285)e niezrobienie tego by(cid:239)oby
nie w porz(cid:200)dku. Wprawdzie nie powinno si(cid:218) wywo(cid:239)ywa(cid:202) funkcji current() przed get(), ale je(cid:258)li
kto(cid:258) to zrobi, to otrzyma poprawny token. Jako warto(cid:258)(cid:202) pocz(cid:200)tkow(cid:200) ct wybra(cid:239)em Kind::end,
aby w przypadku niew(cid:239)a(cid:258)ciwego u(cid:285)ycia funkcji current() program nie otrzyma(cid:239) (cid:285)adnej war-
to(cid:258)ci, która nie pojawi(cid:239)a si(cid:218) w strumieniu wej(cid:258)ciowym.
Funkcj(cid:218) Token_stream::get() przedstawi(cid:218) w dwóch ods(cid:239)onach. Najpierw poka(cid:285)(cid:218) z(cid:239)udnie
prost(cid:200) wersj(cid:218), która b(cid:218)dzie mniej przyjazna dla u(cid:285)ytkownika. A nast(cid:218)pnie zmodyfikuj(cid:218) j(cid:200) do
mniej eleganckiej, ale za to o wiele (cid:239)atwiejszej w u(cid:285)yciu postaci. Ogólnie zadaniem funkcji
get() jest wczytanie znaku, zdecydowanie, do jakiego rodzaju tokenu nale(cid:285)y go u(cid:285)y(cid:202), oraz
w razie potrzeby wczytanie wi(cid:218)kszej ilo(cid:258)ci znaków i zwrócenie tokenu reprezentuj(cid:200)cego te
wczytane znaki.
Pocz(cid:200)tkowe instrukcje wczytuj(cid:200) pierwszy niebia(cid:239)y znak z *ip (strumienia wej(cid:258)ciowego
wskazywanego przez ip) do ch i sprawdzaj(cid:200), czy operacja odczytu si(cid:218) powiod(cid:239)a:
Token Token_stream::get()
{
char ch = 0;
*ip ch;
switch (ch) {
case 0:
return ct={Kind::end}; // przypisanie i zwrot
Kup książkęPoleć książkę280
Rozdzia(cid:239) 10 • Wyra(cid:285)enia
Domy(cid:258)lnie operator pomija bia(cid:239)e znaki (spacje, tabulatory, znaki nowego wiersza itd.) i po-
zostawia warto(cid:258)(cid:202) ch niezmienion(cid:200), je(cid:258)li operacja przyjmowania danych si(cid:218) nie powiedzie.
W konsekwencji ch==0 oznacza koniec wprowadzania danych.
Przypisanie jest operatorem, a jego wynik jest warto(cid:258)ci(cid:200) zmiennej, której dotyczy to przy-
pisanie. Dzi(cid:218)ki temu mog(cid:218) przypisa(cid:202) warto(cid:258)(cid:202) Kind::end do curr_tok i zwróci(cid:202) j(cid:200) w tej samej
instrukcji. Jedna instrukcja zamiast dwóch u(cid:239)atwia konserwacj(cid:218) kodu. Gdybym rozdzieli(cid:239) przy-
pisanie i zwrot, to inny programista móg(cid:239)by zmieni(cid:202) co(cid:258) w jednej cz(cid:218)(cid:258)ci i zapomnie(cid:202) odpo-
wiednio dostosowa(cid:202) drug(cid:200).
Zwró(cid:202) te(cid:285) uwag(cid:218) na sposób u(cid:285)ycia notacji listowej {} (3.2.1.3, 11.3) po prawej stronie
przypisania. Jest to wyra(cid:285)enie. Powy(cid:285)sz(cid:200) instrukcj(cid:218) return mo(cid:285)na by by(cid:239)o napisa(cid:202) równie(cid:285) tak:
ct.kind = Kind::end; // przypisanie
return ct; // zwrot
Uwa(cid:285)am jednak, (cid:285)e przypisanie kompletnego obiektu {Kind::end} jest bardziej zrozumia(cid:239)e
ni(cid:285) pos(cid:239)ugiwanie si(cid:218) poszczególnymi sk(cid:239)adowymi ct. Zapis {Kind::end} jest równowa(cid:285)ny
z {Kind::end,0,0}. To dobrze, je(cid:258)li interesuj(cid:200) nas dwie ostatnie sk(cid:239)adowe tokenu, i (cid:283)le, je(cid:258)li
zale(cid:285)y nam na wydajno(cid:258)ci. Nas w tym przypadku nie dotyczy ani pierwsze, ani drugie, ale
ogólnie rzecz bior(cid:200)c, pos(cid:239)ugiwanie si(cid:218) kompletnymi obiektami stwarza mniej okazji do po-
pe(cid:239)nienia b(cid:239)(cid:218)du ni(cid:285) grzebanie przy poszczególnych sk(cid:239)adowych. Poni(cid:285)ej przedstawiona jest
implementacja tej drugiej strategii.
Najpierw przeanalizuj kilka z poni(cid:285)szych klauzul case osobno, a dopiero potem zastanów si(cid:218)
nad dzia(cid:239)aniem ca(cid:239)ej funkcji. Znak oznaczaj(cid:200)cy koniec wyra(cid:285)enia (;), nawiasy oraz operatory
s(cid:200) obs(cid:239)ugiwane poprzez zwyk(cid:239)e zwracanie ich warto(cid:258)ci:
case ; : // koniec wyra(cid:285)enia; drukowanie
case * :
case / :
case + :
case (cid:344) :
case ( :
case ) :
case = :
return ct={static_cast Kind (ch)};
Operacja static_cast (11.5.2) jest w tym przypadku niezb(cid:218)dna, poniewa(cid:285) nie istnieje niejaw-
na konwersja typu char na Kind (8.4.1). Tylko niektóre znaki odpowiadaj(cid:200) warto(cid:258)ciom Kind,
wi(cid:218)c musimy zagwarantowa(cid:202) to dla ch.
Liczby s(cid:200) obs(cid:239)ugiwane w nast(cid:218)puj(cid:200)cy sposób:
case 0 : case 1 : case 2 : case 3 : case 4 : case 5 : case 6 : case 7 :
(cid:180)case 8 : case 9 : case . :
ip(cid:344) putback(ch); // wstawia pierwsz(cid:200) cyfr(cid:218) (albo .) z powrotem do strumienia wej(cid:258)ciowego
*ip ct.number_value; // wczytuje liczb(cid:218) do ct
ct.kind=Kind::number;
return ct;
Wypisanie wszystkich klauzul case w jednej linii zamiast ka(cid:285)dej w osobnym wierszu nie jest
dobrym pomys(cid:239)em, bo taki kod jest mniej czytelny. Z drugiej strony, wpisywanie ka(cid:285)dej cyfry
w osobnej linijce jest (cid:285)mudne. Dzi(cid:218)ki temu, (cid:285)e operator ju(cid:285) obs(cid:239)uguje wczytywanie liczb
zmiennoprzecinkowych do zmiennych typu double, ten kod jest bardzo prosty. Najpierw
pierwszy znak (cyfra lub kropka) jest umieszczany w cin. Nast(cid:218)pnie warto(cid:258)(cid:202) zmiennoprze-
cinkowa mo(cid:285)e zosta(cid:202) wczytana do ct.number_value.
Kup książkęPoleć książkę10.2. Kalkulator
281
Je(cid:258)li token nie jest ko(cid:241)cem danych wej(cid:258)ciowych ani operatorem, znakiem interpunkcyjnym
czy te(cid:285) liczb(cid:200), to musi by(cid:202) nazw(cid:200). Nazwy s(cid:200) obs(cid:239)ugiwane podobnie do liczb:
default: // name, name = lub b(cid:239)(cid:200)d
if (isalpha(ch)) {
ip(cid:344) putback(ch); // umieszcza pierwszy znak z powrotem w strumieniu wej(cid:258)ciowym
*ip ct.string_value; // wczytuje (cid:239)a(cid:241)cuch do ct
ct.kind=Kind::name;
return ct;
}
W ko(cid:241)cu mo(cid:285)e te(cid:285) wyst(cid:200)pi(cid:202) b(cid:239)(cid:200)d. Proste a zarazem ca(cid:239)kiem efektywne rozwi(cid:200)zanie na pora-
dzenie sobie z b(cid:239)(cid:218)dami to napisanie funkcji error() i zwrócenie tokenu print w warto(cid:258)ci
zwrotnej tej funkcji:
error( Niepoprawny token );
return ct={Kind::print};
Funkcja isalpha() z biblioteki standardowej (36.2.1) zosta(cid:239)a u(cid:285)yta po to, aby unikn(cid:200)(cid:202) ko-
nieczno(cid:258)ci wymieniania ka(cid:285)dego znaku w osobnej klauzuli case. Je(cid:258)li operator zostanie za-
stosowany do (cid:239)a(cid:241)cucha (w tym przypadku string_value), wczytuje znaki do momentu napo-
tkania bia(cid:239)ego znaku. W zwi(cid:200)zku z tym u(cid:285)ytkownik musi po nazwie wpisa(cid:202) bia(cid:239)y znak przed
operatorem u(cid:285)ywaj(cid:200)cym tej nazwy jako argumentu. Jest to bardzo s(cid:239)abe rozwi(cid:200)zanie i b(cid:218)dziemy
musieli jeszcze do tego wróci(cid:202) w sekcji 10.2.3.
Poni(cid:285)ej znajduje si(cid:218) uko(cid:241)czona funkcja wej(cid:258)ciowa:
Token Token_stream::g et()
{
char ch = 0;
*ip ch;
switch (ch) {
case 0:
return ct={Kind::end}; // przypisanie i zwrot
case ; : // koniec wyra(cid:285)enia; drukuje
case * :
case / :
case + :
case (cid:344) :
case ( :
case ) :
case = :
return ct=={static_cast Kind (ch)};
case 0 : case 1 : case 2 : case 3 : case 4 : case 5 : case 6 : case 7 :
(cid:180)case 8 : case 9 : case . :
ip(cid:344) putback(ch); // wstawia pierwsz(cid:200) cyfr(cid:218) (albo .) z powrotem do strumienia wej(cid:258)ciowego
*ip ct.number_value; // wczytuje liczb(cid:218) do ct
ct.kind=Kind::number;
return ct;
default: // name, name = lub b(cid:239)(cid:200)d
if (isalpha(ch)) {
ip(cid:344) putback(ch); // umieszcza pierwszy znak z powrotem w strumieniu wej(cid:258)ciowym
*ip ct.string_value; // wczytuje (cid:239)a(cid:241)cuch do ct
ct.kind=Kind::name;
Kup książkęPoleć książkę282
Rozdzia(cid:239) 10 • Wyra(cid:285)enia
return ct;
}
error( Niepoprawny token );
return ct={Kind::print};
}
}
Konwersja operatora na token jest bardzo prosta, bo rodzaje operatorów zosta(cid:239)y zdefiniowane
jako warto(cid:258)ci ca(cid:239)kowitoliczbowe (10.2.1).
10.2.3. Wej(cid:258)cie niskopoziomowe
W kalkulatorze w obecnej postaci mo(cid:285)na znale(cid:283)(cid:202) kilka niedogodno(cid:258)ci. Trzeba pami(cid:218)ta(cid:202) o do-
dawaniu (cid:258)rednika na ko(cid:241)cu wyra(cid:285)e(cid:241), aby otrzyma(cid:202) wynik, oraz po nazwie zawsze trzeba
wpisa(cid:202) bia(cid:239)y znak, co równie(cid:285) jest uci(cid:200)(cid:285)liwe. Na przyk(cid:239)ad x+7 jest tylko identyfikatorem, a nie
identyfikatorem x, operatorem = i liczb(cid:200) 7. Aby ten zapis zosta(cid:239) zinterpretowany tak, jak by-
(cid:258)my tego normalnie chcieli, trzeba by by(cid:239)o doda(cid:202) bia(cid:239)y znak za x: x =7. Oba problemy mo(cid:285)na
rozwi(cid:200)za(cid:202) poprzez zamian(cid:218) zorientowanych na typy domy(cid:258)lnych operacji w funkcji get() na
kod wczytuj(cid:200)cy pojedyncze znaki.
Najpierw zrównamy znaczenie znaku nowego wiersza ze (cid:258)rednikiem oznaczaj(cid:200)cym koniec
wyra(cid:285)enia:
Token Token_stream::get()
{
char ch;
do { // pomija bia(cid:239)e znaki oprócz
if (!ip(cid:344) get(ch)) return ct={Kind::end};
} while (ch!=
isspace(ch));
switch (ch) {
case ; :
case
:
return ct={Kind::print};
W kodzie tym u(cid:285)y(cid:239)em instrukcji do, która ró(cid:285)ni si(cid:218) od p(cid:218)tli while tylko tym, (cid:285)e kontrolowane
przez ni(cid:200) instrukcje s(cid:200) wykonywane przynajmniej raz. Wywo(cid:239)anie ip- get(ch) wczytuje jeden
znak ze strumienia wej(cid:258)ciowego *ip do ch.
Pobierz darmowy fragment (pdf)