SlideShare a Scribd company logo
IDZ DO
         PRZYK£ADOWY ROZDZIA£

                           SPIS TRE CI   C++. Algorytmy
                                         i struktury danych
           KATALOG KSI¥¯EK
                                         Autor: Adam Drozdek
                      KATALOG ONLINE     T³umaczenie: Piotr Rajca, Tomasz ¯mijewski
                                         ISBN: 83-7361-385-4
       ZAMÓW DRUKOWANY KATALOG           Tytu³ orygina³u: Data Structures and Algorithms
                                         in C++, Second Edition
                                         Format: B5, stron: 616
              TWÓJ KOSZYK
                    DODAJ DO KOSZYKA     Badanie struktur danych, elementarnych sk³adników wykorzystywanych w informatyce,
                                         jest podstaw¹, w oparciu o któr¹ mo¿esz zdobywaæ cenne umiejêtno ci. Znajomo æ
                                         struktur danych jest niezbêdna studentom, którzy chc¹ programowaæ czy te¿ testowaæ
         CENNIK I INFORMACJE             oprogramowanie.
                                         W niniejszej ksi¹¿ce zwrócono uwagê na trzy wa¿ne aspekty struktur danych: po
                   ZAMÓW INFORMACJE      pierwsze, na zwi¹zek struktur danych z algorytmami, miêdzy innymi na z³o¿ono æ
                     O NOWO CIACH        obliczeniow¹ algorytmów. Po drugie, struktury te prezentowane s¹ w sposób zgodny
                                         z zasadami projektowania obiektowego i obiektowym paradygmatem programowania.
                       ZAMÓW CENNIK      Po trzecie, wa¿n¹ czê ci¹ ksi¹¿ki s¹ implementacje struktur danych w jêzyku C++.
                                         Ksi¹¿ka prezentuje:

                 CZYTELNIA                  • Podstawy projektowania obiektowego w C++
                                            • Analizê z³o¿ono ci
          FRAGMENTY KSI¥¯EK ONLINE          • Listy powi¹zane
                                            • Stosy i kolejki
                                            • Rekurencjê
                                            • Drzewa binarne
                                            • Sterty
                                            • Drzewa wielokrotne
                                            • Grafy
                                            • Sortowanie i mieszanie
                                            • Kompresja danych
                                            • Zarz¹dzanie pamiêci¹
                                         Ksi¹¿ka ta dostarcza studentom informatyki nie tylko niezbêdnej wiedzy na temat
                                         algorytmów i struktur danych, ale prezentuje jednocze nie sposoby ich implementacji
Wydawnictwo Helion                       w jêzyku C++, obecnie jednym z wiod¹cych jêzyków programowania. Dostarcza ona
ul. Chopina 6
                                         wiêc nie tylko wiedzy teoretycznej, ale równie¿ pozwala rozwin¹æ praktyczne
44-100 Gliwice
                                         umiejêtno ci przydatnych w przysz³ej pracy zawodowej.
tel. (32)230-98-63
e-mail: helion@helion.pl
Spis treści




Wstęp .....................................................................................................................11

1.
Programowanie obiektowe w C++ ........................................................................15
 1.1.   Abstrakcyjne typy danych ....................................................................................................................... 15
 1.2.   Enkapsulacja ............................................................................................................................................ 15
 1.3.   Dziedziczenie........................................................................................................................................... 19
 1.4.   Wskaźniki ................................................................................................................................................ 22
         1.4.1. Wskaźniki a tablice ...................................................................................................................... 24
         1.4.2. Wskaźniki a konstruktory kopiujące............................................................................................ 26
         1.4.3. Wskaźniki i destruktory ............................................................................................................... 29
         1.4.4. Wskaźniki a referencje................................................................................................................. 29
         1.4.5. Wskaźniki na funkcje................................................................................................................... 32
 1.5.   Polimorfizm ............................................................................................................................................. 33
 1.6.   C++ a programowanie obiektowe............................................................................................................ 35
 1.7.   Standardowa biblioteka szablonów ......................................................................................................... 36
         1.7.1. Kontenery..................................................................................................................................... 36
         1.7.2. Iteratory........................................................................................................................................ 37
         1.7.3. Algorytmy .................................................................................................................................... 37
         1.7.4. Funktory....................................................................................................................................... 38
 1.8.   Wektory w standardowej bibliotece szablonów ...................................................................................... 40
 1.9.   Struktury danych a programowanie obiektowe ....................................................................................... 46
1.10.   Przykład zastosowania: plik z dostępem swobodnym............................................................................. 47
1.11.   Ćwiczenia ................................................................................................................................................ 56
1.12.   Zadania programistyczne......................................................................................................................... 58
        Bibliografia ............................................................................................................................................. 60


2.
Analiza zło oności .................................................................................................61
 2.1. Zło oność obliczeniowa i asymptotyczna ............................................................................................... 61
 2.2. O-notacja.................................................................................................................................................. 62
 2.3. Właściwości O-notacji............................................................................................................................. 64
6                                                                                                                                                       SPIS TREŚCI



 2.4.   Notacje Ω i Θ........................................................................................................................................... 66
 2.5.   Mo liwe problemy................................................................................................................................... 67
 2.6.   Przykłady zło oności ............................................................................................................................... 67
 2.7.   Określanie zło oności asymptotycznej. Przykłady.................................................................................. 68
 2.8.   Zło oność optymistyczna, średnia i pesymistyczna ................................................................................ 71
 2.9.   Zło oność zamortyzowana ...................................................................................................................... 73
2.10.   Ćwiczenia ................................................................................................................................................ 77
        Bibliografia ............................................................................................................................................. 80


3.
Listy .......................................................................................................................81
 3.1. Listy jednokierunkowe ............................................................................................................................ 81
       3.1.1. Wstawianie................................................................................................................................... 86
       3.1.2. Usuwanie ..................................................................................................................................... 88
       3.1.3. Wyszukiwanie.............................................................................................................................. 93
 3.2. Listy dwukierunkowe .............................................................................................................................. 93
 3.3. Listy cykliczne......................................................................................................................................... 97
 3.4. Listy z przeskokami ................................................................................................................................. 99
 3.5. Listy samoorganizujące się.................................................................................................................... 104
 3.6. Tablice rzadkie....................................................................................................................................... 107
 3.7. Listy w bibliotece STL .......................................................................................................................... 110
 3.8. Kolejki dwustronne w bibliotece STL ................................................................................................... 113
 3.9. Podsumowanie ....................................................................................................................................... 117
3.10. Przykład zastosowania. Biblioteka ........................................................................................................ 118
3.11. Ćwiczenia .............................................................................................................................................. 126
3.12. Zadania programistyczne....................................................................................................................... 128
      Bibliografia ........................................................................................................................................... 131


4.
Stosy i kolejki ......................................................................................................133
 4.1.   Stosy ...................................................................................................................................................... 133
 4.2.   Kolejki ................................................................................................................................................... 140
 4.3.   Kolejki priorytetowe .............................................................................................................................. 147
 4.4.   Stosy w bibliotece STL.......................................................................................................................... 148
 4.5.   Kolejki w bibliotece STL....................................................................................................................... 148
 4.6.   Kolejki priorytetowe w bibliotece STL ................................................................................................. 149
 4.7.   Przykład zastosowania. Szukanie wyjścia z labiryntu........................................................................... 152
 4.8.   Ćwiczenia .............................................................................................................................................. 156
 4.9.   Zadania programistyczne....................................................................................................................... 159
        Bibliografia ........................................................................................................................................... 160


5.
Rekurencja ...........................................................................................................161
 5.1.   Definicje rekurencyjne........................................................................................................................... 161
 5.2.   Wywołania funkcji a implementacja rekurencji .................................................................................... 164
 5.3.   Anatomia wywołania rekurencyjnego ................................................................................................... 165
 5.4.   Rekurencja ogonowa ............................................................................................................................. 169
 5.5.   Rekurencja inna ni ogonowa................................................................................................................ 170
SPIS TREŚCI                                                                                                                                                          7

 5.6.   Rekurencja pośrednia............................................................................................................................. 174
 5.7.   Rekurencja zagnie d ona ...................................................................................................................... 176
 5.8.   Nadu ywanie rekurencji ........................................................................................................................ 177
 5.9.   Algorytmy z powrotami......................................................................................................................... 180
5.10.   Wnioski końcowe .................................................................................................................................. 186
5.11.   Przykład zastosowania. Rekurencyjny interpreter................................................................................. 187
5.12.   Ćwiczenia .............................................................................................................................................. 194
5.13.   Zadania programistyczne....................................................................................................................... 197
        Bibliografia ........................................................................................................................................... 199


6.
Drzewa binarne ....................................................................................................201
 6.1.   Drzewa, drzewa binarne i binarne drzewa poszukiwania...................................................................... 201
 6.2.   Implementacja drzew binarnych............................................................................................................ 205
 6.3.   Wyszukiwanie w drzewie binarnym...................................................................................................... 207
 6.4.   Przechodzenie po drzewie ..................................................................................................................... 210
         6.4.1. Przechodzenie wszerz ................................................................................................................ 210
         6.4.2. Przechodzenie w głąb ................................................................................................................ 211
         6.4.3. Przechodzenie po drzewie w głąb bez stosu .............................................................................. 217
 6.5.   Wstawianie ............................................................................................................................................ 223
 6.6.   Usuwanie ............................................................................................................................................... 225
         6.6.1. Usuwanie przez złączanie .......................................................................................................... 226
         6.6.2. Usuwanie przez kopiowanie ...................................................................................................... 229
 6.7.   Równowa enie drzewa .......................................................................................................................... 231
         6.7.1. Algorytm DSW .......................................................................................................................... 234
         6.7.2. Drzewa AVL.............................................................................................................................. 236
 6.8.   Drzewa samoorganizujące się................................................................................................................ 241
         6.8.1. Drzewa samonaprawiające się ................................................................................................... 241
         6.8.2. Ukosowanie ............................................................................................................................... 243
 6.9.   Sterty...................................................................................................................................................... 247
         6.9.1. Sterty jako kolejki priorytetowe................................................................................................. 249
         6.9.2. Organizowanie tablic w sterty ................................................................................................... 251
6.10.   Notacja polska i drzewa wyra eń .......................................................................................................... 255
        6.10.1. Operacje na drzewach wyra eń ................................................................................................. 256
6.11.   Przykład zastosowania. Zliczanie częstości występowania słów .......................................................... 259
6.12.   Ćwiczenia .............................................................................................................................................. 265
6.13.   Zadania programistyczne....................................................................................................................... 268
        Bibliografia ........................................................................................................................................... 272


7.
Drzewa wielokierunkowe ....................................................................................275
 7.1. Rodzina B-drzew ................................................................................................................................... 276
       7.1.1. B-drzewa .................................................................................................................................... 277
       7.1.2. B*-drzewa .................................................................................................................................. 286
       7.1.3. B+-drzewa.................................................................................................................................. 288
       7.1.4. B+-drzewa przedrostkowe ......................................................................................................... 289
       7.1.5. Drzewa bitowe ........................................................................................................................... 291
       7.1.6. R-drzewa .................................................................................................................................... 294
       7.1.7. 2-4-drzewa ................................................................................................................................. 296
       7.1.8. Zbiory i wielozbiory w bibliotece STL...................................................................................... 303
       7.1.9. Mapy i multimapy w bibliotece STL ......................................................................................... 309
8                                                                                                                                                       SPIS TREŚCI



 7.2.    Drzewa słownikowe............................................................................................................................... 313
 7.3.    Uwagi końcowe ..................................................................................................................................... 321
 7.4.    Przykład zastosowania. Sprawdzanie pisowni ...................................................................................... 321
 7.5.    Ćwiczenia .............................................................................................................................................. 330
 7.6.    Zadania programistyczne....................................................................................................................... 331
         Bibliografia ........................................................................................................................................... 334


8.
Grafy ....................................................................................................................337
 8.1. Reprezentacje grafów ............................................................................................................................. 338
 8.2. Przechodzenie po grafach....................................................................................................................... 340
 8.3. Najkrótsza droga .................................................................................................................................... 344
       8.3.1. Problem najkrótszych dróg typu „wszystkie-do-wszystkich” ................................................... 351
 8.4. Wykrywanie cykli .................................................................................................................................. 353
       8.4.1. Problem znajdowania sumy zbiorów rozłącznych..................................................................... 354
 8.5. Drzewa rozpinające ................................................................................................................................ 356
       8.5.1. Algorytm Borůvki...................................................................................................................... 357
       8.5.2. Algorytm Kruskala .................................................................................................................... 358
       8.5.3. Algorytm Jarníka-Prima ............................................................................................................ 360
       8.5.4. Metoda Dijkstry ......................................................................................................................... 361
 8.6. Spójność ................................................................................................................................................. 361
       8.6.1. Spójność w grafach nieskierowanych........................................................................................ 361
       8.6.2. Spójność w grafach skierowanych............................................................................................. 364
 8.7. Sortowanie topologiczne ........................................................................................................................ 365
 8.8. Sieci ........................................................................................................................................................ 368
       8.8.1. Przepływy maksymalne ............................................................................................................. 368
       8.8.2. Maksymalne przepływy o minimalnym koszcie........................................................................ 378
 8.9. Kojarzenie .............................................................................................................................................. 383
       8.9.1. Problem przypisania................................................................................................................... 387
       8.9.2. Skojarzenia w grafach, które nie są dwudzielne........................................................................ 390
8.10. Grafy eulerowskie i hamiltonowskie...................................................................................................... 392
      8.10.1. Grafy eulerowskie...................................................................................................................... 392
      8.10.2. Grafy hamiltonowskie................................................................................................................ 393
8.11. Przykład zastosowania. Unikalni reprezentanci..................................................................................... 396
8.12. Ćwiczenia ............................................................................................................................................... 406
8.13. Zadania programistyczne ....................................................................................................................... 409
      Bibliografia ........................................................................................................................................... 411


9.
Sortowanie ...........................................................................................................413
 9.1. Podstawowe algorytmy sortowania ....................................................................................................... 414
       9.1.1. Sortowanie przez wstawianie..................................................................................................... 414
       9.1.2. Sortowanie przez wybieranie..................................................................................................... 417
       9.1.3. Sortowanie bąbelkowe ............................................................................................................... 419
 9.2. Drzewa decyzyjne.................................................................................................................................. 422
 9.3. Efektywne algorytmy sortowania .......................................................................................................... 425
       9.3.1. Sortowanie Shella ...................................................................................................................... 425
       9.3.2. Sortowanie przez kopcowanie ................................................................................................... 429
       9.3.3. Sortowanie szybkie (quicksort).................................................................................................. 433
       9.3.4. Sortowanie poprzez scalanie...................................................................................................... 440
       9.3.5. Sortowanie pozycyjne................................................................................................................ 443
SPIS TREŚCI                                                                                                                                                      9

 9.4.   Sortowanie przy wykorzystaniu STL .................................................................................................... 448
 9.5.   Uwagi końcowe ..................................................................................................................................... 452
 9.6.   Przykład zastosowania. Dodawanie wielomianów................................................................................ 452
 9.7.   Ćwiczenia .............................................................................................................................................. 459
 9.8.   Zadania programistyczne....................................................................................................................... 461
        Bibliografia ........................................................................................................................................... 463


10.
Mieszanie .............................................................................................................465
10.1. Funkcje mieszające ................................................................................................................................ 466
      10.1.1. Dzielenie .................................................................................................................................... 466
      10.1.2. Składanie.................................................................................................................................... 466
      10.1.3. Funkcja „środek kwadratu” ....................................................................................................... 467
      10.1.4. Wycinanie .................................................................................................................................. 468
      10.1.5. Zmiana podstawy....................................................................................................................... 468
10.2. Rozwiązywanie problemu kolizji .......................................................................................................... 468
      10.2.1. Adresowanie otwarte ................................................................................................................. 469
      10.2.2. Metoda łańcuchowa ................................................................................................................... 475
      10.2.3. Adresowanie kubełkowe............................................................................................................ 476
10.3. Usuwanie ............................................................................................................................................... 477
10.4. Doskonałe funkcje mieszające............................................................................................................... 479
      10.4.1. Metoda Cichelliego.................................................................................................................... 479
      10.4.2. Algorytm FHCD ........................................................................................................................ 482
10.5. Funkcje mieszające dla plików rozszerzalnych ..................................................................................... 484
      10.5.1. Mieszanie przedłu alne.............................................................................................................. 485
      10.5.2. Mieszanie liniowe ...................................................................................................................... 487
10.6. Przykład zastosowania. Mieszanie z u yciem kubełków ...................................................................... 490
10.7. Ćwiczenia .............................................................................................................................................. 498
10.8. Zadania programistyczne....................................................................................................................... 500
      Bibliografia ........................................................................................................................................... 501


11.
Kompresja danych ...............................................................................................503
11.1. Warunki kompresji danych.................................................................................................................... 503
11.2. Kodowanie Huffmana............................................................................................................................ 505
      11.2.1. Adaptacyjne kodowanie Huffmana ........................................................................................... 514
11.3. Metoda Shannona-Fano ......................................................................................................................... 519
11.4. Kodowanie długości serii ...................................................................................................................... 520
11.5. Metoda Ziva-Lempela ........................................................................................................................... 521
11.6. Przykład zastosowania. Metoda Huffmana z kodowaniem długości serii ............................................ 524
11.7. Ćwiczenia .............................................................................................................................................. 535
11.8. Zadania programistyczne....................................................................................................................... 536
      Bibliografia ........................................................................................................................................... 537


12.
Zarządzanie pamięcią ..........................................................................................539
12.1. Metody dopasowywania sekwencyjnego .............................................................................................. 540
12.2. Metody niesekwencyjne ........................................................................................................................ 542
      12.2.1. System bliźniaków..................................................................................................................... 543
10                                                                                                                                                 SPIS TREŚCI



12.3. Odśmiecanie .......................................................................................................................................... 551
      12.3.1. Metoda „zaznacz-i-zamiataj”..................................................................................................... 551
      12.3.2. Metody kopiowania ................................................................................................................... 559
      12.3.3. Krokowe metody odśmiecania................................................................................................... 560
12.4. Uwagi końcowe ..................................................................................................................................... 567
12.5. Przykład zastosowania. Odśmiecanie „w miejscu” ............................................................................... 568
12.6. Ćwiczenia .............................................................................................................................................. 576
12.7. Zadania programistyczne....................................................................................................................... 577
      Bibliografia ........................................................................................................................................... 579


A
Obliczanie zło oności ..........................................................................................583
 A.1. Szereg harmoniczny............................................................................................................................... 583
 A.2. Przybli enie funkcji lg(n!) ..................................................................................................................... 583
 A.3. Przybli ona średnia zło oność sortowania szybkiego ........................................................................... 585
 A.4. Średnia długość ście ki w losowych drzewach binarnych .................................................................... 587


B
Algorytmy dostępne w STL.................................................................................589
 B.1. Algorytmy standardowe......................................................................................................................... 589

Skorowidz ............................................................................................................597
1
Programowanie obiektowe w C++




1.1. Abstrakcyjne typy danych
Przed napisaniem jakiegokolwiek programu trzeba wiedzieć dość dokładnie, jak powinno być re-
alizowane zadanie wykonywane przez ten program. Wobec tego przed początkiem kodowania
powinien powstać szkic programu opisujący wszystkie wymagania. Im większy i bardziej zło ony
jest projekt, tym bardziej szczegółowy powinien być ten szkic. Szczegóły implementacyjne po-
winny zostać odło one do późniejszego etapu prac. W szczególności na później powinny zostać
odło one wszelkie szczegółowe ustalenia dotyczące struktur danych nieokreślone na samym początku.
      Od samego początku trzeba określić ka de zadanie za pomocą jego danych wejściowych
i wyjściowych. Na wstępie bardziej powinno nas interesować to, co program ma robić, a nie jak
ma to robić. Zachowanie się programu jest wa niejsze od tego, dlaczego program tak właśnie
działa. Jeśli, na przykład, realizacja pewnego zadania wymaga jakiegoś narzędzia, narzędzie to
opisuje się jako zestaw mo liwych operacji, a nie podaje się jego wewnętrznej struktury. Operacje
takie mogą modyfikować narzędzie, wyszukiwać dotyczące go szczegóły lub zapisywać w nim
dodatkowe dane. Kiedy wszystkie te operacje zostaną dokładnie opisane, mo na rozpocząć kodo-
wanie. Na tym etapie decyduje się o tym, które struktury danych będą najlepsze z punktu widzenia
czasu wykonania i zajętości pamięci. Takie narzędzie opisane przez jego operacje nazywamy abs-
trakcyjnym typem danych. Abstrakcyjny typ danych nie jest częścią programu, gdy program napi-
sany w pewnym języku programowania wymaga zdefiniowania struktury danych, a nie tylko ope-
racji na tej strukturze. Jednak języki obiektowe, takie jak C++, bezpośrednio wią ą abstrakcyjne
typy danych z kodem w formie klas.




