SlideShare une entreprise Scribd logo
1  sur  24
Télécharger pour lire hors ligne
IDZ DO
         PRZYK£ADOWY ROZDZIA£

                           SPIS TRE CI   C++. Styl
                                         programowania
           KATALOG KSI¥¯EK
                                         Autor: Tom Cargill
                      KATALOG ONLINE     T³umaczenie: Adam Majczak
                                         ISBN: 83-7361-321-8
       ZAMÓW DRUKOWANY KATALOG           Tytu³ orygina³u: C++ Programming Style
                                         Format: B5, stron: 224

              TWÓJ KOSZYK
                                         C++ wspomaga programowanie w du¿ej skali, pozwalaj¹c na precyzyjne wyra¿enie
                    DODAJ DO KOSZYKA     wspó³zale¿no ci pomiêdzy ró¿nymi czê ciami programu. Dlatego zakres pojêciowy
                                         techniki i stylu programowania w C++ wykracza poza tradycyjne jego pojmowanie
                                         w odniesieniu do programowania w ma³ej skali, sprowadzaj¹cego siê do szczegó³ów
         CENNIK I INFORMACJE             kodowania wiersz po wierszu.
                                         Autor dowodzi, ¿e nieprzemy lane stosowanie z³o¿onych i zaawansowanych technik
                   ZAMÓW INFORMACJE      programowania mo¿e prowadziæ do tworzenia chaotycznych, niezrozumia³ych i mêtnych
                     O NOWO CIACH        konstrukcji, stanowi¹cych zarazem czêsto rozwi¹zania mniej efektywne, ni¿ prostsze
                                         i zrozumia³e konstrukcje alternatywne. Tom Cargill dokonuje przeredagowania licznych
                       ZAMÓW CENNIK      programów, stosuj¹c techniki pozwalaj¹ce na udoskonalenie kodu, pocz¹wszy
                                         od poprawy spójno ci, po usuniecie zbêdnego, nadmiarowego dziedziczenia.
                                         Sposób prezentacji zagadnieñ rozpoczyna siê od przegl¹du oryginalnego kodu,
                 CZYTELNIA               który mo¿esz samodzielnie oceniæ i przeanalizowaæ, rozwa¿aj¹c mo¿liwe alternatywne
                                         podej cia do przedstawionych zagadnieñ programistycznych. Te w³asne przemy lenia
          FRAGMENTY KSI¥¯EK ONLINE       mo¿esz nastêpnie porównaæ z analizami i wnioskami Autora.
                                         Na podstawie przyk³adów formu³owane s¹ uniwersalne regu³y i zasady tworzenia kodu
                                         i projektowania programów. Zrozumienie i umiejêtne stosowanie tych regu³ pomo¿e
                                         profesjonalnym programistom projektowaæ i pisaæ lepsze programy w C++.
                                         Kolejne rozdzia³y po wiêcone s¹ nastêpuj¹cym zagadnieniom:
                                            • Abstrakcja —- pojêcia i modele abstrakcyjne
                                            • Spójno æ
                                            • Zbêdne dziedziczenie
                                            • Funkcje wirtualne
                                            • Przeci¹¿anie operatorów
                                            • Nak³adki typu „wrapper”
Wydawnictwo Helion                          • Efektywno æ
ul. Chopina 6
                                         Po wprowadzeniu i zilustrowaniu regu³ programowania w pierwszych siedmiu
44-100 Gliwice
tel. (32)230-98-63                       rozdzia³ach, Tom Cargill prezentuje praktyczne studium, w trakcie którego pojedynczy
e-mail: helion@helion.pl                 przyk³adowy program przechodzi kolejne transformacje, które pozwalaj¹ poprawiæ
                                         jego ogóln¹ jako æ przy jednoczesnym zredukowaniu wielko ci kodu. Konkluzjê ksi¹¿ki
                                         stanowi rozdzia³ po wiêcony wielokrotnemu dziedziczeniu.
                                         Ksi¹¿ka Toma Cargilla to nie tylko cenne ród³o wiedzy dla zaawansowanych
                                         programistów — przyda siê ona równie¿ studentom informatyki i pokrewnych kierunków,
                                         zainteresowanych zdobyciem profesjonalnych umiejêtno ci programistycznych.
Spis treści




Przedmowa...............................................................................................................7
Wprowadzenie .........................................................................................................9

1.
Abstrakcja ..............................................................................................................15
Przykład techniki programowania: ceny komputerów...................................................................................... 15
Poszukiwanie wspólnego pojęcia abstrakcyjnego............................................................................................. 19
Ró nice pomiędzy klasami................................................................................................................................ 22
Powtórnie wprowadzamy do programu dziedziczenie...................................................................................... 26
Wyeliminowanie typów wyliczeniowych ......................................................................................................... 27
Podsumowanie .................................................................................................................................................. 30
Bibliografia ....................................................................................................................................................... 31
Ćwiczenie .......................................................................................................................................................... 31

2.
Spójność kodu........................................................................................................35
Przykład techniki programowania: klasa string ................................................................................................ 36
Precyzyjnie zdefiniowany stan obiektu............................................................................................................. 37
Spójność fizycznego stanu obiektu ................................................................................................................... 38
Niezmienne warunki, czyli inwariancja klas..................................................................................................... 39
Konsekwentne stosowanie dynamicznego zarządzania pamięcią..................................................................... 41
Zwolnienie dynamicznie przyporządkowanej pamięci ..................................................................................... 43
Przykład techniki programowania: drugie podejście do tego samego problemu.............................................. 44
Podsumowanie .................................................................................................................................................. 50
Bibliografia ....................................................................................................................................................... 51
Ćwiczenia .......................................................................................................................................................... 51

3.
Zbędne dziedziczenie.............................................................................................55
Przykład techniki programowania: stos ............................................................................................................ 55
Reguły widoczności nazw w procesie dziedziczenia........................................................................................ 59
Relacje tworzone poprzez dziedziczenie........................................................................................................... 60
4                                                                                                                                                      SPIS TREŚCI



Enkapsulacja...................................................................................................................................................... 65
Interfejs a implementacja .................................................................................................................................. 67
Zastosowanie szablonów................................................................................................................................... 71
Podsumowanie .................................................................................................................................................. 73
Bibliografia ....................................................................................................................................................... 73
Ćwiczenie .......................................................................................................................................................... 74

4.
Funkcje wirtualne ..................................................................................................75
Przykład techniki programowania: problem pojazdów i gara y....................................................................... 75
Spójność kodu ................................................................................................................................................... 79
Destruktory klas bazowych ............................................................................................................................... 81
Dziedziczenie .................................................................................................................................................... 82
Sprzę enie ......................................................................................................................................................... 85
Podsumowanie .................................................................................................................................................. 91
Bibliografia ....................................................................................................................................................... 92
Ćwiczenie .......................................................................................................................................................... 92

5.
Przecią anie operatorów ........................................................................................93
Przecią anie operatorów — podstawy .............................................................................................................. 93
Przykład techniki programowania: tablica plików FileArray ........................................................................... 98
Dziedziczenie implementacji .......................................................................................................................... 105
Programistyczny dylemat — jak lepiej: przecią one operatory czy metody .................................................. 110
Podsumowanie ................................................................................................................................................ 112
Bibliografia ..................................................................................................................................................... 112
Ćwiczenia ........................................................................................................................................................ 112

6.
Klasy otaczające (ang. wrappers) ........................................................................113
Biblioteka C .................................................................................................................................................... 113
Przykład techniki programowania: klasa otaczająca dla struktury dirent w C++........................................... 114
Wiele obiektów klasy Directory...................................................................................................................... 116
Gdy zawodzi konstruktor ................................................................................................................................ 119
Publiczny dostęp do stanu obiektu .................................................................................................................. 121
Dodatkowy argument słu ący obsłudze błędów ............................................................................................. 123
Podsumowanie ................................................................................................................................................ 127
Bibliografia ..................................................................................................................................................... 128
Ćwiczenie ........................................................................................................................................................ 128

7.
Efektywność.........................................................................................................129
Przykład techniki programowania: klasa BigInt ............................................................................................. 130
Egzaminujemy klasę BigInt ............................................................................................................................ 136
Długość dynamicznych łańcuchów znaków ................................................................................................... 138
Liczba dynamicznie zapamiętywanych łańcuchów znaków........................................................................... 140
Kod klienta ...................................................................................................................................................... 144
Modyfikujemy klasę BigInt ............................................................................................................................ 145
SPIS TREŚCI                                                                                                                                                         5

Podsumowanie ................................................................................................................................................ 151
Bibliografia ..................................................................................................................................................... 152
Ćwiczenia ........................................................................................................................................................ 152

8.
Studium praktyczne .............................................................................................153
Przykład techniki programowania: Finite State Machine, czyli automat stanów skończonych ..................... 153
Zainicjowanie .................................................................................................................................................. 158
Sprzę enia ....................................................................................................................................................... 165
Spójność .......................................................................................................................................................... 169
Moduły kontra abstrakcyjne typy danych ....................................................................................................... 172
Wartość kontra zachowanie ............................................................................................................................ 175
Uogólnienie ..................................................................................................................................................... 180
Bibliografia ..................................................................................................................................................... 184
Ćwiczenia ........................................................................................................................................................ 185

9.
Dziedziczenie wielokrotne...................................................................................187
Niejednoznaczności w mechanizmie wielokrotnego dziedziczenia................................................................ 187
Skierowane niecykliczne grafy hierarchii dziedziczenia ................................................................................ 189
Eksplorujemy wirtualne klasy bazowe............................................................................................................ 193
Przykład techniki programowania: klasa Monitor .......................................................................................... 200
Przykład techniki programowania: wirtualna klasa bazowa ........................................................................... 204
Protokół powiadomień zwrotnych i przydatne wielokrotne dziedziczenie..................................................... 210
Podsumowanie ................................................................................................................................................ 213
Bibliografia ..................................................................................................................................................... 213
Ćwiczenia ........................................................................................................................................................ 213

10.
Zbiorcza lista reguł ..............................................................................................215
Rozdział 1.: „Abstrakcja”................................................................................................................................ 215
Rozdział 2.: „Spójność kodu” ......................................................................................................................... 215
Rozdział 3.: „Zbędne dziedziczenie” .............................................................................................................. 216
Rozdział 4.: „Funkcje wirtualne” .................................................................................................................... 216
Rozdział 5.: „Przecią anie operatorów”.......................................................................................................... 216
Rozdział 6.: „Klasy otaczające (ang. wrappers)”............................................................................................ 216
Rozdział 7.: „Efektywność” ............................................................................................................................ 217
Rozdział 8.: „Studium praktyczne”................................................................................................................. 217
Rozdział 9.: „Dziedziczenie wielokrotne” ...................................................................................................... 217

Skorowidz ............................................................................................................219
3
Zbędne dziedziczenie




