[7] Klasy i obiekty
(Część C++ FAQ Lite, Copyright © 1991-2002, Marshall Cline, cline@parashift.com)


FAQ - sekcja [7]:


[7.1] Co to jest klasa?

Klasa jest podstawowym blokiem programu zorientowanego obiektowo.

"Klasa" definiuje nowy typ danych, w znacznym stopniu tak jak "struktura" w języku C. W informatyce typ danych oznacza zbiór stanów oraz zbiór operacji dokonujących przejść między tymi stanami. Na przykład int jest typem danych, ponieważ zawiera on zbiór stanów [czyli zbiór wszystkich wartości, jakie zmienna typu int może przyjmować - przyp. tłum.] oraz zbiór operacji takich jak i + j , i++, itd. Dokładnie tak samo "klasa" zawiera zbiór operacji (na ogół "publicznych") oraz zbiór danych (przeważnie "prywatnych") reprezentujących różne, abstrakcyjne wartości, które obiekty tej klasy mogą przyjmować.

Zgodnie z powyższym można to tak ująć, że int jest "klasą" zawierającą funkcje o nazwach w stylu operator++, operator-- etc. (int tak naprawdę nie jest "klasą", ale istnieje między nimi pewna analogia: "klasa" jest typem danych, w znacznym stopniu tak jak int jest typem danych).

Notka: Programista piszący w języku C może traktować "klasę" jak "strukturę", której zawartość domyślnie jest "prywatna". Jednak jeżeli tylko w taki sposób masz zamiar rozumieć pojęcie "klasy", przypuszczalnie przydałoby Ci się doświadczyć małej, osobistej rewolucji w sposobie myślenia.

GóraDółPoprzednia sekcjaNastępna sekcjaSzukaj w FAQ ]


[7.2] Co to jest obiekt?

[Przypis tłumacza: Postanowiłem nieznacznie "rozwinąć" treść tego podrozdziału, aby stał się on trochę bardziej zrozumiały - przynajmniej według mojego mniemania. Mam nadzieję, że Czytelnicy nie ucierpią na tym za bardzo :-]

Obiekt jest fragmentem pamięci, któremu przyporządkowano pewien typ i sposób odwoływania się do niego przy użyciu języka programowania (semantykę).

Po zadeklarowaniu int i; mówimy, że i jest obiektem typu int. Mamy teraz do dyspozycji pewien fragment pamięci, którego zawartość traktujemy jako liczbę całkowitą z jakiegoś tam przedziału. Pisząc w C i mamy na myśli właśnie liczbę zapisaną w tym regionie pamięci. Możemy wpływać na jej wartość pisząc np. i++, i--, i=(a+b)/2 - czyli zgodnie z semantyką przewidzianą dla typu int.

W programowaniu zorientowanym obiektowo "obiekt" przeważnie oznacza zmienną lub stałą (ogólnie jakąś część pamięci) zgodną z opisem klasy (jeżeli mamy zdefiniowaną klasę o nazwie powiedzmy "Plik" to pisząc "Plik conf;" tworzymy nową zmienną - obiekt klasy "Plik") - tak jak i jest zgodne z opisem typu int (może przyjmować wartości tylko z określonego zakresu, np. od -32768 do 32767 i można na nim dokonywać pewnych operacji, takich samych dla wszystkich obiektów typu int). Inaczej mówiąc klasa jest nowym typem danych, zdefiniowanym przez użytkownika. Tak więc jedna klasa definiuje zbiór cech, które może posiadać całkiem spora liczba obiektów.

GóraDółPoprzednia sekcjaNastępna sekcjaSzukaj w FAQ ]


[7.3] Kiedy interfejs jest "dobrym interfejsem"?

Wtedy gdy daje prosty i wygodny dostęp do fragmentu programu i jest wyrażony w słownictwie znanym użytkownikowi (gdzie "fragment programu" zwykle oznacza klasę lub wąską grupę klas, a "użytkownik interfejsu" to programista korzystający z niego, a nie końcowy odbiorca programu).

GóraDółPoprzednia sekcjaNastępna sekcjaSzukaj w FAQ ]


[7.4] Co to jest enkapsulacja?

Enkapsulacja polega na ograniczaniu dostępu do pewnego fragmentu danych lub pewnych funkcji.