1.2. Enkapsulacja
Programowanie obiektowe obraca się wokół pojęcia obiektu. Obiekty tworzone są zgodnie z defi-
nicją klasy. Klasa to szablon, według którego tworzy się obiekty. Klasa to fragment kodu, który
zawiera opis danych oraz funkcje przetwarzające te dane i, ewentualnie, tak e dane z innych klas.
Funkcje definiowane w ramach klasy nazywamy metodami lub funkcjami składowymi, zaś zmienne
u ywane w klasach to dane składowe lub po prostu pola. Takie łączenie danych i związanych
z nimi operacji nazywamy enkapsulacją danych. Obiekt to instancja klasy — coś, co jest tworzone
zgodnie z definicją tej klasy.
16                                                                1. PROGRAMOWANIE OBIEKTOWE W C++



      W przeciwieństwie do funkcji z języków nieobiektowych, w obiektach połączenie między
danymi a metodami jest ścisłe i ma istotne znaczenie. W językach nieobiektowych deklaracje da-
nych i definicje funkcji mogą przeplatać się w całym programie, a jedynie z dokumentacji wynika,
jak dane z funkcjami są powiązane. W językach obiektowych związek ten jest ustalany ju na
wstępie; cała struktura programu opiera się na tym powiązaniu. Obiekt jest opisany przez powią-
zane dane i operacje, a jako e w tym samym programie u ywanych mo e być wiele obiektów,
obiekty komunikują się, wymieniając komunikaty, które o ich strukturze wewnętrznej mówią tylko
tyle, ile jest niezbędne. Podział programu na obiekty pozwala osiągnąć kilka celów.
      Po pierwsze, silnie powiązane dane i operacje mogą znacznie lepiej opisywać modelowany
fragment świata, co jest szczególnie istotne w przypadku in ynierii oprogramowania. Nie powinno
zaskakiwać, e programowanie obiektowe ma swoje korzenie w symulacjach, czyli modelowaniu
rzeczywistych obiektów. Pierwszym językiem obiektowym była Simula, która powstała w latach
60-tych w Norwegii.
      Po drugie, u ycie obiektów ułatwia szukanie błędów, gdy operacje są wiązane od razu ze
„swoimi” obiektami. Nawet jeśli pojawiają się efekty uboczne, łatwiej jest je wyśledzić.
      Po trzecie, u ycie obiektów pozwala ukryć pewne szczegóły operacji przed innymi obiekta-
mi, dzięki czemu operacje te nie ulegają tak łatwo zmianom w przypadku zmieniania innych
obiektów. Jest to zasada ukrywania informacji. W językach nieobiektowych zasada ta w pewnym
zakresie jest realizowana przez stosowanie zmiennych lokalnych, a (na przykład w Pascalu) tak e
przez stosowanie lokalnych funkcji i procedur, które są dostępne jedynie w funkcjach je zawiera-
jących. Jednak jest to zawsze albo bardzo dokładne ukrywanie, albo ukrywania nie ma w ogóle.
Czasami (na przykład w Pascalu) funkcja f2 zdefiniowana w f1 mo e być potrzebna poza f1, ale
poza f1 jest ona całkowicie niewidoczna. Czasami potrzebne jest sięgnięcie do pewnych danych
lokalnych f1 bez dokładnej znajomości struktury tych danych, ale to te jest niemo liwe. Dlatego
te w programowaniu obiektowym nieco zmieniają się zasady dostępności danych.
      U ytkowników interesuje działanie zegarka, ale jego budowa wewnętrzna nie ma ju znacze-
nia. Wiadomo, e wewnątrz są tryby i sprę yny, ale zwykle niewiele wiadomo o sposobie ich
działania, wobec czego dostęp do nich jest zbędny, gdy mógłby prowadzić do uszkodzenia me-
chanizmu. Mechanizm jest przed u ytkownikiem ukryty, nie ma do niego bezpośredniego dostępu,
dzięki czemu zegarek nie jest nara ony na zniszczenie bardziej, ni gdyby mechanizm był cały
czas otwarty.
      Obiekt to czarna skrzynka o dokładnie opisanym działaniu; obiektu u ywa się dlatego, e
wiadomo, co on robi, ale nie ma się dostępu do jego wnętrza. Owa nieprzezroczystość obiektów jest
wyjątkowo przydatna do serwisowania jednych obiektów niezale nie od innych. Jeśli dobrze zo-
staną określone kanały komunikacyjne między obiektami, zmiany w jednym obiekcie będą wpły-
wały na inne obiekty tylko wtedy, gdy będą dotyczyły tych kanałów. Wiedząc, jakie informacje są
wysyłane i odbierane przez obiekt, mo na łatwiej zastąpić jeden obiekt innym — nowy obiekt mo-
  e realizować te same zadania inaczej, na przykład szybciej w danym środowisku. Obiekt ujawnia
tylko tyle informacji o sobie, ile jest potrzebnych u ytkownikowi, aby tego obiektu u yć. Obiekt
ma część publiczną, która jest dostępna dla wszystkich, którzy prześlą do obiektu komunikat
w formie jednej z funkcji przez obiekt udostępnianych. Do części publicznej nale ą przyciski po-
kazywane u ytkownikowi; wciśnięcie ka dego z tych przycisków powoduje wykonanie operacji
obiektu. U ytkownik zna jedynie nazwy operacji i wie, co te operacje robią.
      Ukrywanie informacji prowadzi do zacierania się rozgraniczenia między danymi a operacjami.
W językach programowania takich jak Pascal podział na dane i funkcje jest prosty i stały. Inaczej
definiuje się jedne i drugie, inne jest ich zastosowanie. W programowaniu obiektowym dane
i metody są zestawione razem, zaś dla u ytkownika obiektu podział jest znacznie mniej wyraźny.
1.2. ENKAPSULACJA                                                                          17

W pewnym zakresie jest to te cecha języków funkcyjnych. LISP, jeden z najstarszych języków
programowania, pozwala traktować dane i funkcje tak samo, gdy struktura jednych i drugich jest
identyczna.
     Dokonaliśmy ju podziału między konkretne obiekty a typy obiektów czyli klasy. Funkcje pi-
szemy tak, aby u ywały ró nych zmiennych, nie chcemy jednak być zmuszani do zapisywania tylu
deklaracji obiektów, ilu obiektów potrzebujemy w całym programie. Pewne obiekty są tego samego
typu i chcielibyśmy u ywać pojedynczego typu jako ogólnej definicji takiego typu. W przypadku
pojedynczych zmiennych odró niamy deklarację typu od deklaracji zmiennej. W przypadku
obiektów mamy deklarację klasy i deklarację obiektu. Poni ej pokazano przykład klasy % i obiek-
tów QDLGEV, QDLGEV i QDLGEV:

ENCUU % ]
RWDNKE
    %
