r06.pdf

(336 KB) Pobierz
Szablon dla tlumaczy
Rozdział 6.
Programowanie
zorientowane obiektowo
Klasy rozszerzają wbudowane w C++ możliwości, ułatwiające rozwiązywanie złożonych,
„rzeczywistych” problemów.
Z tego rozdziału dowiesz się:
czym są klasy i obiekty,
jak definiować nową klasę oraz tworzyć obiekty tej klasy,
czym są funkcje i dane składowe,
czym są konstruktory i jak z nich korzystać.
Czy C++ jest zorientowane obiektowo?
Język C++ stanowi pomost pomiędzy programowaniem zorientowanym obiektowo a językiem C,
najpopularniejszym językiem programowania aplikacji komercyjnych. Celem jego autorów było
stworzenie obiektowo zorientowanego języka dla tej szybkiej i efektywnej platformy.
Język C jest etapem pośrednim pomiędzy wysokopoziomowymi językami aplikacji „firmowych”,
takimi jak COBOL, a niskopoziomowym, wysokowydajnym, lecz trudnym do użycia asemblerem.
C wymusza programowanie „strukturalne”, w którym poszczególne zagadnienia są dzielone na
mniejsze jednostki powtarzalnych działań, zwanych funkcjami.
Programy, które piszemy na początku dwudziestego pierwszego wieku, są dużo bardziej złożone
niż te, które były pisane pod koniec wieku dwudziestego. Programy stworzone w językach
proceduralnych są trudne w zarządzaniu i konserwacji, a ich rozbudowa jest niemożliwa.
Graficzne interfejsy użytkownika, Internet, telefonia cyfrowa i bezprzewodowa oraz wiele innych
technologii, znacznie zwiększyły poziom skomplikowania nowych projektów, a wymagania
konsumentów dotyczące jakości interfejsu użytkownika wzrosły.
W obliczu rosnących wymagań, programiści bacznie przyjrzeli się przemysłowi informatycznemu.
Wnioski, do jakich doszli, były co najmniej przygnębiające. Oprogramowanie powstawało z
opóźnieniem, posiadało błędy, działało niestabilnie i było drogie. Projekty regularnie przekraczały
budżet i trafiały na rynek z opóźnieniem. Koszt obsługi tych projektów był znaczny, zmarnowano
ogromne ilości pieniędzy.
Jedynym wyjściem z tej sytuacji okazało się tworzenie oprogramowania zorientowanego
obiektowo. Języki programowania obiektowego stworzyły silne więzy pomiędzy strukturami
danych a metodami manipulowania tymi danymi. A co najważniejsze, w programowaniu
zorientowanym obiektowo nie już musisz myśleć o strukturach danych i manipulujących nimi
funkcjami; myślisz o obiektach. Rzeczach.
Świat jest wypełniony przedmiotami: samochodami, psami, drzewami, chmurami, kwiatami.
Rzeczy. Każda rzecz ma charakterystykę (szybki, przyjazny, brązowy, puszysty, ładny).
Większość rzeczy cechuje jakieś zachowanie (ruch, szczekanie, wzrost, deszcz, uwiąd). Nie
myślimy o danych psa i o tym, jak moglibyśmy nimi manipulować — myślimy o psie jako o
rzeczy: do czego jest podobny i co robi.
Tworzenie nowych typów
Poznałeś już kilka typów zmiennych, m.in. liczby całkowite i znaki. Typ zmiennej dostarcza nam
kilka informacji o niej. Na przykład, jeśli zadeklarujesz zmienne Height (wysokość) i Width
(szerokość) jako liczby całkowite typu unsigned short int , wiesz, że w każdej z nich możesz
przechować wartość z przedziału od 0 do 65 535 (przy założeniu że typ unsigned short int
zajmuje dwa bajty pamięci). Są to liczby całkowite bez znaku; próba przechowania w nich
czegokolwiek innego powoduje błąd. W zmiennej typu unsigned short nie możesz umieścić
swojego imienia, nie powinieneś nawet próbować.
Deklarując te zmienne jako unsigned short int , wiesz, że możesz dodać do siebie wysokość i
szerokość oraz przypisać tę wartość innej zmiennej.
Typ zmiennych informuje:
o ich rozmiarze w pamięci,
jaki rodzaj informacji mogą zawierać,
jakie działania można na nich wykonywać.
W tradycyjnych językach, takich jak C, typy były wbudowane w język. W C++ programista może
rozszerzyć język, tworząc potrzebne mu typy, zaś każdy z tych nowych typów może być w pełni
funkcjonalny i dysponować tą samą siłą, co typy wbudowane.
Po co tworzyć nowy typ?
Programy są zwykle pisane w celu rozwiązania jakiegoś realnego problemu, takiego jak
prowadzenie rejestru pracowników czy symulacja działania systemu grzewczego. Choć istnieje
możliwość rozwiązywania tych problemów za pomocą programów napisanych wyłącznie przy
użyciu liczb całkowitych i znaków, jednak w przypadku większych, bardziej rozbudowanych
problemów, dużo łatwiej jest stworzyć reprezentacje obiektów, o których się mówi. Innymi słowy,
symulowanie działania systemu grzewczego będzie łatwiejsze, gdy stworzymy zmienne
reprezentujące pomieszczenia, czujniki ciepła, termostaty i bojlery. Im bardziej te zmienne
odpowiadają rzeczywistości, tym łatwiejsze jest napisanie programu.
Klasy i składowe
Nowy typ zmiennych tworzy się, deklarując klasę. Klasa jest właściwie grupą zmiennych —
często o różnych typach — skojarzonych z zestawem odnoszących się do nich funkcji.
Jedną z możliwości myślenia o samochodzie jest potraktowanie go jako zbioru kół, drzwi, foteli,
okien, itd. Inna możliwość to wyobrażenie sobie, co samochód może zrobić: jeździć, przyspieszać,
zwalniać, zatrzymywać się, parkować, itd. Klasa umożliwia kapsułkowanie, czyli upakowanie,
tych różnych części oraz różnych działań w jeden zbiór, który jest nazywana obiektem.
Upakowanie wszystkiego, co wiesz o samochodzie, w jedną klasę przynosi programiście liczne
korzyści. Wszystko jest na miejscu, ułatwia to odwoływanie się, kopiowanie i manipulowanie
danymi. Klienty twojej klasy — tj. te części programu, które z niej korzystają — mogą używać
twojego obiektu bez zastanawiania się, co znajduje się w środku i jak on działa.
Klasa może składać się z dowolnej kombinacji zmiennych prostych oraz zmiennych innych klas.
Zmienna wewnątrz klasy jest nazywana zmienną składową lub daną składową. Klasa Car
(samochód) może posiadać składowe reprezentujące siedzenia, typ radia, opony, itd.
Zmienne składowe są zmiennymi w danej klasie. Stanowią one część klasy, tak jak koła i silnik
stanowią część samochodu.
Funkcje w danej klasie zwykle manipulują zmiennymi składowymi. Funkcje klasy nazywa się
funkcjami składowymi lub metodami klasy. Metodami klasy Car mogą być Start() (uruchom)
oraz Brake() (hamuj). Klasa Cat (kot) może posiadać zmienne składowe, reprezentujące wiek i
wagę; jej metodami mogą być Sleep() (śpij), Meow() (miaucz) czy ChaseMice() (łap myszy).
Funkcje składowe (metody) są funkcjami w klasie. Podobnie jak zmienne składowe, stanowią
część klasy i określają, co dana klasa może zrobić.
Deklarowanie klasy
Aby zadeklarować klasę, użyj słowa kluczowego class , po którym następuje otwierający nawias
klamrowy, a następnie lista danych składowych i metod tej klasy. Deklaracja kończy się
zamykającym nawiasem klamrowym i średnikiem. Oto deklaracja klasy o nazwie Cat (kot):
class Cat
{
unsigned int itsAge;
unsigned int itsWeight;
void Meow();
};
Zadeklarowanie takiej klasy nie powoduje zaalokowania pamięci dla obiektu Cat . Informuje
jedynie kompilator, czym jest typ Cat , jakie dane zawiera ( itsAge — jego wiek oraz itsWeight
— jego waga) oraz co może robić ( Meow() — miaucz). Informuje także kompilator, jak duża jest
zmienna typu Cat — to jest, jak dużo miejsca w pamięci ma przygotować w przypadku tworzenia
zmiennej typu Cat . W tym przykładzie, o ile typ int ma cztery bajty, zmienna typu Cat zajmuje
osiem bajtów: cztery bajty dla zmiennej itsAge i cztery dla zmiennej itsWeight . Funkcja
Meow() nie zajmuje miejsca, gdyż dla funkcji składowych (metod) miejsce nie jest rezerwowane.
Kilka słów o konwencji nazw
Jako programista, musisz nazwać wszystkie swoje zmienne składowe, funkcje składowe oraz
klasy. Jak przeczytałeś w rozdziale 3., „Stałe i zmienne,” nazwy te powinny być zrozumiałe i
znaczące. Dobrymi nazwami klas mogą być wspomniana Cat , Rectangle (prostokąt) czy
Employee (pracownik). Meow() , ChaseMice() czy StopEngine() (zatrzymaj silnik) również
są dobrymi nazwami funkcji, gdyż informują, co robią te funkcje. Wielu programistów nadaje
nazwom zmiennych składowych przedrostek „its” (jego), tak jak w zmiennych itsAge ,
itsWeight czy itsSpeed (jego szybkość). Pomaga to w odróżnieniu zmiennych składowych od
innych zmiennych.
Niektórzy programiści wolą przedrostek „my” (mój), tak jak w nazwach myAge , myWeight czy
mySpeed . Jeszcze inni używają po prostu litery m (od słowa member — składowa), czasem wraz
ze znakiem podkreślenia ( _ ): mAge i m_age , mWeight i m_weight czy mSpeed i m_speed .
Język C++ uwzględnia wielkość liter, dlatego wszystkie nazwy klas powinny przestrzegać tej
samej konwencji. Dzięki temu nigdy nie będziesz musiał sprawdzać pisowni nazwy klasy (czy to
było Rectangle , rectangle czy RECTANGLE ?).
Niektórzy programiści lubią poprzedzić każdą nazwę klasy określoną literą — na przykład cCat
czy cPerson — podczas, gdy inni używają wyłącznie dużych lub małych liter. Ja sam korzystam
z konwencji, w której wszystkie nazwy klas rozpoczynają się od dużej litery, tak jak Cat czy
Person (osoba).
Wielu programistów rozpoczyna wszystkie nazwy funkcji od dużej litery, zaś wszystkie nazwy
zmiennych — od małej. Słowa zwykle rozdzielane są znakiem podkreślenia — tak jak w
Chase_Mice — lub poprzez zastosowanie dużej litery dla każdego słowa — na przykład
ChaseMice czy DrawCircle (rysuj okrąg).
Ważne jest, by wybrać określony styl i trzymać się go w każdym programie. Z czasem rozwiniesz
swój styl nie tylko na konwencje nazw, ale także na wcięcia, wyrównanie nawiasów klamrowych
oraz styl komentarzy.
UWAGA W firmach programistycznych powszechne jest określenie standardu wielu elementów
stylu zapisu kodu źródłowego. Sprawia on, że wszyscy programiści mogą łatwo odczytywać
wzajemnie swój kod.
Definiowanie obiektu
Definiowanie obiektu nowego typu przypomina definiowanie zmiennej całkowitej:
unsigned int GrossWeight; // definicja zmiennej typu unsigned int
Cat Mruczek; // definicja zmiennej typu Cat
Ten kod definiuje zmienną o nazwie GrossWeight (łączna waga), której typem jest unsigned
int . Oprócz tego definiuje zmienną o nazwie Mruczek , która jest obiektem klasy (typu) Cat .
Klasy a obiekty
Nigdy nie karmi się definicji kota, lecz konkretnego kota. Należy dokonać rozróżnienia pomiędzy
ideą kota a konkretnym kotem, który właśnie ociera się o twoje nogi. C++ również dokonuje
rozróżnienia pomiędzy klasą Cat , będącą ideą kota, a poszczególnymi obiektami typu Cat . Tak
więc Mruczek jest obiektem typu Cat , tak jak GrossWeight jest zmienną typu unsigned int .
Obiekt jest indywidualnym egzemplarzem klasy.
Dostęp do składowych klasy
Gdy zdefiniujesz już faktyczny obiekt Cat — na przykład Mruczek — w celu uzyskania dostępu
do jego składowych możesz użyć operatora kropki ( . ). Aby zmiennej składowej itsWeight
obiektu Mruczek przypisać wartość 50 , powinieneś napisać:
Mruczek.itsWeight = 50;
Aby wywołać funkcję Meow() , możesz napisać:
Mruczek.Meow();
Gdy używasz metody klasy, oznacza to, że wywołujesz tę metodę. W tym przykładzie wywołałeś
metodę Meow() obiektu Mruczek .
Przypisywać należy obiektom, nie klasom
W C++ nie przypisuje się wartości typom; przypisuje się je zmiennym. Na przykład, nie można
napisać:
int = 5; // źle
Kompilator uzna to za błąd, gdyż nie można przypisać wartości pięć typowi całkowitemu. Zamiast
tego musisz zdefiniować zmienną typu całkowitego i przypisać jej wartość 5 . Na przykład:
Zgłoś jeśli naruszono regulamin