Nieraz bardzo ważne jest, aby oddzielić "wrażliwą" część programu od części stabilnej. Enkapsulacja zabezpiecza "wrażliwą" część przed dostępem do niej z innych fragmentów programu. Tylko stabilne części są ogólnodostępne. Zabezpiecza to program przed błędami wynikającymi z ingerencji we "wrażliwe" części programu. W kontekście programowania obiektowego "część programu" oznacza klasę lub wąską grupę klas.

"Wrażliwe" fragmenty programu stanowią szczegóły związane z konkretną implementacją [np. sposób dostępu do urządzeń, zależny od systemu operacyjnego - przyp. tłum.]. Jeżeli mamy do czynienia z pojedynczą klasą, enkapsulację można zastosować przy użyciu słów kluczowych private i/lub protected. Z kolei jeśli "wrażliwą" część programu stanowi grupa klas, enkapsulacja może polegać na ograniczeniu dostępu do całych klas. Dziedziczenie również może zostać użyte jako forma enkapsulacji.

"Stabilne" fragmenty programu dostępne są poprzez interfejsy klas. Dobry interfejs pozwala użytkownikowi na łatwą i wygodną obsługę przy użyciu znanego mu słownictwa, i jest zaprojektowany "od zewnątrz" (słowo "użytkownik" oznacza tu innego programistę - użytkownika klasy - nie końcowego użytkownika, który kupuje gotową aplikację). Jeżeli fragment programu stanowi pojedyncza klasa to interfejsem jest "publiczna" zawartość klasy oraz "zaprzyjaźnione" z nią funkcje. Z kolei jeśli fragment programu oznacza grupę klas, interfejs może zawierać kilka klas pochodzących z tej grupy.

Zaprojektowanie prostego interfejsu i oddzielenie go od szczegółów związanych z implementacją jedynie daje możliwość użytkownikom na korzystanie z niego. Natomiast enkapsulacja (umieszczanie "w kapsułce") implementacji wymusza na użytkownikach używanie interfejsu.

GóraDółPoprzednia sekcjaNastępna sekcjaSzukaj w FAQ ]


[7.5] W jaki sposób C++ pomaga w uzyskaniu kompromisu pomiędzy bezpieczeństwem a wygodą w użyciu?

[Przypis tłumacza: drugi akapit postanowiłem nieco rozszerzyć, gdyż nie potrafiłem go przetłumaczyć do tak zwięzłej postaci, w jakiej występował w angielskim oryginale - mam nadzieję, że nie ucierpi na tym ani czytelność ani Czytelnik :-]

W języku C enkapsulację osiągało się przez definiowanie zmiennych i funkcji jako statyczne (ze słowem kluczowym static) w obrębie danego modułu. Uniemożliwiało to dostęp do tych składowych z pozostałych modułów. (Swoją drogą, odradza się stosowanie tej metody w języku C++)

W ten sposób część danych w module jest dostępna publicznie (wszystkie dane i funkcje bez słowa static) zaś część jest "prywatna" (ze słowem static). Niestety, moduły (jako osobne pliki) w języku C nie pozwalają w łatwy sposób na stworzenie na ich podstawie kilku obiektów, w których obowiązywałyby te same zasady enkapsulacji (tak by odpowiednie zmienne i funkcje były publiczne, pozostałe prywatne). Moduły w języku C (w odróżnieniu od klas w C++) nie są traktowane jako "wzorce" do tworzenia nowych obiektów, lecz same w sobie są tak jakby osobnymi obiektami. Programiści, aby móc tworzyć wiele obiektów na podstawie pewnego "wzorca", najczęściej po prostu definiowali strukturę (słowo kluczowe struct). Niestety, struktury w języku C nie pozwalają na stosowanie enkapsulacji (nie można ukryć części danych jako "prywatne"). Uwidacznia się tu konflikt pomiędzy dążeniem do zapewnienia bezpieczeństwa w trakcie rozwijania programu (enkapsulacja) a prostotą w użyciu (możliwość tworzenia wielu obiektów na podstawie "wzorca"/typu danych).

Programista w C++ ma do dyspozycji zarówno możliwość dokonywania enkapsulacji jak i definiowania wielu obiektów tego samego typu - dzięki klasom. "Publiczna" część klasy zawiera jej interfejs, na który przeważnie składają się "publiczne" metody [funkcje zawarte wewnątrz klasy - przyp. tłum.] oraz funkcje "zaprzyjaźnione". "Prywatne" i "chronione" składowe klasy stanowią jej implementację - to tam zazwyczaj zawarte są "właściwe dane" klasy.

