Darmowy fragment publikacji:
IDZ DO
IDZ DO
PRZYK£ADOWY ROZDZIA£
PRZYK£ADOWY ROZDZIA£
SPIS TREĎCI
SPIS TREĎCI
KATALOG KSI¥¯EK
KATALOG KSI¥¯EK
KATALOG ONLINE
KATALOG ONLINE
ZAMÓW DRUKOWANY KATALOG
ZAMÓW DRUKOWANY KATALOG
TWÓJ KOSZYK
TWÓJ KOSZYK
DODAJ DO KOSZYKA
DODAJ DO KOSZYKA
CENNIK I INFORMACJE
CENNIK I INFORMACJE
ZAMÓW INFORMACJE
ZAMÓW INFORMACJE
O NOWOĎCIACH
O NOWOĎCIACH
ZAMÓW CENNIK
ZAMÓW CENNIK
CZYTELNIA
CZYTELNIA
FRAGMENTY KSI¥¯EK ONLINE
FRAGMENTY KSI¥¯EK ONLINE
Wydawnictwo Helion
ul. Chopina 6
44-100 Gliwice
tel. (32)230-98-63
e-mail: helion@helion.pl
C++. In¿ynieria
programowania
Autor: Victor Shtern
T³umaczenie: Daniel Kaczmarek (rozdz. 1 – 6), Adam
Majczak (rozdz. 7 – 11), Rafa³ Szpoton (rozdz. 12 – 19)
ISBN: 83-7361-171-1
Tytu³ orygina³u: Core C++: A Software Engineering Approach
Format: B5, stron: 1084
Naucz siê jêzyka C++ w najlepszy sposób: poznaj¹c go z punktu widzenia
in¿ynierii programowania
• Demonstruje praktyczne techniki stosowane przez zawodowych programistów
• Zawiera poprawny, gruntownie przetestowany przyk³adowy kod ĥród³owy
programów oraz przyk³ady zaczerpniête z praktyki
• Skoncentrowana na nowoczesnych technologiach, które musz¹ poznaæ programiġci
• Zawiera rady profesjonalistów, które pozwol¹ czytelnikowi tworzyæ
najlepsze programy
Ksi¹¿ka Wiktora Shterna zatytu³owana „C++. In¿ynieria programowania” stosuje wyj¹tkowy
sposób nauki jêzyka C++ przeznaczony dla programistów maj¹cych doġwiadczenie
w dowolnym jêzyku programowania: prezentuje mo¿liwoġæ zastosowania w C++
najlepszych technik programistycznych oraz metodologii in¿ynierii programowania.
Nawet je¿eli ju¿ wczeġniej wykorzystywa³eġ jêzyk C++, ta wyczerpuj¹ca ksi¹¿ka przedstawi
sposób tworzenia poprawniejszego kodu, ³atwiejszego do utrzymania i modyfikacji. Ksi¹¿ka
niniejsza uczy zasad programowania obiektowego przed sam¹ nauk¹ jêzyka, co pozwala
wykorzystaæ wszystkie zalety OOP do tworzenia poprawnych aplikacji. Udoskonalisz
znajomoġæ kluczowych sk³adników standardu ANSI/ISO C++ rozpatrywanych z punktu
widzenia in¿yniera: klas, metod, modyfikatorów const, dynamicznego zarz¹dzania pamiêci¹,
z³o¿eñ klas, dziedziczenia, polimorfizmu, operacji wejġcia-wyjġcia i wielu innych.
Je¿eli pragniesz tworzyæ w jêzyku C++ najlepsze programy, musisz projektowaæ, myġleæ
i programowaæ stosuj¹c najlepsze obecnie praktyki in¿ynierii programowania.
Lektura ksi¹¿ki „C++. In¿ynieria programowania” pomo¿e Ci w tym.
Ksi¹¿ka „C++. In¿ynieria programowania” k³adzie nacisk na:
• Prezentacjê zastosowañ zasad in¿ynierii programowania w programach pisanych w C++
• Tworzenie kodu ³atwego do póĥniejszych modyfikacji
• Praktyczne zrozumienie zasad programowania obiektowego przed nauk¹
samego jêzyka
• Przedstawienie najnowszych cech standardu ANSI/ISO C++
• Zaprezentowanie setek realistycznych przyk³adów kodu programów
Wiktor Shtern jest profesorem wyk³adaj¹cym w college’u przy uniwersytecie w Bostonie,
uznawanym za jedn¹ z najlepszych w Stanach Zjednoczonych szkó³ dla osób pracuj¹cych
zawodowo. Oprócz wyk³adów z jêzyka C++ na poziomie uniwersyteckim, Shtern prowadzi
równie¿ zajêcia praktyczne dla doġwiadczonych programistów.
Dan Costello jest in¿ynierem oprogramowania w firmie GE Marquette Medical Systems
Spis treści
Wprowadzenie
15
Co odróżnia tę książkę od innych książek o C++? ...................................................a.... 15
Dla kogo jest przeznaczona ta książka? ...................................................a.................. 17
Jak korzystać z tej książki? ...................................................a.................................... 17
Konwencje stosowane w książce...................................................a............................ 18
Dostęp do kodów źródłowych ...................................................a................................. 19
Część I Wprowadzenie do programowania w języku C++
21
Rozdział 1. Podejście zorientowane obiektowo — co je wyróżnia?
23
Źródła kryzysu oprogramowania...................................................a.............................. 24
Rozwiązanie 1. — wyeliminowanie programistów ...................................................a..... 28
Rozwiązanie 2. — ulepszone techniki zarządzania ...................................................a... 30
Metoda wodospadu ...................................................a......................................... 31
Szybkie tworzenie prototypu...................................................a.............................. 32
Rozwiązanie 3. — projektowanie złożonego i rozwlekłego języka .................................. 33
Podejście zorientowane obiektowo — czy dostaniemy coś za nic?................................ 34
Na czym polega praca projektanta?...................................................a................... 35
Jakość projektu — spójność...................................................a............................. 37
Jakość projektu — łączność ...................................................a............................. 37
Jakość projektu — wiązanie danych i funkcji ...................................................a...... 38
Jakość projektu — ukrywanie informacji i kapsułkowanie ....................................... 40
Sprawa projektowania — konflikty nazewnictwa ...................................................a. 41
Sprawa projektowania — inicjalizacja obiektu ...................................................a.... 42
Czym jest obiekt? ...................................................a............................................ 43
Zalety stosowania obiektów...................................................a.............................. 44
Charakterystyka języka C++ ...................................................a................................... 45
Cele języka C — wydajność, czytelność, piękno i przenośność................................ 45
Cele języka C++ — klasy ze wsteczną zgodnością z C............................................ 47
Podsumowanie ...................................................a...................................................a.. 50
Rozdział 2. Szybki start — krótki przegląd języka C++
53
Podstawowa struktura programu ...................................................a............................ 54
Dyrektywy preprocesora...................................................a......................................... 56
Komentarze...................................................a...................................................a....... 60
Deklaracje i definicje ...................................................a............................................. 63
Instrukcje i wyrażenia ...................................................a............................................ 69
Funkcje i wywołania funkcji ...................................................a.................................... 77
6
C++. Inżynieria programowania
Klasy ...................................................a...................................................a................ 86
Praca z narzędziami programistycznymi...................................................a................... 90
Podsumowanie ...................................................a...................................................a.. 94
Rozdział 3. Praca z danymi i wyrażeniami w C++
95
Wartości i ich typy...................................................a................................................. 96
Typy całkowitoliczbowe ...................................................a.......................................... 98
Kwalifikatory typu całkowitoliczbowego ...................................................a............ 100
Znaki ...................................................a...................................................a......... 104
Wartości logiczne...................................................a........................................... 106
Typy liczb zmiennoprzecinkowych...................................................a.......................... 107
Praca z wyrażeniami C++ ...................................................a..................................... 109
Operatory o wysokim priorytecie...................................................a...................... 110
Operatory arytmetyczne ...................................................a.................................. 111
Operatory przesunięcia...................................................a................................... 114
Bitowe operatory logiczne...................................................a............................... 115
Operatory relacji i równości...................................................a............................. 118
Operatory logiczne ...................................................a......................................... 120
Operatory przypisania...................................................a..................................... 122
Operator warunkowy...................................................a....................................... 123
Operator przecinkowy ...................................................a..................................... 124
Wyrażenia mieszane — ukryte zagrożenia ...................................................a............. 125
Podsumowanie ...................................................a...................................................a 131
Rozdział 4. Sterowanie przebiegiem programu C++
133
Instrukcje i wyrażenia ...................................................a.......................................... 134
Instrukcje warunkowe...................................................a.......................................... 136
Standardowe formy instrukcji warunkowych...................................................a...... 136
Częste błędy w instrukcjach warunkowych...................................................a........ 140
Zagnieżdżone instrukcje warunkowe i ich optymalizacja ....................................... 152
Iteracje ...................................................a...................................................a........... 158
Zastosowanie pętli WHILE ...................................................a.............................. 159
Iteracje w pętli DO-WHILE ...................................................a............................... 167
Iteracje w pętli FOR...................................................a........................................ 170
Instrukcje skoków w C++...................................................a..................................... 173
Instrukcja BREAK...................................................a........................................... 174
Instrukcja CONTINUE......................................a...................................................a 177
Instrukcja GOTO ...................................................a............................................ 178
Instrukcje skoków RETURN i EXIT...................................................a.................... 179
Instrukcja SWITCH ...................................................a......................................... 183
Podsumowanie ...................................................a...................................................a 186
Rozdział 5. Agregacja za pomocą typów danych zdefiniowanych przez programistę
187
Tablice jako agregaty homogeniczne...................................................a..................... 188
Tablice jako wektory wartości...................................................a.......................... 188
Definiowanie tablic C++ ...................................................a................................. 190
Operacje na tablicach ...................................................a.................................... 193
Sprawdzanie poprawności indeksów...................................................a................ 194
Tablice wielowymiarowe ...................................................a................................. 197
Definiowanie tablic znaków...................................................a............................. 200
Operacje na tablicach znaków...................................................a......................... 202
Funkcje łańcuchowe a błędy pamięci ...................................................a............... 204
Spis treści
7
Dwuwymiarowe tablice znaków...................................................a........................ 208
Przepełnienie tablic w algorytmach je wypełniających ........................................... 210
Definiowanie typów tablicowych ...................................................a...................... 214
Struktury jako agregaty heterogeniczne...................................................a................. 216
Definiowanie struktur jako typów zdefiniowanych przez programistę ...................... 216
Tworzenie i inicjalizowanie zmiennych strukturalnych ........................................... 217
Struktury hierarchiczne i ich komponenty ...................................................a......... 219
Operacje na zmiennych strukturalnych...................................................a............. 220
Definiowanie struktur w programach złożonych z wielu plików ............................... 222
Unie, typy wyliczeniowe i pola bitowe ...................................................a.................... 223
Unie ...................................................a...................................................a.......... 223
Typy wyliczeniowe ...................................................a.......................................... 227
Pola bitowe ...................................................a...................................................a 229
Podsumowanie ...................................................a...................................................a 233
Rozdział 6. Zarządzanie pamięcią — stos i sterta
235
Zasięg nazw jako narzędzie współpracy...................................................a................. 236
Zasięgi leksykalne C++ ...................................................a.................................. 236
Konflikty nazw w tym samym zasięgu ...................................................a.............. 237
Stosowanie takich samych nazw w zasięgach niezależnych .................................. 241
Stosowanie takich samych nazw w zasięgach zagnieżdżonych .............................. 241
Zasięg zmiennych pętli...................................................a................................... 246
Zarządzanie pamięcią — klasy pamięci...................................................a................. 246
Zmienne automatyczne ...................................................a.................................. 248
Zmienne zewnętrzne ...................................................a...................................... 251
Zmienne statyczne...................................................a......................................... 257
Zarządzanie pamięcią — zastosowanie sterty...................................................a........ 261
Wskaźniki C++ jako zmienne o określonym typie ................................................. 263
Alokowanie pamięci na stercie...................................................a........................ 268
Tablice i wskaźniki ...................................................a......................................... 273
Tablice dynamiczne...................................................a........................................ 276
Struktury dynamiczne ...................................................a..................................... 290
Operacje wejścia i wyjścia na plikach...................................................a.................... 300
Zapisywanie do pliku...................................................a...................................... 301
Odczyt z pliku ...................................................a................................................ 304
Plikowe obiekty wejścia-wyjścia ...................................................a....................... 308
Podsumowanie ...................................................a...................................................a 311
Część II Programowanie obiektowe w C++
313
Rozdział 7. Programowanie w C++ z zastosowaniem funkcji
315
Funkcje w C++ jako narzędzie modularyzacji programu .............................................. 317
Deklaracje funkcji ...................................................a.......................................... 318
Definicje funkcji ...................................................a............................................. 319
Wywołania funkcji ...................................................a.......................................... 320
Promocja i konwersja argumentów funkcji ...................................................a............. 323
Przekazywanie parametrów do funkcji w C++ ...................................................a......... 326
Przekazanie parametru przez wartość ...................................................a.............. 326
Przekazanie parametrów poprzez wskaźnik ...................................................a...... 328
Przekazanie parametrów do funkcji charakterystycznej dala C++
— poprzez referencję...................................................a................................ 336
Struktury...................................................a...................................................a.... 341
8
C++. Inżynieria programowania
Tablice...................................................a...................................................a....... 348
Więcej o konwersjach typów ...................................................a........................... 352
Zwracanie wartości z funkcji ...................................................a........................... 355
Funkcje wplecione — inline...................................................a.................................. 361
Parametry funkcji z wartościami domyślnymi ...................................................a......... 364
Przeciążanie nazw funkcji...................................................a..................................... 370
Podsumowanie ...................................................a...................................................a 377
Rozdział 8. Programowanie obiektowe z zastosowaniem funkcji
381
Kohezja...................................................a...................................................a........... 385
Sprzęganie ...................................................a...................................................a...... 386
Niejawne sprzężenie ...................................................a...................................... 386
Jawne sprzężenie...................................................a........................................... 390
Jak zredukować intensywność sprzęgania? ...................................................a...... 395
Hermetyzacja danych...............................................a............................................... 400
Ukrywanie danych ...................................................a............................................... 407
Większy przykład hermetyzacji danych...................................................a................... 413
Wady hermetyzacji danych przy użyciu funkcji ...................................................a........ 422
Podsumowanie ...................................................a...................................................a 425
Rozdział 9. Klasy w C++ jako jednostki modularyzacji
427
Podstawowa składnia definicji klasy ...................................................a..................... 430
Połączenie danych i operacji ...................................................a........................... 430
Eliminowanie konfliktów nazw ...................................................a......................... 435
Implementacja kodów metod poza definicją klasy................................................ 439
Definiowane obiektów przechowywanych w pamięci różnych kategorii.................... 443
Kontrolowanie dostępu do komponentów klasy ...................................................a..... 444
Inicjowanie obiektów danej klasy...................................................a.......................... 451
Konstruktory — jako metody...................................................a........................... 452
Konstruktory domyślne...................................................a................................... 455
Konstruktory kopiujące...................................................a................................... 457
Konstruktory konwersji ...................................................a................................... 461
Destruktory ...................................................a...................................................a 463
Co i kiedy, czyli co naprawdę robią konstruktory i destruktory ............................... 468
Widoczność nazw w obrębie klasy i przesłanianie nazw przy zagnieżdżaniu ............ 469
Zarządzanie pamięcią za pomocą operatorów i wywołań funkcji ............................ 472
Zastosowanie w kodzie klienta obiektów zwracanych przez funkcje............................. 476
Zwrot wskaźników i referencji...................................................a.......................... 476
Zwrot obiektów z funkcji ...................................................a................................. 479
Więcej o stosowaniu słowa kluczowego const ...................................................a....... 482
Statyczne komponenty klas ...................................................a................................. 488
Zastosowanie zmiennych globalnych jako charakterystyk klas .............................. 489
Czwarte znaczenie słowa kluczowego static ...................................................a..... 491
Inicjowanie statycznych pól danych...................................................a.................. 492
Statyczne metody ...................................................a.......................................... 493
Podsumowanie ...................................................a...................................................a 497
Rozdział 10. Funkcje operatorowe — jeszcze jeden dobry pomysł
499
Przeciążanie operatorów ...................................................a...................................... 501
Ograniczenia w przeciążaniu operatorów ...................................................a............... 510
Które operatory nie mogą być poddane przeciążaniu? .......................................... 510
Ograniczenia typów wartości zwracanych przez funkcje operatorowe...................... 512
Spis treści
9
Ograniczenia liczby parametrów funkcji operatorowych ......................................... 514
Ograniczenia wynikające z priorytetu operatorów ................................................. 515
Przeciążone operatory jako komponenty składowe klas ............................................. 516
Zastępowanie funkcji globalnej metodą należącą do klasy ................................... 516
Zastosowanie komponentów klas w operacjach łańcuchowych ............................. 519
Zastosowanie słowa kluczowego const...................................................a............ 521
Analiza przedmiotowa — ułamki zwykłe...................................................a................. 523
Mieszane typy danych jako parametry...................................................a................... 533
Funkcje zaprzyjaźnione „friend” ...................................................a............................ 541
Podsumowanie ...................................................a...................................................a 556
Rozdział 11. Konstruktory i destruktory — potencjalne problemy
557
Więcej o przekazywaniu obiektów poprzez wartość...................................................a... 559
Przeciążanie operatorów w klasach nie będących klasami numerycznymi .................... 566
Klasa String ...................................................a.................................................. 567
Dynamiczne zarządzanie pamięcią na stercie ...................................................a... 569
Ochrona danych na stercie należących do obiektu od strony kodu klienta.............. 574
Przeciążony operator konkatenacji łańcuchów znakowych ..................................... 574
Zapobieganie wyciekom pamięci ...................................................a..................... 577
Ochrona integralności programu...................................................a...................... 578
Jak „stąd” przejść „tam”? ...................................................a.............................. 583
Więcej o konstruowaniu kopii obiektów ...................................................a................. 585
Sposób na zachowanie integralności programu ...................................................a 585
Semantyka referencji i semantyka wartości...................................................a...... 590
Konstruktor kopiujący definiowany przez programistę........................................... 592
Zwrot poprzez wartość...................................................a.................................... 597
Ograniczenia skuteczności konstruktorów kopiujących ......................................... 600
Przeciążenie operatora przypisania ...................................................a....................... 601
Problem z dodaną przez kompilator obsługą operatora przypisania ....................... 602
Przeciążenie przypisania — wersja pierwsza (z wyciekiem pamięci) ....................... 603
Przeciążenie przypisania — wersja następna (samoprzypisanie) ........................... 604
Przeciążenie przypisania — jeszcze jedna wersja (wyrażenia łańcuchowe)................... 605
Pierwszy środek zapobiegawczy — więcej przeciążania ........................................ 610
Drugi środek zapobiegawczy — zwrot wartości poprzez referencję......................... 611
Rozważania praktyczne — jak chcielibyśmy to zaimplementować? ............................. 612
Podsumowanie ...................................................a...................................................a 616
Część III Programowanie obiektowe przy wykorzystaniru agregacji
oraz dziedziczenia
619
Rozdział 12. Klasy złożone — pułapki i zalety
621
Wykorzystywanie obiektów jako danych składowych .................................................. 623
Składnia C++ dotycząca złożenia klas ...................................................a............. 625
Dostęp do danych składowych komponentów klasy ............................................. 626
Dostęp do danych składowych parametrów metody ............................................. 629
Inicjalizacja obiektów złożonych...................................................a............................ 630
Wykorzystanie domyślnych konstruktorów komponentów...................................... 632
Wykorzystanie listy inicjalizującej składowe ...................................................a...... 638
Dane składowe ze specjalnymi właściwościami ...................................................a..... 644
Stałe dane składowe ...................................................a..................................... 645
Dane składowe określone przez referencje ...................................................a...... 646
10
C++. Inżynieria programowania
Wykorzystywanie obiektów w charakterze danych składowych ich własnej klasy ..... 649
Wykorzystywanie statycznych danych składowych
w charakterze składowych ich własnych klas.................................................. 651
Klasy kontenerów..............................................a...................................................a.. 654
Klasy zagnieżdżone...................................................a........................................ 670
Klasy zaprzyjaźnione ...................................................a...................................... 673
Podsumowanie ...................................................a...................................................a 676
Rozdział 13. Klasy podobne — jak je traktować?
677
Traktowanie podobnych klas ...................................................a................................ 679
Łączenie cech podklas w jednej klasie...................................................a............. 681
Przekazywanie odpowiedzialności za integralność programu do klasy serwera........ 683
Oddzielenie klas dla każdego rodzaju obiektu serwera ......................................... 688
Wykorzystywanie dziedziczenia w języku C++ w celu łączenia powiązanych klas...... 691
Składnia dziedziczenia w języku C++ ...................................................a.................... 694
Różne tryby dziedziczenia z klasy bazowej ...................................................a........ 695
Definiowanie oraz wykorzystywanie obiektów klas bazowych oraz klas pochodnych ....699
Dostęp do usług klasy bazowej oraz pochodnej ...................................................a..... 701
Dostęp do komponentów bazowych w obiektach klasy pochodnej .............................. 706
Dziedziczenie publiczne...................................................a.................................. 706
Dziedziczenie chronione ...................................................a................................. 711
Dziedziczenie prywatne...................................................a................................... 716
Zwiększanie dostępu do składowych bazowych w klasie pochodnej....................... 718
Domyślny tryb dziedziczenia...................................................a............................ 720
Reguły zakresu widoczności oraz rozwiązywanie nazw przy stosowaniu dziedziczenia ... 722
Przeciążanie oraz ukrywanie nazw ...................................................a................... 725
Wywoływanie metody klasy bazowej ukrytej przez klasę pochodną......................... 729
Wykorzystanie dziedziczenia w celu rozwoju programu.......................................... 733
Konstruktory oraz destruktory klas pochodnych ...................................................a..... 736
Wykorzystanie list inicjalizujących w konstruktorach klas pochodnych.................... 740
Destruktory w przypadku dziedziczenia ...................................................a............ 743
Podsumowanie ...................................................a...................................................a 745
Rozdział 14. Wybór pomiędzy dziedziczeniem a złożeniem
747
Wybór techniki wielokrotnego wykorzystywania kodu ................................................. 749
Przykład relacji typu klient-serwer pomiędzy klasami ............................................ 749
Ponowne wykorzystanie kodu poprzez ludzką inteligencjęa
— po prostu zrób to jeszcze raz...................................................a................. 753
Ponowne użycie kodu poprzez kupowanie usług...................................................a 755
Ponowne wykorzystanie kodu poprzez dziedziczenie............................................. 759
Dziedziczenie wraz z ponownym zdefiniowaniem funkcji........................................ 764
Plusy i minusy dziedziczenia oraz złożenia ...................................................a....... 766
Język UML ...................................................a...................................................a....... 768
Cele stosowania języka UML...................................................a........................... 768
Podstawy UML — Notacja klas ...................................................a....................... 772
Podstawy UML — notacja relacji ...................................................a..................... 773
Podstawy UML — notacja dla agregacji oraz uogólnienia...................................... 774
Podstawy UML — notacja krotności ...................................................a................ 776
Studium przypadku — wypożyczalnia filmów...................................................a.......... 778
Klasy oraz ich skojarzenia ...................................................a.............................. 779
Spis treści
11
Widoczność klasy oraz podział odpowiedzialności ...................................................a.. 796
Widoczność klas oraz relacje pomiędzy klasami .................................................. 797
Przekazywanie odpowiedzialności do klas serwera............................................... 799
Stosowanie dziedziczenia ...................................................a............................... 801
Podsumowanie ...................................................a...................................................a 804
Część IV Zaawansowane wykorzystanie języka C++
805
Rozdział 15. Funkcje wirtualne oraz inne zaawansowane nsposoby
wykorzystania dziedziczenia
807
Konwersje pomiędzy klasami niepowiązanymi...................................................a........ 809
Ścisła oraz słaba kontrola typów ...................................................a..................... 812
Konstruktory konwertujące ...................................................a............................. 813
Rzutowania pomiędzy wskaźnikami (lub referencjami) .......................................... 815
Operatory konwersji ...................................................a....................................... 816
Konwersje pomiędzy klasami powiązanymi poprzez dziedziczenie ............................... 817
Konwersje bezpieczne oraz niebezpieczne ...................................................a....... 818
Konwersje wskaźników oraz referencji do obiektów.............................................. 824
Konwersje wskaźników oraz referencji występujących w charakterze argumentów... 833
Funkcje wirtualne — kolejny nowy pomysł ...................................................a............. 840
Wiązanie dynamiczne — podejście tradycyjne ...................................................a.. 843
Wiązanie dynamiczne — podejście obiektowe ...................................................a.. 852
Wiązanie dynamiczne — funkcje wirtualne ...................................................a....... 861
Wiązanie dynamiczne oraz statyczne ...................................................a............... 865
Funkcje czysto wirtualne...................................................a................................. 869
Funkcje wirtualne — destruktory ...................................................a..................... 873
Wielodziedziczenie — kilka klas bazowych ...................................................a............ 875
Wielodziedziczenie — reguły dostępu ...................................................a.............. 877
Konwersje pomiędzy klasami ...................................................a.......................... 878
Wielodziedziczenie — konstruktory oraz destruktory ............................................ 880
Wielodziedziczenie — niejednoznaczności...................................................a........ 881
Wielodziedziczenie — grafy skierowane ...................................................a........... 884
Czy wielodziedziczenie jest przydatne?...................................................a............. 885
Podsumowanie ...................................................a...................................................a 886
Rozdział 16. Zaawansowane wykorzystanie przeciążania operatorów
889
Przeciążanie operatorów — krótki wstęp ...................................................a............... 890
Operatory jednoargumentowe...................................................a............................... 898
Operatory inkrementacji oraz dekrementacji ...................................................a..... 899
Przyrostkowe operatory przeciążone ...................................................a................ 907
Operatory konwersji ...................................................a....................................... 910
Operatory indeksowania oraz wywołania funkcji ...................................................a..... 918
Operator indeksowania ...................................................a.................................. 918
Operator wywołania funkcji ...................................................a............................. 927
Operatory wejścia-wyjścia ...................................................a.................................... 933
Przeciążanie operatora ...................................................a.............................. 933
Przeciążanie operatora ...................................................a.............................. 937
Podsumowanie ...................................................a...................................................a 939
12
C++. Inżynieria programowania
Rozdział 17. Szablony — jeszcze jedno narzędzie projektowania
941
Prosty przykład projektowania klas przeznaczonych do wielokrotnego wykorzystania......... 942
Składnia definicji klasy szablonu ...................................................a.......................... 951
Specyfikacja klasy szablonu ...................................................a........................... 952
Konkretyzacja szablonu ...................................................a.................................. 953
Implementacja funkcji szablonu ...................................................a...................... 955
Szablony zagnieżdżone...................................................a................................... 962
Klasy szablonów z wieloma parametrami ...................................................a.............. 963
Kilka parametrów określających typ...................................................a................. 963
Szablony z parametrami określonymi za pomocą stałego wyrażenia ...................... 967
Związki pomiędzy konkretyzacjami klas szablonów...................................................a. 970
Zaprzyjaźnione klasy szablonów ...................................................a...................... 970
Zagnieżdżone klasy szablonów...................................................a........................ 974
Szablony ze składowymi statycznymi ...................................................a............... 977
Specjalizacje szablonów ...................................................a...................................... 979
Funkcje szablonowe ...................................................a............................................ 983
Podsumowanie ...................................................a...................................................a 985
Rozdział 18. Programowanie przy użyciu wyjątków
987
Prosty przykład obsługi wyjątków ...................................................a.......................... 988
Składnia wyjątków w języku C++...................................................a........................... 995
Generowanie wyjątków ...................................................a................................... 997
Przechwytywanie wyjątków ...................................................a.............................. 998
Deklaracja wyjątków...................................................a..................................... 1005
Przekazywanie wyjątków ...................................................a............................... 1007
Wykorzystywanie wyjątków z obiektami.............................................a...................... 1011
Składnia generowania, deklaracji oraz przechwytywania obiektów ....................... 1011
Wykorzystywanie dziedziczenia podczas stosowania wyjątków ............................ 1015
Wyjątki zdefiniowane w bibliotece standardowej ................................................ 1020
Operatory rzutowania...................................................a......................................... 1021
Operator static_cast ...................................................a.................................... 1022
Operator reinterpret_cast ...................................................a............................. 1026
Operator const_cast ...................................................a.................................... 1026
Operator dynamic_cast ...................................................a................................ 1029
Operator typeid...................................................a............................................ 1032
Podsumowanie ...................................................a................................................. 1033
Rozdział 19. Czego nauczyłeś się dotychczas?
1035
C++ jako tradycyjny język programowania...................................................a............ 1036
Wbudowane typy danych języka C++...................................................a.............. 1036
Wyrażenia języka C++ ...................................................a.................................. 1038
Przepływ kontroli w programie C++ ...................................................a................ 1040
C++ jako język modułowy...................................................a................................... 1041
Typy agregacyjne języka C++ — tablice...................................................a.......... 1042
Typy agregacyjne języka C++ — struktury, unie, wyliczenia ................................. 1043
Funkcje C++ jako narzędzia modularyzacji...................................................a...... 1044
Funkcje C++ — przekazywanie parametrów...................................................a.... 1046
Zakres widoczności oraz klasy pamięci w języku C++......................................... 1048
C++ jako język obiektowy...................................................a................................... 1049
Klasy języka C++ ...................................................a......................................... 1050
Konstruktory, destruktory oraz operatory przeciążone......................................... 1051
Spis treści
13
Składanie klas oraz dziedziczenie ...................................................a................. 1052
Funkcje wirtualne oraz klasy abstrakcyjne ...................................................a...... 1054
Szablony ...................................................a...................................................a.. 1055
Wyjątki...................................................a...................................................a..... 1056
Język C++ a konkurencja ...................................................a................................... 1058
Język C++ a starsze języki programowania...................................................a..... 1058
Język C++ a Visual Basic...................................................a.............................. 1058
Język C++ a C ...................................................a............................................. 1059
Język C++ a Java ...................................................a......................................... 1060
Podsumowanie ...................................................a................................................. 1062
Dodatki
Skorowidz
1063
1065
Konstruktory i destruktory
— potencjalne problemy
Zagadnienia omówione w tym rozdziale:
n
Więcej o przekazywaniu obiektów poprzez wartość.
n
Przeciążanie operatorów w klasach nie będących klasrami numerycznymi.
n
Więcej o konstruowaniu kopii obiektów.
n
Przeciążenie operatora przypisania.
n
Rozważania praktyczne — jak chcielibyśmy to zaimplemrentować?
n
Podsumowanie.
Funkcje operatorowe dokonujące przeciążenia operatorów przydają nowego impulsu progra-
mowaniu obiektowemu. Okazało się, że oto zamiast koncentrować się na łączeniu w jedną,
logicznie powiązaną całość danych i operacji w oparciu o pewne wspólne koncepcje, zaj-
mujemy się rozważaniami w kategoriach estetycznych i zagadnieniami równego traktowania
wbudowanych, elementarnych typów danych oraz typów definiowanych przez programistę
w programach pisanych w C++.
Ten rozdział stanowi bezpośrednią kontynuację poprzedniego. W rozdziale 10. „Funkcje ope-
ratorowe — jeszcze jeden dobry pomysł” omawiałem zagadnienia odnoszące się do projekto-
wania klas typu numerycznego na przykładzie klas QORNGZ (liczba zespolona) oraz 4CVKQPCN
(ułamek zwykły). Obiekty stanowiące zmienne (instancje) tych klas są pełnoprawnymi obiek-
tami, rzec można z prawdziwego zdarzenia. Stosują się do nich wszystkie zagadnienia od-
noszące się do klas i obiektów — deklaracja klasy, kontrola dostępu do składników klasy,
projektowanie metod, definiowanie obiektów i przesyłranie komunikatów do obiektów.
Typy danych definiowanych przez programistę (klasy) omawiane poprzednio są danymi nume-
rycznymi. Nawet jeśli mają wewnętrzną strukturę bardziej skomplikowaną niż elementarne typy
liczb całkowitych czy liczb zmiennoprzecinkowych, obriekty takich klas mogą być w kodzie
558
Część II n Programowanie obiektowe w C++
klienta obsługiwane w sposób podobny do liczb całkowitych i liczb zmiennoprzecinkowych.
W kodzie klienta obiekty takich typów mogą być dodarwane, mnożone, porównywane itp.
Popatrzmy uważnie na sposób wyartykułowania ostatniej myśli (w ostatnich dwóch zdaniach).
Określenie „obiekty takich typów mogą…” odnosi się oczywiście do typów zdefiniowanych
przez programistę. Co natomiast oznacza „podobny do liczb całkowitych czy liczb zmienno-
przecinkowych…”? Skoro te dane porównujemy z typami zdefiniowanymi przez programi-
stę, mamy tu na myśli „typy wartości całkowitych i zmiennoprzecinkowych”, a nie same
zmienne tychże typów. Lepiej zapewne byłoby tu użyć sformułowania „wbudowane typy
danych”. Co oznacza „obiekty takich klas mogą być w kodzie klienta obsługiwane…”? Tu
chyba także chodzi o typy zdefiniowane przez programistę? Niezupełnie, ponieważ w tym
zdaniu mówi się o obsłudze po stronie kodu klienta. Kod klienta nie obsługuje typów zdefi-
niowanych przez programistę, lecz obiekty typu zdefiniowanego przez programistę. To zmien-
ne określonego typu (instancje, obiekty) są dodawane, mnożone, porównywane, itp. Autor
podkreśla tu wyraźnie ten szczegół, ponieważ wiesz już o klasach i obiektach wystarczają-
co dużo, by wyczuwać brak precyzji w niektórych sformułowaniach w dyskusji o programo-
waniu obiektowym i by samemu unikać, w miarę możliwości, takich nieprecyzyjnych sfor-
mułowań.
Innymi słowy, obiekty klas (typów) numerycznych, zdefiniowanych przez programistę, mogą
po stronie kodu klienta być obsługiwane podobnie do zmiennych elementarnych typów wbu-
dowanych. Z tego powodu obsługa przeciążania operatorów wobec takich klas zdecydowanie
ma sens. Zasada C++, by umożliwiać traktowanie zmiennych typów elementarnych i obiek-
tów typów zdefiniowanych przez programistę w jednakowy sposób — działa prawidłowo
wobec tych klas. W tym rozdziale autor zamierza omówić przeciążanie operatorów wobec
takich klas, których obiekty nie mogą być dodawane, mnożone, odejmowane ani dzielone.
Na przykład do obsługi łańcuchów znaków w pamięci można utworzyć klasę 5VTKPI. Z ra-
cji nienumerycznego charakteru takich klas (z samej ich natury) funkcje operatorowe doko-
nujące przeciążenia operatorów wobec tych klas wyglądają sztucznie i nienaturalnie. Na przy-
kład możemy dokonać przeciążenia operatora dodawania (
w taki sposób, by umożliwiał
konkatenację dwóch obiektów klasy 5VTKPI (dodanie drugiego łańcucha znaków do końca
pierwszego) lub np. przeciążenia operatora numerycznej równości ( w taki sposób, by
umożliwiał porównanie dwóch łańcuchów znaków reprezentowanych przez obiekty klasy
5VTKPI. I to wygląda dość rozsądnie. Z drugiej jednak strony, trudno wymyślić jakąkolwiek
rozsądną interpretację dla operatorów mnożenia czy dzielenia wobec obiektów klasy 5VTKPI.
Niemniej jednak funkcje operatorowe dokonujące przeciążania operatorów C++1 dla klas nie-
numerycznych są popularne i powinno się wiedzieć, jak z nimi postępować.
Ważną różnicą pomiędzy klasami numerycznymi a nienumerycznymi jest to, że w klasach
nienumerycznych mogą występować znaczące różnice w objętości danych, którymi mogą
posługiwać się obiekty tej samej klasy. Obiekty klas numerycznych zawsze zajmują taką
samą ilość miejsca w pamięci. Na przykład obiekty klasy 4CVKQPCN zawierają zawsze dwa
pola danych — licznik i mianownik.
Natomiast w przypadku klasy 5VTKPI objętość tekstu, który może być przechowywany w po-
jedynczym obiekcie tej klasy, może być inna niż objętość tekstu przechowywana w innym
obiekcie tej samej klasy. Jeśli klasa rezerwuje dla każdego obiektu taką samą (zbyt dużą)
1
Przypomnijmy: pierwotnie, z natury arytmetycznych —j przyp. tłum.
Rozdział 11. n Konstruktory i destruktory — potencjalne problemy
559
ilość pamięci, mamy do czynienia w programie z dwoma niekorzystnymi, a skrajnymi zja-
wiskami — marnowaniem pamięci (gdy rzeczywista wielkość tekstu jest mniejsza niż ilość
zarezerwowanej pamięci) albo z przepełnieniem pamięci (gdy rzeczywista wielkość tekstu
okaże się większa niż ilość zarezerwowanej pamięci). Te dwa niebezpieczeństwa czyhają stale
i w którąś z tych dwu pułapek zawsze, prędzej czy później, wpadną ci projektanci klas, któ-
rzy rezerwują tę samą ilość pamięci dla każdego takriego obiektu.
C++ rozwiązuje ten problem poprzez przyporządkowanie dla każdego obiektu tej samej ilości
pamięci (na stercie albo na stosie) zgodnie ze specyfikacją klasy, a następnie ewentualne do-
danie, w miarę potrzeby, dodatkowej pamięci na stercie2. Taka dodatkowa ilość pamięci na
stercie zmienia się i może być zupełnie inna dla poszczególnych obiektów. Nawet dla jednego,
konkretnego obiektu podczas jego życia ta ilość dodatkowej pamięci może się zmieniać. Na
przykład jeśli do obiektu klasy 5VTKPI zawierającego jakiś tekst dodawany jest następny
łańcuch znaków (konkatenacja), taki obiekt może powiększyć swoją pamięć, by pomieścić
nowy, dłuższy tekst.
Dynamiczne zarządzanie pamięcią na stercie obejmuje zastosowanie konstruktorów i destruk-
torów. Ich nieumiejętne, niezręczne stosowanie może negatywnie wpłynąć na efektywność
działania programu. Co gorsza, może to spowodować utratę danych przechowywanych
w pamięci i utratę integralności programu, co jest zjawiskiem charakterystycznym dla C++,
nieznanym w innych językach programowania. Każdy programista pracujący w C++ powi-
nien być świadom tych zagrożeń. To z tego powodu zagadnienia te zostały włączone do tytułu
niniejszego rozdziału, mimo że ten rozdział stanowi w istocie kontynuację rozważań o funk-
cjach operatorowych dokonujących przeciążenia operatorów.
Dla uproszczenia dyskusji niezbędne podstawowe koncepcje zostaną tu wprowadzone w opar-
ciu o klasę 4CVKQPCN (o stałej wielkości obiektów), znaną z rozdziału 10. W tym rozdziale te
koncepcje zostaną zastosowane w odniesieniu do klasy 5VTKPI z dynamicznym zarządzaniem
pamięci na stercie. W rezultacie twoja intuicja programistyczna wzbogaci się o wyczucie relacji
pomiędzy instancjami obiektów po stronie kodu klienta. Jak się przekonasz, relacje pomiędzy
obiektami okażą się inne niż relacje pomiędzy zmiennymi typów elementarnych, pomimo
wysiłków, by takie zmienne i obiekty były traktowane tak samo. Innymi słowy, powinieneś
przygotować się na duże niespodzianki.
Lepiej nie pomijać materiału zawartego w niniejszym rozdziale. Zagrożenia związane z za-
stosowaniem i rolą konstruktorów i destruktorów w C++ są to niebezpieczeństwa zdecydo-
wanie realne i należy wiedzieć, jak się przed nimi bronić (broniąc przy okazji swojego szefa
i swoich użytkowników).
Więcej o przekazywaniu obiektów poprzez wartość
Wcześniej, w rozdziale 7. („Programowanie w C++ z zastosowaniem funkcji”) przytaczano
argumenty przeciwko przekazywaniu obiektów do funkcji jako parametrów poprzez war-
tość albo poprzez wskaźnik do obiektu, natomiast zachęcano, by zamiast tego przekazywać
obiekty jako parametry — poprzez referencje.
W sposób dynamiczny — przyp. tłum.
2
560
Część II n Programowanie obiektowe w C++
Autor wyjaśniał tam, że przekazanie parametru poprzez referencję jest prawie równie proste,
jak przekazanie go poprzez wartość, jest jednakże szybsze — w przypadku tych parametrów
wejściowych, które nie zostaną zmodyfikowane przez daną funkcję. Przekazywanie poprzez
referencję jest równie szybkie, jak przekazywanie poprzez wskaźnik, ale składnia odnosząca
się do parametrów przekazywanych poprzez referencję jest znacznie prostsza — dla parame-
trów wyjściowych, które zostają zmodyfikowane przez rdaną funkcję w trakcie jej wykonania.
Zaznaczono tam również, że składnia przy przekazywaniu parametrów poprzez referencje
jest dokładnie taka sama — i dla parametrów wejściowych, i dla parametrów wyjściowych
funkcji. Z tego też powodu autor sugerował stosowanie słowa kluczowego (modyfikatora) EQPUV
dla parametrów wejściowych w celu wskazania, że te parametry nie zostaną zmodyfikowane
w wyniku wykonania danej funkcji. Jeśli nie stosujemy żadnych takich sugestii, powinno to
w sposób nie wzbudzający wątpliwości wskazywać, że te parametry będą zmienione w trak-
cie wykonania danej funkcji.
Oprócz tego autor przytaczał argumenty przeciwko zwracaniu obiektów z funkcji poprzez
wartość, jeśli tylko nie jest to niezbędne w celu przesłania innych komunikatów do takiego
zwróconego obiektu (składnia łańcuchowa w wyrażeniach).r
Przy takim podejściu przekazywanie parametrów poprzez wartość powinno być ograniczone
do przekazywania parametrów wejściowych funkcji, jeśli są one typów elementarnych, i zwrotu
z funkcji wartości tychże typów elementarnych. Dlaczego parametry wejściowe typów wbu-
dowanych są akceptowalne? Przekazywanie ich poprzez wskaźnik zwiększy stopień złożo-
ności i może wprowadzić w błąd osobę czytającą kod, sugerując, że taki parametr może zostać
zmodyfikowany podczas wykonania funkcji. Przekazanie ich poprzez referencje (z modyfi-
katorem EQPUV) nie jest trudne, ale zwiększa nieco stopień złożoności kodu. Skoro takie pa-
rametry są niewielkie, przekazywanie ich poprzez referencje nie zwiększy w najmniejszym
stopniu szybkości działania programu. Z wymienionych powodów najprostszy sposób prze-
kazywania parametrów (poprzez wartość) jest stosowny dla typów wbudowanych.
W trakcie ostatniego rozdziału poznaliśmy wystarczająco techniki programowania, umożli-
wiające nam nie tylko omówienie wad i zalet różnych trybów przekazywania parametrów
do funkcji i z funkcji, lecz także umożliwiających nam prześledzenie kolejności wywołań
funkcji.
Oprócz tego przy różnych okazjach autor podkreślał, że inicjowanie i przypisanie, nawet je-
śli w obu przypadkach następuje użycie tego samego symbolu , są różnie traktowane . W tym
podrozdziale przy użyciu wydruków komunikatów diagnostycznych zostaną zademonstrowane
te różnice.
Oba zagadnienia zostaną zademonstrowane za pomocą prrzykładowego kodu z listingu 11.1,
zawierającego uproszczoną (i zmodyfikowaną) wersję klasy 4CVKQPCN z poprzedniego rozdziału
oraz funkcję testującą — VGUVFTKXGT.
Listing 11.1. Przykład przekazania obiektów jako parametrów funkpcji poprzez wartość
KPENWFGKQUVTGCOJ
ENCUU4CVKQPCN
]
NQPIPOTFPORT[YCVPGFCPG
XQKFPQTOCNKG
RT[YCVPGOGVQF[
Rozdział 11. n Konstruktory i destruktory — potencjalne problemy
561
RWDNKE
4CVKQPCN
NQPIPNQPIFMQPUVTWMVQTQIÎNP[MQPYGTULKKFQO[ħNP[
]POTPFPOF
VJKU PQTOCNKG
EQWVQDKGMVWVYQTQP[
MQPUVTWMVQTPOTFPOGPFN_
4CVKQPCN
EQPUV4CVKQPCNTMQPUVTWMVQTMQRKWLæE[
]POTTPOTFPOTFPO
EQWVQDKGMVUMQRKQYCP[
MQPUVTWMVQTMQRKWLæE[POTFPOGPFN
_
XQKFQRGTCVQT
EQPUV4CVKQPCNTQRGTCVQTRT[RKUCPKC
]POTTPOTFPOTFPO
EQWVQDKGMVRT[RKUCP[
QRGTCVQT
POTFPOGPFN_
`4CVKQPCN
FGUVTWMVQT
]EQWVQDKGMVWUWPKúV[
FGUVTWMVQTPOTFPOGPFN_
HTKGPF4CVKQPCNQRGTCVQT
EQPUV4CVKQPCNZEQPUV4CVKQPCN[
XQKFUJQY
EQPUV
_MQPKGEURGE[HKMCELKMNCU[
XQKF4CVKQPCNUJQY
EQPUV
]EQWVPOTFPO_
XQKF4CVKQPCNPQTOCNKG
RT[YCVPCOGVQFC
]KH
POT]FPOTGVWTP_
KPVUKIP
KH
POT]UKIPPOTPOT_OKGēPCM
KH
FPO]UKIPUKIPFPOFPO_D[QD[FYCD[đ[FQFCVPKG
NQPIIEFPOTXCNWGFPOPCLYKúMU[YURÎNP[RQFKGNPKM
YJKNG
XCNWGIEF]CVT[OCLRQPCNGKGPKWPYR
KH
IEF XCNWG
IEFIEFXCNWGQFGLOWLNKEDúOPKGLUæQFYKúMUGL
GNUGXCNWGXCNWGIEF_
POTUKIP
POTIEFFPOFPOIEF_OKCPQYPKMFQFCVPK
4CVKQPCNQRGTCVQT
EQPUV4CVKQPCNZEQPUV4CVKQPCN[
]TGVWTP4CVKQPCN
[POTZFPO
ZPOT[FPO[FPOZFPO_
KPVOCKP
]4CVKQPCNC
D
E
EQWVGPFN
EC
D
CUJQY
EQWV
DUJQY
EQWVEUJQY
EQWVGPFNGPFN
TGVWTP
_
Spośród wszystkich funkcji odnoszących się uprzednio do klasy 4CVKQPCN pozostawiono tu
jedynie funkcje PQTOCNKG
, UJQY
oraz QRGTCVQT
. Poza tym zwróć uwagę, że funkcja
dokonująca przeciążenia operatora dodawania, QRGTCVQT
, nie jest w tym przypadku me-
todą, lecz funkcją zaprzyjaźnioną kategorii HTKGPF. Z tego powodu na początku tego pod-
rozdziału (i dalej) w odniesieniu do klasy 4CVKQPCN użyto stwierdzenia: „wszystkich funkcji
odnoszących się uprzednio do klasy”, a nie „wszystkich metod należących do klasy”. Autor
postąpił tak, choć chciałby jeszcze raz zaakcentować, że zaprzyjaźnione funkcje kategorii
HTKGPF z punktu widzenia wszelkich zamiarów i zastosowań są jak metody należące do kla-
sy. Funkcja zaprzyjaźniona jest implementowana w tym samym pliku, co wszystkie metody,
ma takie same prawa dostępu do prywatnych składników klasy, jak wszystkie metody, jest
całkowicie bezużyteczna wobec obiektów klasy innej niż jej klasa „zaprzyjaźniona”, w tym
przypadku klasa 4CVKQPCN — jak wszystkie inne metody. Różnica polega jedynie na składni
stosowanej przy wywołaniu tej funkcji. Tylko tu funkcja zaprzyjaźniona różni się od metod,
562
Część II n Programowanie obiektowe w C++
ale w przypadku funkcji operatorowych, dokonujących przeciążania operatorów, składnia
operatorowa jest dokładnie taka sama dla funkcji zaprzyjaźnionych i dla metod należących
do klasy.
W obrębie ogólnego (dwuargumentowego) konstruktora klasy 4CVKQPCN dodano wydruk ko-
munikatu o charakterze diagnostycznym. Ten wydruk komunikatu powinien następować za
każdym razem, gdy obiekt klasy 4CVKQPCN jest tworzony i inicjowany przez ten konstruktor
— na początku kodu funkcji OCKP
i we wnętrzu kodu funkcji operatorowej QRGTCVQT
.
4CVKQPCN4CVKQPCN
NQPIPNQPIFYCTVQħEKFQO[ħNPG
]
POTPFPOFKPKELQYCPKGFCP[EJ
VJKU PQTOCNKG
EQWVQDKGMVWVYQTQP[
MQPUVTWMVQTPOTFPOGPFN
_
Dodano tu także konstruktor kopiujący z wydrukiem komunikatu diagnostycznego. Ten ko-
munikat diagnostyczny zostanie wyprowadzony na ekran zawsze, gdy obiekt klasy 4CVKQPCN
będzie inicjowany za pomocą kopiowania pól danych innego obiektu klasy 4CVKQPCN. Takie
kopiowanie obiektu na przykład nastąpi wtedy, gdy parametry będą przekazywane poprzez
wartość do funkcji QRGTCVQT
lub gdy będzie następował zwrot wartości z funkcji (zwrot
obiektu poprzez wartość).
4CVKQPCN4CVKQPCN
EQPUV4CVKQPCNTMQPUVTWMVQTMQRKWLæE[
]
POTTPOTFPOTFPOMQRKWLRQNCFCP[EJ
EQWVQDKGMVUMQRKQYCP[
MQPUVTWMVQTMQRKWLæE[POTFPOGPFN
_
Ten konstruktor kopiujący jest wywoływany, gdy argumenty klasy (typu) 4CVKQPCN są poprzez
wartość przekazywane do zaprzyjaźnionej funkcji operatorowej HTKGPFQRGTCVQT
. Wbrew
mylnemu pierwszemu wrażeniu, ten konstruktor kopiujący nie zostanie wywołany, gdy funk-
cja QRGTCVQT
będzie zwracać obiekt poprzez wartość, ponieważ przed powrotem z tej funk-
cji operatorowej nastąpi wywołanie dwuargumentowego konstruktora ogólnego.
W klasie 4CVKQPCN destruktor nie ma do wykonania odpowiedzialnego zadania i został dodany
do specyfikacji tej klasy tylko w celu ułatwienia wyprowadzania komunikatów diagnostycz-
nych; destruktor zgłosi się poprzez wydruk komunikatu diagnostycznego zawsze, gdy obiekt
klasy 4CVKQPCN będzie usuwany.
Najciekawszą funkcją jest tu funkcja dokonująca przeciążenia operatora przypisania (). Jej
praca polega na kopiowaniu pól danych jednego obiektu klasy 4CVKQPCN na pola danych in-
nego obiektu klasy 4CVKQPCN. Czym jej działanie różni się od działania konstruktora kopiu-
jącego? W tym stadium możemy stwierdzić, że niczym, choć inny jest typ wartości zwracanej.
Konstruktor kopiujący, jak to konstruktor, nie może mieć żadnego typu wartości zwracanej,
natomiast metoda operatorowa, jak większość metod, musi mieć jakiś typ wartości zwracanej.
Dla uproszczenia przyjęto tu ten typ wartości zwracranej jako XQKF.
XQKF4CVKQPCNQRGTCVQT
EQPUV4CVKQPCNTQRGTCELCRT[RKUCPKC
]
POTTPOTFPOTFPOMQRKQYCPKGFCP[EJ
EQWVQDKGMVRT[RKUCP[
QRGTCVQT
POTFPOGPFN
_
Rozdział 11. n Konstruktory i destruktory — potencjalne problemy
563
Poddany tu przeciążeniu operator przypisania ( jest operatorem dwuargumentowym (bi-
narnym). Skąd to wiadomo? Po pierwsze, funkcja operatorowa ma jako jeden parametr obiekt
klasy 4CVKQPCN, a nie jest to funkcja zaprzyjaźniona, lecz metoda. Skoro tak, jak każda metoda
z jednym parametrem obiektowym, działa na dwóch argumentach. Jednym, niejawnym ar-
gumentem jest obiekt docelowy komunikatu (widziany przez metodę jako własny obiekt), dru-
gim, jawnym argumentem jest obiekt — parametr. Drugim wyjaśnieniem jest składnia sto-
sowania operatora przypisania (po stronie kodu klienta). Operator dwuargumentowy jest zawsze
wstawiany pomiędzy pierwszy a drugi operand. Gdy dodaje się dwa operandy, kolejność
jest następująca: pierwszy operand, operator, drugi operand (np. C
D). Podobnie jest, gdy
dokonuje się przypisania. I tu kolejność jest następująca: pierwszy operand, operator, drugi
operand (np. C D). Odnosząc to teraz do składni wywołania funkcji, zauważamy, że
obiekt C jest docelowym obiektem komunikatu. W podanej funkcji operatorowej, dokonującej
przeciążenia operatora przypisania, pola POT (licznik ułamka) oraz FPO (mianownik ułamka)
należą do docelowego obiektu komunikatu, C. Obiekt D jest bieżącym argumentem danego
wywołania funkcji operatorowej. W podanej funkcji operatorowej, dokonującej przeciążenia
operatora przypisania, pola TPOT oraz TFPO należą do bieżącego argumentu metody, D.
Skoro tak, to operator (CD) przypisania odpowiada wywołaniu funkcji operatorowej o na-
stępującej składni: CQRGTCVQT
D.
Ponieważ ta metoda ma t
Pobierz darmowy fragment (pdf)