Chocia w rozdziale 2. uwa nie rozró nialiśmy interfejs klasy i implementację klasy, nie czynili-
śmy tego w kontekście dziedziczenia. Aby dokładnie zrozumieć relację dziedziczenia pomiędzy klasą
pochodną a jej klasą bazową, musimy rozpatrywać część interfejsową i część implementacyjną klasy
w sposób odrębny. W tym rozdziale przeanalizujemy przypadek, który z pozoru wydaje się być
naturalną kandydaturą do zastosowania dziedziczenia. Mimo to, dokładniejsza analiza dziedzicze-
nia i implementacji klas bazowej i pochodnej spowoduje w efekcie znaczącą modyfikację kodu.




Przykład techniki programowania: stos
Na listingu 3.1 pokazano program, w którym zostały zdefiniowane klasy %JCT5VCEM (dosł. stos prze-
znaczony na znaki) oraz +PV5VCEM (dosł. stos przeznaczony na liczby typu KPV). Przeanalizujmy i oceń-
my te klasy. Czy widać tu uogólnienie pojęć abstrakcyjnych? Czy dziedziczenie działa w sposób
poprawny? Czy dziedziczenie zostało wykorzystane we właściwy sposób?

LISTING 3.1.
Oryginalna wersja klas Stack, CharStack oraz IntStack

 KPENWFG CUUGTVJ
 KPENWFG UVTKPIJ

ENCUU 5VCEM ]  MNCUC DCQYC UVQU
   KPV VQR             YKGTEJQ GM UVQUW
   KPV UKG            TQOKCT