Klasy w C++ - jako wynik tych wszystkich rozszerzeń - można określić mianem "struktury z wbudowaną możliwością enkapsulacji". Dzięki temu kompromis pomiędzy bezpieczeństwem (enkapsulacja) a łatwością użycia (możliwość tworzenia wielu obiektów tej samej klasy) jest znacznie prostszy do uzyskania.

GóraDółPoprzednia sekcjaNastępna sekcjaSzukaj w FAQ ]


[7.6] W jaki sposób mogę uniemożliwić innym programistom podglądanie "prywatnych" fragmentów mojej klasy? UPDATED!

[Recently Wesja polska - poprawiono treść drugiego akapitu, poprzednia odbiegała od oryginału (in 9/02). Click here to go to the next FAQ in the "chain" of recent changes.]

Nie warto się nawet wysilać - enkapsulacja dotyczy kodu, nie ludzi.

Możliwość podejrzenia "prywatnych" i "chronionych" fragmentów klasy przez programistę nie stanowi naruszenia enkapsulacji dopóty, dopóki tenże programista nie napisze kodu, który w jakiś sposób polega na ukrytej zawartości klasy. Inaczej mówiąc, enkapsulacja nie zabrania ludziom poznania wnętrza klasy, tylko zabezpiecza kod przed zależnością od ukrytych fragmentów klasy. Firma w której pracujesz nie musi ponosić kosztów utrzymania szarej materii znajdującej się między Twoimi uszami; musi jednak opłacać koszty utrzymania kodu który wychodzi spod Twoich palców. Twoja wiedza i doświadczenie nie zwiększą kosztów utrzymania, pod warunkiem że kod który piszesz zależy głównie od interfejsu klasy a nie od jej implementacji.

Zresztą, to rzadko kiedy stanowi problem. Nie znam żadnego programisty, który kiedykolwiek potrzebowałby uzyskać dostęp do "ukrytych" fragmentów klasy. "W takich przypadkach proponowałbym zmienić programistę, nie kod" [James Kanze; zacytowano za zgodą].

GóraDółPoprzednia sekcjaNastępna sekcjaSzukaj w FAQ ]


[7.7] Czy enkapsulacja chroni jakoś program w systemie operacyjnym przed innymi?

Nie.

Enkapsulacja != ochrona.

Enkapsulacja zabezpiecza przed pomyłkami, nie przed szpiegostwem.

GóraDółPoprzednia sekcjaNastępna sekcjaSzukaj w FAQ ]


[7.8] Jaka jest różnica między słowami kluczowymi struct i class?

Domyślnie zawartość "struktury" jest "publiczna", natomiast zawartość "klasy" jest "prywatna". Uwaga: powinno się raczej wyraźnie deklarować zawartość klasy jako "publiczna", "prywatna" lub "chroniona" niż polegać na domyślnym stopniu ukrycia.

Poza tym "struktura" i "klasa" są funkcjonalnie identyczne.

OK, dosyć już tej technicznej gadaniny. Wielu programistów wyraźnie rozróżnia między "klasą" a "strukturą". "Struktura" jest jak sterta bitów nie poddana wogóle (lub w niewielkim stopniu) enkapsulacji i powiązaniu z funkcjami. "Klasa" natomiast jest jak żywy i odpowiedzialny członek społeczeństwa, świadczący reszcie pewne usługi, otoczony barierą enkapsulacji i oferujący dobrze zaprojektowany interfejs. Ponieważ jest to dość powszechnie występująca konotacja, powinieneś (powinnaś) używać słowa kluczowego struct raczej tylko wtedy, gdy potrzebujesz klasy dysponującej niewielką ilością metod - w przeciwnym wypadku użyj słowa class.

GóraDółPoprzednia sekcjaNastępna sekcjaSzukaj w FAQ ]


E-Mail E-mail the author
C++ FAQ LiteSpis treściSkorowidzO autorze©Pobierz swoją własną kopię ]
Ostatnia aktualizacja Jun 17, 2002
Wersja polska: 0.1i Jul 12, 2004