Na język C++ składa się wiele drobnych rozszerzeń klasycznego C oraz jeden ważny dodatek: klasy. W tym, ostatnim już, odcinku podstaw C++ zajmiemy się podstawami programowania obiektowego. Najprostsze wyjaśnienie (nie oddające głębi problemu), czym są klasy, brzmi mniej więcej tak: klasa to struktura uzupełniona o funkcje (nazywane funkcjami składowymi albo - z angielskiego - metodami klasy). Posłużymy tu się prostym przykładem: sięgniemy do wiedzy wyniesionej ze szkoły i utworzymy klasę o nazwie "wektor". Do jednoznacznego opisania wektora w układzie współrzędnych potrzebujemy czterech liczb (rzeczywistych): współrzędne x i y początku oraz końca wektora. Odpowiednia struktura danych mogłaby wyglądać tak: struct wektor { double xp, yp; double xk, yk; }; Pamiętamy, że odwołanie do wnętrza struktury odbywa się przy użyciu ".". Chcielibyśmy też wykonywać na strukturze jakieś sensowne działanie, np. dodawanie wektorów. I tu zaczynamy myśleć o wektorze jako obiekcie, który "modelujemy" w języku C++ - zawieramy w modelu (czyli klasie) pewne dane, którymi w określony sposób manipulujemy. A oto prosta definicja klasy "wektor": class wektor { private: double xp, yp; double xk, yk; public: void Dodaj(wektor w1, wektor w2); void Wypisz(void); }; Widzimy, że klasa została podzielona na część prywatną (zaczynającą się słówkiem "private:") i publicznie dostępną ("public:"). Otóż część prywatna (w której mogą znajdować się zarówno zmienne, jak i funkcje składowe; w naszym przykładzie są tam tylko zmienne) jest dostępna tylko i wyłącznie z wewnątrz klasy i można z nich korzystać, np. w funkcjach składowych należących do tej samej klasy. Część publiczna nie ma już takich ograniczeń i można z niej korzystać do woli. To trochę niejasne wytłumaczenie najlepiej obrazuje dalsza część przykładu: class wektor { ... // jak wyżej }; void wektor::Wypisz(void) { // w tym miejscu wolno // nam korzystać z danych //z części "private:" cout << "xp = " >> xp << endl << "yp = " << yp << endl << "xk = " << xk << endl << "yk = " << yk << endl; } void main(void) { wektor wekt1; wekt1.Wypisz(); //Wypisz() jest w części //"public:", więc można używać wekt1.xp = 3.55; //Błąd! "xp" jest składnikiem //prywatnym! } Ale, ale... Jak dotąd możemy wypisać na ekranie współrzędne wektora, lecz w żaden sposób nie mamy wpływu na to, jakie wartości mają te współrzędne. Musimy wstawić do klasy (oczywiście po słówku "public:") jeszcze jedną funkcję: void Ustaw(double _xp, double _yp, double _xk, double _yk) { xp = _xp; yp = _yp; xk = _xk; yk = _yk; } Teraz inicjalizację wektora robimy tak: wektor wekt1; wekt1.Ustaw(0, 1, 5.3, 8.1);
Oczywiście gdybyśmy nasze zmienne oznaczające współrzędne wektora umieścili w części publicznej klasy, wtedy nie zachodziłaby potrzeba pisania funkcji "Ustaw" - do współrzędnych moglibyśmy zaglądać bezpośrednio, pisząc w kodzie programu np. "cout << wekt1.xp;". Nasz prosty przykład obrazuje tzw. enkapsulację danych. Często tak bywa, że z klasy napisanej przez jednego programistę korzystają inni programiści na całym świecie. Tak było i w naszym przypadku, gdy zajmowaliśmy się operacjami dyskowymi w jednym z poprzednich odcinków - użyliśmy wtedy obiektów stworzonych z klas "ifstream", "ofstream" i "fstream". Podczas pisania programu widzieliśmy jedynie publiczną część tych klas, czyli np. funkcje "open", "close", "read" itp., natomiast wszystkie wewnętrzne szczegóły (jak bufory, konwersje danych) zostały przed nami ukryte. void wektor::Dodaj(wektor w1, wektor w2) { xp = w1.xp; yp = w1.yp; xk = w1.xk + w2.xk - w2.xp; yk = w1.yk + w2.yk - w2.yp; } Jak widzimy, napisaliśmy jedynie kod dodający wektory w1 i w2. Teraz w głównym programie możemy utworzyć dowolną liczbę obiektów typu "wektor" (np. dużą tablicę) i wykonywać na nich działania: wektor v1, v2, v3; v1.Ustaw(0, 1, 5.3, 8.1); v2.Ustaw(3, -1.1, 3, -0.5); //v3 = v1 + v2: v3.Dodaj(v1, v2); v3.Wypisz();
Niestety, w naszym krótkim wprowadzeniu do programowania obiektowego pominęliśmy wiele bardzo ważnych informacji, jak chociażby ta, czym są i do czego służą konstruktory i destruktory; czym jest przeładowanie operatorów itd. Tak się składa, że tematu klas i programowania obiektowego nie wyczerpują nawet 600-stronicowe książki, tym bardziej nie uda się to w czasopiśmie (chyba że w 100 odcinkach, na co sobie nie możemy pozwolić). wektor wekt1; wektor *wsk_wekt; wsk_wekt = &wekt1; wekt1.Wypisz(); //dobrze wsk_wekt.Wypisz(); //źle! wsk_wekt->Wypisz(); //dobrze wekt1->Wypisz(); //źle! Zastosowanie "." zamiast "-< " w przypadku pracy ze wskaźnikiem na obiekt, to jeden z najczęściej popełnianych błędów.
Otwórzcie okna
Button1-<Enable = false;
Na podstawie powyższego zapisu od razu domyślamy się, że "Button1" jest wskaźnikiem do obiektu... Nieco historii...
Dlaczego język C++ właśnie tak się nazywa? Otóż pod koniec lat 60. w laboratoriach firmy Bell Telephone powstał język programowania wysokiego poziomu (tzn. wyższego od asemblera) przeznaczony do usprawnienia tworzenia nowych programów dla opracowywanego również w tych samych laboratoriach systemu Unix. Kierujący projektem Ken Thompson opracował język nazwany przez niego po prostu B. Działał on na platformie sprzętowej PDP-7 (pamięć tego komputera to oszałamiające... 8192 słowa 18-bitowe). Niedługo póĽniej, po wprowadzeniu PDP-11 (24 kB) na scenę wkracza Dennis M. Ritchie (rok 1971), który wprowadza nieco zmian do języka B i nazywa go NB (New B - nowy B).
|
|
|
|
Copyright © 2000-2001 Bartosz 'SILV' Jaworski |
|