RTQVGEVGF              FQUVúRPG V[NMQ FNC MNCU RQEJQFP[EJ
   XQKF
XGE          VCDNKEC YUMC PKMÎY 
YGMVQT
RWDNKE                 RWDNKEP[ KPVGTHGLU MNCU[ DCQYGL
   5VCEM
KPV U       MQPUVTWMVQT QIÎNP[
   `5VCEM
            FGUVTWMVQT MNCU[ DCQYGL
   XQKF
RWUJ
        OGVQFC QF Î PC UVQU
   XQKF
RQR
         OGVQFC FGLOKL G UVQUW
_
56                                                                    3. ZBĘDNE DZIEDZICZENIE



5VCEM5VCEM
KPV U    FGHKPKELC MQPUVTWMVQTC
]
  XGE  PGY XQKF
=UKGU?
  VQR  
_

5VCEM`5VCEM

]
  FGNGVG =? XGE         YCNPKC RCOKúè CLOQYCPæ RTG VCDNKEú YUMC PKMÎY
_

XQKF
5VCEMRWUJ

]
  CUUGTV
VQR  UKG
  TGVWTP XGE=VQR

?
_

XQKF
5VCEMRQR

]
  CUUGTV
VQR   
  TGVWTP XGE=VQR?
_

EQPUV KPV FGHCWNV5VCEM        FQO[ NP[ TQOKCT UVQUW

ENCUU %JCT5VCEM  RWDNKE 5VCEM ]
  EJCT
FCVC                     RT[YCVP[ YUMC PKM FQ FCP[EJ
RWDNKE
  %JCT5VCEM
                    MQPUVTWMVQT FQO[ NP[
  %JCT5VCEM
KPV UKG
  %JCT5VCEM
KPV UKG EJCT
KPKV
  `%JCT5VCEM


  XQKF RWUJ
EJCT
  EJCT RQR

_

%JCT5VCEM%JCT5VCEM
  5VCEM
 FGHCWNV5VCEM 
]
  FCVC  PGY EJCT=FGHCWNV5VCEM?
  HQT
 KPV K KFGHCWNV5VCEM 

K
    XGE=K?  FCVC=K?
_

%JCT5VCEM%JCT5VCEM
KPV UKG  5VCEM
UKG
]
  FCVC  PGY EJCT=UKG?
  HQT
 KPV K KUKG 

K
    XGE=K?  FCVC=K?
_
PRZYKŁAD TECHNIKI PROGRAMOWANIA: STOS                        57

%JCT5VCEM%JCT5VCEM
KPV UKG EJCT
KPKV  5VCEM
UKG
]
  FCVC  PGY EJCT=UKG?
  HQT
 KPV K KUKG 

K
    XGE=K?  FCVC=K?
  HQT
K KUVTNGP
KPKV 

K
EJCT
5VCEMRWUJ
  KPKV=K?
_

%JCT5VCEM`%JCT5VCEM

]
  FGNGVG =? FCVC
_

XQKF %JCT5VCEMRWUJ
EJCT F
]
EJCT
5VCEMRWUJ
  F
_

EJCT %JCT5VCEMRQR

]
  TGVWTP
EJCT
5VCEMRQR

_

ENCUU +PV5VCEM  RWDNKE 5VCEM ]
  KPV
FCVC                 RT[YCVP[ YUMC PKM FQ FCP[EJ
RWDNKE
  +PV5VCEM
                MQPUVTWMVQT FQO[ NP[
  +PV5VCEM
KPV UKG
  `+PV5VCEM


  XQKF RWUJ
KPV
  KPV RQR

_

+PV5VCEM+PV5VCEM
  5VCEM
 FGHCWNV5VCEM 
]
  FCVC  PGY KPV=FGHCWNV5VCEM?
  HQT
 KPV K KFGHCWNV5VCEM 

K
    XGE=K?  FCVC=K?
_

+PV5VCEM+PV5VCEM
KPV UKG  5VCEM
UKG
]
  FCVC  PGY KPV=UKG?
  HQT
 KPV K KUKG 

K
    XGE=K?  FCVC=K?
_

+PV5VCEM`+PV5VCEM

]

Contenu connexe

En vedette (6)

ABC Linux
ABC LinuxABC Linux
ABC Linux
 
Perl. Receptury. Wydanie II
Perl. Receptury. Wydanie IIPerl. Receptury. Wydanie II
Perl. Receptury. Wydanie II
 
UML. Wprowadzenie
UML. WprowadzenieUML. Wprowadzenie
UML. Wprowadzenie
 
Access 2003 PL. Kurs
Access 2003 PL. KursAccess 2003 PL. Kurs
Access 2003 PL. Kurs
 
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
 
Tworzenie stron WWW. Kurs
Tworzenie stron WWW. KursTworzenie stron WWW. Kurs
Tworzenie stron WWW. Kurs
 

Similaire à C++. Styl programowania

Język C++. Standardy kodowania. 101 zasad, wytycznych i zalecanych praktyk
Język C++. Standardy kodowania. 101 zasad, wytycznych i zalecanych praktykJęzyk C++. Standardy kodowania. 101 zasad, wytycznych i zalecanych praktyk
Język C++. Standardy kodowania. 101 zasad, wytycznych i zalecanych praktykWydawnictwo Helion
 
C++. Styl i technika zaawansowanego programowania
C++. Styl i technika zaawansowanego programowaniaC++. Styl i technika zaawansowanego programowania
C++. Styl i technika zaawansowanego programowaniaWydawnictwo Helion
 
C++Builder Borland Developer Studio 2006. Kompendium programisty
C++Builder Borland Developer Studio 2006. Kompendium programistyC++Builder Borland Developer Studio 2006. Kompendium programisty
C++Builder Borland Developer Studio 2006. Kompendium programistyWydawnictwo 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ówWydawnictwo Helion
 
C++Builder. Kompendium programisty
C++Builder. Kompendium programistyC++Builder. Kompendium programisty
C++Builder. Kompendium programistyWydawnictwo Helion
 
C++. 50 efektywnych sposobów na udoskonalenie Twoich programów
C++. 50 efektywnych sposobów na udoskonalenie Twoich programówC++. 50 efektywnych sposobów na udoskonalenie Twoich programów
C++. 50 efektywnych sposobów na udoskonalenie Twoich programówWydawnictwo Helion
 
J2EE. Stosowanie wzorców projektowych
J2EE. Stosowanie wzorców projektowychJ2EE. Stosowanie wzorców projektowych
J2EE. Stosowanie wzorców projektowychWydawnictwo Helion
 
J2EE. Podstawy programowania aplikacji korporacyjnych
J2EE. Podstawy programowania aplikacji korporacyjnychJ2EE. Podstawy programowania aplikacji korporacyjnych
J2EE. Podstawy programowania aplikacji korporacyjnychWydawnictwo Helion
 
Wyjątkowy język C++. 40 nowych łamigłówek, zadań programistycznych i rozwiązań
Wyjątkowy język C++. 40 nowych łamigłówek, zadań programistycznych i rozwiązańWyjątkowy język C++. 40 nowych łamigłówek, zadań programistycznych i rozwiązań
Wyjątkowy język C++. 40 nowych łamigłówek, zadań programistycznych i rozwiązańWydawnictwo Helion
 
Visual C# 2005. Zapiski programisty
Visual C# 2005. Zapiski programistyVisual C# 2005. Zapiski programisty
Visual C# 2005. Zapiski programistyWydawnictwo Helion
 
Delphi 8 .NET. Kompendium programisty
Delphi 8 .NET. Kompendium programistyDelphi 8 .NET. Kompendium programisty
Delphi 8 .NET. Kompendium programistyWydawnictwo Helion
 
Więcej niż architektura oprogramowania
Więcej niż architektura oprogramowaniaWięcej niż architektura oprogramowania
Więcej niż architektura oprogramowaniaWydawnictwo Helion
 
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 komputerowejWydawnictwo Helion
 

Similaire à C++. Styl programowania (20)

Język C++. Standardy kodowania. 101 zasad, wytycznych i zalecanych praktyk
Język C++. Standardy kodowania. 101 zasad, wytycznych i zalecanych praktykJęzyk C++. Standardy kodowania. 101 zasad, wytycznych i zalecanych praktyk
Język C++. Standardy kodowania. 101 zasad, wytycznych i zalecanych praktyk
 
C++. Styl i technika zaawansowanego programowania
C++. Styl i technika zaawansowanego programowaniaC++. Styl i technika zaawansowanego programowania
C++. Styl i technika zaawansowanego programowania
 
C++Builder Borland Developer Studio 2006. Kompendium programisty
C++Builder Borland Developer Studio 2006. Kompendium programistyC++Builder Borland Developer Studio 2006. Kompendium programisty
C++Builder Borland Developer Studio 2006. Kompendium programisty
 
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
 
Visual C# .NET. Encyklopedia
Visual C# .NET. EncyklopediaVisual C# .NET. Encyklopedia
Visual C# .NET. Encyklopedia
 
C++Builder. Kompendium programisty
C++Builder. Kompendium programistyC++Builder. Kompendium programisty
C++Builder. Kompendium programisty
 
C++. 50 efektywnych sposobów na udoskonalenie Twoich programów
C++. 50 efektywnych sposobów na udoskonalenie Twoich programówC++. 50 efektywnych sposobów na udoskonalenie Twoich programów
C++. 50 efektywnych sposobów na udoskonalenie Twoich programów
 
J2EE. Stosowanie wzorców projektowych
J2EE. Stosowanie wzorców projektowychJ2EE. Stosowanie wzorców projektowych
J2EE. Stosowanie wzorców projektowych
 
J2EE. Podstawy programowania aplikacji korporacyjnych
J2EE. Podstawy programowania aplikacji korporacyjnychJ2EE. Podstawy programowania aplikacji korporacyjnych
J2EE. Podstawy programowania aplikacji korporacyjnych
 
C# i .NET
C# i .NETC# i .NET
C# i .NET
 
ABC Delphi 2006
ABC Delphi 2006ABC Delphi 2006
ABC Delphi 2006
 
eXtreme programming
eXtreme programmingeXtreme programming
eXtreme programming
 
Wyjątkowy język C++. 40 nowych łamigłówek, zadań programistycznych i rozwiązań
Wyjątkowy język C++. 40 nowych łamigłówek, zadań programistycznych i rozwiązańWyjątkowy język C++. 40 nowych łamigłówek, zadań programistycznych i rozwiązań
Wyjątkowy język C++. 40 nowych łamigłówek, zadań programistycznych i rozwiązań
 
C#. Programowanie
C#. ProgramowanieC#. Programowanie
C#. Programowanie
 
Visual C# 2005. Zapiski programisty
Visual C# 2005. Zapiski programistyVisual C# 2005. Zapiski programisty
Visual C# 2005. Zapiski programisty
 
Delphi 8 .NET. Kompendium programisty
Delphi 8 .NET. Kompendium programistyDelphi 8 .NET. Kompendium programisty
Delphi 8 .NET. Kompendium programisty
 
C# i ASP.NET. Szybki start
C# i ASP.NET. Szybki startC# i ASP.NET. Szybki start
C# i ASP.NET. Szybki start
 
Więcej niż architektura oprogramowania
Więcej niż architektura oprogramowaniaWięcej niż architektura oprogramowania
Więcej niż architektura oprogramowania
 
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
 

Plus de 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. ProjektyWydawnictwo 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ętnikWydawnictwo 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 praktyczneWydawnictwo 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 biznesieWydawnictwo 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 WindowsWydawnictwo 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 IIWydawnictwo Helion
 
Makrofotografia. Magia szczegółu
Makrofotografia. Magia szczegółuMakrofotografia. Magia szczegółu
Makrofotografia. Magia szczegółuWydawnictwo Helion
 
Java. Efektywne programowanie. Wydanie II
Java. Efektywne programowanie. Wydanie IIJava. Efektywne programowanie. Wydanie II
Java. Efektywne programowanie. Wydanie IIWydawnictwo Helion
 
Ajax, JavaScript i PHP. Intensywny trening
Ajax, JavaScript i PHP. Intensywny treningAjax, JavaScript i PHP. Intensywny trening
Ajax, JavaScript i PHP. Intensywny treningWydawnictwo Helion
 
PowerPoint 2007 PL. Seria praktyk
PowerPoint 2007 PL. Seria praktykPowerPoint 2007 PL. Seria praktyk
PowerPoint 2007 PL. Seria praktykWydawnictwo 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 moderacjaWydawnictwo Helion
 

Plus de 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++. Styl programowania

  • 1. IDZ DO PRZYK£ADOWY ROZDZIA£ SPIS TRE CI C++. Styl programowania KATALOG KSI¥¯EK Autor: Tom Cargill KATALOG ONLINE T³umaczenie: Adam Majczak ISBN: 83-7361-321-8 ZAMÓW DRUKOWANY KATALOG Tytu³ orygina³u: C++ Programming Style Format: B5, stron: 224 TWÓJ KOSZYK C++ wspomaga programowanie w du¿ej skali, pozwalaj¹c na precyzyjne wyra¿enie DODAJ DO KOSZYKA wspó³zale¿no ci pomiêdzy ró¿nymi czê ciami programu. Dlatego zakres pojêciowy techniki i stylu programowania w C++ wykracza poza tradycyjne jego pojmowanie w odniesieniu do programowania w ma³ej skali, sprowadzaj¹cego siê do szczegó³ów CENNIK I INFORMACJE kodowania wiersz po wierszu. Autor dowodzi, ¿e nieprzemy lane stosowanie z³o¿onych i zaawansowanych technik ZAMÓW INFORMACJE programowania mo¿e prowadziæ do tworzenia chaotycznych, niezrozumia³ych i mêtnych O NOWO CIACH konstrukcji, stanowi¹cych zarazem czêsto rozwi¹zania mniej efektywne, ni¿ prostsze i zrozumia³e konstrukcje alternatywne. Tom Cargill dokonuje przeredagowania licznych ZAMÓW CENNIK programów, stosuj¹c techniki pozwalaj¹ce na udoskonalenie kodu, pocz¹wszy od poprawy spójno ci, po usuniecie zbêdnego, nadmiarowego dziedziczenia. Sposób prezentacji zagadnieñ rozpoczyna siê od przegl¹du oryginalnego kodu, CZYTELNIA który mo¿esz samodzielnie oceniæ i przeanalizowaæ, rozwa¿aj¹c mo¿liwe alternatywne podej cia do przedstawionych zagadnieñ programistycznych. Te w³asne przemy lenia FRAGMENTY KSI¥¯EK ONLINE mo¿esz nastêpnie porównaæ z analizami i wnioskami Autora. Na podstawie przyk³adów formu³owane s¹ uniwersalne regu³y i zasady tworzenia kodu i projektowania programów. Zrozumienie i umiejêtne stosowanie tych regu³ pomo¿e profesjonalnym programistom projektowaæ i pisaæ lepsze programy w C++. Kolejne rozdzia³y po wiêcone s¹ nastêpuj¹cym zagadnieniom: • Abstrakcja —- pojêcia i modele abstrakcyjne • Spójno æ • Zbêdne dziedziczenie • Funkcje wirtualne • Przeci¹¿anie operatorów • Nak³adki typu „wrapper” Wydawnictwo Helion • Efektywno æ ul. Chopina 6 Po wprowadzeniu i zilustrowaniu regu³ programowania w pierwszych siedmiu 44-100 Gliwice tel. (32)230-98-63 rozdzia³ach, Tom Cargill prezentuje praktyczne studium, w trakcie którego pojedynczy e-mail: helion@helion.pl przyk³adowy program przechodzi kolejne transformacje, które pozwalaj¹ poprawiæ jego ogóln¹ jako æ przy jednoczesnym zredukowaniu wielko ci kodu. Konkluzjê ksi¹¿ki stanowi rozdzia³ po wiêcony wielokrotnemu dziedziczeniu. Ksi¹¿ka Toma Cargilla to nie tylko cenne ród³o wiedzy dla zaawansowanych programistów — przyda siê ona równie¿ studentom informatyki i pokrewnych kierunków, zainteresowanych zdobyciem profesjonalnych umiejêtno ci programistycznych.
  • 2. Spis treści Przedmowa...............................................................................................................7 Wprowadzenie .........................................................................................................9 1. Abstrakcja ..............................................................................................................15 Przykład techniki programowania: ceny komputerów...................................................................................... 15 Poszukiwanie wspólnego pojęcia abstrakcyjnego............................................................................................. 19 Ró nice pomiędzy klasami................................................................................................................................ 22 Powtórnie wprowadzamy do programu dziedziczenie...................................................................................... 26 Wyeliminowanie typów wyliczeniowych ......................................................................................................... 27 Podsumowanie .................................................................................................................................................. 30 Bibliografia ....................................................................................................................................................... 31 Ćwiczenie .......................................................................................................................................................... 31 2. Spójność kodu........................................................................................................35 Przykład techniki programowania: klasa string ................................................................................................ 36 Precyzyjnie zdefiniowany stan obiektu............................................................................................................. 37 Spójność fizycznego stanu obiektu ................................................................................................................... 38 Niezmienne warunki, czyli inwariancja klas..................................................................................................... 39 Konsekwentne stosowanie dynamicznego zarządzania pamięcią..................................................................... 41 Zwolnienie dynamicznie przyporządkowanej pamięci ..................................................................................... 43 Przykład techniki programowania: drugie podejście do tego samego problemu.............................................. 44 Podsumowanie .................................................................................................................................................. 50 Bibliografia ....................................................................................................................................................... 51 Ćwiczenia .......................................................................................................................................................... 51 3. Zbędne dziedziczenie.............................................................................................55 Przykład techniki programowania: stos ............................................................................................................ 55 Reguły widoczności nazw w procesie dziedziczenia........................................................................................ 59 Relacje tworzone poprzez dziedziczenie........................................................................................................... 60
  • 3. 4 SPIS TREŚCI Enkapsulacja...................................................................................................................................................... 65 Interfejs a implementacja .................................................................................................................................. 67 Zastosowanie szablonów................................................................................................................................... 71 Podsumowanie .................................................................................................................................................. 73 Bibliografia ....................................................................................................................................................... 73 Ćwiczenie .......................................................................................................................................................... 74 4. Funkcje wirtualne ..................................................................................................75 Przykład techniki programowania: problem pojazdów i gara y....................................................................... 75 Spójność kodu ................................................................................................................................................... 79 Destruktory klas bazowych ............................................................................................................................... 81 Dziedziczenie .................................................................................................................................................... 82 Sprzę enie ......................................................................................................................................................... 85 Podsumowanie .................................................................................................................................................. 91 Bibliografia ....................................................................................................................................................... 92 Ćwiczenie .......................................................................................................................................................... 92 5. Przecią anie operatorów ........................................................................................93 Przecią anie operatorów — podstawy .............................................................................................................. 93 Przykład techniki programowania: tablica plików FileArray ........................................................................... 98 Dziedziczenie implementacji .......................................................................................................................... 105 Programistyczny dylemat — jak lepiej: przecią one operatory czy metody .................................................. 110 Podsumowanie ................................................................................................................................................ 112 Bibliografia ..................................................................................................................................................... 112 Ćwiczenia ........................................................................................................................................................ 112 6. Klasy otaczające (ang. wrappers) ........................................................................113 Biblioteka C .................................................................................................................................................... 113 Przykład techniki programowania: klasa otaczająca dla struktury dirent w C++........................................... 114 Wiele obiektów klasy Directory...................................................................................................................... 116 Gdy zawodzi konstruktor ................................................................................................................................ 119 Publiczny dostęp do stanu obiektu .................................................................................................................. 121 Dodatkowy argument słu ący obsłudze błędów ............................................................................................. 123 Podsumowanie ................................................................................................................................................ 127 Bibliografia ..................................................................................................................................................... 128 Ćwiczenie ........................................................................................................................................................ 128 7. Efektywność.........................................................................................................129 Przykład techniki programowania: klasa BigInt ............................................................................................. 130 Egzaminujemy klasę BigInt ............................................................................................................................ 136 Długość dynamicznych łańcuchów znaków ................................................................................................... 138 Liczba dynamicznie zapamiętywanych łańcuchów znaków........................................................................... 140 Kod klienta ...................................................................................................................................................... 144 Modyfikujemy klasę BigInt ............................................................................................................................ 145
  • 4. SPIS TREŚCI 5 Podsumowanie ................................................................................................................................................ 151 Bibliografia ..................................................................................................................................................... 152 Ćwiczenia ........................................................................................................................................................ 152 8. Studium praktyczne .............................................................................................153 Przykład techniki programowania: Finite State Machine, czyli automat stanów skończonych ..................... 153 Zainicjowanie .................................................................................................................................................. 158 Sprzę enia ....................................................................................................................................................... 165 Spójność .......................................................................................................................................................... 169 Moduły kontra abstrakcyjne typy danych ....................................................................................................... 172 Wartość kontra zachowanie ............................................................................................................................ 175 Uogólnienie ..................................................................................................................................................... 180 Bibliografia ..................................................................................................................................................... 184 Ćwiczenia ........................................................................................................................................................ 185 9. Dziedziczenie wielokrotne...................................................................................187 Niejednoznaczności w mechanizmie wielokrotnego dziedziczenia................................................................ 187 Skierowane niecykliczne grafy hierarchii dziedziczenia ................................................................................ 189 Eksplorujemy wirtualne klasy bazowe............................................................................................................ 193 Przykład techniki programowania: klasa Monitor .......................................................................................... 200 Przykład techniki programowania: wirtualna klasa bazowa ........................................................................... 204 Protokół powiadomień zwrotnych i przydatne wielokrotne dziedziczenie..................................................... 210 Podsumowanie ................................................................................................................................................ 213 Bibliografia ..................................................................................................................................................... 213 Ćwiczenia ........................................................................................................................................................ 213 10. Zbiorcza lista reguł ..............................................................................................215 Rozdział 1.: „Abstrakcja”................................................................................................................................ 215 Rozdział 2.: „Spójność kodu” ......................................................................................................................... 215 Rozdział 3.: „Zbędne dziedziczenie” .............................................................................................................. 216 Rozdział 4.: „Funkcje wirtualne” .................................................................................................................... 216 Rozdział 5.: „Przecią anie operatorów”.......................................................................................................... 216 Rozdział 6.: „Klasy otaczające (ang. wrappers)”............................................................................................ 216 Rozdział 7.: „Efektywność” ............................................................................................................................ 217 Rozdział 8.: „Studium praktyczne”................................................................................................................. 217 Rozdział 9.: „Dziedziczenie wielokrotne” ...................................................................................................... 217 Skorowidz ............................................................................................................219
  • 5. 3 Zbędne dziedziczenie Chocia w rozdziale 2. uwa nie rozró nialiśmy interfejs klasy i implementację klasy, nie czynili- śmy tego w kontekście dziedziczenia. Aby dokładnie zrozumieć relację dziedziczenia pomiędzy klasą pochodną a jej klasą bazową, musimy rozpatrywać część interfejsową i część implementacyjną klasy w sposób odrębny. W tym rozdziale przeanalizujemy przypadek, który z pozoru wydaje się być naturalną kandydaturą do zastosowania dziedziczenia. Mimo to, dokładniejsza analiza dziedzicze- nia i implementacji klas bazowej i pochodnej spowoduje w efekcie znaczącą modyfikację kodu. Przykład techniki programowania: stos Na listingu 3.1 pokazano program, w którym zostały zdefiniowane klasy %JCT5VCEM (dosł. stos prze- znaczony na znaki) oraz +PV5VCEM (dosł. stos przeznaczony na liczby typu KPV). Przeanalizujmy i oceń- my te klasy. Czy widać tu uogólnienie pojęć abstrakcyjnych? Czy dziedziczenie działa w sposób poprawny? Czy dziedziczenie zostało wykorzystane we właściwy sposób? LISTING 3.1. Oryginalna wersja klas Stack, CharStack oraz IntStack KPENWFG CUUGTVJ KPENWFG UVTKPIJ ENCUU 5VCEM ] MNCUC DCQYC UVQU KPV VQR YKGTEJQ GM UVQUW KPV UKG TQOKCT RTQVGEVGF FQUVúRPG V[NMQ FNC MNCU RQEJQFP[EJ XQKF
  • 6.
  • 7. XGE VCDNKEC YUMC PKMÎY YGMVQT RWDNKE RWDNKEP[ KPVGTHGLU MNCU[ DCQYGL 5VCEM KPV U MQPUVTWMVQT QIÎNP[ `5VCEM FGUVTWMVQT MNCU[ DCQYGL XQKF
  • 8. RWUJ OGVQFC QF Î PC UVQU XQKF
  • 9. RQR OGVQFC FGLOKL G UVQUW _
  • 10. 56 3. ZBĘDNE DZIEDZICZENIE 5VCEM5VCEM KPV U FGHKPKELC MQPUVTWMVQTC ] XGE PGY XQKF
  • 11. =UKGU? VQR _ 5VCEM`5VCEM ] FGNGVG =? XGE YCNPKC RCOKúè CLOQYCPæ RTG VCDNKEú YUMC PKMÎY _ XQKF
  • 12. 5VCEMRWUJ ] CUUGTV VQR UKG TGVWTP XGE=VQR ? _ XQKF
  • 13. 5VCEMRQR ] CUUGTV VQR TGVWTP XGE=VQR? _ EQPUV KPV FGHCWNV5VCEM FQO[ NP[ TQOKCT UVQUW ENCUU %JCT5VCEM RWDNKE 5VCEM ] EJCT
  • 14. FCVC RT[YCVP[ YUMC PKM FQ FCP[EJ RWDNKE %JCT5VCEM MQPUVTWMVQT FQO[ NP[ %JCT5VCEM KPV UKG %JCT5VCEM KPV UKG EJCT
  • 15. KPKV `%JCT5VCEM XQKF RWUJ EJCT EJCT RQR _ %JCT5VCEM%JCT5VCEM 5VCEM FGHCWNV5VCEM ] FCVC PGY EJCT=FGHCWNV5VCEM? HQT KPV K KFGHCWNV5VCEM K XGE=K? FCVC=K? _ %JCT5VCEM%JCT5VCEM KPV UKG 5VCEM UKG ] FCVC PGY EJCT=UKG? HQT KPV K KUKG K XGE=K? FCVC=K? _
  • 16. PRZYKŁAD TECHNIKI PROGRAMOWANIA: STOS 57 %JCT5VCEM%JCT5VCEM KPV UKG EJCT
  • 17. KPKV 5VCEM UKG ] FCVC PGY EJCT=UKG? HQT KPV K KUKG K XGE=K? FCVC=K? HQT K KUVTNGP KPKV K
  • 18. EJCT
  • 19. 5VCEMRWUJ KPKV=K? _ %JCT5VCEM`%JCT5VCEM ] FGNGVG =? FCVC _ XQKF %JCT5VCEMRWUJ EJCT F ]
  • 20. EJCT
  • 21. 5VCEMRWUJ F _ EJCT %JCT5VCEMRQR ] TGVWTP
  • 22. EJCT
  • 23. 5VCEMRQR _ ENCUU +PV5VCEM RWDNKE 5VCEM ] KPV
  • 24. FCVC RT[YCVP[ YUMC PKM FQ FCP[EJ RWDNKE +PV5VCEM MQPUVTWMVQT FQO[ NP[ +PV5VCEM KPV UKG `+PV5VCEM XQKF RWUJ KPV KPV RQR _ +PV5VCEM+PV5VCEM 5VCEM FGHCWNV5VCEM ] FCVC PGY KPV=FGHCWNV5VCEM? HQT KPV K KFGHCWNV5VCEM K XGE=K? FCVC=K? _ +PV5VCEM+PV5VCEM KPV UKG 5VCEM UKG ] FCVC PGY KPV=UKG? HQT KPV K KUKG K XGE=K? FCVC=K? _ +PV5VCEM`+PV5VCEM ]
  • 25. 58 3. ZBĘDNE DZIEDZICZENIE FGNGVG =? FCVC _ XQKF +PV5VCEMRWUJ KPV F ]
  • 26. KPV
  • 27. 5VCEMRWUJ F _ KPV +PV5VCEMRQR ] TGVWTP
  • 28. KPV
  • 29. 5VCEMRQR _ Natychmiastowa, odruchowa reakcja wielu Czytelników na samo hasło %JCT5VCEM oraz +PV 5VCEM mo e polegać na stwierdzeniu, e takie klasy powinny zostać skonstruowane przy zastoso- waniu typów sparametryzowanych, czyli szablonów (ang. templates), zgodnie z tym, co proponuje standard ANSI C++ (patrz: Ellis i Stroustrup). Ignorujemy tę mo liwość i skoncentrujemy się na programie w takiej postaci, w jakiej został napisany. A to z dwóch powodów. Po pierwsze, wa ne jest zrozumienie, przy wykorzystaniu najbardziej podstawowych konstrukcji języka C++, w jaki sposób powstała struktura tego programu, zanim jeszcze zaczniemy rozwa ać, w jaki sposób mo na by go udoskonalić, wykorzystując rozszerzenie języka. Pewne błędy w rozumowaniu, które dopro- wadziły do powstania tego programu, mogłyby łatwo wystąpić w bardziej kłopotliwej sytuacji, gdy u ycie typów parametryzowanych (szablonów) nie dałoby nam adnej alternatywy. Po drugie, w chwili pisania tej ksią ki, implementacje typów parametryzowanych nie były jeszcze szeroko rozpowszechnione i dostępne. Co więcej, nale ało się liczyć z tym, e jeszcze przez pewien czas szablony nie zostaną poprawnie zaadaptowane do języka C++. Przedwczesne byłoby rozwa anie technik programowania w odniesieniu do typów parametryzowanych przed nagromadzeniem sto- sownego praktycznego doświadczenia, co pozwoliłoby na poradnictwo, jak właściwie i efektywnie stosować te techniki. Wersja kodu napisana z zastosowaniem szablonów została podana na końcu tego rozdziału. Istota tej konstrukcji kodu sprowadza się do tego, e obydwie klasy: %JCT5VCEM oraz +PV5VCEM reprezentują stos (pierwsza dla znaków, druga dla liczb całkowitych), zatem obie mają wspólną klasę bazową 5VCEM (po prostu „Stos”, bez skonkretyzowania szczegółów). Taka hierarchia dzie- dziczenia została schematycznie przedstawiona na rysunku 3.1. RYSUNEK 3.1. Hierarchia dziedziczenia w programie z listingu 3.1 Musimy popatrzeć na ten program znacznie uwa niej, by dostrzec, e takie dziedziczenie nie jest niezbędne. Co więcej, okazuje się mylące i wręcz powinno zostać wyeliminowane. W istocie, zastosowanie dziedziczenia z specyfikatorem dostępu RWDNKE w tym programie tworzy niebez- pieczną lukę w enkapsulacji takich stosów.
  • 30. REGUŁY WIDOCZNOŚCI NAZW W PROCESIE DZIEDZICZENIA 59 Reguły widoczności nazw w procesie dziedziczenia Dziedziczenie mo e następować z u yciem specyfikatorów dostępu RWDNKE, RTKXCVG, RTQVGEVGF. Sposób dziedziczenia decyduje o widoczności i dostępności nazw (ang. inheritance scope rules). Publiczny interfejs klasy bazowej 5VCEM jest następujący: RWDNKE 5VCEM KPV U `5VCEM XQKF
  • 31. RWUJ XQKF
  • 32. RQR _ Patrząc na klasy pochodne, widzimy tam metody o tych samych nazwach (RQR oraz RWUJ ), co w klasie bazowej. Zwróćmy uwagę, e metody 5VCEMRWUJ oraz 5VCEMRQR nie są funkcjami wirtualnymi. Zauwa my tak e, e typy argumentów tych metod w klasach pochod- nych nie są zgodne z typami argumentów odpowiednich metod w klasie bazowej. Na przykład, metoda 5VCEMRWUJ jest bezargumentowa, podczas gdy metoda +PV5VCEMRWUJ KPV pobiera jeden argument typu KPV. W przypadku takich funkcji reguły widoczności nazw C++ mówią, e metoda zawarta w klasie pochodnej przesłania metodę o tej samej nazwie zawartą w klasie bazowej, poniewa klasa pochodna wprowadza nowy poziom widoczności nazw (ang. new scope level). Re- zultat tych reguł widoczności mo na wyraźnie dostrzec na następującym przykładzie: ENCUU $CUG ] MNCUC DCQYC RWDNKE XQKF H HNQCV XQKF I HNQCV _ ENCUU GTKXGF RWDNKE $CUG ] MNCUC RQEJQFPC RWDNKE XQKF H KPV _ KPV OCKP GTKXGF F FH Y[YQ CPKG GTKXGFH FI Y[YQ CPKG $CUGI Wyraźnie widać, e w tym przypadku (przy dziedziczeniu) funkcja — metoda o nazwie H nie jest przecią ona (ang. not overloaded). Klasa pochodna definiuje funkcję o nazwie H , a zatem wyra enie FH musi jednoznacznie wywołać metodę H zdefiniowaną w klasie pochodnej, a nie w klasie bazowej. Natomiast wyra enie FI wywołuje metodę z klasy bazowej, poniewa w klasie pochodnej nie została zdefiniowana własna wersja metody o nazwie I . Gdy kompilator C++ poszukuje w celu wywołania metody I , najpierw przeszukiwana jest klasa pochodna, jeśli w klasie pochodnej nie zostanie odszukana adna „pasująca” metoda, w drugiej kolejności poszu- kiwanie nastąpi w klasie bazowej. Zatem wywołanie metody I wobec obiektu klasy pochodnej spowoduje w istocie zastosowanie wersji $CUGI z klasy bazowej, ale wywołanie metody H będzie oznaczać GTKXGFH , a nie $CUGH , która została przesłonięta i stała się w ten sposób niewidoczna.
  • 33. 60 3. ZBĘDNE DZIEDZICZENIE Publiczny interfejs klasy +PV5VCEM jest następujący: RWDNKE +PV5VCEM +PV5VCEM KPV UKG `+PV5VCEM XQKF RWUJ KPV KPV RQR _ Zgodnie z zasadami widoczności (dostępności) nazw opisanymi powy ej, kod klienta mo e manipulować obiektami klas +PV5VCEM lub %JCT5VCEM przy u yciu wywołań ich własnych metod RWUJ oraz RQR , a nie poprzez metody odziedziczone po klasie bazowej 5VCEM. Klasy pochodne +PV5VCEM oraz %JCT5VCEM dziedziczą publiczny interfejs po klasie bazowej 5VCEM, ale odziedziczone metody przesłaniają własnymi wersjami tych funkcji. Powrócimy jeszcze do tego zagadnienia w dal- szej części tego rozdziału. Relacje tworzone poprzez dziedziczenie Przyjrzyjmy się na razie bli ej relacjom tworzonym poprzez dziedziczenie. Klasa bazowa 5VCEM zapewnia, e w ka dej jej klasie pochodnej będzie zaimplementowany mechanizm indeksujący (ang. indexing service). Odpowiedzialna jest za to jednowymiarowa tablica (czyli wektor) o na- zwie XGE. Tablica ta jest typu chronionego i składa się ze wskaźników do typu XQKF. Klasa 5VCEM zarządza tak e prywatnym polem danych KPV VQR (wierzchołek stosu) pozwalającą na obsługę tablicy w odpowiedzi na wywołania metod RWUJ oraz RQR z klas pochodnych. Klasy pochodne tworzą własne tablice — wektory wskazywane poprzez wskaźniki FCVC dla wartości przechowy- wanych na stosie i inicjują te wektory tak, e dla wszystkich wartości indeksu tablicy K (oczywi- ście, w granicach wektora) element XGE=K? jest wskaźnikiem do elementu FCVC=K?. Wskaźniki typu XQKF zwracane przez metody 5VCEMRWUJ oraz 5VCEMRWUJ mówią klasie pochodnej, na któ- rym elemencie tablicy FCVC mają być wykonywane odpowiednio operacje RWUJ (odłó na stos) oraz RQR (zdejmij ze stosu). Struktura danych została przedstawiona na rysunku 3.2. Zwróćmy uwagę na spójność układu wskaźników. Taka struktura danych zawiera, niestety, niewiele informacji. Konstruktory klas po- chodnych zawierają i wykonują instrukcję: XGE=K? FCVC=K? dla ka dego z elementów wskazywanych w tablicy FCVC=?, aby poprawnie zainicjować wskaźniki wchodzące w skład tablicy XGE=?. Po takim zadziałaniu konstruktora i zainicjowaniu, te wskaźniki nigdy nie ulegają zmianie. Klasa bazowa odsyła te wskaźniki z powrotem, by „powiedzieć” klasie pochodnej, gdzie (pod jakim adresem) znajdują się dane, do których mo na się odwoływać. Coś tu jest jednak nie tak. Chyba trochę za du o wskaźników w porównaniu z niewielką ilością rzeczywi- stej, u ytecznej informacji. Gdy skoncentrujemy się na wymuszonej konwersji typu (ang. type casting) w kodzie metody 5VCEMRQR , zobaczymy tę samą sytuację z innej perspektywy.
  • 34. RELACJE TWORZONE POPRZEZ DZIEDZICZENIE 61 RYSUNEK 3.2. Relacja wskaźników z wektora vec do elementów tablicy data KPV +PV5VCEMRQR ] TGVWTP
  • 35. KPV
  • 36. 5VCEMRQR _ Ta wymuszona konwersja powoduje przekształcenie wskaźnika do typu XQKF zwróconego przez metodę 5VCEMRQR na wskaźnik do typu KPV w celu odwołania się do elementu tablicy wska- zywanej przez wskaźnik +PV5VCEMFCVC. Aby uniknąć niespodzianek i niebezpieczeństw kryją- cych się w mechanizmach rzutowania, zawsze lepiej programować bez wymuszania konwersji typu. Ta konwersja mo e być łatwo wyeliminowana. Gdy to zrobimy, wyjdzie na jaw problem, który sprawia wektor XGE. Ogólnie rzecz biorąc, logika i kolejność działań jest tu następująca: • metoda 5VCEMRQR zwraca wskaźnik XGE=K?, • wskaźnik XGE=K? wskazuje element tablicy FCVC=K?, • metoda +PV5VCEMRQR zwraca FCVC=K?. adna konwersja typów nie byłaby tu potrzebna, gdyby funkcja 5VCEMRQR zwracała sam indeks K, bezpośrednio, zamiast wskaźnika XGE=K?. Mając wartość indeksu K, metoda +PV5VCEM RQR bezpośrednio odwoływałaby się do elementu tablicy FCVC=K?, bez adnej konwersji typu. Metody RWUJ oraz RQR nale ące do klasy bazowej 5VCEM mogłyby zwracać pojedynczą liczbę całkowitą (indeks), której obiekt klasy pochodnej rzeczywiście potrzebuje, zamiast wskaźnika typu XQKF, który przed u yciem musi zostać poddany konwersji typu. Taka prostsza wersja klasy 5VCEM została pokazana na listingu 3.2. Zwróćmy uwagę, e metody RWUJ oraz RQR nale ące do klas pochod- nych +PV5VCEM oraz %JCT5VCEM w tej wersji ju nie stosują wymuszonej konwersji typu. Zauwa my tak e, e nazwa 5VCEM została zmieniona na 5VCEM+PFGZ, co lepiej opisuje to pojęcie abstrakcyjne. LISTING 3.2. Uproszczona klasa abstrakcji „Indeksacja stosu” KPENWFG CUUGTVJ KPENWFG UVTKPIJ ENCUU 5VCEM+PFGZ ] MNCUC DCQYC KPFGMUCELC UVQUW RT[YCVPG RQNC FCP[EJ
  • 37. 62 3. ZBĘDNE DZIEDZICZENIE KPV VQR VQR VQ YKGTEJQ GM UVQUW KPV UKG UKG VQ TQOKCT UVQUW RWDNKE RWDNKEP[ KPVGTHGLU MNCU[ DCQYGL 5VCEM+PFGZ KPV U MQPUVTWMVQT QIÎNP[ `5VCEM+PFGZ FGUVTWMVQT MNCU[ DCQYGL KPV RWUJ OGVQFC QF Î PC UVQU KPV RQR OGVQFC FGLOKL G UVQUW _ 5VCEM+PFGZ5VCEM+PFGZ KPV U ] UKG U VQR _ 5VCEM+PFGZ`5VCEM+PFGZ ]_ RWUV[ FGUVTWMVQT KPV 5VCEM+PFGZRWUJ ] CUUGTV VQR UKG TGVWTP VQR _ KPV 5VCEM+PFGZRQR ] CUUGTV VQR TGVWTP VQR _ EQPUV KPV FGHCWNV5VCEM FQO[ NP[ TQOKCT UVQUW ENCUU %JCT5VCEM RWDNKE 5VCEM+PFGZ ] EJCT
  • 38. FCVC RT[YCVP[ YUMC PKM FQ FCP[EJ RWDNKE %JCT5VCEM MQPUVTWMVQT FQO[ NP[ %JCT5VCEM KPV UKG %JCT5VCEM KPV UKG EJCT
  • 39. KPKV `%JCT5VCEM XQKF RWUJ EJCT EJCT RQR _ %JCT5VCEM%JCT5VCEM 5VCEM+PFGZ FGHCWNV5VCEM ] FCVC PGY EJCT=FGHCWNV5VCEM? _ %JCT5VCEM%JCT5VCEM KPV UKG 5VCEM+PFGZ UKG ] FCVC PGY EJCT=UKG? _
  • 40. RELACJE TWORZONE POPRZEZ DZIEDZICZENIE 63 %JCT5VCEM%JCT5VCEM KPV UKG EJCT
  • 41. KPKV 5VCEM+PFGZ UKG ] FCVC PGY EJCT=UKG? HQT KPV K KUVTNGP KPKV K FCVC=5VCEM+PFGZRWUJ ? KPKV=K? _ %JCT5VCEM`%JCT5VCEM ] FGNGVG =? FCVC _ XQKF %JCT5VCEMRWUJ EJCT F ] FCVC=5VCEM+PFGZRWUJ ? F _ EJCT %JCT5VCEMRQR ] TGVWTP FCVC=5VCEM+PFGZRQR ? _ ENCUU +PV5VCEM RWDNKE 5VCEM+PFGZ ] KPV
  • 42. FCVC RT[YCVP[ YUMC PKM FQ FCP[EJ RWDNKE +PV5VCEM MQPUVTWMVQT FQO[ NP[ +PV5VCEM KPV UKG `+PV5VCEM XQKF RWUJ KPV KPV RQR _ +PV5VCEM+PV5VCEM 5VCEM+PFGZ FGHCWNV5VCEM ] FCVC PGY KPV=FGHCWNV5VCEM? _ +PV5VCEM+PV5VCEM KPV UKG 5VCEM+PFGZ UKG ] FCVC PGY KPV=UKG? _ +PV5VCEM`+PV5VCEM ] FGNGVG =? FCVC _ XQKF +PV5VCEMRWUJ KPV F ] FCVC=5VCEM+PFGZRWUJ ? F _
  • 43. 64 3. ZBĘDNE DZIEDZICZENIE KPV +PV5VCEMRQR ] TGVWTP FCVC=5VCEM+PFGZRQR ? _ Zastosowany tu nowy interfejs klasy bazowej 5VCEM+PFGZ lepiej odpowiada abstrakcyjnemu pojęciu „indeksacja stosu”, czyli tym funkcjom, które rzeczywiście zapewnia. Wspólna część abs- trakcyjna — to obsługa indeksacji, mówiąca klasie pochodnej, gdzie znajdują się dane, do których mo na się odwoływać. Informacja o tym, w jaki sposób działa i zachowuje się stos, pozostaje ukryta przed klasą bazową 5VCEM. Informacja o elementach znajdujących się rzeczywiście na poszczegól- nych stosach (obiektach klas pochodnych) zostaje udostępniona klasom pochodnym. Jedyna komu- nikacja następuje tu w zakresie indeksacji. Bez adnego ograniczenia mo liwości funkcjonalnych, taki abstrakcyjny stos mo e zostać zaimplementowany prościej. Jego zakres odpowiedzialności zostanie ograniczony do obsługi indeksacji w taki sposób, e inna, odrębna klasa mo e zapewnić mechanizm obsługi stosu. ► Poszukujmy prostych pojęć abstrakcyjnych. Tablica wskaźników 5VCEMXGE jest nadmiarowa (stanowi redundancję), dlatego zniknęła z nowej wersji klasy 5VCEM+PFGZ. Ka da z klas pochodnych takiej klasy bazowej otrzymuje wszystkie in- formacje, których potrzebuje w postaci indeksu zwracanego poprzez wywołane metody nale ące do klasy bazowej: 5VCEM+PFGZRWUJ oraz 5VCEM+PFGZRQR . Nie ma adnego racjonalnego uza- sadnienia, by w klasie bazowej przechowywać wskaźniki do danych znajdujących się w tablicach deklarowanych w klasach pochodnych. Struktura danych wygląda teraz tak, jak pokazano na ry- sunku 3.3. Takie uproszczenie programu powoduje jednocześnie, e staje się on bardziej efektyw- ny z punktu widzenia wykorzystania pamięci. Wyeliminowanie tablicy 5VCEMXGE gwałtownie zmniejsza ilość pamięci wymaganą do utworzenia stosu. Przy typowej, 32-bitowej architekturze, gdy liczby całkowite typu KPV zajmują po 4 bajty pamięci ka da i przy 4-bajtowych wskaźnikach, obiekt klasy +PV5VCEM zajmuje teraz na stercie dwukrotnie mniej pamięci, ni było to w wersji ory- ginalnej. Na ka dy element przypadają 4 bajty zamiast 8. Obszar pamięci zajmowany na stercie przez obiekt klasy %JCT5VCEM nale y podzielić przez współczynnik 5. Zamiast 5 bajtów na ka dy znak na stosie przypada teraz tylko 1 bajt. RYSUNEK 3.3. Uproszczona struktura danych
  • 44. ENKAPSULACJA 65 Enkapsulacja Taka nowa reprezentacja abstrakcyjnego pojęcia stosu jest prostsza, a sam program jest krótszy i wykorzystuje mniej pamięci. Relacje wprowadzone poprzez mechanizm dziedziczenia pomiędzy klasą bazową 5VCEM+PFGZ a jej klasami pochodnymi nie zostały jeszcze do końca wyjaśnione. Wcze- śniej w tym rozdziale zasygnalizowano, e metody RWUJ oraz RQR nale ące do klas pochodnych przesłaniają metody o tych samych nazwach nale ące do klasy bazowej. Jeśli jednak stosuje się pełne, rozwinięte nazwy funkcji, np.: 5VCEM+PFGZRWUJ i odpowiednio 5VCEM+PFGZRQR , te me- tody mogą nadal być wywołane w zakresie widoczności nazw utworzonym przez klasy pochodne, przez obiekty klas +PV5VCEM lub %JCT5VCEM. W istocie, metody 5VCEM+PFGZRWUJ QTC 5VCEM+P FGZRQR są właśnie w taki sposób wywoływane w kodzie przez odpowiednie metody nale ące do klas pochodnych. Metody z klasy bazowej, 5VCEM+PFGZRWUJ oraz 5VCEM+PFGZRQR , mogą zostać wywoła- ne nawet bez potrzeby sięgania do operatora widoczności . Jeśli do obiektu klasy pochodnej +PV5VCEM lub %JCT5VCEM odwołujemy się za pośrednictwem wskaźnika do obiektu klasy bazowej 5VCEM+PFGZ albo za pośrednictwem referencji do obiektu klasy 5VCEM+PFGZ, to RWUJ i RQR oznaczają wywołania metod nale ących do klasy bazowej. Problem dostępności metod nale ących do klas bazowych to bardzo powa ne zagadnienie (a w tym przypadku — naruszenie) z punktu widzenia enkapsulacji stosów. Przy takiej konstrukcji programu mo liwe jest zamierzone bądź omyłkowe wprowadzenie obiektu „stos” w stan niespójny logicznie poprzez odwołanie z innych części pro- gramu. Poni sza funkcja prezentuje trzy sposoby naruszenia hermetyzacji obiektu klasy +PV5VCEM. XQKF 8KQNCVG ] +PV5VCEM U U5VCEM+PFGZRWUJ RWDNKEPG RQNG RWDNKEPGL MNCU[ DCQYGL 5VCEM+PFGZ
  • 45. R U R RWUJ Y[YQ CPKG 5VCEM+PFGZRWUJ 5VCEM+PFGZ T U TRWUJ Y[YQ CPKG 5VCEM+PFGZRWUJ _ Poprzez bezpośrednie wywołanie publicznych składowych klasy bazowej z kodu klienta, funk- cja 8KQNCVG (dosł. „naruszająca”) zwiększa indeks stosu bez jednoczesnego dostarczenia jakiej- kolwiek wartości przeznaczonej do umieszczenia na stosie. Efekt jest taki, e stos pozornie rośnie o jeden nowy element, ale skoro w chwili wykonania operacji „push” nie zostaje dostarczona adna wartość do umieszczenia na stosie, to wartość zwracana przez metodę +PV5VCEMRQR pozostaje nieokreślona. Ta wartość pozornie umieszczona na stosie pozostanie tą wartością, która znajdo- wała się w pamięci przeznaczonej dla danego elementu tablicy — poprzednio, w chwili wykona- nia operacji RWUJ. Jak widać, kod klienta mo e bezpośrednio manipulować implementacją stosu, co mo e dopro- wadzić obiekt — stos — do stanu niezdefiniowanego. Enkapsulacja stosu (rozumiana jako jego od- izolowanie od kodu klienta) zostaje naruszona. Ten problem nie powstał nagle, w momencie naszej modyfikacji kodu w celu wyeliminowania tablicy zawierającej wskaźniki w klasie bazowej. Ta luka w enkapsulacji występowała ju w oryginalnym kodzie wyjściowym. Nale ałoby ją zlikwidować. Jest tam jeszcze inny problem związany z dziedziczeniem. Destruktor klasy bazowej nie zo- stał zadeklarowany jako funkcja wirtualna. Jeśli obiekt klasy +PV5VCEM zostanie utworzony w spo- sób dynamiczny, a następnie zostanie usunięty operatorem FGNGVG, kasującym wskaźnik do klasy bazowej, to zostanie wywołany tylko destruktor klasy bazowej. Pod tym względem destruktory
  • 46. 66 3. ZBĘDNE DZIEDZICZENIE zachowują się tak samo, jak inne metody. Rodzaj destruktora (tj. jego przynale ność do określonej klasy) jest determinowany poprzez typ wskaźnika (typ wartości wskazywanej przez dany wskaźnik u yty w momencie deklaracji). +PV5VCEM
  • 47. R PGY +PV5VCEM 5VCEM+PFGZ
  • 48. S R FGNGVG S URQYQFWLG Y[YQ CPKG V[NMQ 5VCEM+PFGZ`5VCEM+PFGZ Skoro destruktor klasy pochodnej nie mo e zostać wywołany, programy (kod klienta) posłu- gujące się klasą +PV5VCEM lub %JCT5VCEM są potencjalnie zagro one występowaniem „wycieków pamięci”. Wyciek pamięci omawiany w rozdziale 2. na przykładzie klasy UVTKPI występował dla- tego, e pominięto po ądany operator FGNGVG w kodzie metody. W tym przypadku „wyciek pamięci” wystąpi nawet wtedy, gdy destruktor w klasie pochodnej będzie całkowicie poprawny. Operator FGNGVG u yty w kodzie destruktora klasy pochodnej mo e zostać wykonany tylko wtedy, gdy ten destruktor zostanie wywołany. Ten destruktor nie zostanie wywołany, jeśli obiekt klasy pochodnej będzie usuwany poprzez skasowanie wskaźnika do klasy bazowej (wskaźniki do klas bazowych mogą wskazywać tak e obiekty klas pochodnych i o taką sytuację tu chodzi). Jeśli wektor przy- dzielony dla danych stosu nie zostanie poprawnie usunięty, a jego pamięć zwolniona i zwrócona do systemu, w miarę działania programu będzie wzrastać ilość zajętej, choć bezu ytecznej pamięci na stercie, co mo e doprowadzić nawet do przepełnienia pamięci przeznaczonej na stertę. Wycieki pamięci są trudno wykrywalne we wczesnych stadiach ycia oprogramowania. Niewielkie testy mogą nie zaanga ować wystarczająco du ej ilości pamięci, by mo na było uzyskać zauwa alne rezultaty. W rozdziale 7. pokazano, w jaki sposób wyposa yć program w monitorowanie wykorzy- stania pamięci na stercie i jak dzięki temu wykrywać ewentualne wycieki pamięci. Ten potencjalny wyciek pamięci mo e zostać wyeliminowany poprzez zadeklarowanie de- struktora w klasie bazowej jako funkcji wirtualnej, choć jest to metoda doraźnego łatania dziury, która nie rozwiązuje rzeczywistego strukturalnego problemu występującego w tym kodzie źródło- wym. W przypadku takich klas mo na znaleźć lepsze rozwiązania tego problemu. Do zagadnienia wirtualnych destruktorów w klasach bazowych wrócimy w rozdziałach 4. i 9. Istnieją dwa środki zapobiegawcze. Ka dy z tych środków pozwala na jednoczesne „wyle- czenie” i problemu luki w enkapsulacji, i problemu wycieku pamięci. Pierwsze lekarstwo polega na tym, by 5VCEM+PFGZ stała się prywatną klasą bazową. Dziedziczenie z u yciem specyfikatora do- stępu RTKXCVG zapobiega przenoszeniu (propagacji) publicznego interfejsu klasy bazowej na pu- bliczne interfejsy klas pochodnych. W ten sposób wyklucza tak e tę mo liwość, by wskaźnik do klasy bazowej lub referencja do klasy bazowej stały się referencjami (wskazaniami) do obiektów klas pochodnych. Jeśli 5VCEM+PFGZ stanie się prywatną klasą bazową (innymi słowy, jeśli dziedzi- czenie będzie następować z u yciem specyfikatora RTKXCVG), próba u ycia funkcji takiej jak 8KQ NCVG po stronie kodu klienta spowoduje wygenerowanie całej serii błędów kompilacji. ENCUU %JCT5VCEM RTKXCVG 5VCEM+PFGZ ] _ ENCUU +PV5VCEM RTKXCVG 5VCEM+PFGZ ] _ XQKF 8KQNCVG ]
  • 49. INTERFEJS A IMPLEMENTACJA 67 +PV5VCEM U U5VCEM+PFGZRWUJ MQOWPKMCV Q D úFKG 5VCEM+PFGZ
  • 50. R U MQOWPKMCV Q D úFKG R RWUJ 5VCEM+PFGZ T U MQOWPKMCV Q D úFKG TRWUJ _ Próba odwołania się do prywatnych pól klasy bazowej jest formalnie nielegalna, podobnie jak próba wskazania obiektu klasy pochodnej za pomocą wskaźnika do klasy bazowej lub referencji do klasy bazowej. Jednocześnie problem z destruktorem został tak e skorygowany. Skoro wskaźnik do klasy bazowej formalnie nie mo e wskazywać obiektu klasy pochodnej, to niepo ądany efekt działania operatora FGNGVG przy zastosowaniu takiego wskaźnika, jak opisano wy ej został wyeli- minowany formalnie, „z definicji”. Interfejs a implementacja Dlaczego i czy w ogóle musimy tu u ywać dziedziczenia? Jeśli przeanalizujemy dokładniej relacje dziedziczenia, przekonamy się, e to dziedziczenie mo e zostać całkowicie wyeliminowane. Dru- gim, alternatywnym rozwiązaniem mo e być zastosowanie obiektu, jako elementu klasy, zamiast dziedziczenia. Jak opisano to w rozdziale 2., klasa w C++ składa się z dwóch głównych części: publicznego interfejsu, który charakteryzuje zachowanie się obiektów danej klasy oraz z prywatnej implemen- tacji mechanizmów realizujących to zachowanie. Większość przypadków dziedziczenia to dzie- dziczenie po publicznej klasie bazowej (innymi słowy, z specyfikatorem RWDNKE). Klasa pochodna dziedziczy wtedy i interfejs, i implementację po klasie bazowej. Mo liwe jest jednak równie bar- dziej selektywne (wybiórcze) dziedziczenie, w którym klasa pochodna dziedziczy albo wyłącznie interfejs, albo wyłącznie implementację. Po prywatnej klasie bazowej (inaczej: przy dziedziczeniu z specyfikatorem RTKXCVG) klasa pochodna dziedziczy całą (prywatną) implementację, ale równo- cześnie nie dziedziczy ani jednego elementu publicznego interfejsu klasy bazowej. Po publicznej, abstrakcyjnej klasie bazowej klasa pochodna dziedziczy cały interfejs, ale równocześnie odziedzi- czona implementacja mo e okazać się niekompletna lub niespójna. Ka de zastosowanie dziedziczenia powinno zostać poddane uwa nej ocenie. Czy dziedziczo- ny jest interfejs, implementacja, czy i jedno, i drugie? W tym programie klasy pochodne %JCT5VCEM oraz +PV5VCEM dziedziczą tylko implementację. Interfejs klasy pochodnej %JCT5VCEM jest podobny, lecz ró ni się jednak od interfejsu klasy pochodnej +PV5VCEM. Metody nale ące do obu tych klas pochodnych mają takie same nazwy, ale jedne operują na wartościach typu EJCT, drugie na warto- ściach typu KPV. Klasy pochodne %JCT5VCEM oraz +PV5VCEM nie w mają adnym stopniu wspólnego interfejsu. Kod klienta nie mo e traktować obiektów tych klas w sposób jednakowy ani zamiennie. Choć jednak pojęcia abstrakcyjne reprezentowane poprzez klasy +PV5VCEM oraz %JCT5VCEM stanowią specjalizację w stosunku do pojęć abstrakcyjnych odnoszących się do ogólnego pojęcia stosu, nie stanowią one specjalizacji w stosunku do abstrakcyjnego pojęcia „mechanizmu indeksacji” defi- niowanego przez ich klasę bazową 5VCEM+PFGZ. Z punktu widzenia obiektów klienta ka da spośród tych trzech klas: +PV5VCEM, %JCT5VCEM, 5VCEM+PFGZ oferuje odrębne usługi. Klasa 5VCEM+PFGZ oferuje obsługę mechanizmu indeksacji, klasa +PV5VCEM oferuje zarządzanie stosem liczb całkowitych, a klasa %JCT5VCEM umo liwia obsługę stosu znakowego. Relacja specyfikacji — uogólnienia, którą mo na by słownie wyrazić jako „A jest szczególnym przypadkiem B” (ang. „is a kind of”) nie ma w odniesieniu
  • 51. 68 3. ZBĘDNE DZIEDZICZENIE do tych klas sensu z punktu widzenia kodu klienta (u ytkownika tych klas). Dlatego w tym przypadku dziedziczenia zastosowanie dziedziczenia publicznego interfejsu nie jest rozwiąza- niem właściwym. Relacja pomiędzy klasą pochodną a jej prywatną klasą bazową przypomina relację „klasa klienta-klasa serwera”. Jeśli klasa bazowa 5VCEM+PFGZ będzie prywatną klasą bazową, klasy po- chodne +PV5VCEM oraz %JCT5VCEM odziedziczą jej prywatną implementację, w celu wykorzystania jej mechanizmu obsługi indeksacji. W ten sposób klasy pochodne staną się „klientami”, a klasa bazowa będzie ich „serwerem”. Alternatywnym sposobem wyra enia w C++ takiej relacji „klient- serwer”, bez stosowania dziedziczenia, jest zagnie d enie prywatnej części (implementacji), czyli obiektu klasy 5VCEM+PFGZ wewnątrz ka dego obiektu klas +PV5VCEM oraz %JCT5VCEM. Zamiast pozostawać klasą bazową, 5VCEM+PFGZ mo e stać się obiektem składowym wewnątrz %JCT5VCEM oraz +PV5VCEM. To zmieni strukturę programu w bardzo niewielkim stopniu — pokazano to na listingu 3.3. Ta sama funkcjonalność w obu przypadkach jest realizowana poprzez obiekt takiego samego typu (klasy). Ró nica polega na tym, e w tej wersji serwerem jest wewnętrzny obiekt na- le ący do klasy, a nie prywatna część klasy bazowej. Zatem taki serwer jest identyfikowany poprzez nazwę (identyfikator) składowej klasy, a nie poprzez nazwę klasy. W tym konkretnym przypadku wybór jednego z tych rozwiązań: albo prywatnej klasy bazowej, albo prywatnego składowego obiektu wewnątrz klasy jest zdecydowanie kwestią gustu. Te dwie konstrukcje są z funkcjonalnego punktu widzenia równowa ne. Mimo to, rozwiązanie stosujące obiekt składowy mo e być prefe- rowane w celu uproszczenia kodu, poniewa składnia i semantyka stosowania składowych obiek- tów jest banalnie prosta w porównaniu z semantyką stosowaną podczas dziedziczenia. ► Wykorzystajmy dziedziczenie do przekazania implementacji klasy bazowej, a nie jej interfejsu; w takich przypadkach stosujmy prywatne klasy bazowe albo (lepiej) obiekty składowe klas. LISTING 3.3. Obiekt jako składowa klasy zastępuje dziedziczenie KPENWFG CUUGTVJ KPENWFG UVTKPIJ ENCUU 5VCEM+PFGZ ] KPV VQR KPV UKG RWDNKE 5VCEM+PFGZ KPV U KPV RWUJ KPV RQR _ 5VCEM+PFGZ5VCEM+PFGZ KPV U ] UKG U VQR _ KPV 5VCEM+PFGZRWUJ ]
  • 52. INTERFEJS A IMPLEMENTACJA 69 CUUGTV VQR UKG TGVWTP VQR _ KPV 5VCEM+PFGZRQR ] CUUGTV VQR TGVWTP VQR _ EQPUV KPV FGHCWNV5VCEM ENCUU %JCT5VCEM ] 5VCEM+PFGZ KPFGZ EJCT
  • 53. FCVC RWDNKE %JCT5VCEM %JCT5VCEM KPV UKG %JCT5VCEM KPV UKG EJCT
  • 54. KPKV `%JCT5VCEM XQKF RWUJ EJCT EJCT RQR _ %JCT5VCEM%JCT5VCEM KPFGZ FGHCWNV5VCEM ] FCVC PGY EJCT=FGHCWNV5VCEM? _ %JCT5VCEM%JCT5VCEM KPV UKG KPFGZ UKG ] FCVC PGY EJCT=UKG? _ %JCT5VCEM%JCT5VCEM KPV UKG EJCT
  • 55. KPKV KPFGZ UKG ] FCVC PGY EJCT=UKG? HQT KPV K KUVTNGP KPKV K FCVC=KPFGZRWUJ ? KPKV=K? _ %JCT5VCEM`%JCT5VCEM ] FGNGVG =? FCVC _ XQKF %JCT5VCEMRWUJ EJCT F ] FCVC=KPFGZRWUJ ? F _
  • 56. 70 3. ZBĘDNE DZIEDZICZENIE EJCT %JCT5VCEMRQR ] TGVWTP FCVC=KPFGZRQR ? _ ENCUU +PV5VCEM ] 5VCEM+PFGZ KPFGZ KPV
  • 57. FCVC RWDNKE +PV5VCEM MQPUVTWMVQT FQO[ NP[ +PV5VCEM KPV UKG `+PV5VCEM XQKF RWUJ KPV KPV RQR _ +PV5VCEM+PV5VCEM KPFGZ FGHCWNV5VCEM ] FCVC PGY KPV=FGHCWNV5VCEM? _ +PV5VCEM+PV5VCEM KPV UKG KPFGZ UKG ] FCVC PGY KPV=UKG? _ +PV5VCEM`+PV5VCEM ] FGNGVG =? FCVC _ XQKF +PV5VCEMRWUJ KPV F ] FCVC=KPFGZRWUJ ? F _ KPV +PV5VCEMRQR ] TGVWTP FCVC=KPFGZRQR ? _ Przecią anie funkcji w porównaniu ze stosowaniem domyślnych argumentów Zanim przejdziemy do ostatniego przykładu, zwróćmy uwagę na podobieństwa w poddanych prze- cią eniu funkcji (ang. overloading) konstruktorach w obydwu klasach %JCT5VCEM oraz +PV5VCEM. Podobnie jak w przypadku przecią onego konstruktora klasy UVTKPI, opisanym w rozdziale 2.,
  • 58. ZASTOSOWANIE SZABLONÓW 71 zastosowanie domyślnych wartości argumentów powinno było zastąpić stosowanie dwóch kon- struktorów, czyli przecią anie funkcji w podobny sposób, jak pokazano to wobec klasy %JCT5VCEM na listingu 3.4. Dla ka dej spośród tych klas wiele konstruktorów sprowadza się do jednego (bardziej zło onego) konstruktora, co upraszcza obsługę takiego kodu. Zastąpienie przecią ania funkcji u yciem domyślnych wartości argumentów nie zawsze jest takie proste, niemniej jednak — po- winno zawsze zostać rozwa one, jako rozwiązanie alternatywne. Przypomnijmy stosowną regułę: ► Rozwa u ycie domyślnych wartości argumentów funkcji jako rozwiązanie alter- natywne wobec przecią ania funkcji. Na koniec, zwróćmy jeszcze uwagę, e konstruktor %JCT5VCEM%JCT5VCEM na listingu 3.4 wywołuje funkcję biblioteczną UVTNGP podczas ka dego cyklu iteracyjnego pętli programowej. Jeśli oka e się, e to ten właśnie konstruktor tworzy „wąskie gardło”, powodując znaczące pogor- szenie prędkości działania programu, usunięcie tego błędu powinno okazać się łatwe. LISTING 3.4. Zastosowanie domyślnych wartości argumentów pozwala zastąpić przecią anie funkcji ENCUU %JCT5VCEM ] 5VCEM+PFGZ KPFGZ EJCT
  • 59. FCVC RWDNKE %JCT5VCEM KPV UKG FGHCWNV5VCEM EJCT
  • 60. KPKV `%JCT5VCEM XQKF RWUJ EJCT EJCT RQR _ %JCT5VCEM%JCT5VCEM KPV UKG EJCT
  • 61. KPKV KPFGZ UKG ] FCVC PGY EJCT=UKG? HQT KPV K KUVTNGP KPKV K FCVC=KPFGZRWUJ ? KPKV=K? _ Zastosowanie szablonów Wspólne własności klas +PV5VCEM oraz %JCT5VCEM mogą zostać wyra one w sposób zupełnie inny przy u yciu szablonów w C++ (ang. templates), nazywanych tak e typami parametryzowanymi. Odpowiedni szablon klasy (ang. class template) dla klasy reprezentującej stos został pokazany na listingu 3.5. Szablon klasy 5VCEM definiuje rodzinę klas. Gdy szablon klasy 5VCEM zostaje u yty do zade- klarowania obiektu, w deklaracji nazwa typu 6 musi zostać zastąpiony konkretnym typem danych. Na przykład, stos przeznaczony na elementy typu EJCT: 5VCEMEJCT UVCEM1H%JCT
  • 62. 72 3. ZBĘDNE DZIEDZICZENIE LISTING 3.5. Stos w postaci szablonu klasy Stack EQPUV KPV FGHCWNV5VCEM VGORNCVG ENCUU 6 ENCUU 5VCEM ] KPV UKG KPV VQR 6
  • 63. FCVC RWDNKE 5VCEM KPV UKG FGHCWNV5VCEM `5VCEM XQKF RWUJ 6 6 RQR XQKF _ VGORNCVG ENCUU 6 5VCEM6 5VCEM KPV U ] UKG U VQR FCVC PGY 6=UKG? _ VGORNCVG ENCUU 6 5VCEM6 `5VCEM ] FGNGVG =? FCVC _ VGORNCVG ENCUU 6 5VCEM6 RWUJ 6 F ] CUUGTV VQRUKG FCVC=VQR ? F _ VGORNCVG ENCUU 6 6 5VCEM6 RQR ] CUUGTV VQR TGVWTP FCVC=VQR? _ Powy sza deklaracja powoduje utworzenie obiektu o nawie UVCEM1H%JCT będącego stosem do przechowywania maksymalnie 10 elementów typu EJCT, natomiast: 5VCEMKPV UVCEM1H+PV
  • 64. PODSUMOWANIE 73 spowoduje utworzenie obiektu o nazwie UVCEM1H+PV, czyli stosu do przechowywania maksymalnie 20 wartości typu KPV. Typ argumentu metody odkładającej na stos RWUJ oraz typ wartości zwra- canej metody zdejmującej ze stosu RQR są tak e określone za pomocą nazwy typu 6. Podstawowym i zasadniczym motywem, który spowodował dodanie szablonów do C++ była zapewniana przez szablony obsługa ogólnych klas — kolekcji. W ten sposób mo na utworzyć nie tylko stos liczb całkowitych i znaków, lecz równie dobrze mo na zbudować stosy zło one z liczb zmiennoprzecinkowych, ze wskaźników do znaków, itd. Zachowanie się obiektów utworzonych na podstawie takiego szablonu klas w jeden, dość subtelny sposób ró ni się od tych obiektów, które były uprzednio tworzone na podstawie oryginal- nych definicji klas +PV5VCEM oraz %JCT5VCEM. Oryginalny konstruktor z klasy %JCT5VCEM mógłby obierać drugi argument, który mógłby określać łańcuch znaków przeznaczony do umieszczenia (RWUJ) na stosie. Jednak e w klasie +PV5VCEM nie ma adnego konstruktora, który mógłby pobierać taki (analogiczny) argument. Jeśli zastosujemy szablon do opisu obu tych klas jednocześnie, nie ma adnego sposobu, by wyrazić takie zró nicowanie. Podsumowanie Pierwszą i najwa niejszą zmianą, której dokonaliśmy w pierwszym programie było zmodyfikowa- nie abstrakcyjnej konstrukcji zdefiniowanej poprzez klasę 5VCEM. Oryginalny interfejs był zdefi- niowany w kategoriach wskaźników do elementów tablicy u ytkownika. Abstrakcyjna konstrukcja stosu została uproszczona poprzez wyra enie interfejsu za pomocą innej kategorii — liczby cał- kowitej reprezentującej indeks stosu. Powstała w rezultacie tych modyfikacji nowa klasa, nazwana 5VCEM+PFGZ, w sposób bardziej spójny i klarowny obejmowała ogólne własności stosu i jednocze- śnie pozwoliła zignorować nie mające istotnego znaczenia szczegóły techniczne reprezentacji. Ogólnie, im prostsze jest pojęcie abstrakcyjne, tym, po prostu, lepiej, dopóki tylko taka abstrak- cyjna reprezentacja pozostaje wystarczająca. W przypadku tego programu, prostsza abstrakcja okazała się bardziej bezpieczna, poniewa to uproszczenie pozwoliło wyeliminować liczne wymu- szone konwersje typu. Stała się jednocześnie bardziej efektywna, poniewa wyeliminowana zo- stała z programu tablica zawierająca wskaźniki do danych. Drugą fundamentalną zmianą w tym programie, która pozwoliła na jego skorygowanie i wy- eliminowanie luki w enkapsulacji stosu (wywołanej poprzez zastosowanie publicznego dziedzi- czenia, podczas gdy klasy pochodne potrzebowały tylko części implementacyjnej po klasie bazo- wej), było zastąpienie dziedziczenia. Prywatny, obiekt składowy klasy 5VCEM+PFGZ okazał się dla klas %JCT5VCEM oraz +PV5VCEM rozwiązaniem prostszym, a umo liwiającym im wykorzystanie funkcjonalności klasy 5VCEM+PFGZ. Bibliografia Model „klient-serwer” został opisany w ksią ce [2], Gorlena i in. oraz [3], Wirfsa-Brocka i in. Termin „klient” jest równie stosowany w odniesieniu do programisty piszącego „kod klienta” (tj. kod u ytkowy, posługujący się obiektami danych klas). Termin „serwer” (oznaczający generalnie „stronę usługową”, klasę, funkcję, itp.) bywa czasem zastępowany określeniem „usługodawca” (ang. supplier).
  • 65. 74 3. ZBĘDNE DZIEDZICZENIE [1] Ellis M.A. Stroustrup B., The Annotated C++ Reference Manual. Reading, MA: Addison- -Wesley, 1990. [2] Gorlen K. E., Orlow S. M., Plexico P. S., Data Abstraction and Object-Oriented Programming in C++. Chichester, England: Wiley, 1990. [3] Wirfs-Brock R., Wilkerson B., Wiener L., Designing Object-Oriented Software. Englewoods Cliffs, NJ: Prentice-Hall, 1990. Ćwiczenie 3.1. Klasa 5VCEM+PFGZ mo e być albo prywatną klasą bazową, albo posłu yć do utworzenia prywatnego obiektu składowego wewnątrz klas +PV5VCEM oraz %JCT5VCEM. Skonstruuj taką sytuację, w której nie mo na by mieć takiego wyboru. Najpierw utwórz klasę korzystającą z usług innej klasy, która to musi zostać prywatną klasą bazową. Następnie utwórz taką klasę, w której potrzebna funkcjonalność musi zostać zaimplementowana w postaci pry- watnego obiektu składowego wewnątrz tej klasy.