Język C++. Efektywne programowanie obiektowe - Helion
Tytuł oryginału: C++: Effective Object-Oriented Software Construction
Tłumaczenie: Michał Grzegorczyk, Jaromir Senczyk, Przemysław Steć, Przemysław Szeremiota, Tomasz Walczak
ISBN: 83-7361-812-0
stron: 800, Format: B5, okładka: miękka
Data wydania: 2005-05-12
Księgarnia: Helion
Cena książki: 89,00 zł
Poznaj metody programowania
stosowane przez profesjonalistów
Programowanie obiektowe jest nierozerwalnie związane z językiem C++. Koncepcje i metody programowania obiektowego, niezbędne do swobodnego posługiwania się tą techniką, pomimo pozornej prostoty są stosunkowo trudne do opanowania. Projektowanie aplikacji w języku C++ wymaga jednak nie tylko znajomości podstawowych zasad programowania obiektowego, ale również wielu innych technik programistycznych. Należy prawidłowo zaplanować strukturę aplikacji, poznać zasady pisania poprawnego kodu i nauczyć się korzystać z notacji UML do modelowania zależności pomiędzy elementami aplikacji.
"C++. Efektywne programowanie obiektowe" to podręcznik przeznaczony zarówno dla początkujących, jak i zaawansowanych programistów C++. Przedstawia metody programowania obiektowego stosowane przez profesjonalistów. Opisuje techniki obiektowe w kontekście rzeczywistych problemów, przed jakimi stają twórcy oprogramowania podczas codziennej pracy.
- Podstawowe pojęcia i koncepcje programowania obiektowego
- Abstrakcja danych
- Notacja UML
- Zarządzanie pamięcią w programowaniu obiektowym
- Dziedziczenie
- Zasady programowania generycznego
- Obsługa wyjątków
- Zaawansowane aplikacje obiektowe
Dzięki zawartym w tej książce wiadomościom wykonasz nawet najtrudniejsze zadania programistyczne, wykorzystując techniki obiektowe.
Spis treści
Język C++. Efektywne programowanie obiektowe -- spis treści
Rekomendacje (13)
Przedmowa (15)
Wstęp (17)
Część I Pojęcia, techniki i aplikacje (21)
Rozdział 1. Czym jest programowanie obiektowe? (23)
- Pochodzenie (23)
- Przykład programowania proceduralnego (24)
- Reprezentacja konta bankowego (25)
- Bezpieczeństwo konta bankowego (26)
- Rozwiązywanie problemów w programowaniu obiektowym (27)
- Wprowadzenie do modelu obiektowego (28)
- Terminologia (30)
- Poznajemy komunikaty, metody i zmienne egzemplarza (30)
- Z czego składa się obiekt? (31)
- Tworzenie obiektów (32)
- Co można uznać za klasę? (33)
- Co nie jest klasą? (34)
- Cel klasy (35)
- Więcej o obiektach (36)
- Stan obiektu (36)
- Dlaczego stan obiektu jest ważny? (37)
- Kto kontroluje stan obiektu? (38)
- Zachowanie obiektu (39)
- Etapy w konstruowaniu oprogramowania obiektowego (40)
- Analiza obiektowa (40)
- Projektowanie obiektowe (41)
- Programowanie obiektowe (43)
- Kluczowe elementy modelu obiektowego (43)
- Paradygmaty i języki programowania obiektowego (45)
- Jakie wymagania musi spełniać język obiektowy? (46)
- Zalety modelu obiektowego (47)
- Podsumowanie (48)
Rozdział 2. Czym jest abstrakcja danych? (49)
- Analiza projektu odtwarzacza (51)
- Oddzielanie interfejsu od implementacji (52)
- Znaczenie interfejsu (52)
- Dlaczego interfejs obiektu jest tak ważny? (53)
- Jaki interfejs jest wystarczający? (53)
- Znaczenie implementacji (54)
- Ochrona implementacji (54)
- Jakie są korzyści ukrywania danych? (56)
- Relacje między interfejsem, implementacją i hermetyzacją danych (57)
- Środki ostrożności przy hermetyzacji danych (58)
- Co i kiedy ukrywać? (58)
- Abstrakcyjne typy danych (59)
- Implementacja abstrakcyjnego typu danych - stosu (60)
- Abstrakcja danych w języku C++ (62)
- Regiony dostępu klasy (63)
- Niektóre pojęcia związane z klasami (69)
- Kto jest implementatorem klasy? (70)
- Implementowanie funkcji składowych (70)
- Identyfikacja obiektu docelowego w funkcjach składowych (71)
- Przykładowy program (73)
- Uwaga skoncentrowana jest na obiekcie (74)
- Drugi rzut oka na interfejs (75)
- Czym są bezpieczne klasy wielowątkowe? (76)
- Zapewnianie niezawodności abstrakcji - niezmienniki i asercje klasy (78)
- Niezmienniki klasy (79)
- Warunki wstępne i warunki końcowe (79)
- Używanie asercji do implementowania niezmienników i warunków (80)
- Efektywne korzystanie z asercji (81)
- Sposoby reprezentacji projektów obiektowych (82)
- Notacja Boocha (83)
- Relacje między klasami (83)
- Asocjacja (84)
- Agregacja (ma-coś) (84)
- Relacja korzystania (86)
- Relacja dziedziczenia (jest-czymś) (87)
- Kategorie klas (88)
- UML (88)
- Relacje między klasami (90)
- Asocjacja (90)
- Asocjacja jako agregacja (92)
- Asocjacja typu OR (93)
- Kompozycja (93)
- Relacja uogólniania (jest-czymś) (94)
- Znaczenie relacji ma-coś (95)
- Podsumowanie (97)
Rozdział 3. Abstrakcja danych w języku C++ (99)
- Podstawowe informacje o klasie (99)
- Elementy klasy (100)
- Regiony dostępu (100)
- Konstruktor kopiujący (103)
- Dostęp do danych składowych obiektu - model języka C++ (106)
- Operacja przypisania (111)
- Więcej o wskaźniku this i dekorowaniu nazw (116)
- Metoda stała (const) (118)
- Jak kompilator implementuje metody stałe? (120)
- Różnice między klasą a strukturą w języku C++ (120)
- Co może zawierać klasa? (121)
- W czasie projektowania najważniejszy jest interfejs klasy (122)
- Nazwy klas, nazwy metod, typy argumentów i dokumentacja (123)
- Sposoby przekazywania argumentów z perspektywy klienta (124)
- Semantyka własności (128)
- Wybór odpowiedniego sposobu przekazywania argumentu (130)
- Wartości zwracane przez funkcję (131)
- Zwracanie referencji (133)
- Jak napisać bezpieczną pod względem pamięci klasę? (134)
- Optymalizacja kodu (134)
- Obowiązki klienta w pracy z klasami i funkcjami (134)
- Podsumowanie (136)
Rozdział 4. Inicjalizacja i zwalnianie pamięci w programowaniu obiektowym (137)
- Co to jest inicjalizacja? (137)
- Inicjalizacja za pomocą konstruktora (139)
- Reguły pracy z obiektami zagnieżdżonymi (146)
- Zagadnienia związane z przywracaniem pamięci (146)
- Śmieci (146)
- Wiszące referencje (147)
- Jak zapobiegać powstawaniu śmieci i wiszących referencji? (148)
- Przywracanie pamięci a projektowanie języka (149)
- Kiedy powstają śmieci w języku C++? (151)
- Kiedy obiekt zajmuje zasoby? (152)
- Przywracanie pamięci w języku C++ (152)
- Tożsamość obiektów (154)
- Semantyka kopiowania obiektów (157)
- Semantyka prostej operacji kopiowania (158)
- Semantyka przypisywania obiektów (163)
- Przypisanie jako operacja na l-wartości (166)
- Semantyka porównywania obiektów (166)
- Równość obiektów a ekwiwalencja (168)
- Dlaczego potrzebna jest kontrola kopiowania? (170)
- Przykład semafora (171)
- Przykład - serwer licencji (173)
- Przykład - klasa String (174)
- Analiza (180)
- Kopiowanie przy zapisie (182)
- Kiedy używać zliczania referencji? (188)
- Podsumowanie kopiowania przy zapisywaniu (188)
- Klasy i typy (189)
- Podsumowanie (190)
Rozdział 5. Dziedziczenie (191)
- Podstawy dziedziczenia (191)
- Znaczenie relacji dziedziczenia (205)
- Skutki relacji dziedziczenia (205)
- Bezpośrednie i pośrednie klasy bazowe (206)
- Zasada podstawiania polimorficznego (207)
- Inicjalizacja obiektów klasy bazowej (210)
- Rozszerzanie hierarchii klas za pomocą dziedziczenia (213)
- Podstawowe zalety dziedziczenia (215)
- Wiązanie dynamiczne, funkcje wirtualne i polimorfizm (216)
- Co oznacza wiązanie dynamiczne? (219)
- Obsługa wiązania dynamicznego - funkcje wirtualne (220)
- Wpływ dziedziczenia na hermetyzację danych (222)
- Co oznacza polimorfizm? (224)
- Efektywne stosowanie funkcji wirtualnych (225)
- Przesłanianie (225)
- Kiedy potrzeba wirtualnego destruktora? (228)
- Konstruktory i funkcje wirtualne (231)
- Uogólnianie-uszczegóławianie (233)
- Klasy abstrakcyjne (233)
- Zastosowania klas abstrakcyjnych (237)
- Zaawansowany przykład klasy abstrakcyjnej - gra w szachy (241)
- Waga dziedziczenia (249)
- Efektywne wielokrotne używanie kodu (250)
- Klient abstrakcyjnej klasy bazowej (253)
- Podsumowanie zalet dziedziczenia (254)
- Zagrożenia związane z dziedziczeniem i wiązaniem dynamicznym (256)
- Jak implementowane są funkcje wirtualne w języku C++? (257)
- Koszty funkcji wirtualnych (258)
- Dynamiczne wiązanie i sprawdzanie typu (259)
- Zbędne używanie dziedziczenia i wiązania dynamicznego (259)
- Wypożyczanie zbiorów bibliotecznych (259)
- Różne sposoby używania funkcji wirtualnych (270)
- Podsumowanie (272)
Rozdział 6. Dziedziczenie wielokrotne (273)
- Prosta definicja dziedziczenia wielokrotnego (273)
- Abstrakcja uniwersytetu (274)
- Powtórne wykorzystanie kodu z ulepszeniami (278)
- Znaczenie wielokrotnego dziedziczenia (280)
- Przykład dziedziczenia wielokrotnego (281)
- Rozwiązywanie konfliktów nazw w języku C++ (282)
- Problem z wieloznacznością klas bazowych (285)
- Podstawowe zalety dziedziczenia wielokrotnego (287)
- Rozwiązania alternatywne dla dziedziczenia wielokrotnego (287)
- Pierwsze rozwiązanie alternatywne (287)
- Drugie rozwiązanie alternatywne (290)
- Problem powtórnego dziedziczenia (291)
- Rozwiązanie problemu powtórnego dziedziczenia (295)
- Dzielenie obiektów za pomocą wirtualnych klas bazowych (295)
- Zalety wirtualnych klas bazowych (297)
- Nowe problemy wynikające z użycia wirtualnych klas bazowych (297)
- Porównanie dziedziczenia wielokrotnego w językach Eiffel i C++ (302)
- Ogólne problemy z dziedziczeniem (304)
- Dodawanie statycznych możliwości za pomocą klas mieszanych (306)
- Definicja klasy mieszanej (306)
- Kiedy należy używać klas mieszanych? (310)
- Dynamicznie zmieniająca się sytuacja (311)
- Elastyczność projektu z klasami pełniącymi różne role (316)
- Jak używać klas pełniących różne role? (316)
- Inne rozwiązanie zarządzania rolami (324)
- Polimorficzne używanie obiektów TUniversityMember (326)
- Wprowadzanie zmian w istniejących klasach (326)
- Klasy mieszane a obiekty pełniące role - możliwości zastosowań (328)
- Wyprowadzenie prywatne w języku C++ (330)
- Kiedy używać wyprowadzenia prywatnego? (332)
- Ponowne eksportowanie składowych prywatnej klasy bazowej (334)
- Alternatywne rozwiązanie dla wyprowadzenia prywatnego - zawieranie (335)
- Kiedy potrzebne jest prywatne wyprowadzenie? (337)
- Bardzo użyteczny przykład dotyczący klas mieszanych i wyprowadzenia prywatnego (340)
- Dziedziczenie a zawieranie (345)
- Podsumowanie (347)
Rozdział 7. Selektywny eksport z klas (funkcje zaprzyjaźnione) (349)
- Czego nam potrzeba? (349)
- Eksport selektywny w języku C++ (350)
- Konsekwencje związku przyjaźni (353)
- Zastosowania funkcji niebędących składowymi oraz funkcji zaprzyjaźnionych (357)
- Przypadek 1. Minimalizowanie silnych interakcji pomiędzy klasami (357)
- Przypadek 2. Przezwyciężanie problemów składniowych (363)
- Przypadek 3. Funkcje, które wymagają komunikacji z więcej niż jedną klasą (374)
- Przewaga funkcji niebędących składowymi (376)
- Wybór pomiędzy funkcjami zaprzyjaźnionymi a funkcjami składowymi (379)
- Podsumowanie (380)
Rozdział 8. Przeciążanie operatorów (383)
- Różnica pomiędzy typami standardowymi a typami definiowanymi przez programistę (383)
- Czym jest operator przeciążony? (386)
- Przeciążać czy nie przeciążać - plusy i minusy przeciążania operatorów (388)
- Bardziej eleganckie abstrakcyjne typy danych (388)
- Zagmatwane przeciążanie operatorów (389)
- Brak zrozumienia zasad pierwszeństwa i łączności (389)
- Operatory przeciążone w języku C++ (392)
- Inne zastosowanie operatorów ++ oraz -- (397)
- Operator indeksowania - operator [ ] (399)
- Rzecz bardziej wyrafinowana - operator dostępu do składowych, czyli -> (405)
- Operatory jako funkcje składowe lub jako funkcje niebędące składowymi (414)
- Operatory będące funkcjami składowymi (415)
- Operatory implementowane w postaci funkcji niebędących składowymi (416)
- Dlaczego potrzebujemy konwersji? (420)
- Funkcje konwersji (421)
- Interakcje pomiędzy konstruktorami konwertującymi a funkcjami konwersji (424)
- Eliminacja potrzeby tworzenia obiektów tymczasowych (428)
- Zwracanie wyników z funkcji operatorowych (430)
- Operator przypisania (435)
- Podsumowanie (435)
Rozdział 9. Typy generyczne (437)
- Problem powtarzania kodu (437)
- Eleganckie rozwiązanie - programowanie generyczne (444)
- Podstawy typu generycznego (klasy generycznej) (446)
- Co się dzieje podczas konkretyzacji nowej klasy szablonowej w języku C++? (448)
- Typy generyczne a powielanie kodu (453)
- Kontrakt pomiędzy implementatorem klasy generycznej a jej klientami (454)
- Czy można to uznać za "dobry projekt"? (459)
- Operatory a funkcje składowe w implementacji klas generycznych (462)
- Rozwiązanie alternatywne - specjalizacja klas generycznych (464)
- Specjalizacje szablonów (464)
- Specjalizacja funkcji składowej szablonu (465)
- Inne rozwiązanie - wydzielenie operacji porównania obiektów (467)
- A jeśli nie można zdefiniować specjalizacji określonej funkcji składowej szablonu? (469)
- Specjalizacja klas szablonowych (470)
- Koncepcja funkcji generycznych (472)
- Konkretyzacja klas szablonowych i funkcji składowych w języku C++ (476)
- Typy generyczne a kontrola typów (482)
- Generyczność z ograniczeniami i bez ograniczeń (484)
- Ograniczenia parametrów szablonu w języku C++ (488)
- Konkretne typy jako parametry szablonu w języku C++ (488)
- Wartości domyślne parametrów szablonu (490)
- Nakładanie ograniczeń na parametry szablonu w języku C++ (491)
- Klasy generyczne a eksport selektywny (494)
- Dziedziczenie a klasy generyczne (497)
- Polimorfizm a klasy generyczne (501)
- Przydatne zastosowania dziedziczenia wraz z klasami generycznymi (504)
- Podejście typu singleton (504)
- Ogólna technika kontrolowania tworzenia obiektów (506)
- Implementacja wskaźników zliczanych (508)
- Minimalizowanie powielania kodu w przypadku obiektów szablonowych (517)
- Zapotrzebowanie programu na pamięć (519)
- Sposoby redukcji rozmiaru kodu szablonowego (519)
- Klasy szablonowe a ochrona kodu źródłowego (531)
- Klasy szablonowe w bibliotekach współdzielonych (dynamicznych) (531)
- Klasy szablonowe w bibliotekach współdzielonych - problem wielokrotnych egzemplarzy (534)
- Eliminacja wielokrotnie występujących egzemplarzy w bibliotekach współdzielonych (535)
- Konsolidacja z istniejącymi bibliotekami współdzielonymi (537)
- Klasy kontenerowe (538)
- Porównanie klas generycznych i mechanizmu dziedziczenia (539)
- Podsumowanie (540)
Rozdział 10. W oczekiwaniu nieoczekiwanego (543)
- Po co obsługiwać sytuacje wyjątkowe? (543)
- Dlaczego kody błędów nie są wystarczające? (544)
- Jakie mamy możliwości? (545)
- Model obsługi wyjątków języka C++ (546)
- Działanie mechanizmu wyjątków w języku C++ (547)
- Wpływ bloku kodu chronionego na program (549)
- Wpływ zgłaszanego wyjątku na program (550)
- Dynamiczny łańcuch wywołań (551)
- Obsługa wielu wyjątków (554)
- Odpowiedzialność klauzuli catch (555)
- Model wyjątków w języku Eiffel (556)
- Porównanie modeli wyjątków w językach C++ i Eiffel (560)
- Efektywne stosowanie wyjątków w C++ (563)
- Tworzenie hierarchii wyjątków (563)
- Kolejność klauzul przechwytujących (566)
- Odporność funkcji na wyjątki (568)
- Zagadnienia projektowe dotyczące obsługi wyjątków (570)
- Kiedy zgłaszać wyjątki? (570)
- Strategie skutecznego zarządzania błędami w projekcie (573)
- Funkcje nie są zaporami (574)
- Projektowanie hierarchii wyjątków (575)
- Zarządzanie zasobami w środowisku wyjątków (578)
- Automatyzacja zarządzania zasobami (579)
- Uogólnianie rozwiązania zarządzania zasobami (582)
- Wyjątki a konstruktory (584)
- Zwracanie zabezpieczonych zasobów z funkcji (585)
- Klasa pomocna w zarządzaniu tablicami obiektów (588)
- Koszt automatycznego zarządzania zasobami (594)
- Częściowa skuteczność konstruktora (594)
- Bezpieczne tworzenie tablic z wykorzystaniem wyjątków (595)
- Podsumowanie (601)
Część II Tworzenie zaawansowanych aplikacji obiektowych (603)
Rozdział 11. Poznawanie abstrakcji danych (605)
- Ukrywanie szczegółów implementacji abstrakcji (605)
- Zalety używania uchwytów (609)
- Wady używania uchwytów (609)
- Wskaźniki w roli danych składowych (opóźnianie ewaluacji) (613)
- Kontrolowanie sposobu tworzenia obiektów (616)
- Wymuszanie stosowania operatora new() (616)
- Blokowanie stosowania operatora new() (619)
- Używanie wskaźników i referencji zamiast obiektów zagnieżdżonych (619)
- Wady stosowania dużych tablic jako zmiennych automatycznych (lub jako danych składowych) (620)
- Używanie tablic obiektów oraz tablic wskaźników do obiektów (621)
- Obiekty zamiast wskaźników typów prostych (w danych składowych i wartościach zwracanych przez funkcje składowe) (624)
- Zgodność z językiem C (627)
- Rozmiar obiektu a efektywność kodu - szukanie implementacji alternatywnych (629)
- Unikanie obiektów tymczasowych (632)
- Inicjalizowanie obiektów konstruktorem kopiującym (633)
- Efektywne używanie obiektów proxy (lub obiektów zastępczych) (634)
- Obiekty proxy ułatwiające bezpieczne współdzielenie obiektów (634)
- Łatwość używania obiektów proxy (637)
- Obiekty proxy będące zastępcami obiektów zdalnych (638)
- Inteligentne obiekty proxy dostarczające dodatkowej funkcjonalności (638)
- Klasy proxy do rozwiązywania problemów składniowych i semantycznych (639)
- Technika ogólnego indeksowego obiektu proxy (642)
- Używanie prostych abstrakcji do budowy bardziej złożonych (644)
- Abstrakcje dające użytkownikom wybór sposobu stosowania klas (645)
- Podsumowanie (647)
Rozdział 12. Efektywne korzystanie z dziedziczenia (649)
- Wykorzystanie dziedziczenia w eleganckich implementacjach menu (649)
- Obsługa menu różnych typów (655)
- Hermetyzacja szczegółów fazy tworzenia obiektu (656)
- Koncepcja konstruktorów wirtualnych (658)
- Funkcje wirtualne i niewirtualne w kontroli protokołu (661)
- Koncepcja podwójnego rozgłaszania wywołań (670)
- Projektowanie i implementacja klas kontenerów (677)
- Projektowanie obsługi różnych kontenerów (679)
- Implementacja klas kontenerów homogenicznych z użyciem programowania generycznego (691)
- Cele projektowe (692)
- Zalety kontenerów homogenicznych opartych na szablonach (697)
- Wady kontenerów szablonowych (698)
- Implementacja heterogenicznych kontenerów na podstawie homogenicznych kontenerów wskaźników (698)
- Przeglądanie kontenerów (701)
- Iteratory pasywne (702)
- Iteratory aktywne (705)
- Iteratory jako obiekty (708)
- Zarządzanie kolekcjami i iteratorami z punktu widzenia użytkownika (715)
- Metoda 1. Utworzenie iteratora w kontenerze i przekazanie go użytkownikowi (715)
- Metoda 2. Zwracanie kopii kontenera, aby użytkownik swobodnie nim manipulował (716)
- Biblioteka standardowa języka C++ (STL) (718)
- Kontenery STL (719)
- Iteratory (720)
- Algorytmy biblioteki STL (721)
- Podsumowanie (723)
- Kod implementujący kontener TArray (724)
Rozdział 13. Wewnętrzny model obiektowy w C++ (735)
- Efektywna implementacja (735)
- Reprezentacja obiektów w C++ (735)
- Obiekty klas pozbawionych funkcji wirtualnych (736)
- Metody (736)
- Statyczne dane składowe (738)
- Konstruktory (738)
- Klasy z metodami wirtualnymi (739)
- Rozmieszczenie wskaźnika tablicy vtbl (740)
- Współużytkowanie tablic funkcji wirtualnych przez biblioteki współdzielone (743)
- Metody wirtualne a dziedziczenie wielokrotne (bez wirtualnych klas bazowych) (743)
- Wirtualne klasy bazowe (749)
- Odwołania do składowych z wirtualnymi klasami bazowymi (750)
- Wirtualne klasy bazowe z metodami wirtualnymi (752)
- Implementacja mechanizmu RTTI (informacja o typie w czasie wykonania) (754)
- Programowanie obiektowe a programowanie z wykorzystaniem obiektów (756)
- Referencje, wskaźniki i wartości (756)
- Przypisania referencji i wskaźników (756)
- Konstruktor kopiujący (758)
- Zadania konstruktora (758)
- Zadania konstruktora kopiującego (761)
- Optymalizacja przekazywania i zwracania obiektów przez wartość (763)
- Przekazywanie przez wartość (763)
- Zwracanie przez wartość (765)
- Inicjalizacja czasu wykonania (768)
- Podsumowanie (768)
Dodatki (769)
Dodatek A Przestrzenie nazw (771)
- Deklaracja using (772)
- Dyrektywa using (773)
- Przestrzeń nazw std (773)
Dodatek B Bibliografia i lista lektur zalecanych (775)
Skorowidz (779)