EJCT
U     KPV K   FQWDNG F   ]
        UVTER[
FCVC/GODGTU
        FCVC/GODGT  K
        FCVC/GODGT  F
    _
    XQKF OGODGT(WPEVKQP
 ]
        EQWV  FCVC/GODGT       FCVC/GODGT 
              FCVC/GODGT  GPFN
    _
    XQKF OGODGT(WPEVKQP
KPV K EJCT
U  PKGPCPC  ]
        FCVC/GODGT  K
        EQWV  K     RQDTCPC    U  GPFN
    _
RTQVGEVGF
    EJCT FCVC/GODGT=?
    KPV FCVC/GODGT
    FQWDNG FCVC/GODGT
_

% QDLGEV
 QDKGMV  QDLGEV
 QDKGMV  QDLGEV

     Przekazywanie komunikatów jest odpowiednikiem wywoływania funkcji w tradycyjnych ję-
zykach programowania, jednak wa ne jest, e w przypadku programowania obiektowego metody
są powiązane z obiektami — stąd właśnie u ywany jest nowy termin. Przykładowo, wywołanie
publicznej metody OGODGT(WPEVKQP
 obiektu QDLGEV:

QDLGEVOGODGT(WPEVKQP


jest widziane jako wysłanie do obiektu QDLGEV komunikatu OGODGT(WPEVKQP
. Po otrzymaniu
takiego komunikatu obiekt wywołuje swoją metodę i wyświetla wszystkie odpowiednie w danej
sytuacji informacje. Komunikaty mogą zawierać parametry:

QDLGEVOGODGT(WPEVKQP


Powy szy zapis to wywołanie komunikatu OGODGT(WPEVKQP
 obiektu QDLGEV z parametrem .
18                                                                1. PROGRAMOWANIE OBIEKTOWE W C++



     Wiersze zawierające takie komunikaty mogą być umieszczone albo w głównym programie,
albo w funkcji, albo w metodzie innego obiektu. Wobec tego odbiorca komunikatu mo e zostać
zidentyfikowany, ale nie dotyczy to wywołującego. Jeśli QDLGEV otrzyma komunikat OGODGT(WPE
VKQP
, nie wie, skąd ten komunikat pochodzi. Odpowiada na komunikat, pokazując dane za-
kodowane w metodzie OGODGT(WPEVKQP
, to samo dotyczy metody OGODGT(WPEVKQP
. Wobec
tego nadawca komunikatu mo e do komunikatu dołączyć informacje umo liwiające jego zi-
dentyfikowanie:

QDLGEVOGODGT(WPEVKQP
     QDKGMV 

     Istotną cechą C++ jest mo liwość deklarowania ogólnych klas dzięki u yciu parametrów typu
w deklaracji klasy. Jeśli, na przykład, trzeba zadeklarować klasę, która będzie coś przechowywała
w tablicy, mo na zadeklarować ją następująco:

ENCUU KPV%NCUU ]
    KPV UVQTCIG=?
    
_

jednak w ten sposób ogranicza się przydatność takiej klasy jedynie do liczb całkowitych; jeśli po-
trzebna będzie analogiczna klasa z liczbami zmiennoprzecinkowymi, konieczna będzie nowa de-
klaracja:

ENCUU HNQCV%NCUU ]
    HNQCV UVQTCIG=?
    
_

     Jeśli UVQTCIG ma zawierać struktury lub wskaźniki do znaków, konieczne byłoby zadeklaro-
wanie kolejnych dwóch klas. Znacznie lepiej byłoby zadeklarować ogólną klasę i dopiero podczas
definiowania obiektów decydować, jakiego typu dane będą w obiekcie przechowywane. Język
C++ umo liwia takie deklarowanie klasy, na przykład:

VGORNCVGENCUU IGP6[RG
ENCUU IGP%NCUU ]
    IGP6[RG UVQTCIG=?
    
_

Dopiero potem decydujemy, jak inicjalizowany będzie typ IGP6[RG:

IGP%NCUUKPV KPV1DLGEV
IGP%NCUUHNQCV HNQCV1DLGEV

    Taka klasa ogólna przybiera ró ne postacie w zale ności od konkretnej deklaracji. Jedna
ogólna deklaracja mo e udostępnić wszystkie te postacie.
    Mo emy pójść jeszcze dalej i decyzję o wielkości bufora, obecnie 50 komórek, odło yć na
później, do czasu tworzenia obiektu. Jednak na wszelki wypadek mo emy te zostawić wartość
domyślną:
1.3. DZIEDZICZENIE                                                                             19

VGORNCVGENCUU IGP6[RG KPV UKG  
ENCUU IGP%NCUU ]
    IGP6[RG UVQTCIG=UKG?
    
_

Definicje obiektów będą teraz wyglądały następująco:

IGP%NCUUKPV KPV1DLGEV  W [V[ QUVCPKG TQOKCT FQO[ NP[
IGP%NCUUKPV KPV1DLGEV
IGP%NCUUHNQCV HNQCV1DLGEV

      Pokazana metoda u ywania typów ogólnych nie ogranicza się jedynie do klas; mo na u ywać
jej te w deklaracjach funkcji. Przykładowo, standardowa operacja zamiany miejscami dwóch
wartości mo e być zdefiniowana następująco:

VGORNCVGENCUU IGP6[RG
XQKF UYCR
IGV6[RG GN IGP6[RG GN ]
    IGP6[RG VOR  GN GN  GN GN  VOR
_

     Przykład ten pokazuje konieczność dostosowania operatorów wbudowanych do konkretnych
sytuacji. Jeśli IGP6[RG jest liczbą, znakiem lub strukturą, operator przypisania zadziała prawidło-
wo. Jeśli jednak IGP6[RG jest tablicą, nale y się spodziewać kłopotów ze strony funkcji UYCR
.
Problem ten mo na rozwiązać, przecią ając operator przypisania tak, aby rozszerzyć jego mo li-
wości w stosunku do określonych typów danych.
     Po zadeklarowaniu funkcji ogólnej w czasie kompilacji programu mo na wygenerować kon-
kretne funkcje. Jeśli, na przykład, kompilator „zobaczy” następujące dwa wywołania:

UYCR
PO  COKCPC FYÎEJ NKED EC MQYKV[EJ
UYCR
Z[  COKCPC FYÎEJ NKED OKGPPQRTGEKPMQY[EJ

wygeneruje dwie funkcje UYCR
, które będą u ywane w programie.




1.3. Dziedziczenie
Programowanie obiektowe pozwala tworzyć własne hierarchie klas tak, e obiekty nie muszą nale-
 eć tylko do pojedynczych klas. Zanim przejdziemy do omówienia dziedziczenia, przyjrzyjmy się
następującym definicjom klas:

ENCUU $CUG%NCUU ]
RWDNKE
   $CUG%NCUU
 ] _
    XQKF H
EJCT
U  PKGPCP[  ]
        EQWV  (WPMELC H
 Y $CUG%NCUU Y[YQ CPC            U  GPFN
        J

    _
20                                                           1. PROGRAMOWANIE OBIEKTOWE W C++



RTQVGEVGF
    XQKF I
EJCT
U  PKGPCP[  ]
         EQWV  (WPMELC I
 Y $CUG%NCUU Y[YQ CPC       U  GPFN
    _
RTKXCVG
    XQKF J
 ]
         EQWV  (WPMELC J
 Y $CUG%NCUUP 
    _
_
ENCUU GTKXGF.GXGN  RWDNKE XKTVWCN $CUG%NCUU ]
RWDNKE
    XQKF H
EJCT
U  PKGPCP[  ]
         EQWV  (WPMELC H
 Y GTKXGF.GXGN Y[YQ CPC       U  GPFN
         I
 GTKXGF.GXGN 
         J
 GTKXGF.GXGN 
    _
    XQKF J
EJCT
U  PKGPCPC  ]
         EQWV  (WPMELC J
 Y GTKXGF.GXGN Y[YQ CPC       U  GPFN
    _
_
ENCUU GTKXGF.GXGN  RWDNKE XKTVWCN $CUG%NCUU ]
RWDNKE
    XQKF H
EJCT
U  PKGPCP[  ]
         EQWV  (WPMELC H
 Y GTKXGF.GXGN Y[YQ CPC       U  GPFN
         I
 GTKXGF.GXGN 
       J
  D æF $CUG%NCUUJ
 PKG LGUV FQUVúRPC
    _
_
ENCUU GTKXGF.GXGN  RWDNKE GTKXGF.GXGN RWDNKE GTKXGF.GXGN ]
RWDNKE
    XQKF H
EJCT
U  PKGPCP[  ]
         EQWV  (WPMELC H
 Y GTKXGF.GXGN Y[YQ CPC       U  GPFN
         I
 GTKXGF.GXGN 
         GTKXGF.GXGNJ
 GTKXGF.GXGN 
         $CUG%NCUUH
 GTKXGF.GXGN 
    _
_

A oto przykładowy program:

KPV OCKP
 ]
    $CUG%NCUU DE
    GTKXGF.GXGN FN
    GTKXGF.GXGN FN
    GTKXGF.GXGN FN
    DEH
 OCKP
 
 DEI
  D æF $CUG%NCUUI
 LGUV PKGFQUVúRPC
 DEJ
  D æF $CUG%NCUUJ
 LGUV PKGFQUVúRPC
    FNH
 OCKP
 
 FNI
  D æF $CUG%NCUUI
 LGUV PKGFQUVúRPC
    FNJ
 OCKP
 
    FNH
 OCKP
1.3. DZIEDZICZENIE                                                                               21

   FNI
  D æF $CUG%NCUUI
 LGUV PKGFQUVúRPC
   FNJ
  D æF $CUG%NCUUJ
 LGUV PKGFQUVúRPC
     FNH
 OCKP
 
   FNI
  D æF $CUG%NCUUI
 LGUV PKGFQUVúRPC
     FNJ

       TGVWTP 
_

Program powy szy da następujące wyniki:

(WPMELC   H
   Y    $CUG%NCUU Y[YQ CPC  OCKP

(WPMELC   J
   Y    $CUG%NCUU
(WPMELC   H
   Y    GTKXGF.GXGN Y[YQ CPC  OCKP

(WPMELC   I
   Y    $CUG%NCUU Y[YQ CPC  GTKXGF.GXGN
(WPMELC   J
   Y    GTKXGF.GXGN Y[YQ CPC  GTKXGF.GXGN
(WPMELC   J
   Y    GTKXGF.GXGN Y[YQ CPC  OCKP

(WPMELC   H
   Y    GTKXGF.GXGN Y[YQ CPC  OCKP

(WPMELC   I
   Y    $CUG%NCUU Y[YQ CPC  GTKXGF.GXGN
(WPMELC   H
   Y    GTKXGF.GXGN Y[YQ CPC  OCKP

(WPMELC   I
   Y    $CUG%NCUU Y[YQ CPC  GTKXGF.GXGN
(WPMELC   J
   Y    GTKXGF.GXGN Y[YQ CPC  GTKXGF.GXGN
(WPMELC   H
   Y    $CUG%NCUU Y[YQ CPC  GTKXGF.GXGN
(WPMELC   J
   Y    $CUG%NCUU
(WPMELC   J
   Y    GTKXGF.GXGN Y[YQ CPC  PKGPCP[

      Klasa $CUG%NCUU jest nazywana klasą bazową, zaś pozostałe klasy to klasy pochodne, gdy po-
chodzą od klasy bazowej w tym sensie, e mogą korzystać z pól i metod $CUG%NCUU oznaczonych jako
chronione (słowo kluczowe RTQVGEVGF) lub publiczne (RWDNKE). Klasy te dziedziczą wszystkie takie
pola po klasie bazowej, dzięki czemu zbędne jest powtarzanie w nich tych samych definicji. Jednak
klasa pochodna mo e przykryć definicję z klasy bazowej, podając własną definicję tej samej składowej.
W ten sposób zarówno klasa bazowa, jak i klasy pochodne mogą zapanować nad swoimi składowymi.
      Klasa bazowa mo e decydować, które metody i które pola mogą zostać ujawnione klasom
pochodnym, wobec czego zasada ukrywania informacji jest zachowana nie tylko względem u ytkow-
ników klasy bazowej, ale tak e klas pochodnych. Co więcej, klasa pochodna mo e zdecydować,
które części metod i pól publicznych i chronionych zostaną zachowane, a które będą modyfikowane.
Przykładowo, w obu klasach pochodnych pierwszego poziomu, GTKXGF.GXGN i GTKXGF.GXGN,
zdefiniowane są lokalne wersje metody H
. Jednak nadal mo na skorzystać z tak samo nazwanej
metody z wy szych poziomów hierarchii; w tym celu nazwę metody nale y poprzedzić nazwą klasy
i operatorem zakresu, jak pokazano to w przypadku wywołania $CUG%NCUUH
 z metody H
 w klasie
GTKXGF.GXGN.
      Klasa pochodna sama te mo e zawierać dodatkowe pola danych. Klasa taka mo e stać się
z kolei klasą bazową dla innej klasy i tak dalej; hierarchię dziedziczenia mo na dowolnie rozsze-
rzać. Przykładowo, klasa GTKXGF.GXGN pochodzi od $CUG%NCUU, ale jednocześnie jest klasą bazową
dla GTKXGF.GXGN.
      W pokazanych przykładach dziedziczenie jest publiczne — po dwukropku w nagłówku defi-
nicji klasy pochodnej występuje słowo RWDNKE. Dziedziczenie publiczne oznacza, e pola publicz-
ne klasy bazowej będą w klasie pochodnej tak e publiczne, zaś chronione te będą chronione.
W przypadku dziedziczenia chronionego (w nagłówku klasy po dwukropku pojawia się słowo klu-
czowe RTQVGEVGF) pola i metody publiczne i chronione klasy bazowej w klasie pochodnej będą
chronione. W końcu, jeśli dziedziczenie jest prywatne (słowo kluczowe RTKXCVG), pola publiczne
i chronione klasy bazowej stają się prywatnymi polami klasy pochodnej. We wszystkich rodzajach
22                                                                1. PROGRAMOWANIE OBIEKTOWE W C++



dziedziczenia metody i pola prywatne klasy bazowej we wszystkich klasach pochodnych są niedo-
stępne. Przykładowo, próba wywołania J
 z metody H
 w klasie GTKXGF.GXGN powoduje błąd
kompilacji „$CUG%NCUUJ
 is not accessible”. Jednak wywołanie z H
 metody J
 w klasie G
TKXGF.GXGN nie sprawia adnych kłopotów, gdy jest ono interpretowane jako wywołanie metody
J
 zdefiniowanej w klasie GTKXGF.GXGN.
      Pola i metody chronione klasy bazowej dostępne są jedynie dla klasy pochodnej tej klasy.
Z tego powodu klasy GTKXGF.GXGN i GTKXGF.GXGN mogą wywołać metodę chronioną I
 klasy
$CUG%NCUU
, ale wywołanie tej metody w funkcji OCKP
 jest ju niedopuszczalne.
      Klasa pochodna nie musi pochodzić od jednej tylko klasy bazowej. Przykładowo, klasa G
TKXGF.GXGN pochodzi od klas GTKXGF.GXGN i GTKXGF.GXGN, dziedzicząc w ten sposób wszystkie
metody obu tych klas. GTKXGF.GXGN dziedziczy jednak te same metody z $CUG%NCUU dwukrotnie,
gdy obie klasy pochodne poziomu pierwszego pochodzą od klasy $CUG%NCUU. Jest to w najlep-
szym razie nadmiarowe i jako takie zbędne, a w najgorszym razie mo e spowodować błąd kompi-
lacji „member is ambiguous $CUG%NCUUI
 and $CUG%NCUUI
”. Aby to się nie zdarzyło, definicje
obu klas bazowych zawierają modyfikator XKTVWCN, który oznacza, e klasa GTKXGF.GXGN zawiera
jedną tylko kopię ka dej metody klasy $CUG%NCUU. Analogiczny problem pojawi się, jeśli H
 z G
TKXGF.GXGN wywoła J
 bez podania operatora zakresu i nazwy klasy, tutaj GTKXGF.GXGNJ
.
Nie ma znaczenia fakt, e metoda J
 w $CUG%NCUU jest prywatna i przez to niedostępna w GTKXG
F.GXGN — opisana sytuacja spowodowałaby wystąpienie błędu „member is ambiguous GTKXG
F.GXGNJ
 and $CUG%NCUUJ
”.




1.4. Wskaźniki
Zmienne u ywane w programie mo na traktować jako pojemniki, które nigdy nie są puste — zawsze
coś jest w środku, albo wstawione przez programistę, albo, w przypadku braku inicjalizacji, przez
system operacyjny. Ka da taka zmienna ma co najmniej dwa atrybuty: zawartość czyli wartość
oraz poło enie pojemnika w pamięci komputera. Zawartość mo e być liczbą, znakiem lub wielko-
ścią zło oną, jak struktura czy unia. Jednak wartość ta mo e być te poło eniem innej zmiennej;
zmienna z taką wartością nazywane są wskaźnikami. Wskaźniki to zwykle zmienne pomocnicze,
które umo liwiają nam pośrednie sięganie do innych wartości. Wskaźnik jest analogią do znaku
drogowego, który wskazuje pewne miejsce, lub fiszki, na której zanotowano adres. Są to zmienne
prowadzące do zmiennych; pomocnicze zmienne wskazujące wartości, które są naprawdę istotne.
     Jeśli mamy następującą deklarację:

KPV K   L
R
S

K i L są zmiennymi liczbowymi, zaś R i S są wskaźnikami na te zmienne liczbowe; o ich roli decy-
duje poprzedzająca je gwiazdka. Zakładając, e adresy zmiennych K, L, R i S to, odpowiednio,
1080, 1082, 1084 i 1086, po przypisaniu zmiennej K wartości 15, uzyskamy w pamięci komputera
obraz taki, jak na rysunku 1.1a.
      Moglibyśmy teraz wykonać przypisanie R  K (lub R  
KPV
K, gdyby kompilator nie chciał
uznać pierwszej wersji), ale zmienna R została stworzona po to, aby przechowywać adres zmiennej
liczbowej, a nie jej wartość. Wobec tego prawidłowe przypisanie to R  K, gdzie symbol wystę-
pujący przed K oznacza, e chodzi o adres zmiennej K, a nie o jej wartość. Pokazano to na rysunku
1.1b. Na rysunku 1.1c strzałka z R do K wskazuje, e R jest wskaźnikiem zawierającym adres K.
1.4. WSKAŹNIKI                                                                                          23




                                                                      RYSUNEK 1.1.
                                                                      Zmiany wartości
                                                                      po przypisaniach realizowane
                                                                      są przy u yciu wskaźników.
                                                                      Przypadki (b) i (c) opisują tę
                                                                      samą sytuację, tak samo (d)
                                                                      i (e), (g) i (h), (i) i (j), (k) i (l)
                                                                      oraz (m) i (n)


     Musimy być w stanie odró niać wartość R — adres — od wartości umieszczonej pod tym adre-
sem. Aby na przykład przypisać wartość 20 zmiennej wskazywanej przez R trzeba u yć wyra enia:
R  

     Gwiazdka to operator dereferencji, który wymusza najpierw pobranie wartości R, potem się-
gnięcie do wskazywanego przez tę wartość miejsca i wpisanie tam liczby 20 (rysunek 1.1d). Ry-
sunki 1.1e do 1.1n to dalsze przykłady instrukcji przypisania, na których pokazano sposób umiesz-
czania wartości w pamięci komputera.
24                                                                1. PROGRAMOWANIE OBIEKTOWE W C++



     Tak naprawdę wskaźniki, tak samo jak inne zmienne, mają dwa atrybuty: zawartość i poło e-
nie. Poło enie mo na zapisać w innej zmiennej, która staje się wskaźnikiem na wskaźnik.
     Na rysunku 1.1 adresy zmiennych są przypisywane wskaźnikom, jednak wskaźniki mogą od-
nosić się do anonimowych lokalizacji w pamięci dostępnych jedynie przez adres, a niemających
nazw. Lokalizacje takie muszą być dynamicznie określane przez proces zarządzający pamięcią
podczas wykonywania programu, podczas gdy poło enie zmiennych określane jest ju na etapie
kompilacji.
     Aby dynamicznie alokować i zwalniać pamięć, u ywa się dwóch funkcji. Jedna to PGY; pobiera
ona z pamięci taki fragment, jaki jest potrzebny na zapisanie danej typu, który zostanie podany za
słowem PGY. Przykładowo, instrukcja:

R  PGY KPV

spowoduje za ądanie przez program pamięci potrzebnej na zamieszczenie jednej liczby całkowi-
tej, zaś adres tej pamięci zostanie umieszczony w zmiennej R. Teraz mo na blokowi wskazywa-
nemu przez R przypisywać wartości; trzeba to robić pośrednio, przez wskaźnik R lub dowolny inny
wskaźnik S, któremu przypiszemy adres z R instrukcją S  R.
      Kiedy pamięć zajmowana przez liczbę wskazywaną przez R przestaje być potrzebna, mo na
ją zwolnić do puli obsługiwanej przez system operacyjny instrukcją:

FGNGVG R

Jednak nawet po wykonaniu tej instrukcji zmienna R nadal zawiera adres zwolnionego bloku, choć
blok ten przestaje być w programie dostępny. To tak, jakby traktować adres zburzonego domu jako
adres mo liwego zamieszkania. Ka da próba znalezienia kogoś pod takim adresem jest z góry
skazana na niepowodzenie. Analogicznie, jeśli po wywołaniu instrukcji FGNGVG nie usuniemy ze
zmiennej wskaźnikowej adresu, nara amy się na ryzyko błędów; program mo e przestać działać
podczas prób dostępu do nienale ącej ju do niego pamięci. Jest to szczególnie niebezpieczne
w przypadku sięgania do obiektów bardziej zło onych ni liczby. Aby uniknąć opisanego problemu,
nale y wskaźnikowi przypisać nowy adres; jeśli nie ma adnego prawidłowego adresu na podorędziu,
nale y u yć adresu pustego, o wartości . Po wykonaniu przypisania:

R  

nie mówimy, e R wskazuje zero czy 07.., lecz e R ma wartość 07.. (pustą).



1.4.1. Wskaźniki a tablice
W pokazanym powy ej przykładzie wskaźnik R wskazywał blok pamięci zawierający jedną liczbę
całkowitą. Znacznie ciekawsza jest sytuacja, kiedy wskaźnik wskazuje strukturę danych tworzoną
i modyfikowaną dynamicznie. Pozwala to obejść ograniczenia dotyczące tablic. W C++, podobnie
jak większości innych języków programowania, tablice trzeba zawczasu zadeklarować. Wobec te-
go ich rozmiar musi być znany przed uruchomieniem programu, a zatem programista musi dość
du o wiedzieć o oprogramowanym problemie, gdy jest to warunkiem poprawnego określenia
wielkości tablicy. Jeśli tablica będzie zbyt du a, niepotrzebnie zajmowana przez nią pamięć będzie
zmarnowana. Jeśli tablica będzie zbyt mała, dane będą umieszczane za jej końcem, co powoduje
powa ną awarię programu. Czasami jednak rozmiaru tablicy po prostu nie da się przewidzieć —
w takiej sytuacji decyzję o wielkości tablicy i przez to alokowanej pamięci odkłada się do czasu
wykonywania programu.
1.4. WSKAŹNIKI                                                                                 25

     Do rozwiązania opisanego problemu u ywa się wskaźników. Spójrzmy na rysunek 1.1b.
Wskaźnik R wskazuje adres 1080, ale mo na za jego pośrednictwem sięgnąć te pod adresy 1082,
1084 i tak dalej — jest to mo liwe dzięki temu, e kolejne dane przesuwane są o taką samą wiel-
kość. Aby, na przykład, sięgnąć do wartości zmiennej L sąsiadującej z K, wystarczy dodać do adresu
K trzymanego w R rozmiar wartości zmiennej L; wtedy wskaźnik R będzie wskazywał adres zmien-
nej L. Tak właśnie w C++ obsługiwane są tablice.
     Przyjrzyjmy się następującym deklaracjom:

KPV C=?
R

     Deklaracje te mówią, e C jest wskaźnikiem bloku pamięci, który mo e zawierać pięć liczb
całkowitych. Wskaźnik jest stały, to znaczy nale y go traktować jako stały; wobec tego ka da próba
przypisania zmiennej C wartości, na przykład:

C  R

lub:

C



traktowana jest jako błąd kompilacji. Zmienna C jest wskaźnikiem, więc do sięgnięcia do poszcze-
gólnych komórek tablicy C mo na u ywać zapisu wskaźnikowego. Tak oto pętlę dodającą wszystkie
wartości z tej tablicy:

HQT 
UWO  C=? K   K   K


    UWO 
 C=K?

mo na zamienić na zapis wskaźnikowy tak:

HQT 
UWO
C K   K   K


    UWO
C 
 K

lub tak:

HQT 
UWO
C R  C
 R  C
 R


    UWO
R

Zauwa my, e skoro C
 oznacza poło enie następnej komórki tablicy C, to C
 jest odpowiednikiem
 C=?. Wobec tego, jeśli C wskazuje adres 1020, to C
 nie zawiera adresu 1021, lecz 1022, gdy sto-
sowana jest arytmetyka wskaźników zale na od typu wskazywanych danych. Jeśli dane są deklaracje:

EJCT D=?
NQPI E=?

i wiadomo, e D równe jest 1050, E równe jest 1055, to D
 równe jest 1051, gdy jeden znak zaj-
muje jeden bajt, zaś E
 równe jest 1059, gdy liczba typu NQPI zajmuje cztery bajty. Jest to wyni-
kiem faktu, e w arytmetyce wskaźników wyra enie E
K oznacza adres E
K
UKGQH
NQPI.
      Dotąd tablica C była deklarowana statycznie i zawierała pięć komórek. Rozmiar takiej tablicy
jest ustalony na cały czas działania programu. Tablice mo na deklarować tak e dynamicznie; wtedy
u ywane są zmienne wskaźnikowe. Przykładowo, przypisanie:

R  PGY KPV=P?
26                                                                1. PROGRAMOWANIE OBIEKTOWE W C++



powoduje zaalokowanie pamięci na P liczb całkowitych. Wskaźnik R mo na traktować jako
zmienną tablicową i mo na stosować doń notację tablicową. Sumę liczb z tablicy R mo na wyzna-
czyć tak:

HQT 
UWO  R=? K   K  P K


    UWO 
 R=K?

Mo na zastosować te notację wskaźnikową normalnie:

HQT 
UWO
R K   K  P K


    UWO
R
K

lub korzystając z dwóch wskaźników:

HQT 
UWO
R S  R
 S  R
P S


    UWO
S

R jest zmienną, więc mo na jej przypisać nową tablicę. Kiedy tablica wskazywana przez R prze-
staje być potrzebna, przypisaną jej pamięć mo na zwolnić instrukcją:

FGNGVG =? R

U ycie pustej pary nawiasów kwadratowych jest wa ne, gdy informuje, e R wskazuje tablicę.
     Bardzo wa nym rodzajem tablic są łańcuchy czyli tablice znaków. Istnieje wiele funkcji pre-
definiowanych przetwarzających łańcuchy. Nazwy tych funkcji zaczynają się od UVT, na przykład
UVTNGP
U określająca długość łańcucha U, UVTER[
UU kopiująca łańcuch U do U. Trzeba pa-
miętać, e wszystkie te funkcje zakładają, e łańcuchy kończą się znakiem 07..,  . I tak UVTE
R[
UU kopiuje U tak długo, a znajdzie w nim znak 07... Jeśli programista tego znaku w łań-
cuchu nie umieści, kopiowanie zostanie przerwane dopiero po napotkaniu pierwszego takiego
znaku gdziekolwiek w pamięci komputera, za adresem zmiennej U. Oznacza to, e kopiowane będą
znaki za U, co w końcu mo e doprowadzić do awarii programu.



1.4.2. Wskaźniki a konstruktory kopiujące
Kiedy wskaźniki zapisane w polach obiektu nie będą podczas kopiowania obiektów prawidłowo
obsłu one, trzeba liczyć się z problemami. Niech dana będzie taka oto definicja:

UVTWEV 0QFG ]
    EJCT
PCOG
    KPV CIG
    0QFG
 EJCT
P     KPV C   ]
        PCOG  PGY EJCT=UVTNGP
P
?
        UVTER[
PCOGP
        CIG  C
    _
_
1.4. WSKAŹNIKI                                                                                 27

Celem deklaracji:

0QFG PQFG
 4QIGT  PQFG
PQFG  NWD PQFG  PQFG

jest stworzenie obiektu PQFG, przypisanie wartości dwu jego polom, a następnie stworzenie obiektu
PQFG i zainicjalizowanie jego pól takimi samymi wartościami jak PQFG. Obiekty muszą być od
siebie niezale ne, więc przypisanie wartości pól jednego obiektu nie powinno wpływać na drugi
obiekt. Jednak po przypisaniu:

UVTER[
PQFGPCOG 9GPF[ 
PQFGCIG  

przy próbie zajrzenia do zawartości obiektów:

EQWVPQFGPCOG     PQFGCIG     PQFGPCOG     PQFGCIG

otrzymamy:

9GPF[  9GPF[ 

Wiek jest ró ny, ale imię jest takie samo. Co się właściwie stało? Chodzi o to, e w definicji klasy
0QFG nie podano konstruktora kopiującego:

0QFG
EQPUV 0QFG 

który jest niezbędny do wykonania inicjalizacji PQFG
PQFG. Jeśli u ytkownik nie poda kon-
struktora kopiującego, konstruktor taki zostanie automatycznie wygenerowany przez kompilator.
Jednak konstruktor stworzony przez kompilator kopiuje pole po polu. Pole PCOG jest wskaźnikiem,
więc skopiowany zostanie adres łańcucha PQFGPCOG do PQFGPCOG, a zawartość łańcucha ju ko-
piowana nie będzie. Wobec tego po wykonaniu pokazanej wcześniej deklaracji sytuacja będzie się
przedstawiała tak jak na rysunku 1.2a. Jeśli teraz wykonane zostaną przypisania:

UVTER[
PQFGPCOG 9GPF[ 
PQFGCIG  

pole PQFGCIG zostanie przypisane prawidłowo, ale łańcuch 4QIGT wskazywany przez pole PCOG
obu obiektów zostanie nadpisany napisem 9GPF[ wskazywanym przez oba obiekty (rysunek 1.2b).
Aby do takiej sytuacji nie dopuścić, konieczne jest zdefiniowanie prawidłowego konstruktora ko-
piującego:

UVTWEV 0QFG ]
    EJCT
PCOG
    KPV CIG
    0QFG
EJCT
P   KPV C   ]
        PCOG  PGY EJCT=UVTNGP
P
?
        UVTER[
PCOGP
        CIG  C
    _
28                                                               1. PROGRAMOWANIE OBIEKTOWE W C++




                                                                            RYSUNEK 1.2.
                                                                            Dlaczego w przypadku
                                                                            obiektów
                                                                            zawierających
                                                                            pola wskaźnikowe
                                                                            konieczne jest
                                                                            u ycie konstruktora
                                                                            kopiującego

     0QFG
EQPUV 0QFG P ]  MQPUVTWMVQT MQRKWLæE[
         PCOG  PGY EJCT=UVTNGP
PPCOG
?
         UVTER[
PCOGPPCOG
         CIG  PCIG
     _
_

Kiedy dany jest nowy konstruktor, PQFG
PQFG wygeneruje kopię napisu 4QIGT wskazywanego
przez PQFGPCOG (rysunek 1.2c), a przypisanie pól jednego obiektu nie wpływa na pola drugiego
obiektu:

UVTER[
PQFGPCOG 9GPF[ 
PQFGCIG  

Obiekt PQFG pozostanie niezmieniony, co widać na rysunku 1.2d.
     Podobne problemy pojawiają się w przypadku u ycia operatora przypisania. Jeśli u ytkownik
nie poda definicji operatora przypisania, instrukcja:

PQFG  PQFG

spowoduje przypisanie kolejno ka dego pola, co spowoduje problemy analogiczne jak na rysunku
1.2a – b. Aby tych problemów uniknąć, konieczne jest przecią enie operatora przypisania. W przy-
padku klasy 0QFG przecią enie mo e wyglądać następująco:

0QFG QRGTCVQT
EQPUV 0QFG P ]
    KH 
VJKU  P ]  PKG RT[RKUWLGO[ QDKGMVW FQ UCOGIQ UKGDKG
        KH 
PCOG  
            FGNGVG =? PCOG
        PCOG  PGY EJCT=UVTNGP
PPCOG
?
        UVTER[
PCOGPPCOG
        CIG  PCIG
1.4. WSKAŹNIKI                                                                                29

     _
     TGVWTP
VJKU
_

   W powy szym fragmencie kodu u yto specjalnego wskaźnika VJKU. Ka dy obiekt mo e za
pomocą tego wskaźnika uzyskać swój własny adres, wobec czego
VJKU to sam obiekt.



1.4.3. Wskaźniki i destruktory
Co się dzieje z lokalnie definiowanymi obiektami typu 0QFG? Tak jak wszystkie inne zmienne lo-
kalne, są niszczone w tym sensie, e poza blokiem, w którym je zdefiniowano, stają się niedostępne,
zaś zajmowana przez nie pamięć jest zwalniana. Jednak, mimo e pamięć zajmowana przez obiekt
0QFG jest zwalniana, to nie cała zaalokowana pamięć zostanie zwolniona. Jedno z pól tego obiektu
to wskaźnik łańcucha, wobec czego zwolniona zostanie pamięć przeznaczona na wskaźnik, ale nie
zostanie zwolniona pamięć na sam łańcuch. Po zniszczeniu obiektu dostępny dotąd łańcuch z pola
PCOG staje się niedostępny (o ile nie został przypisany polu PCOG innego obiektu lub całkiem innej
zmiennej łańcuchowej), więc nie mo na ju nawet zwolnić pamięci przyporządkowanej temu łań-
cuchowi. Jest to problem związany z polami wskazującymi dynamicznie alokowaną pamięć. Aby
tego problemu uniknąć, definicja klasy powinna zawierać definicję destruktora. Destruktor to
funkcja automatycznie wywoływana w chwili niszczenia obiektu, które to niszczenie odbywa się
w chwili wyjścia z bloku, w którym obiekt zdefiniowano, lub w chwili wywołania FGNGVG. De-
struktory nie mają adnych parametrów ani wartości zwracanych, więc w ka dej klasie istnieć mo e
jeden tylko destruktor. W przypadku klasy 0QFG będzie on wyglądał następująco:

`0QFG
 ]
    KH 
PCOG  
        FGNGVG =? PCOG
_




1.4.4. Wskaźniki a referencje
Przyjrzyjmy się następującym deklaracjom:

KPV P
R    P   T  P

Zmienna R została zadeklarowana jako zmienna typu KPV
, wskaźnik na liczbę całkowitą, zaś T jako
zmienna typu KPV — referencja do liczby całkowitej. Zmienna referencji musi być zainicjalizo-
wana w chwili deklaracji referencją do konkretnej zmiennej, wobec czego nigdy nie mo e być pu-
sta. Zmienną referencji T mo na traktować jako inną nazwę zmiennej P, jeśli zatem zmieni się P, to
zmieni się te wartość T. Wynika to stąd, e zmienne referencji implementuje się jako stałe wskaź-
niki do zmiennych.
      Wywołanie instrukcji wyświetlającej dane po powy szych deklaracjach:

EQWV  P
R         T  GPFN

More Related Content

Similar to C++. Algorytmy i struktury danych

Projektowanie oprogramowania. Wstęp do programowania i techniki komputerowej
Projektowanie oprogramowania. Wstęp do programowania i techniki komputerowejProjektowanie oprogramowania. Wstęp do programowania i techniki komputerowej
Projektowanie oprogramowania. Wstęp do programowania i techniki komputerowej
Wydawnictwo Helion
 
Struktura organizacyjna i architektura systemów komputerowych
Struktura organizacyjna i architektura systemów komputerowychStruktura organizacyjna i architektura systemów komputerowych
Struktura organizacyjna i architektura systemów komputerowych
Wydawnictwo Helion
 
SQL. Optymalizacja
SQL. OptymalizacjaSQL. Optymalizacja
SQL. Optymalizacja
Wydawnictwo Helion
 
Algorytmy. Od podstaw
Algorytmy. Od podstawAlgorytmy. Od podstaw
Algorytmy. Od podstaw
Wydawnictwo Helion
 
Projektowanie i analiza algorytmów
Projektowanie i analiza algorytmówProjektowanie i analiza algorytmów
Projektowanie i analiza algorytmów
Wydawnictwo Helion
 
C++. Styl i technika zaawansowanego programowania
C++. Styl i technika zaawansowanego programowaniaC++. Styl i technika zaawansowanego programowania
C++. Styl i technika zaawansowanego programowania
Wydawnictwo Helion
 
Relacyjne bazy danych
Relacyjne bazy danychRelacyjne bazy danych
Relacyjne bazy danych
Wydawnictwo Helion
 
C++. Strategie i taktyki. Vademecum profesjonalisty
C++. Strategie i taktyki. Vademecum profesjonalistyC++. Strategie i taktyki. Vademecum profesjonalisty
C++. Strategie i taktyki. Vademecum profesjonalisty
Wydawnictwo Helion
 
SQL. Od podstaw
SQL. Od podstawSQL. Od podstaw
SQL. Od podstaw
Wydawnictwo Helion
 
Bazy danych SQL. Teoria i praktyka
Bazy danych SQL. Teoria i praktykaBazy danych SQL. Teoria i praktyka
Bazy danych SQL. Teoria i praktyka
Wydawnictwo Helion
 
Po prostu Access 2003 PL
Po prostu Access 2003 PLPo prostu Access 2003 PL
Po prostu Access 2003 PL
Wydawnictwo Helion
 
Język C++. Gotowe rozwiązania dla programistów
Język C++. Gotowe rozwiązania dla programistówJęzyk C++. Gotowe rozwiązania dla programistów
Język C++. Gotowe rozwiązania dla programistów
Wydawnictwo Helion
 
C#. Wzorce projektowe
C#. Wzorce projektoweC#. Wzorce projektowe
C#. Wzorce projektowe
Wydawnictwo Helion
 
Programowanie w języku C. FAQ
Programowanie w języku C. FAQProgramowanie w języku C. FAQ
Programowanie w języku C. FAQ
Wydawnictwo Helion
 
Access 2003 PL. Kurs
Access 2003 PL. KursAccess 2003 PL. Kurs
Access 2003 PL. Kurs
Wydawnictwo Helion
 
Oracle8. Programowanie w języku PL/SQL
Oracle8. Programowanie w języku PL/SQLOracle8. Programowanie w języku PL/SQL
Oracle8. Programowanie w języku PL/SQL
Wydawnictwo Helion
 
Oracle9i. Przewodnik dla początkujących
Oracle9i. Przewodnik dla początkującychOracle9i. Przewodnik dla początkujących
Oracle9i. Przewodnik dla początkujących
Wydawnictwo Helion
 
Access 2003 PL dla każdego
Access 2003 PL dla każdegoAccess 2003 PL dla każdego
Access 2003 PL dla każdego
Wydawnictwo Helion
 
C++. Potęga języka. Od przykładu do przykładu
C++. Potęga języka. Od przykładu do przykładuC++. Potęga języka. Od przykładu do przykładu
C++. Potęga języka. Od przykładu do przykładu
Wydawnictwo Helion
 
Access 2003 PL. Ćwiczenia praktyczne. Wydanie II
Access 2003 PL. Ćwiczenia praktyczne. Wydanie IIAccess 2003 PL. Ćwiczenia praktyczne. Wydanie II
Access 2003 PL. Ćwiczenia praktyczne. Wydanie II
Wydawnictwo Helion
 

Similar to C++. Algorytmy i struktury danych (20)

Projektowanie oprogramowania. Wstęp do programowania i techniki komputerowej
Projektowanie oprogramowania. Wstęp do programowania i techniki komputerowejProjektowanie oprogramowania. Wstęp do programowania i techniki komputerowej
Projektowanie oprogramowania. Wstęp do programowania i techniki komputerowej
 
Struktura organizacyjna i architektura systemów komputerowych
Struktura organizacyjna i architektura systemów komputerowychStruktura organizacyjna i architektura systemów komputerowych
Struktura organizacyjna i architektura systemów komputerowych
 
SQL. Optymalizacja
SQL. OptymalizacjaSQL. Optymalizacja
SQL. Optymalizacja
 
Algorytmy. Od podstaw
Algorytmy. Od podstawAlgorytmy. Od podstaw
Algorytmy. Od podstaw
 
Projektowanie i analiza algorytmów
Projektowanie i analiza algorytmówProjektowanie i analiza algorytmów
Projektowanie i analiza algorytmów
 
C++. Styl i technika zaawansowanego programowania
C++. Styl i technika zaawansowanego programowaniaC++. Styl i technika zaawansowanego programowania
C++. Styl i technika zaawansowanego programowania
 
Relacyjne bazy danych
Relacyjne bazy danychRelacyjne bazy danych
Relacyjne bazy danych
 
C++. Strategie i taktyki. Vademecum profesjonalisty
C++. Strategie i taktyki. Vademecum profesjonalistyC++. Strategie i taktyki. Vademecum profesjonalisty
C++. Strategie i taktyki. Vademecum profesjonalisty
 
SQL. Od podstaw
SQL. Od podstawSQL. Od podstaw
SQL. Od podstaw
 
Bazy danych SQL. Teoria i praktyka
Bazy danych SQL. Teoria i praktykaBazy danych SQL. Teoria i praktyka
Bazy danych SQL. Teoria i praktyka
 
Po prostu Access 2003 PL
Po prostu Access 2003 PLPo prostu Access 2003 PL
Po prostu Access 2003 PL
 
Język C++. Gotowe rozwiązania dla programistów
Język C++. Gotowe rozwiązania dla programistówJęzyk C++. Gotowe rozwiązania dla programistów
Język C++. Gotowe rozwiązania dla programistów
 
C#. Wzorce projektowe
C#. Wzorce projektoweC#. Wzorce projektowe
C#. Wzorce projektowe
 
Programowanie w języku C. FAQ
Programowanie w języku C. FAQProgramowanie w języku C. FAQ
Programowanie w języku C. FAQ
 
Access 2003 PL. Kurs
Access 2003 PL. KursAccess 2003 PL. Kurs
Access 2003 PL. Kurs
 
Oracle8. Programowanie w języku PL/SQL
Oracle8. Programowanie w języku PL/SQLOracle8. Programowanie w języku PL/SQL
Oracle8. Programowanie w języku PL/SQL
 
Oracle9i. Przewodnik dla początkujących
Oracle9i. Przewodnik dla początkującychOracle9i. Przewodnik dla początkujących
Oracle9i. Przewodnik dla początkujących
 
Access 2003 PL dla każdego
Access 2003 PL dla każdegoAccess 2003 PL dla każdego
Access 2003 PL dla każdego
 
C++. Potęga języka. Od przykładu do przykładu
C++. Potęga języka. Od przykładu do przykładuC++. Potęga języka. Od przykładu do przykładu
C++. Potęga języka. Od przykładu do przykładu
 
Access 2003 PL. Ćwiczenia praktyczne. Wydanie II
Access 2003 PL. Ćwiczenia praktyczne. Wydanie IIAccess 2003 PL. Ćwiczenia praktyczne. Wydanie II
Access 2003 PL. Ćwiczenia praktyczne. Wydanie II
 

More from Wydawnictwo Helion

Tworzenie filmów w Windows XP. Projekty
Tworzenie filmów w Windows XP. ProjektyTworzenie filmów w Windows XP. Projekty
Tworzenie filmów w Windows XP. Projekty
Wydawnictwo Helion
 
Blog, więcej niż internetowy pamiętnik
Blog, więcej niż internetowy pamiętnikBlog, więcej niż internetowy pamiętnik
Blog, więcej niż internetowy pamiętnik
Wydawnictwo Helion
 
Access w biurze i nie tylko
Access w biurze i nie tylkoAccess w biurze i nie tylko
Access w biurze i nie tylko
Wydawnictwo Helion
 
Pozycjonowanie i optymalizacja stron WWW. Ćwiczenia praktyczne
Pozycjonowanie i optymalizacja stron WWW. Ćwiczenia praktycznePozycjonowanie i optymalizacja stron WWW. Ćwiczenia praktyczne
Pozycjonowanie i optymalizacja stron WWW. Ćwiczenia praktyczne
Wydawnictwo Helion
 
E-wizerunek. Internet jako narzędzie kreowania image'u w biznesie
E-wizerunek. Internet jako narzędzie kreowania image'u w biznesieE-wizerunek. Internet jako narzędzie kreowania image'u w biznesie
E-wizerunek. Internet jako narzędzie kreowania image'u w biznesie
Wydawnictwo Helion
 
Microsoft Visual C++ 2008. Tworzenie aplikacji dla Windows
Microsoft Visual C++ 2008. Tworzenie aplikacji dla WindowsMicrosoft Visual C++ 2008. Tworzenie aplikacji dla Windows
Microsoft Visual C++ 2008. Tworzenie aplikacji dla Windows
Wydawnictwo Helion
 
Co potrafi Twój iPhone? Podręcznik użytkownika. Wydanie II
Co potrafi Twój iPhone? Podręcznik użytkownika. Wydanie IICo potrafi Twój iPhone? Podręcznik użytkownika. Wydanie II
Co potrafi Twój iPhone? Podręcznik użytkownika. Wydanie II
Wydawnictwo Helion
 
Makrofotografia. Magia szczegółu
Makrofotografia. Magia szczegółuMakrofotografia. Magia szczegółu
Makrofotografia. Magia szczegółu
Wydawnictwo Helion
 
Windows PowerShell. Podstawy
Windows PowerShell. PodstawyWindows PowerShell. Podstawy
Windows PowerShell. Podstawy
Wydawnictwo Helion
 
Java. Efektywne programowanie. Wydanie II
Java. Efektywne programowanie. Wydanie IIJava. Efektywne programowanie. Wydanie II
Java. Efektywne programowanie. Wydanie II
Wydawnictwo Helion
 
JavaScript. Pierwsze starcie
JavaScript. Pierwsze starcieJavaScript. Pierwsze starcie
JavaScript. Pierwsze starcie
Wydawnictwo Helion
 
Ajax, JavaScript i PHP. Intensywny trening
Ajax, JavaScript i PHP. Intensywny treningAjax, JavaScript i PHP. Intensywny trening
Ajax, JavaScript i PHP. Intensywny trening
Wydawnictwo Helion
 
PowerPoint 2007 PL. Seria praktyk
PowerPoint 2007 PL. Seria praktykPowerPoint 2007 PL. Seria praktyk
PowerPoint 2007 PL. Seria praktyk
Wydawnictwo Helion
 
Excel 2007 PL. Seria praktyk
Excel 2007 PL. Seria praktykExcel 2007 PL. Seria praktyk
Excel 2007 PL. Seria praktyk
Wydawnictwo Helion
 
Access 2007 PL. Seria praktyk
Access 2007 PL. Seria praktykAccess 2007 PL. Seria praktyk
Access 2007 PL. Seria praktyk
Wydawnictwo Helion
 
Word 2007 PL. Seria praktyk
Word 2007 PL. Seria praktykWord 2007 PL. Seria praktyk
Word 2007 PL. Seria praktyk
Wydawnictwo Helion
 
Serwisy społecznościowe. Budowa, administracja i moderacja
Serwisy społecznościowe. Budowa, administracja i moderacjaSerwisy społecznościowe. Budowa, administracja i moderacja
Serwisy społecznościowe. Budowa, administracja i moderacja
Wydawnictwo Helion
 
AutoCAD 2008 i 2008 PL
AutoCAD 2008 i 2008 PLAutoCAD 2008 i 2008 PL
AutoCAD 2008 i 2008 PL
Wydawnictwo Helion
 
Bazy danych. Pierwsze starcie
Bazy danych. Pierwsze starcieBazy danych. Pierwsze starcie
Bazy danych. Pierwsze starcie
Wydawnictwo Helion
 
Inventor. Pierwsze kroki
Inventor. Pierwsze krokiInventor. Pierwsze kroki
Inventor. Pierwsze kroki
Wydawnictwo Helion
 

More from Wydawnictwo Helion (20)

Tworzenie filmów w Windows XP. Projekty
Tworzenie filmów w Windows XP. ProjektyTworzenie filmów w Windows XP. Projekty
Tworzenie filmów w Windows XP. Projekty
 
Blog, więcej niż internetowy pamiętnik
Blog, więcej niż internetowy pamiętnikBlog, więcej niż internetowy pamiętnik
Blog, więcej niż internetowy pamiętnik
 
Access w biurze i nie tylko
Access w biurze i nie tylkoAccess w biurze i nie tylko
Access w biurze i nie tylko
 
Pozycjonowanie i optymalizacja stron WWW. Ćwiczenia praktyczne
Pozycjonowanie i optymalizacja stron WWW. Ćwiczenia praktycznePozycjonowanie i optymalizacja stron WWW. Ćwiczenia praktyczne
Pozycjonowanie i optymalizacja stron WWW. Ćwiczenia praktyczne
 
E-wizerunek. Internet jako narzędzie kreowania image'u w biznesie
E-wizerunek. Internet jako narzędzie kreowania image'u w biznesieE-wizerunek. Internet jako narzędzie kreowania image'u w biznesie
E-wizerunek. Internet jako narzędzie kreowania image'u w biznesie
 
Microsoft Visual C++ 2008. Tworzenie aplikacji dla Windows
Microsoft Visual C++ 2008. Tworzenie aplikacji dla WindowsMicrosoft Visual C++ 2008. Tworzenie aplikacji dla Windows
Microsoft Visual C++ 2008. Tworzenie aplikacji dla Windows
 
Co potrafi Twój iPhone? Podręcznik użytkownika. Wydanie II
Co potrafi Twój iPhone? Podręcznik użytkownika. Wydanie IICo potrafi Twój iPhone? Podręcznik użytkownika. Wydanie II
Co potrafi Twój iPhone? Podręcznik użytkownika. Wydanie II
 
Makrofotografia. Magia szczegółu
Makrofotografia. Magia szczegółuMakrofotografia. Magia szczegółu
Makrofotografia. Magia szczegółu
 
Windows PowerShell. Podstawy
Windows PowerShell. PodstawyWindows PowerShell. Podstawy
Windows PowerShell. Podstawy
 
Java. Efektywne programowanie. Wydanie II
Java. Efektywne programowanie. Wydanie IIJava. Efektywne programowanie. Wydanie II
Java. Efektywne programowanie. Wydanie II
 
JavaScript. Pierwsze starcie
JavaScript. Pierwsze starcieJavaScript. Pierwsze starcie
JavaScript. Pierwsze starcie
 
Ajax, JavaScript i PHP. Intensywny trening
Ajax, JavaScript i PHP. Intensywny treningAjax, JavaScript i PHP. Intensywny trening
Ajax, JavaScript i PHP. Intensywny trening
 
PowerPoint 2007 PL. Seria praktyk
PowerPoint 2007 PL. Seria praktykPowerPoint 2007 PL. Seria praktyk
PowerPoint 2007 PL. Seria praktyk
 
Excel 2007 PL. Seria praktyk
Excel 2007 PL. Seria praktykExcel 2007 PL. Seria praktyk
Excel 2007 PL. Seria praktyk
 
Access 2007 PL. Seria praktyk
Access 2007 PL. Seria praktykAccess 2007 PL. Seria praktyk
Access 2007 PL. Seria praktyk
 
Word 2007 PL. Seria praktyk
Word 2007 PL. Seria praktykWord 2007 PL. Seria praktyk
Word 2007 PL. Seria praktyk
 
Serwisy społecznościowe. Budowa, administracja i moderacja
Serwisy społecznościowe. Budowa, administracja i moderacjaSerwisy społecznościowe. Budowa, administracja i moderacja
Serwisy społecznościowe. Budowa, administracja i moderacja
 
AutoCAD 2008 i 2008 PL
AutoCAD 2008 i 2008 PLAutoCAD 2008 i 2008 PL
AutoCAD 2008 i 2008 PL
 
Bazy danych. Pierwsze starcie
Bazy danych. Pierwsze starcieBazy danych. Pierwsze starcie
Bazy danych. Pierwsze starcie
 
Inventor. Pierwsze kroki
Inventor. Pierwsze krokiInventor. Pierwsze kroki
Inventor. Pierwsze kroki
 

C++. Algorytmy i struktury danych

  • 1. IDZ DO PRZYK£ADOWY ROZDZIA£ SPIS TRE CI C++. Algorytmy i struktury danych KATALOG KSI¥¯EK Autor: Adam Drozdek KATALOG ONLINE T³umaczenie: Piotr Rajca, Tomasz ¯mijewski ISBN: 83-7361-385-4 ZAMÓW DRUKOWANY KATALOG Tytu³ orygina³u: Data Structures and Algorithms in C++, Second Edition Format: B5, stron: 616 TWÓJ KOSZYK DODAJ DO KOSZYKA Badanie struktur danych, elementarnych sk³adników wykorzystywanych w informatyce, jest podstaw¹, w oparciu o któr¹ mo¿esz zdobywaæ cenne umiejêtno ci. Znajomo æ struktur danych jest niezbêdna studentom, którzy chc¹ programowaæ czy te¿ testowaæ CENNIK I INFORMACJE oprogramowanie. W niniejszej ksi¹¿ce zwrócono uwagê na trzy wa¿ne aspekty struktur danych: po ZAMÓW INFORMACJE pierwsze, na zwi¹zek struktur danych z algorytmami, miêdzy innymi na z³o¿ono æ O NOWO CIACH obliczeniow¹ algorytmów. Po drugie, struktury te prezentowane s¹ w sposób zgodny z zasadami projektowania obiektowego i obiektowym paradygmatem programowania. ZAMÓW CENNIK Po trzecie, wa¿n¹ czê ci¹ ksi¹¿ki s¹ implementacje struktur danych w jêzyku C++. Ksi¹¿ka prezentuje: CZYTELNIA • Podstawy projektowania obiektowego w C++ • Analizê z³o¿ono ci FRAGMENTY KSI¥¯EK ONLINE • Listy powi¹zane • Stosy i kolejki • Rekurencjê • Drzewa binarne • Sterty • Drzewa wielokrotne • Grafy • Sortowanie i mieszanie • Kompresja danych • Zarz¹dzanie pamiêci¹ Ksi¹¿ka ta dostarcza studentom informatyki nie tylko niezbêdnej wiedzy na temat algorytmów i struktur danych, ale prezentuje jednocze nie sposoby ich implementacji Wydawnictwo Helion w jêzyku C++, obecnie jednym z wiod¹cych jêzyków programowania. Dostarcza ona ul. Chopina 6 wiêc nie tylko wiedzy teoretycznej, ale równie¿ pozwala rozwin¹æ praktyczne 44-100 Gliwice umiejêtno ci przydatnych w przysz³ej pracy zawodowej. tel. (32)230-98-63 e-mail: helion@helion.pl
  • 2. Spis treści Wstęp .....................................................................................................................11 1. Programowanie obiektowe w C++ ........................................................................15 1.1. Abstrakcyjne typy danych ....................................................................................................................... 15 1.2. Enkapsulacja ............................................................................................................................................ 15 1.3. Dziedziczenie........................................................................................................................................... 19 1.4. Wskaźniki ................................................................................................................................................ 22 1.4.1. Wskaźniki a tablice ...................................................................................................................... 24 1.4.2. Wskaźniki a konstruktory kopiujące............................................................................................ 26 1.4.3. Wskaźniki i destruktory ............................................................................................................... 29 1.4.4. Wskaźniki a referencje................................................................................................................. 29 1.4.5. Wskaźniki na funkcje................................................................................................................... 32 1.5. Polimorfizm ............................................................................................................................................. 33 1.6. C++ a programowanie obiektowe............................................................................................................ 35 1.7. Standardowa biblioteka szablonów ......................................................................................................... 36 1.7.1. Kontenery..................................................................................................................................... 36 1.7.2. Iteratory........................................................................................................................................ 37 1.7.3. Algorytmy .................................................................................................................................... 37 1.7.4. Funktory....................................................................................................................................... 38 1.8. Wektory w standardowej bibliotece szablonów ...................................................................................... 40 1.9. Struktury danych a programowanie obiektowe ....................................................................................... 46 1.10. Przykład zastosowania: plik z dostępem swobodnym............................................................................. 47 1.11. Ćwiczenia ................................................................................................................................................ 56 1.12. Zadania programistyczne......................................................................................................................... 58 Bibliografia ............................................................................................................................................. 60 2. Analiza zło oności .................................................................................................61 2.1. Zło oność obliczeniowa i asymptotyczna ............................................................................................... 61 2.2. O-notacja.................................................................................................................................................. 62 2.3. Właściwości O-notacji............................................................................................................................. 64
  • 3. 6 SPIS TREŚCI 2.4. Notacje Ω i Θ........................................................................................................................................... 66 2.5. Mo liwe problemy................................................................................................................................... 67 2.6. Przykłady zło oności ............................................................................................................................... 67 2.7. Określanie zło oności asymptotycznej. Przykłady.................................................................................. 68 2.8. Zło oność optymistyczna, średnia i pesymistyczna ................................................................................ 71 2.9. Zło oność zamortyzowana ...................................................................................................................... 73 2.10. Ćwiczenia ................................................................................................................................................ 77 Bibliografia ............................................................................................................................................. 80 3. Listy .......................................................................................................................81 3.1. Listy jednokierunkowe ............................................................................................................................ 81 3.1.1. Wstawianie................................................................................................................................... 86 3.1.2. Usuwanie ..................................................................................................................................... 88 3.1.3. Wyszukiwanie.............................................................................................................................. 93 3.2. Listy dwukierunkowe .............................................................................................................................. 93 3.3. Listy cykliczne......................................................................................................................................... 97 3.4. Listy z przeskokami ................................................................................................................................. 99 3.5. Listy samoorganizujące się.................................................................................................................... 104 3.6. Tablice rzadkie....................................................................................................................................... 107 3.7. Listy w bibliotece STL .......................................................................................................................... 110 3.8. Kolejki dwustronne w bibliotece STL ................................................................................................... 113 3.9. Podsumowanie ....................................................................................................................................... 117 3.10. Przykład zastosowania. Biblioteka ........................................................................................................ 118 3.11. Ćwiczenia .............................................................................................................................................. 126 3.12. Zadania programistyczne....................................................................................................................... 128 Bibliografia ........................................................................................................................................... 131 4. Stosy i kolejki ......................................................................................................133 4.1. Stosy ...................................................................................................................................................... 133 4.2. Kolejki ................................................................................................................................................... 140 4.3. Kolejki priorytetowe .............................................................................................................................. 147 4.4. Stosy w bibliotece STL.......................................................................................................................... 148 4.5. Kolejki w bibliotece STL....................................................................................................................... 148 4.6. Kolejki priorytetowe w bibliotece STL ................................................................................................. 149 4.7. Przykład zastosowania. Szukanie wyjścia z labiryntu........................................................................... 152 4.8. Ćwiczenia .............................................................................................................................................. 156 4.9. Zadania programistyczne....................................................................................................................... 159 Bibliografia ........................................................................................................................................... 160 5. Rekurencja ...........................................................................................................161 5.1. Definicje rekurencyjne........................................................................................................................... 161 5.2. Wywołania funkcji a implementacja rekurencji .................................................................................... 164 5.3. Anatomia wywołania rekurencyjnego ................................................................................................... 165 5.4. Rekurencja ogonowa ............................................................................................................................. 169 5.5. Rekurencja inna ni ogonowa................................................................................................................ 170
  • 4. SPIS TREŚCI 7 5.6. Rekurencja pośrednia............................................................................................................................. 174 5.7. Rekurencja zagnie d ona ...................................................................................................................... 176 5.8. Nadu ywanie rekurencji ........................................................................................................................ 177 5.9. Algorytmy z powrotami......................................................................................................................... 180 5.10. Wnioski końcowe .................................................................................................................................. 186 5.11. Przykład zastosowania. Rekurencyjny interpreter................................................................................. 187 5.12. Ćwiczenia .............................................................................................................................................. 194 5.13. Zadania programistyczne....................................................................................................................... 197 Bibliografia ........................................................................................................................................... 199 6. Drzewa binarne ....................................................................................................201 6.1. Drzewa, drzewa binarne i binarne drzewa poszukiwania...................................................................... 201 6.2. Implementacja drzew binarnych............................................................................................................ 205 6.3. Wyszukiwanie w drzewie binarnym...................................................................................................... 207 6.4. Przechodzenie po drzewie ..................................................................................................................... 210 6.4.1. Przechodzenie wszerz ................................................................................................................ 210 6.4.2. Przechodzenie w głąb ................................................................................................................ 211 6.4.3. Przechodzenie po drzewie w głąb bez stosu .............................................................................. 217 6.5. Wstawianie ............................................................................................................................................ 223 6.6. Usuwanie ............................................................................................................................................... 225 6.6.1. Usuwanie przez złączanie .......................................................................................................... 226 6.6.2. Usuwanie przez kopiowanie ...................................................................................................... 229 6.7. Równowa enie drzewa .......................................................................................................................... 231 6.7.1. Algorytm DSW .......................................................................................................................... 234 6.7.2. Drzewa AVL.............................................................................................................................. 236 6.8. Drzewa samoorganizujące się................................................................................................................ 241 6.8.1. Drzewa samonaprawiające się ................................................................................................... 241 6.8.2. Ukosowanie ............................................................................................................................... 243 6.9. Sterty...................................................................................................................................................... 247 6.9.1. Sterty jako kolejki priorytetowe................................................................................................. 249 6.9.2. Organizowanie tablic w sterty ................................................................................................... 251 6.10. Notacja polska i drzewa wyra eń .......................................................................................................... 255 6.10.1. Operacje na drzewach wyra eń ................................................................................................. 256 6.11. Przykład zastosowania. Zliczanie częstości występowania słów .......................................................... 259 6.12. Ćwiczenia .............................................................................................................................................. 265 6.13. Zadania programistyczne....................................................................................................................... 268 Bibliografia ........................................................................................................................................... 272 7. Drzewa wielokierunkowe ....................................................................................275 7.1. Rodzina B-drzew ................................................................................................................................... 276 7.1.1. B-drzewa .................................................................................................................................... 277 7.1.2. B*-drzewa .................................................................................................................................. 286 7.1.3. B+-drzewa.................................................................................................................................. 288 7.1.4. B+-drzewa przedrostkowe ......................................................................................................... 289 7.1.5. Drzewa bitowe ........................................................................................................................... 291 7.1.6. R-drzewa .................................................................................................................................... 294 7.1.7. 2-4-drzewa ................................................................................................................................. 296 7.1.8. Zbiory i wielozbiory w bibliotece STL...................................................................................... 303 7.1.9. Mapy i multimapy w bibliotece STL ......................................................................................... 309
  • 5. 8 SPIS TREŚCI 7.2. Drzewa słownikowe............................................................................................................................... 313 7.3. Uwagi końcowe ..................................................................................................................................... 321 7.4. Przykład zastosowania. Sprawdzanie pisowni ...................................................................................... 321 7.5. Ćwiczenia .............................................................................................................................................. 330 7.6. Zadania programistyczne....................................................................................................................... 331 Bibliografia ........................................................................................................................................... 334 8. Grafy ....................................................................................................................337 8.1. Reprezentacje grafów ............................................................................................................................. 338 8.2. Przechodzenie po grafach....................................................................................................................... 340 8.3. Najkrótsza droga .................................................................................................................................... 344 8.3.1. Problem najkrótszych dróg typu „wszystkie-do-wszystkich” ................................................... 351 8.4. Wykrywanie cykli .................................................................................................................................. 353 8.4.1. Problem znajdowania sumy zbiorów rozłącznych..................................................................... 354 8.5. Drzewa rozpinające ................................................................................................................................ 356 8.5.1. Algorytm Borůvki...................................................................................................................... 357 8.5.2. Algorytm Kruskala .................................................................................................................... 358 8.5.3. Algorytm Jarníka-Prima ............................................................................................................ 360 8.5.4. Metoda Dijkstry ......................................................................................................................... 361 8.6. Spójność ................................................................................................................................................. 361 8.6.1. Spójność w grafach nieskierowanych........................................................................................ 361 8.6.2. Spójność w grafach skierowanych............................................................................................. 364 8.7. Sortowanie topologiczne ........................................................................................................................ 365 8.8. Sieci ........................................................................................................................................................ 368 8.8.1. Przepływy maksymalne ............................................................................................................. 368 8.8.2. Maksymalne przepływy o minimalnym koszcie........................................................................ 378 8.9. Kojarzenie .............................................................................................................................................. 383 8.9.1. Problem przypisania................................................................................................................... 387 8.9.2. Skojarzenia w grafach, które nie są dwudzielne........................................................................ 390 8.10. Grafy eulerowskie i hamiltonowskie...................................................................................................... 392 8.10.1. Grafy eulerowskie...................................................................................................................... 392 8.10.2. Grafy hamiltonowskie................................................................................................................ 393 8.11. Przykład zastosowania. Unikalni reprezentanci..................................................................................... 396 8.12. Ćwiczenia ............................................................................................................................................... 406 8.13. Zadania programistyczne ....................................................................................................................... 409 Bibliografia ........................................................................................................................................... 411 9. Sortowanie ...........................................................................................................413 9.1. Podstawowe algorytmy sortowania ....................................................................................................... 414 9.1.1. Sortowanie przez wstawianie..................................................................................................... 414 9.1.2. Sortowanie przez wybieranie..................................................................................................... 417 9.1.3. Sortowanie bąbelkowe ............................................................................................................... 419 9.2. Drzewa decyzyjne.................................................................................................................................. 422 9.3. Efektywne algorytmy sortowania .......................................................................................................... 425 9.3.1. Sortowanie Shella ...................................................................................................................... 425 9.3.2. Sortowanie przez kopcowanie ................................................................................................... 429 9.3.3. Sortowanie szybkie (quicksort).................................................................................................. 433 9.3.4. Sortowanie poprzez scalanie...................................................................................................... 440 9.3.5. Sortowanie pozycyjne................................................................................................................ 443
  • 6. SPIS TREŚCI 9 9.4. Sortowanie przy wykorzystaniu STL .................................................................................................... 448 9.5. Uwagi końcowe ..................................................................................................................................... 452 9.6. Przykład zastosowania. Dodawanie wielomianów................................................................................ 452 9.7. Ćwiczenia .............................................................................................................................................. 459 9.8. Zadania programistyczne....................................................................................................................... 461 Bibliografia ........................................................................................................................................... 463 10. Mieszanie .............................................................................................................465 10.1. Funkcje mieszające ................................................................................................................................ 466 10.1.1. Dzielenie .................................................................................................................................... 466 10.1.2. Składanie.................................................................................................................................... 466 10.1.3. Funkcja „środek kwadratu” ....................................................................................................... 467 10.1.4. Wycinanie .................................................................................................................................. 468 10.1.5. Zmiana podstawy....................................................................................................................... 468 10.2. Rozwiązywanie problemu kolizji .......................................................................................................... 468 10.2.1. Adresowanie otwarte ................................................................................................................. 469 10.2.2. Metoda łańcuchowa ................................................................................................................... 475 10.2.3. Adresowanie kubełkowe............................................................................................................ 476 10.3. Usuwanie ............................................................................................................................................... 477 10.4. Doskonałe funkcje mieszające............................................................................................................... 479 10.4.1. Metoda Cichelliego.................................................................................................................... 479 10.4.2. Algorytm FHCD ........................................................................................................................ 482 10.5. Funkcje mieszające dla plików rozszerzalnych ..................................................................................... 484 10.5.1. Mieszanie przedłu alne.............................................................................................................. 485 10.5.2. Mieszanie liniowe ...................................................................................................................... 487 10.6. Przykład zastosowania. Mieszanie z u yciem kubełków ...................................................................... 490 10.7. Ćwiczenia .............................................................................................................................................. 498 10.8. Zadania programistyczne....................................................................................................................... 500 Bibliografia ........................................................................................................................................... 501 11. Kompresja danych ...............................................................................................503 11.1. Warunki kompresji danych.................................................................................................................... 503 11.2. Kodowanie Huffmana............................................................................................................................ 505 11.2.1. Adaptacyjne kodowanie Huffmana ........................................................................................... 514 11.3. Metoda Shannona-Fano ......................................................................................................................... 519 11.4. Kodowanie długości serii ...................................................................................................................... 520 11.5. Metoda Ziva-Lempela ........................................................................................................................... 521 11.6. Przykład zastosowania. Metoda Huffmana z kodowaniem długości serii ............................................ 524 11.7. Ćwiczenia .............................................................................................................................................. 535 11.8. Zadania programistyczne....................................................................................................................... 536 Bibliografia ........................................................................................................................................... 537 12. Zarządzanie pamięcią ..........................................................................................539 12.1. Metody dopasowywania sekwencyjnego .............................................................................................. 540 12.2. Metody niesekwencyjne ........................................................................................................................ 542 12.2.1. System bliźniaków..................................................................................................................... 543
  • 7. 10 SPIS TREŚCI 12.3. Odśmiecanie .......................................................................................................................................... 551 12.3.1. Metoda „zaznacz-i-zamiataj”..................................................................................................... 551 12.3.2. Metody kopiowania ................................................................................................................... 559 12.3.3. Krokowe metody odśmiecania................................................................................................... 560 12.4. Uwagi końcowe ..................................................................................................................................... 567 12.5. Przykład zastosowania. Odśmiecanie „w miejscu” ............................................................................... 568 12.6. Ćwiczenia .............................................................................................................................................. 576 12.7. Zadania programistyczne....................................................................................................................... 577 Bibliografia ........................................................................................................................................... 579 A Obliczanie zło oności ..........................................................................................583 A.1. Szereg harmoniczny............................................................................................................................... 583 A.2. Przybli enie funkcji lg(n!) ..................................................................................................................... 583 A.3. Przybli ona średnia zło oność sortowania szybkiego ........................................................................... 585 A.4. Średnia długość ście ki w losowych drzewach binarnych .................................................................... 587 B Algorytmy dostępne w STL.................................................................................589 B.1. Algorytmy standardowe......................................................................................................................... 589 Skorowidz ............................................................................................................597
  • 8. 1 Programowanie obiektowe w C++ 1.1. Abstrakcyjne typy danych Przed napisaniem jakiegokolwiek programu trzeba wiedzieć dość dokładnie, jak powinno być re- alizowane zadanie wykonywane przez ten program. Wobec tego przed początkiem kodowania powinien powstać szkic programu opisujący wszystkie wymagania. Im większy i bardziej zło ony jest projekt, tym bardziej szczegółowy powinien być ten szkic. Szczegóły implementacyjne po- winny zostać odło one do późniejszego etapu prac. W szczególności na później powinny zostać odło one wszelkie szczegółowe ustalenia dotyczące struktur danych nieokreślone na samym początku. Od samego początku trzeba określić ka de zadanie za pomocą jego danych wejściowych i wyjściowych. Na wstępie bardziej powinno nas interesować to, co program ma robić, a nie jak ma to robić. Zachowanie się programu jest wa niejsze od tego, dlaczego program tak właśnie działa. Jeśli, na przykład, realizacja pewnego zadania wymaga jakiegoś narzędzia, narzędzie to opisuje się jako zestaw mo liwych operacji, a nie podaje się jego wewnętrznej struktury. Operacje takie mogą modyfikować narzędzie, wyszukiwać dotyczące go szczegóły lub zapisywać w nim dodatkowe dane. Kiedy wszystkie te operacje zostaną dokładnie opisane, mo na rozpocząć kodo- wanie. Na tym etapie decyduje się o tym, które struktury danych będą najlepsze z punktu widzenia czasu wykonania i zajętości pamięci. Takie narzędzie opisane przez jego operacje nazywamy abs- trakcyjnym typem danych. Abstrakcyjny typ danych nie jest częścią programu, gdy program napi- sany w pewnym języku programowania wymaga zdefiniowania struktury danych, a nie tylko ope- racji na tej strukturze. Jednak języki obiektowe, takie jak C++, bezpośrednio wią ą abstrakcyjne typy danych z kodem w formie klas. 1.2. Enkapsulacja Programowanie obiektowe obraca się wokół pojęcia obiektu. Obiekty tworzone są zgodnie z defi- nicją klasy. Klasa to szablon, według którego tworzy się obiekty. Klasa to fragment kodu, który zawiera opis danych oraz funkcje przetwarzające te dane i, ewentualnie, tak e dane z innych klas. Funkcje definiowane w ramach klasy nazywamy metodami lub funkcjami składowymi, zaś zmienne u ywane w klasach to dane składowe lub po prostu pola. Takie łączenie danych i związanych z nimi operacji nazywamy enkapsulacją danych. Obiekt to instancja klasy — coś, co jest tworzone zgodnie z definicją tej klasy.
  • 9. 16 1. PROGRAMOWANIE OBIEKTOWE W C++ W przeciwieństwie do funkcji z języków nieobiektowych, w obiektach połączenie między danymi a metodami jest ścisłe i ma istotne znaczenie. W językach nieobiektowych deklaracje da- nych i definicje funkcji mogą przeplatać się w całym programie, a jedynie z dokumentacji wynika, jak dane z funkcjami są powiązane. W językach obiektowych związek ten jest ustalany ju na wstępie; cała struktura programu opiera się na tym powiązaniu. Obiekt jest opisany przez powią- zane dane i operacje, a jako e w tym samym programie u ywanych mo e być wiele obiektów, obiekty komunikują się, wymieniając komunikaty, które o ich strukturze wewnętrznej mówią tylko tyle, ile jest niezbędne. Podział programu na obiekty pozwala osiągnąć kilka celów. Po pierwsze, silnie powiązane dane i operacje mogą znacznie lepiej opisywać modelowany fragment świata, co jest szczególnie istotne w przypadku in ynierii oprogramowania. Nie powinno zaskakiwać, e programowanie obiektowe ma swoje korzenie w symulacjach, czyli modelowaniu rzeczywistych obiektów. Pierwszym językiem obiektowym była Simula, która powstała w latach 60-tych w Norwegii. Po drugie, u ycie obiektów ułatwia szukanie błędów, gdy operacje są wiązane od razu ze „swoimi” obiektami. Nawet jeśli pojawiają się efekty uboczne, łatwiej jest je wyśledzić. Po trzecie, u ycie obiektów pozwala ukryć pewne szczegóły operacji przed innymi obiekta- mi, dzięki czemu operacje te nie ulegają tak łatwo zmianom w przypadku zmieniania innych obiektów. Jest to zasada ukrywania informacji. W językach nieobiektowych zasada ta w pewnym zakresie jest realizowana przez stosowanie zmiennych lokalnych, a (na przykład w Pascalu) tak e przez stosowanie lokalnych funkcji i procedur, które są dostępne jedynie w funkcjach je zawiera- jących. Jednak jest to zawsze albo bardzo dokładne ukrywanie, albo ukrywania nie ma w ogóle. Czasami (na przykład w Pascalu) funkcja f2 zdefiniowana w f1 mo e być potrzebna poza f1, ale poza f1 jest ona całkowicie niewidoczna. Czasami potrzebne jest sięgnięcie do pewnych danych lokalnych f1 bez dokładnej znajomości struktury tych danych, ale to te jest niemo liwe. Dlatego te w programowaniu obiektowym nieco zmieniają się zasady dostępności danych. U ytkowników interesuje działanie zegarka, ale jego budowa wewnętrzna nie ma ju znacze- nia. Wiadomo, e wewnątrz są tryby i sprę yny, ale zwykle niewiele wiadomo o sposobie ich działania, wobec czego dostęp do nich jest zbędny, gdy mógłby prowadzić do uszkodzenia me- chanizmu. Mechanizm jest przed u ytkownikiem ukryty, nie ma do niego bezpośredniego dostępu, dzięki czemu zegarek nie jest nara ony na zniszczenie bardziej, ni gdyby mechanizm był cały czas otwarty. Obiekt to czarna skrzynka o dokładnie opisanym działaniu; obiektu u ywa się dlatego, e wiadomo, co on robi, ale nie ma się dostępu do jego wnętrza. Owa nieprzezroczystość obiektów jest wyjątkowo przydatna do serwisowania jednych obiektów niezale nie od innych. Jeśli dobrze zo- staną określone kanały komunikacyjne między obiektami, zmiany w jednym obiekcie będą wpły- wały na inne obiekty tylko wtedy, gdy będą dotyczyły tych kanałów. Wiedząc, jakie informacje są wysyłane i odbierane przez obiekt, mo na łatwiej zastąpić jeden obiekt innym — nowy obiekt mo- e realizować te same zadania inaczej, na przykład szybciej w danym środowisku. Obiekt ujawnia tylko tyle informacji o sobie, ile jest potrzebnych u ytkownikowi, aby tego obiektu u yć. Obiekt ma część publiczną, która jest dostępna dla wszystkich, którzy prześlą do obiektu komunikat w formie jednej z funkcji przez obiekt udostępnianych. Do części publicznej nale ą przyciski po- kazywane u ytkownikowi; wciśnięcie ka dego z tych przycisków powoduje wykonanie operacji obiektu. U ytkownik zna jedynie nazwy operacji i wie, co te operacje robią. Ukrywanie informacji prowadzi do zacierania się rozgraniczenia między danymi a operacjami. W językach programowania takich jak Pascal podział na dane i funkcje jest prosty i stały. Inaczej definiuje się jedne i drugie, inne jest ich zastosowanie. W programowaniu obiektowym dane i metody są zestawione razem, zaś dla u ytkownika obiektu podział jest znacznie mniej wyraźny.
  • 10. 1.2. ENKAPSULACJA 17 W pewnym zakresie jest to te cecha języków funkcyjnych. LISP, jeden z najstarszych języków programowania, pozwala traktować dane i funkcje tak samo, gdy struktura jednych i drugich jest identyczna. Dokonaliśmy ju podziału między konkretne obiekty a typy obiektów czyli klasy. Funkcje pi- szemy tak, aby u ywały ró nych zmiennych, nie chcemy jednak być zmuszani do zapisywania tylu deklaracji obiektów, ilu obiektów potrzebujemy w całym programie. Pewne obiekty są tego samego typu i chcielibyśmy u ywać pojedynczego typu jako ogólnej definicji takiego typu. W przypadku pojedynczych zmiennych odró niamy deklarację typu od deklaracji zmiennej. W przypadku obiektów mamy deklarację klasy i deklarację obiektu. Poni ej pokazano przykład klasy % i obiek- tów QDLGEV, QDLGEV i QDLGEV: ENCUU % ] RWDNKE % EJCT
  • 11. U KPV K FQWDNG F ] UVTER[ FCVC/GODGTU FCVC/GODGT K FCVC/GODGT F _ XQKF OGODGT(WPEVKQP ] EQWV FCVC/GODGT FCVC/GODGT FCVC/GODGT GPFN _ XQKF OGODGT(WPEVKQP KPV K EJCT
  • 12. U PKGPCPC ] FCVC/GODGT K EQWV K RQDTCPC U GPFN _ RTQVGEVGF EJCT FCVC/GODGT=? KPV FCVC/GODGT FQWDNG FCVC/GODGT _ % QDLGEV QDKGMV QDLGEV QDKGMV QDLGEV Przekazywanie komunikatów jest odpowiednikiem wywoływania funkcji w tradycyjnych ję- zykach programowania, jednak wa ne jest, e w przypadku programowania obiektowego metody są powiązane z obiektami — stąd właśnie u ywany jest nowy termin. Przykładowo, wywołanie publicznej metody OGODGT(WPEVKQP obiektu QDLGEV: QDLGEVOGODGT(WPEVKQP jest widziane jako wysłanie do obiektu QDLGEV komunikatu OGODGT(WPEVKQP . Po otrzymaniu takiego komunikatu obiekt wywołuje swoją metodę i wyświetla wszystkie odpowiednie w danej sytuacji informacje. Komunikaty mogą zawierać parametry: QDLGEVOGODGT(WPEVKQP Powy szy zapis to wywołanie komunikatu OGODGT(WPEVKQP obiektu QDLGEV z parametrem .
  • 13. 18 1. PROGRAMOWANIE OBIEKTOWE W C++ Wiersze zawierające takie komunikaty mogą być umieszczone albo w głównym programie, albo w funkcji, albo w metodzie innego obiektu. Wobec tego odbiorca komunikatu mo e zostać zidentyfikowany, ale nie dotyczy to wywołującego. Jeśli QDLGEV otrzyma komunikat OGODGT(WPE VKQP , nie wie, skąd ten komunikat pochodzi. Odpowiada na komunikat, pokazując dane za- kodowane w metodzie OGODGT(WPEVKQP , to samo dotyczy metody OGODGT(WPEVKQP . Wobec tego nadawca komunikatu mo e do komunikatu dołączyć informacje umo liwiające jego zi- dentyfikowanie: QDLGEVOGODGT(WPEVKQP QDKGMV Istotną cechą C++ jest mo liwość deklarowania ogólnych klas dzięki u yciu parametrów typu w deklaracji klasy. Jeśli, na przykład, trzeba zadeklarować klasę, która będzie coś przechowywała w tablicy, mo na zadeklarować ją następująco: ENCUU KPV%NCUU ] KPV UVQTCIG=? _ jednak w ten sposób ogranicza się przydatność takiej klasy jedynie do liczb całkowitych; jeśli po- trzebna będzie analogiczna klasa z liczbami zmiennoprzecinkowymi, konieczna będzie nowa de- klaracja: ENCUU HNQCV%NCUU ] HNQCV UVQTCIG=? _ Jeśli UVQTCIG ma zawierać struktury lub wskaźniki do znaków, konieczne byłoby zadeklaro- wanie kolejnych dwóch klas. Znacznie lepiej byłoby zadeklarować ogólną klasę i dopiero podczas definiowania obiektów decydować, jakiego typu dane będą w obiekcie przechowywane. Język C++ umo liwia takie deklarowanie klasy, na przykład: VGORNCVGENCUU IGP6[RG ENCUU IGP%NCUU ] IGP6[RG UVQTCIG=? _ Dopiero potem decydujemy, jak inicjalizowany będzie typ IGP6[RG: IGP%NCUUKPV KPV1DLGEV IGP%NCUUHNQCV HNQCV1DLGEV Taka klasa ogólna przybiera ró ne postacie w zale ności od konkretnej deklaracji. Jedna ogólna deklaracja mo e udostępnić wszystkie te postacie. Mo emy pójść jeszcze dalej i decyzję o wielkości bufora, obecnie 50 komórek, odło yć na później, do czasu tworzenia obiektu. Jednak na wszelki wypadek mo emy te zostawić wartość domyślną:
  • 14. 1.3. DZIEDZICZENIE 19 VGORNCVGENCUU IGP6[RG KPV UKG ENCUU IGP%NCUU ] IGP6[RG UVQTCIG=UKG? _ Definicje obiektów będą teraz wyglądały następująco: IGP%NCUUKPV KPV1DLGEV W [V[ QUVCPKG TQOKCT FQO[ NP[ IGP%NCUUKPV KPV1DLGEV IGP%NCUUHNQCV HNQCV1DLGEV Pokazana metoda u ywania typów ogólnych nie ogranicza się jedynie do klas; mo na u ywać jej te w deklaracjach funkcji. Przykładowo, standardowa operacja zamiany miejscami dwóch wartości mo e być zdefiniowana następująco: VGORNCVGENCUU IGP6[RG XQKF UYCR IGV6[RG GN IGP6[RG GN ] IGP6[RG VOR GN GN GN GN VOR _ Przykład ten pokazuje konieczność dostosowania operatorów wbudowanych do konkretnych sytuacji. Jeśli IGP6[RG jest liczbą, znakiem lub strukturą, operator przypisania zadziała prawidło- wo. Jeśli jednak IGP6[RG jest tablicą, nale y się spodziewać kłopotów ze strony funkcji UYCR . Problem ten mo na rozwiązać, przecią ając operator przypisania tak, aby rozszerzyć jego mo li- wości w stosunku do określonych typów danych. Po zadeklarowaniu funkcji ogólnej w czasie kompilacji programu mo na wygenerować kon- kretne funkcje. Jeśli, na przykład, kompilator „zobaczy” następujące dwa wywołania: UYCR PO COKCPC FYÎEJ NKED EC MQYKV[EJ UYCR Z[ COKCPC FYÎEJ NKED OKGPPQRTGEKPMQY[EJ wygeneruje dwie funkcje UYCR , które będą u ywane w programie. 1.3. Dziedziczenie Programowanie obiektowe pozwala tworzyć własne hierarchie klas tak, e obiekty nie muszą nale- eć tylko do pojedynczych klas. Zanim przejdziemy do omówienia dziedziczenia, przyjrzyjmy się następującym definicjom klas: ENCUU $CUG%NCUU ] RWDNKE $CUG%NCUU ] _ XQKF H EJCT
  • 15. U PKGPCP[ ] EQWV (WPMELC H Y $CUG%NCUU Y[YQ CPC U GPFN J _
  • 16. 20 1. PROGRAMOWANIE OBIEKTOWE W C++ RTQVGEVGF XQKF I EJCT
  • 17. U PKGPCP[ ] EQWV (WPMELC I Y $CUG%NCUU Y[YQ CPC U GPFN _ RTKXCVG XQKF J ] EQWV (WPMELC J Y $CUG%NCUUP _ _ ENCUU GTKXGF.GXGN RWDNKE XKTVWCN $CUG%NCUU ] RWDNKE XQKF H EJCT
  • 18. U PKGPCP[ ] EQWV (WPMELC H Y GTKXGF.GXGN Y[YQ CPC U GPFN I GTKXGF.GXGN J GTKXGF.GXGN _ XQKF J EJCT
  • 19. U PKGPCPC ] EQWV (WPMELC J Y GTKXGF.GXGN Y[YQ CPC U GPFN _ _ ENCUU GTKXGF.GXGN RWDNKE XKTVWCN $CUG%NCUU ] RWDNKE XQKF H EJCT
  • 20. U PKGPCP[ ] EQWV (WPMELC H Y GTKXGF.GXGN Y[YQ CPC U GPFN I GTKXGF.GXGN J D æF $CUG%NCUUJ PKG LGUV FQUVúRPC _ _ ENCUU GTKXGF.GXGN RWDNKE GTKXGF.GXGN RWDNKE GTKXGF.GXGN ] RWDNKE XQKF H EJCT
  • 21. U PKGPCP[ ] EQWV (WPMELC H Y GTKXGF.GXGN Y[YQ CPC U GPFN I GTKXGF.GXGN GTKXGF.GXGNJ GTKXGF.GXGN $CUG%NCUUH GTKXGF.GXGN _ _ A oto przykładowy program: KPV OCKP ] $CUG%NCUU DE GTKXGF.GXGN FN GTKXGF.GXGN FN GTKXGF.GXGN FN DEH OCKP DEI D æF $CUG%NCUUI LGUV PKGFQUVúRPC DEJ D æF $CUG%NCUUJ LGUV PKGFQUVúRPC FNH OCKP FNI D æF $CUG%NCUUI LGUV PKGFQUVúRPC FNJ OCKP FNH OCKP
  • 22. 1.3. DZIEDZICZENIE 21 FNI D æF $CUG%NCUUI LGUV PKGFQUVúRPC FNJ D æF $CUG%NCUUJ LGUV PKGFQUVúRPC FNH OCKP FNI D æF $CUG%NCUUI LGUV PKGFQUVúRPC FNJ TGVWTP _ Program powy szy da następujące wyniki: (WPMELC H Y $CUG%NCUU Y[YQ CPC OCKP (WPMELC J Y $CUG%NCUU (WPMELC H Y GTKXGF.GXGN Y[YQ CPC OCKP (WPMELC I Y $CUG%NCUU Y[YQ CPC GTKXGF.GXGN (WPMELC J Y GTKXGF.GXGN Y[YQ CPC GTKXGF.GXGN (WPMELC J Y GTKXGF.GXGN Y[YQ CPC OCKP (WPMELC H Y GTKXGF.GXGN Y[YQ CPC OCKP (WPMELC I Y $CUG%NCUU Y[YQ CPC GTKXGF.GXGN (WPMELC H Y GTKXGF.GXGN Y[YQ CPC OCKP (WPMELC I Y $CUG%NCUU Y[YQ CPC GTKXGF.GXGN (WPMELC J Y GTKXGF.GXGN Y[YQ CPC GTKXGF.GXGN (WPMELC H Y $CUG%NCUU Y[YQ CPC GTKXGF.GXGN (WPMELC J Y $CUG%NCUU (WPMELC J Y GTKXGF.GXGN Y[YQ CPC PKGPCP[ Klasa $CUG%NCUU jest nazywana klasą bazową, zaś pozostałe klasy to klasy pochodne, gdy po- chodzą od klasy bazowej w tym sensie, e mogą korzystać z pól i metod $CUG%NCUU oznaczonych jako chronione (słowo kluczowe RTQVGEVGF) lub publiczne (RWDNKE). Klasy te dziedziczą wszystkie takie pola po klasie bazowej, dzięki czemu zbędne jest powtarzanie w nich tych samych definicji. Jednak klasa pochodna mo e przykryć definicję z klasy bazowej, podając własną definicję tej samej składowej. W ten sposób zarówno klasa bazowa, jak i klasy pochodne mogą zapanować nad swoimi składowymi. Klasa bazowa mo e decydować, które metody i które pola mogą zostać ujawnione klasom pochodnym, wobec czego zasada ukrywania informacji jest zachowana nie tylko względem u ytkow- ników klasy bazowej, ale tak e klas pochodnych. Co więcej, klasa pochodna mo e zdecydować, które części metod i pól publicznych i chronionych zostaną zachowane, a które będą modyfikowane. Przykładowo, w obu klasach pochodnych pierwszego poziomu, GTKXGF.GXGN i GTKXGF.GXGN, zdefiniowane są lokalne wersje metody H . Jednak nadal mo na skorzystać z tak samo nazwanej metody z wy szych poziomów hierarchii; w tym celu nazwę metody nale y poprzedzić nazwą klasy i operatorem zakresu, jak pokazano to w przypadku wywołania $CUG%NCUUH z metody H w klasie GTKXGF.GXGN. Klasa pochodna sama te mo e zawierać dodatkowe pola danych. Klasa taka mo e stać się z kolei klasą bazową dla innej klasy i tak dalej; hierarchię dziedziczenia mo na dowolnie rozsze- rzać. Przykładowo, klasa GTKXGF.GXGN pochodzi od $CUG%NCUU, ale jednocześnie jest klasą bazową dla GTKXGF.GXGN. W pokazanych przykładach dziedziczenie jest publiczne — po dwukropku w nagłówku defi- nicji klasy pochodnej występuje słowo RWDNKE. Dziedziczenie publiczne oznacza, e pola publicz- ne klasy bazowej będą w klasie pochodnej tak e publiczne, zaś chronione te będą chronione. W przypadku dziedziczenia chronionego (w nagłówku klasy po dwukropku pojawia się słowo klu- czowe RTQVGEVGF) pola i metody publiczne i chronione klasy bazowej w klasie pochodnej będą chronione. W końcu, jeśli dziedziczenie jest prywatne (słowo kluczowe RTKXCVG), pola publiczne i chronione klasy bazowej stają się prywatnymi polami klasy pochodnej. We wszystkich rodzajach
  • 23. 22 1. PROGRAMOWANIE OBIEKTOWE W C++ dziedziczenia metody i pola prywatne klasy bazowej we wszystkich klasach pochodnych są niedo- stępne. Przykładowo, próba wywołania J z metody H w klasie GTKXGF.GXGN powoduje błąd kompilacji „$CUG%NCUUJ is not accessible”. Jednak wywołanie z H metody J w klasie G TKXGF.GXGN nie sprawia adnych kłopotów, gdy jest ono interpretowane jako wywołanie metody J zdefiniowanej w klasie GTKXGF.GXGN. Pola i metody chronione klasy bazowej dostępne są jedynie dla klasy pochodnej tej klasy. Z tego powodu klasy GTKXGF.GXGN i GTKXGF.GXGN mogą wywołać metodę chronioną I klasy $CUG%NCUU , ale wywołanie tej metody w funkcji OCKP jest ju niedopuszczalne. Klasa pochodna nie musi pochodzić od jednej tylko klasy bazowej. Przykładowo, klasa G TKXGF.GXGN pochodzi od klas GTKXGF.GXGN i GTKXGF.GXGN, dziedzicząc w ten sposób wszystkie metody obu tych klas. GTKXGF.GXGN dziedziczy jednak te same metody z $CUG%NCUU dwukrotnie, gdy obie klasy pochodne poziomu pierwszego pochodzą od klasy $CUG%NCUU. Jest to w najlep- szym razie nadmiarowe i jako takie zbędne, a w najgorszym razie mo e spowodować błąd kompi- lacji „member is ambiguous $CUG%NCUUI and $CUG%NCUUI ”. Aby to się nie zdarzyło, definicje obu klas bazowych zawierają modyfikator XKTVWCN, który oznacza, e klasa GTKXGF.GXGN zawiera jedną tylko kopię ka dej metody klasy $CUG%NCUU. Analogiczny problem pojawi się, jeśli H z G TKXGF.GXGN wywoła J bez podania operatora zakresu i nazwy klasy, tutaj GTKXGF.GXGNJ . Nie ma znaczenia fakt, e metoda J w $CUG%NCUU jest prywatna i przez to niedostępna w GTKXG F.GXGN — opisana sytuacja spowodowałaby wystąpienie błędu „member is ambiguous GTKXG F.GXGNJ and $CUG%NCUUJ ”. 1.4. Wskaźniki Zmienne u ywane w programie mo na traktować jako pojemniki, które nigdy nie są puste — zawsze coś jest w środku, albo wstawione przez programistę, albo, w przypadku braku inicjalizacji, przez system operacyjny. Ka da taka zmienna ma co najmniej dwa atrybuty: zawartość czyli wartość oraz poło enie pojemnika w pamięci komputera. Zawartość mo e być liczbą, znakiem lub wielko- ścią zło oną, jak struktura czy unia. Jednak wartość ta mo e być te poło eniem innej zmiennej; zmienna z taką wartością nazywane są wskaźnikami. Wskaźniki to zwykle zmienne pomocnicze, które umo liwiają nam pośrednie sięganie do innych wartości. Wskaźnik jest analogią do znaku drogowego, który wskazuje pewne miejsce, lub fiszki, na której zanotowano adres. Są to zmienne prowadzące do zmiennych; pomocnicze zmienne wskazujące wartości, które są naprawdę istotne. Jeśli mamy następującą deklarację: KPV K L
  • 24. R
  • 25. S K i L są zmiennymi liczbowymi, zaś R i S są wskaźnikami na te zmienne liczbowe; o ich roli decy- duje poprzedzająca je gwiazdka. Zakładając, e adresy zmiennych K, L, R i S to, odpowiednio, 1080, 1082, 1084 i 1086, po przypisaniu zmiennej K wartości 15, uzyskamy w pamięci komputera obraz taki, jak na rysunku 1.1a. Moglibyśmy teraz wykonać przypisanie R K (lub R KPV
  • 26. K, gdyby kompilator nie chciał uznać pierwszej wersji), ale zmienna R została stworzona po to, aby przechowywać adres zmiennej liczbowej, a nie jej wartość. Wobec tego prawidłowe przypisanie to R K, gdzie symbol wystę- pujący przed K oznacza, e chodzi o adres zmiennej K, a nie o jej wartość. Pokazano to na rysunku 1.1b. Na rysunku 1.1c strzałka z R do K wskazuje, e R jest wskaźnikiem zawierającym adres K.
  • 27. 1.4. WSKAŹNIKI 23 RYSUNEK 1.1. Zmiany wartości po przypisaniach realizowane są przy u yciu wskaźników. Przypadki (b) i (c) opisują tę samą sytuację, tak samo (d) i (e), (g) i (h), (i) i (j), (k) i (l) oraz (m) i (n) Musimy być w stanie odró niać wartość R — adres — od wartości umieszczonej pod tym adre- sem. Aby na przykład przypisać wartość 20 zmiennej wskazywanej przez R trzeba u yć wyra enia:
  • 28. R Gwiazdka to operator dereferencji, który wymusza najpierw pobranie wartości R, potem się- gnięcie do wskazywanego przez tę wartość miejsca i wpisanie tam liczby 20 (rysunek 1.1d). Ry- sunki 1.1e do 1.1n to dalsze przykłady instrukcji przypisania, na których pokazano sposób umiesz- czania wartości w pamięci komputera.
  • 29. 24 1. PROGRAMOWANIE OBIEKTOWE W C++ Tak naprawdę wskaźniki, tak samo jak inne zmienne, mają dwa atrybuty: zawartość i poło e- nie. Poło enie mo na zapisać w innej zmiennej, która staje się wskaźnikiem na wskaźnik. Na rysunku 1.1 adresy zmiennych są przypisywane wskaźnikom, jednak wskaźniki mogą od- nosić się do anonimowych lokalizacji w pamięci dostępnych jedynie przez adres, a niemających nazw. Lokalizacje takie muszą być dynamicznie określane przez proces zarządzający pamięcią podczas wykonywania programu, podczas gdy poło enie zmiennych określane jest ju na etapie kompilacji. Aby dynamicznie alokować i zwalniać pamięć, u ywa się dwóch funkcji. Jedna to PGY; pobiera ona z pamięci taki fragment, jaki jest potrzebny na zapisanie danej typu, który zostanie podany za słowem PGY. Przykładowo, instrukcja: R PGY KPV spowoduje za ądanie przez program pamięci potrzebnej na zamieszczenie jednej liczby całkowi- tej, zaś adres tej pamięci zostanie umieszczony w zmiennej R. Teraz mo na blokowi wskazywa- nemu przez R przypisywać wartości; trzeba to robić pośrednio, przez wskaźnik R lub dowolny inny wskaźnik S, któremu przypiszemy adres z R instrukcją S R. Kiedy pamięć zajmowana przez liczbę wskazywaną przez R przestaje być potrzebna, mo na ją zwolnić do puli obsługiwanej przez system operacyjny instrukcją: FGNGVG R Jednak nawet po wykonaniu tej instrukcji zmienna R nadal zawiera adres zwolnionego bloku, choć blok ten przestaje być w programie dostępny. To tak, jakby traktować adres zburzonego domu jako adres mo liwego zamieszkania. Ka da próba znalezienia kogoś pod takim adresem jest z góry skazana na niepowodzenie. Analogicznie, jeśli po wywołaniu instrukcji FGNGVG nie usuniemy ze zmiennej wskaźnikowej adresu, nara amy się na ryzyko błędów; program mo e przestać działać podczas prób dostępu do nienale ącej ju do niego pamięci. Jest to szczególnie niebezpieczne w przypadku sięgania do obiektów bardziej zło onych ni liczby. Aby uniknąć opisanego problemu, nale y wskaźnikowi przypisać nowy adres; jeśli nie ma adnego prawidłowego adresu na podorędziu, nale y u yć adresu pustego, o wartości . Po wykonaniu przypisania: R nie mówimy, e R wskazuje zero czy 07.., lecz e R ma wartość 07.. (pustą). 1.4.1. Wskaźniki a tablice W pokazanym powy ej przykładzie wskaźnik R wskazywał blok pamięci zawierający jedną liczbę całkowitą. Znacznie ciekawsza jest sytuacja, kiedy wskaźnik wskazuje strukturę danych tworzoną i modyfikowaną dynamicznie. Pozwala to obejść ograniczenia dotyczące tablic. W C++, podobnie jak większości innych języków programowania, tablice trzeba zawczasu zadeklarować. Wobec te- go ich rozmiar musi być znany przed uruchomieniem programu, a zatem programista musi dość du o wiedzieć o oprogramowanym problemie, gdy jest to warunkiem poprawnego określenia wielkości tablicy. Jeśli tablica będzie zbyt du a, niepotrzebnie zajmowana przez nią pamięć będzie zmarnowana. Jeśli tablica będzie zbyt mała, dane będą umieszczane za jej końcem, co powoduje powa ną awarię programu. Czasami jednak rozmiaru tablicy po prostu nie da się przewidzieć — w takiej sytuacji decyzję o wielkości tablicy i przez to alokowanej pamięci odkłada się do czasu wykonywania programu.
  • 30. 1.4. WSKAŹNIKI 25 Do rozwiązania opisanego problemu u ywa się wskaźników. Spójrzmy na rysunek 1.1b. Wskaźnik R wskazuje adres 1080, ale mo na za jego pośrednictwem sięgnąć te pod adresy 1082, 1084 i tak dalej — jest to mo liwe dzięki temu, e kolejne dane przesuwane są o taką samą wiel- kość. Aby, na przykład, sięgnąć do wartości zmiennej L sąsiadującej z K, wystarczy dodać do adresu K trzymanego w R rozmiar wartości zmiennej L; wtedy wskaźnik R będzie wskazywał adres zmien- nej L. Tak właśnie w C++ obsługiwane są tablice. Przyjrzyjmy się następującym deklaracjom: KPV C=?
  • 31. R Deklaracje te mówią, e C jest wskaźnikiem bloku pamięci, który mo e zawierać pięć liczb całkowitych. Wskaźnik jest stały, to znaczy nale y go traktować jako stały; wobec tego ka da próba przypisania zmiennej C wartości, na przykład: C R lub: C traktowana jest jako błąd kompilacji. Zmienna C jest wskaźnikiem, więc do sięgnięcia do poszcze- gólnych komórek tablicy C mo na u ywać zapisu wskaźnikowego. Tak oto pętlę dodającą wszystkie wartości z tej tablicy: HQT UWO C=? K K K UWO C=K? mo na zamienić na zapis wskaźnikowy tak: HQT UWO
  • 32. C K K K UWO
  • 33. C K lub tak: HQT UWO
  • 34. C R C R C R UWO
  • 35. R Zauwa my, e skoro C oznacza poło enie następnej komórki tablicy C, to C jest odpowiednikiem C=?. Wobec tego, jeśli C wskazuje adres 1020, to C nie zawiera adresu 1021, lecz 1022, gdy sto- sowana jest arytmetyka wskaźników zale na od typu wskazywanych danych. Jeśli dane są deklaracje: EJCT D=? NQPI E=? i wiadomo, e D równe jest 1050, E równe jest 1055, to D równe jest 1051, gdy jeden znak zaj- muje jeden bajt, zaś E równe jest 1059, gdy liczba typu NQPI zajmuje cztery bajty. Jest to wyni- kiem faktu, e w arytmetyce wskaźników wyra enie E K oznacza adres E K
  • 36. UKGQH NQPI. Dotąd tablica C była deklarowana statycznie i zawierała pięć komórek. Rozmiar takiej tablicy jest ustalony na cały czas działania programu. Tablice mo na deklarować tak e dynamicznie; wtedy u ywane są zmienne wskaźnikowe. Przykładowo, przypisanie: R PGY KPV=P?
  • 37. 26 1. PROGRAMOWANIE OBIEKTOWE W C++ powoduje zaalokowanie pamięci na P liczb całkowitych. Wskaźnik R mo na traktować jako zmienną tablicową i mo na stosować doń notację tablicową. Sumę liczb z tablicy R mo na wyzna- czyć tak: HQT UWO R=? K K P K UWO R=K? Mo na zastosować te notację wskaźnikową normalnie: HQT UWO
  • 38. R K K P K UWO
  • 39. R K lub korzystając z dwóch wskaźników: HQT UWO
  • 40. R S R S R P S UWO
  • 41. S R jest zmienną, więc mo na jej przypisać nową tablicę. Kiedy tablica wskazywana przez R prze- staje być potrzebna, przypisaną jej pamięć mo na zwolnić instrukcją: FGNGVG =? R U ycie pustej pary nawiasów kwadratowych jest wa ne, gdy informuje, e R wskazuje tablicę. Bardzo wa nym rodzajem tablic są łańcuchy czyli tablice znaków. Istnieje wiele funkcji pre- definiowanych przetwarzających łańcuchy. Nazwy tych funkcji zaczynają się od UVT, na przykład UVTNGP U określająca długość łańcucha U, UVTER[ UU kopiująca łańcuch U do U. Trzeba pa- miętać, e wszystkie te funkcje zakładają, e łańcuchy kończą się znakiem 07.., . I tak UVTE R[ UU kopiuje U tak długo, a znajdzie w nim znak 07... Jeśli programista tego znaku w łań- cuchu nie umieści, kopiowanie zostanie przerwane dopiero po napotkaniu pierwszego takiego znaku gdziekolwiek w pamięci komputera, za adresem zmiennej U. Oznacza to, e kopiowane będą znaki za U, co w końcu mo e doprowadzić do awarii programu. 1.4.2. Wskaźniki a konstruktory kopiujące Kiedy wskaźniki zapisane w polach obiektu nie będą podczas kopiowania obiektów prawidłowo obsłu one, trzeba liczyć się z problemami. Niech dana będzie taka oto definicja: UVTWEV 0QFG ] EJCT
  • 42. PCOG KPV CIG 0QFG EJCT
  • 43. P KPV C ] PCOG PGY EJCT=UVTNGP P ? UVTER[ PCOGP CIG C _ _
  • 44. 1.4. WSKAŹNIKI 27 Celem deklaracji: 0QFG PQFG 4QIGT PQFG PQFG NWD PQFG PQFG jest stworzenie obiektu PQFG, przypisanie wartości dwu jego polom, a następnie stworzenie obiektu PQFG i zainicjalizowanie jego pól takimi samymi wartościami jak PQFG. Obiekty muszą być od siebie niezale ne, więc przypisanie wartości pól jednego obiektu nie powinno wpływać na drugi obiekt. Jednak po przypisaniu: UVTER[ PQFGPCOG 9GPF[ PQFGCIG przy próbie zajrzenia do zawartości obiektów: EQWVPQFGPCOG PQFGCIG PQFGPCOG PQFGCIG otrzymamy: 9GPF[ 9GPF[ Wiek jest ró ny, ale imię jest takie samo. Co się właściwie stało? Chodzi o to, e w definicji klasy 0QFG nie podano konstruktora kopiującego: 0QFG EQPUV 0QFG który jest niezbędny do wykonania inicjalizacji PQFG PQFG. Jeśli u ytkownik nie poda kon- struktora kopiującego, konstruktor taki zostanie automatycznie wygenerowany przez kompilator. Jednak konstruktor stworzony przez kompilator kopiuje pole po polu. Pole PCOG jest wskaźnikiem, więc skopiowany zostanie adres łańcucha PQFGPCOG do PQFGPCOG, a zawartość łańcucha ju ko- piowana nie będzie. Wobec tego po wykonaniu pokazanej wcześniej deklaracji sytuacja będzie się przedstawiała tak jak na rysunku 1.2a. Jeśli teraz wykonane zostaną przypisania: UVTER[ PQFGPCOG 9GPF[ PQFGCIG pole PQFGCIG zostanie przypisane prawidłowo, ale łańcuch 4QIGT wskazywany przez pole PCOG obu obiektów zostanie nadpisany napisem 9GPF[ wskazywanym przez oba obiekty (rysunek 1.2b). Aby do takiej sytuacji nie dopuścić, konieczne jest zdefiniowanie prawidłowego konstruktora ko- piującego: UVTWEV 0QFG ] EJCT
  • 45. PCOG KPV CIG 0QFG EJCT
  • 46. P KPV C ] PCOG PGY EJCT=UVTNGP P ? UVTER[ PCOGP CIG C _
  • 47. 28 1. PROGRAMOWANIE OBIEKTOWE W C++ RYSUNEK 1.2. Dlaczego w przypadku obiektów zawierających pola wskaźnikowe konieczne jest u ycie konstruktora kopiującego 0QFG EQPUV 0QFG P ] MQPUVTWMVQT MQRKWLæE[ PCOG PGY EJCT=UVTNGP PPCOG ? UVTER[ PCOGPPCOG CIG PCIG _ _ Kiedy dany jest nowy konstruktor, PQFG PQFG wygeneruje kopię napisu 4QIGT wskazywanego przez PQFGPCOG (rysunek 1.2c), a przypisanie pól jednego obiektu nie wpływa na pola drugiego obiektu: UVTER[ PQFGPCOG 9GPF[ PQFGCIG Obiekt PQFG pozostanie niezmieniony, co widać na rysunku 1.2d. Podobne problemy pojawiają się w przypadku u ycia operatora przypisania. Jeśli u ytkownik nie poda definicji operatora przypisania, instrukcja: PQFG PQFG spowoduje przypisanie kolejno ka dego pola, co spowoduje problemy analogiczne jak na rysunku 1.2a – b. Aby tych problemów uniknąć, konieczne jest przecią enie operatora przypisania. W przy- padku klasy 0QFG przecią enie mo e wyglądać następująco: 0QFG QRGTCVQT EQPUV 0QFG P ] KH VJKU P ] PKG RT[RKUWLGO[ QDKGMVW FQ UCOGIQ UKGDKG KH PCOG FGNGVG =? PCOG PCOG PGY EJCT=UVTNGP PPCOG ? UVTER[ PCOGPPCOG CIG PCIG
  • 48. 1.4. WSKAŹNIKI 29 _ TGVWTP
  • 49. VJKU _ W powy szym fragmencie kodu u yto specjalnego wskaźnika VJKU. Ka dy obiekt mo e za pomocą tego wskaźnika uzyskać swój własny adres, wobec czego
  • 50. VJKU to sam obiekt. 1.4.3. Wskaźniki i destruktory Co się dzieje z lokalnie definiowanymi obiektami typu 0QFG? Tak jak wszystkie inne zmienne lo- kalne, są niszczone w tym sensie, e poza blokiem, w którym je zdefiniowano, stają się niedostępne, zaś zajmowana przez nie pamięć jest zwalniana. Jednak, mimo e pamięć zajmowana przez obiekt 0QFG jest zwalniana, to nie cała zaalokowana pamięć zostanie zwolniona. Jedno z pól tego obiektu to wskaźnik łańcucha, wobec czego zwolniona zostanie pamięć przeznaczona na wskaźnik, ale nie zostanie zwolniona pamięć na sam łańcuch. Po zniszczeniu obiektu dostępny dotąd łańcuch z pola PCOG staje się niedostępny (o ile nie został przypisany polu PCOG innego obiektu lub całkiem innej zmiennej łańcuchowej), więc nie mo na ju nawet zwolnić pamięci przyporządkowanej temu łań- cuchowi. Jest to problem związany z polami wskazującymi dynamicznie alokowaną pamięć. Aby tego problemu uniknąć, definicja klasy powinna zawierać definicję destruktora. Destruktor to funkcja automatycznie wywoływana w chwili niszczenia obiektu, które to niszczenie odbywa się w chwili wyjścia z bloku, w którym obiekt zdefiniowano, lub w chwili wywołania FGNGVG. De- struktory nie mają adnych parametrów ani wartości zwracanych, więc w ka dej klasie istnieć mo e jeden tylko destruktor. W przypadku klasy 0QFG będzie on wyglądał następująco: `0QFG ] KH PCOG FGNGVG =? PCOG _ 1.4.4. Wskaźniki a referencje Przyjrzyjmy się następującym deklaracjom: KPV P
  • 51. R P T P Zmienna R została zadeklarowana jako zmienna typu KPV
  • 52. , wskaźnik na liczbę całkowitą, zaś T jako zmienna typu KPV — referencja do liczby całkowitej. Zmienna referencji musi być zainicjalizo- wana w chwili deklaracji referencją do konkretnej zmiennej, wobec czego nigdy nie mo e być pu- sta. Zmienną referencji T mo na traktować jako inną nazwę zmiennej P, jeśli zatem zmieni się P, to zmieni się te wartość T. Wynika to stąd, e zmienne referencji implementuje się jako stałe wskaź- niki do zmiennych. Wywołanie instrukcji wyświetlającej dane po powy szych deklaracjach: EQWV P
  • 53. R T GPFN
  • 54. 30 1. PROGRAMOWANIE OBIEKTOWE W C++ da w wyniku 5 5 5. Po przypisaniu: P ta sama instrukcja da ju 7 7 7. Po przypisaniu:
  • 55. R da 9 9 9, zaś po przypisaniu: T da 10 10 10. Z pokazanych instrukcji wynika, e to, co mo na uzyskać, stosując dereferencję wskaźników, mo na te uzyskać, stosując dereferencję zmiennych będących referencjami. Nie jest to przypadek, gdy jak wspomniano wcześniej, referencje są implementowane jako stałe wskaźniki. Zamiast deklaracji: KPV T P mo na zapisać: KPV
  • 56. EQPUV T P gdzie T jest stałym wskaźnikiem na liczbę całkowitą, czyli przypisanie: T S gdzie S jest kolejnym wskaźnikiem, jest błędne, gdy wartość T nie mo e się zmieniać. Jednak przypisanie:
  • 57. T ju jest dopuszczalne, jeśli tylko P nie jest stałą liczbą całkowitą. Trzeba tu odnotować ró nicę między daną typu KPV
  • 58. EQPUV a typu EQPUV KPV
  • 59. . Ten drugi typ to wskaźnik na stałą liczbę całkowitą: EQPUV KPV
  • 60. U O i po takiej deklaracji przypisanie: U O gdzie O jest liczbą całkowitą (stałą lub nie), jest dopuszczalne, zaś przypisanie:
  • 61. U jest błędne, nawet jeśli O nie jest stałą. Zmienne będące referencjami są wykorzystywane przy przykazywaniu do funkcji parame- trów przez referencję. Przekazywanie przez referencję jest potrzebne, jeśli podczas wykonywania
  • 62. 1.4. WSKAŹNIKI 31 funkcji przekazany parametr powinien zostać trwale zmieniony. Ten sam efekt mo na uzyskać, stosując wskaźniki (w języku C jest to jedyny mechanizm przekazywania przez referencję). Na przykład zadeklarowanie funkcji: XQKF H KPV K KPV
  • 63. L KPV M ] K
  • 64. L M _ powoduje, e zmienne: KPV P P P po wywołaniu: H P PP mają wartości: P = 4, P = 2, P = 3. Typy referencyjne są te u ywane do wskazywania rodzaju wartości zwracanych przez funk- cje. Jeśli dana jest na przykład funkcja: KPV H KPV C=? KPV K ] TGVWTP C=K? _ i zadeklarowana zostanie tablica: KPV C=? ]_ funkcji H mo na u yć z dowolnej strony operatora przypisania, po stronie prawej: P H C lub po stronie lewej: H C co spowoduje przypisanie liczby 6 do C=?, czyli C = [1 2 3 6 5]. Zauwa my, e taki sama efekt mo na uzyskać za pomocą wskaźników, ale w takim przypadku konieczne byłoby u ycie jawnej dereferencji: KPV
  • 65. H KPV C=? KPV K ] TGVWTP C=K? _ a potem:
  • 66. H C
  • 67. 32 1. PROGRAMOWANIE OBIEKTOWE W C++ 1.4.5. Wskaźniki na funkcje Jak wspomniano w punkcie 1.4.1, jednym z atrybutów zmiennej jest adres określający poło enie tej zmiennej w pamięci. To samo dotyczy funkcji — jeden z atrybutów funkcji to adres określają- cy poło enie treści tej funkcji w pamięci. Po wywołaniu funkcji system przekazuje sterowanie do tego miejsca po to, aby wykonać tę funkcję. Z tego powodu mo na u ywać wskaźników na funk- cje. Wskaźniki te są bardzo przydatne przy implementowaniu funkcjonałów (czyli funkcji otrzy- mujących jako parametry inne funkcje), takie jak całki. Niech dana będzie prosta funkcja: FQWDNG H FQWDNG Z ] TGVWTP
  • 68. Z _ W przypadku takiej definicji H jest wskaźnikiem na funkcję H ,
  • 69. H to sama funkcja, zaś
  • 70. H to wywołanie tej funkcji. Teraz zastanówmy się nad funkcją C++ wyliczającą następującą sumę: i =m ∑ f (i ) i =n Aby wyliczyć sumę, trzeba podać nie tylko wartości graniczne n i m, ale te funkcję f. Wobec tego zastosowana implementacja pozwolić przekazywać nie tylko parametry liczbowe, ale tak e funk- cyjne. W C++ robi się to następująco: FQWDNG UWO FQWDNG
  • 71. H FQWDNG KPV P KPV O ] FQWDNG TGUWNV HQT KPV K P K O K TGUWNV H K TGVWTP TGUWNV _ W podanej definicji funkcji UWO deklaracja pierwszego parametru formalnego: FQWDNG
  • 72. H FQWDNG oznacza, e H jest wskaźnikiem na funkcję mającej jeden parametr typu FQWDNG i zwracającej war- tość FQWDNG. Dookoła
  • 73. H konieczne jest zastosowanie nawiasów; mają one wy szy priorytet ni operator dereferencji,
  • 74. , więc wyra enie: FQWDNG
  • 75. H FQWDNG to deklaracja funkcji zwracającej wskaźnik na wartość typu FQWDNG. Teraz funkcja UWO mo e być wywołana z dowolną wbudowaną lub zdefiniowaną przez u ytkownika funkcję mającą parametr typu FQWDNG i taki parametr zwracającą: EQWV UWO H GPFN EQWV UWO UKP GPFN
  • 76. 1.5. POLIMORFIZM 33 Innym przykładem mo e być funkcja znajdująca pierwiastek funkcji ciągłej na przedziale. Pierwiastek znajduje się wielokrotnie, dzieląc przedział na pół i znajdując środek aktualnego prze- działu. Jeśli jest on zerem lub jeśli przedział jest mniejszy od pewnej, zało onej małej wartości, zwracany jest ten środek. Jeśli wartości funkcji na lewym brzegu przedziału i w jego środku mają przeciwne znaki, przeszukiwanie kontynuowane jest w lewej połowie przedziału. W przeciwnym przypadku przedziałem bie ącym staje się prawa połowa przedziału dotychczasowego. Oto im- plementacja algorytmu: FQWDNG TQQV FQWDNG
  • 77. H FQWDNG FQWDNG C FQWDNG D FQWDNG GRUKNQP ] RKGTYKCUVGM FQWDNG OKFFNG C D YJKNG H OKFFNG HCDU D C GRUKNQP ] KH H C
  • 78. H OKFFNG LG NK H C K H OKFFNG OCLæ D OKFFNG RTGEKYPG PCMK GNUG C OKFFNG OKFFNG C D _ TGVWTP OKFFNG _ 1.5. Polimorfizm Polimorfizm oznacza mo liwość przybierania wielu postaci. W kontekście programowania obiek- towego oznacza on, e ta sama nazwa funkcji odpowiada wielu funkcjom nale ącym do ró nych obiektów. Oto przykład: ENCUU %NCUU ] RWDNKE XKTVWCN XQKF H ] EQWV (WPMELC H Y MNCUKG %NCUUP _ XQKF I ] EQWV (WPMELC I Y MNCUKG %NCUUP _ _ ENCUU %NCUU ] RWDNKE XKTVWCN XQKF H ] EQWV (WPMELC H Y MNCUKG %NCUUP _ XQKF I ] EQWV (WPMELC I Y MNCUKG %NCUUP _ _ ENCUU %NCUU ] RWDNKE XKTVWCN XQKF J ] EQWV (WPMELC J Y MNCUKG %NCUUP _
  • 79. 34 1. PROGRAMOWANIE OBIEKTOWE W C++ _ KPV OCKP ] %NCUU QDLGEV
  • 80. R %NCUU QDLGEV %NCUU QDLGEV R QDLGEV R H R I R %NCUU
  • 81. QDLGEV R H R I R %NCUU
  • 82. QDLGEV R H #YCT[LPG RTGTYCPKG RTQITCOW R I R J J PKG LGUV OGVQFæ MNCU[ %NCUU TGVWTP _ Wynik działania powy szego programu jest następujący: (WPMELC H Y MNCUKG %NCUU (WPMELC I Y MNCUKG %NCUU (WPMELC H Y MNCUKG %NCUU (WPMELC I Y MNCUKG %NCUU (WPMELC I Y MNCUKG %NCUU Nie powinien zaskakiwać fakt, e kiedy R jest zadeklarowane jako wskaźnik na obiekt QD LGEV klasy %NCUU, uruchamiane są dwie funkcje zadeklarowane w klasie %NCUU. Jednak kiedy R staje się wskaźnikiem na obiekt QDLGEV klasy %NCUU, R H aktywuje funkcję zdefiniowaną w klasie %NCUU, zaś R I aktywuje funkcję z klasy %NCUU. Dlaczego? Chodzi o to, kiedy po- dejmowana jest decyzja, która funkcja zostanie wywołana. W przypadku tak zwanego wiązania statycznego decyzja o wyborze wykonywanej funkcji podejmowana jest na etapie kompilacji. W przypadku wiązania dynamicznego decyzja ta jest od- kładana do czasu wykonania programu. W C++ wiązanie dynamiczne jest wymuszane przez zade- klarowanie metody jako wirtualnej, słowem kluczowym XKTVWCN. W ten sposób, kiedy wywoły- wana jest metoda wirtualna, wybór funkcji na etapie wykonania programu zale ny jest nie od typu wskaźnika określonego w deklaracji, ale od typu wskaźnika faktycznie u ytego. W pokazanym przykładzie wskaźnik R zadeklarowano jako wskaźnik typu %NCUU
  • 83. . Wobec tego, jeśli R wskazuje funkcję I i nie jest to funkcja wirtualna, to niezale nie od tego, w którym miejscu wystąpi R I , zawsze jest ono traktowane jako wywołanie funkcji I z klasy %NCUU. Wynika to stąd, e kom- pilator podejmuje decyzję na podstawie deklaracji typu wskaźnika R i na podstawie faktu, e funk- cja I nie jest zadeklarowana ze słowem kluczowym XKTVWCN. W przypadku metod wirtualnych sytuacja zasadniczo się zmienia. Tym razem decyzja podejmowana jest na etapie wykonywania programu — jeśli metoda jest wirtualna, system określa typ wskaźnika na bie ąco i wywołuje od- powiednią metodę. Początkowo, R zostało zadeklarowane jako wskaźnik typu %NCUU
  • 84. , więc wy- woływana jest funkcja wirtualna H z klasy %NCUU. Po przypisaniu R adresu obiektu QDLGEV klasy %NCUU wywoływana jest metoda H klasy %NCUU. Trzeba te odnotować, e po przypisaniu R adresu obiektu 1DLGEV, nadal wywoływana jest metoda I z klasy %NCUU. Wynika to stąd, e I nie zdefiniowano ponownie w klasie %NCUU, wobec czego u ywana jest definicja z klasy %NCUU. Jednak próba wywołania R H powoduje
  • 85. 1.6. C++ A PROGRAMOWANIE OBIEKTOWE 35 awarię programu, gdy funkcję H zadeklarowano jako wirtualną w klasie %NCUU; system szuka jej zatem (bezskutecznie) w klasie %NCUU. Poza tym, mimo e R wskazuje obiekt QDLGEV, instruk- cja R J powoduje błąd kompilacji, gdy kompilator nie znajduje w klasie %NCUU metody J , a R nadal jest wskaźnikiem typu %NCUU
  • 86. . Z punktu widzenia kompilatora nie ma znaczenia, e J zdefiniowano w klasie %NCUU — czy to jako metodę wirtualną czy nie. Polimorfizm jest potę nym narzędziem programowania obiektowego. Wystarczy wysłać standardowy komunikat do wielu ró nych obiektów, nie podając, jak komunikat ma być interpre- towany. Nie trzeba znać typów obiektów. Odbiorca jest odpowiedzialny za interpretację komuni- katu i jego wykonanie. Nadawca nie musi modyfikować komunikatu w zale ności od typu odbiorcy. Zbędne jest stosowanie jakichkolwiek instrukcji warunkowych. Poza tym do zło onych progra- mów mo na bezproblemowo dodawać nowe moduły bez konieczności ponownej kompilacji całego programu. 1.6. C++ a programowanie obiektowe Dotąd zakładaliśmy, e C++ jest językiem programowania obiektowego, wszystkie mo liwości programowania obiektowego były ilustrowane kodem C++. Jednak C++ nie jest językiem czysto obiektowym. C++ jest bardziej obiektowy ni C czy Pascal, które nie mają adnych cech obiekto- wości. C++ jest te bardziej obiektowy ni Ada obsługująca klasy (pakiety) i instancje. Jednak ję- zyk C++ jest w mniejszym stopniu obiektowy ni języki stricte obiektowe, jak Smalltalk czy Eiffel. C++ nie zmusza do programowania obiektowego. Mo emy programować w C++ bez znajo- mości obiektowych cech tego języka. Powodem tego jest ogromna popularność języka C. C++ stanowi nadzbiór C, więc programiści C nie mają problemów z „przesiadką” na C++; mogą stoso- wać tylko łatwiejsze w u yciu operacje wejścia i wyjścia, mechanizm wywołania przez referencję, domyślne parametry funkcji, przecią anie operatorów, funkcje inline i im podobne. U ycie obiektowe- go języka programowania typu C++ nie gwarantuje programowania obiektowego. Z drugiej strony wywoływanie całej maszynerii klas i metod nie zawsze jest konieczne, szczególnie w przypadku niewielkich programów. Wobec tego mo liwość niekorzystania z obiektowości nie musi być wadą. Poza tym C++ jest łatwiejsze w integrowaniu z istniejącym kodem C ni inne języki programowa- nia obiektowego. C++ zapewnia doskonały mechanizm enkapsulacji pozwalający dobrze kontrolować ukrywa- nie informacji. Jednak od tej reguły istnieją wyjątki — chodzi o „funkcje zaprzyjaźnione”. Infor- macje prywatne nale ące do pewnej klasy nie mogą być dla nikogo dostępne, zaś informacje pu- bliczne są dostępne dla wszystkich. Jednak czasami dobrze byłoby pozwolić niektórym u ytkownikom na dostęp do danych prywatnych. Mo na to zrealizować, jeśli klasa pokazuje funk- cje u ytkownika jako funkcje zaprzyjaźnione. Jeśli na przykład dana jest następująca definicja klasy: ENCUU % ] KPV P HTKGPF KPV H _ QD to funkcja H ma bezpośredni dostęp do zmiennej P nale ącej do klasy %: KPV H ] TGVWTP
  • 87. QDP _
  • 88. 36 1. PROGRAMOWANIE OBIEKTOWE W C++ Mo na byłoby tę sytuację uznać za naruszenie zasady ukrywania informacji. Jednak to sama klasa % daje dostęp do swoich części prywatnych wybranym funkcjom, pozostałym te dane pozo- stają niedostępne. Wobec tego, skoro klasa ma kontrolę nad tym, które funkcje będą uwa ane za zaprzyjaźnione, mechanizm funkcji zaprzyjaźnionych mo na uznać za rozszerzenie zasady ukry- wania informacji. Mechanizm ten jest u ywany do ułatwienia programowania i do przyspieszenia wykonywania programu, gdy przepisywanie kodu bez u ycia funkcji zaprzyjaźnionych mogłoby być nader kłopotliwe. Takie rozluźnienie niektórych zasad nie jest w informatyce czymś niezwy- kłym; wystarczy wspomnieć istnienie pętli w językach funkcyjnych (jak LISP) czy przechowywa- nie dodatkowych informacji w nagłówku pliku danych będące naruszeniem modelu relacyjnego (jak w dBase III+). 1.7. Standardowa biblioteka szablonów C++ jest językiem obiektowym, ale niedawne rozszerzenia języka wynoszą C++ na wy szy po- ziom. Najistotniejszym dodatkiem do języka jest standardowa biblioteka szablonów (STL, Stan- dard Template Library) początkowo stworzona przez Alexandra Stepanova i Menga Lee. Biblio- teka ta zawiera trzy rodzaje bytów ogólnych: kontenery, iteratory i algorytmy. Algorytmy są często u ywanymi funkcjami, które mo na stosować do ró nych struktur danych. W ich stosowa- niu pośredniczą iteratory decydujące, które algorytmy mają być stosowane do jakiego typu obiek- tów. STL zwalnia programistów z pisania własnych implementacji rozmaitych klas i funkcji; od razu gotowe są ogólne implementacje rozwiązania poszczególnych problemów. 1.7.1. Kontenery Kontener to struktura danych zawierająca obiekty, zwykle wszystkie tego samego typu. Ró ne ro- dzaje kontenerów ró nie układają obiekty. Wprawdzie liczba mo liwych uło eń jest teoretycznie nieograniczona, ale jedynie niewielka część tych uło eń ma znaczenie praktyczne; właśnie te naj- częściej u ywane zostały zamieszczone w bibliotece STL. Biblioteka ta zawiera następujące kon- tenery: FGSWG, NKUV, OCR, OWNVKOCR, UGV, OWNVKUGV, UVCEM, SWGWG, RTKQTKV[ASWGWG i XGEVQT. Kontenery STL zaimplementowano jako szablony klas zawierające metody umo liwiające opisanie operacji, które będą wykonywane na obiektach umieszczonych w strukturze lub na samej strukturze. Niektóre operacje są wspólne dla wszystkich kontenerów, choć mogą być one ró nie zaimplementowane w ró nych strukturach. Do metod wspólnych dla wszystkich kontenerów nale ą: konstruktor, konstruktor kopiujący, destruktor, GORV[ , OCZAUKG , UKG , UYCR , QRGTCVQT i (za wyjątkiem kolejki RTKQTKV[ASWGWG) sześć operatorów relacyjnych: QRGTCVQT i tak dalej. Poza tym wszystkie kontenery poza UVCEM, SWGWG i RTKQTKV[ASWGWG mają metody DGIKP , GPF , TDG IKP , TGPF , GTCUG i ENGCT . Elementy umieszczane w kontenerach mogą być dowolnego typu — muszą zapewniać przy- najmniej konstruktor domyślny, destruktor i operator przypisania. Jest to szczególnie istotne w przypadku typów definiowanych przez u ytkownika. Niektóre kompilatory mogą te wymagać przecią enia niektórych operatorów relacyjnych (zwykle i , czasem te i ), nawet jeśli ope- ratory te nie będą w programie u ywane. Poza tym, jeśli pola są wskaźnikami, powinny być zdefi- niowane konstruktor kopiujący i QRGTCVQT, gdy wstawianie korzysta z kopii elementu, a nie sa- mego elementu.
  • 89. 1.7. STANDARDOWA BIBLIOTEKA SZABLONÓW 37 1.7.2. Iteratory Iterator to obiekt u ywany do wskazania elementu z kontenera. Iteratory to swojego rodzaju uogólnienie wskaźników; iterator pozwala sięgnąć do danych z kontenera tak, aby umo liwić wy- konanie na tych danych potrzebnych operacji. Będąc uogólnieniem wskaźników, iteratory mają taki sam zapis dereferencji; na przykład
  • 90. K to element wskazywany przez iterator K. Poza tym arytmetyka iteratorów jest podobna do arytmetyki wskaźników, choć nie wszystkie operacje na iteratorach dozwolone są na wszystkich kontenerach. Nie istnieją iteratory kontenerów UVCEM, SWGWG ani RTKQTKV[ASWGWG. Operacje na iteratorach dla klas NKUV, OCR, OWNVKOCR, UGV i OWNVKUGV są następujące (przy czym K i K to iteratory, P jest liczbą): K K K KN K K K K K K
  • 91. K Poza tym dla klas FGSWG i XGEVQT istnieją jeszcze operacje: K K K K K K K K K P K P K P K P K=P? 1.7.3. Algorytmy Biblioteka STL zawiera ponad 70 ogólnych funkcji nazywanych algorytmami; mogą być one sto- sowane do kontenerów STL i tablic. Listę wszystkich algorytmów z biblioteki STL zamieszczono w dodatku B. Algorytmy te implementują operacje często u ywane w typowych programach, takie jak znalezienie elementu w kontenerze, wstawienie elementu do ciągu elementów, usunięcie ele- mentu z ciągu, modyfikacja i porównywanie elementów, znajdowanie wartości według ciągu ele- mentów, sortowania ciągu i tak dalej. Niemal e wszystkie algorytmy biblioteki STL do wskazy- wania zakresu elementów, na których działają, u ywają iteratorów. Pierwszy iterator wskazuje pierwszy element zakresu, drugi — element po ostatnim elemencie zakresu. Wobec tego zakłada się, e zawsze mo na dojść do miejsca wskazywanego przez drugi iterator przez inkrementację iteratora pierwszego. Oto kilka przykładów. Wywołanie: TCPFQOAUJWHHNG EDGIKP EGPF zmieni losowo kolejność elementów w kontenerze E. Wywołanie: K HKPF K K G zwraca iterator wskazujący poło enie elementu G w zakresie od K do K (bez samego K). Wy- wołanie: P EQWPVAKH K K QFF0WO
  • 92. 38 1. PROGRAMOWANIE OBIEKTOWE W C++ zlicza algorytmem EQWPVAKH elementy z zakresu wskazanego iteratorami K i K, dla których jed- noparametrowa funkcja u ytkownika QFF0WO zwraca wartość VTWG. Algorytmy to funkcje, które stanowią dodatki do metod kontenerów. Jednak niektóre algo- rytmy zdefiniowano tak e jako metody, w celu uzyskania szybszego ich działania. 1.7.4. Funktory W C++ operator wywołania funkcji mo e być traktowany jak ka dy inny operator, w szczegól- ności mo e być przecią any. Mo e zwracać daną dowolnego typu i mieć dowolną liczbę parame- trów, ale tak samo jak operator przypisania, mo e być przecią any tylko jako metoda klasy. Ka dy obiekt zawierający definicję operatora wywołania funkcji nazywany jest funktorem. Funktor to ta- ki obiekt, który zachowuje się, jakby był funkcją. Kiedy obiekt taki jest wywoływany, jego para- metry stają się parametrami operatora wywołania funkcji. Zajmijmy się, dla przykładu, znalezieniem sumy liczb uzyskiwanych z zastosowania funkcji f do liczb całkowitych z przedziału [n, m]. Implementacja UWO , pokazana w punkcie 1.4.5, bazo- wała na u yciu jako parametru funkcji UWO wskaźnika do funkcji. To samo mo na uzyskać, defi- niując najpierw klasę z przecią onym operatorem wywołania funkcji: ENCUU ENCUUH ] RWDNKE ENCUUH ] _ FQWDNG QRGTCVQT FQWDNG Z ] TGVWTP
  • 93. Z _ _ i definiując funkcję: FQWDNG UWO ENCUUH H KPV P KPV O ] FQWDNG TGUWNV HQT KPV K P K O K TGUWNV H K TGVWTP TGUWNV _ ró niącą się od funkcji UWO tylko pierwszym parametrem, który teraz jest funktorem, a nie funk- cją; poza tym wszystko inne jest bez zmian. Nowa funkcja mo e być teraz wywołana następująco: ENCUUH EH EQWV UWO EH GPFN lub po prostu: EQWV UWO ENCUUH GPFN
  • 94. 1.7. STANDARDOWA BIBLIOTEKA SZABLONÓW 39 Druga metoda wywołania wymaga zdefiniowania konstruktora ENCUUH (mimo e nie ma on ciała) tworzącego obiekt typu ENCUUH w chwili wywołania UWO . To samo mo na uzyskać, nie przecią ając operatora wywołania funkcji, jak poni ej: ENCUU ENCUUH ] RWDNKE ENCUUH ] _ FQWDNG TWP FQWDNG Z ] TGVWTP
  • 95. Z _ _ FQWDNG UWO ENCUUH H KPV P KPV O ] FQWDNG TGUWNV HQT KPV K P K O K TGUWNV HTWP K TGVWTP TGUWNV _ gdzie wywołanie przybierze postać: EQWV UWO ENCUUH GPFN Biblioteka STL w du ej mierze oparta jest na funktorach. Mechanizm wskaźników na funkcje nie wystarcza w przypadku operatorów wbudowanych. Jak mo na byłoby przekazać unarny minus do funkcji UWO ? Składnia UWO jest niepoprawna. Aby uniknąć opisanego problemu, w bi- bliotece STL zdefiniowano funktory HWPEVKQPCN wspólne dla wszystkich operatorów C++. Przy- kładowo, minus unarny zdefiniowano następująco: VGORNCVGENCUU 6 UVTWEV PGICVG RWDNKE WPCT[AHWPEVKQP66 ] 6 QRGTCVQT EQPUV 6 Z EQPUV ] TGVWTP Z _ _ Teraz, po ponownym zdefiniowaniu funkcji UWO , staje się ona ju funkcją ogólną: VGORNCVGENCUU ( FQWDNG UWO ( H KPV P KPV O ] FQWDNG TGUWNV HQT KPV K P K O K TGUWNV H K TGVWTP TGUWNV _ Mo na te wywołać funkcję z funktorem PGICVG: UWO PGICVGFQWDNG .