Opracował: mgr inŝ. Zbigniew JANIK Strona 1/8 Temat: Podstawy języka Object Pascal Zakres tematyki: Zasięg deklaracji Moduły Schematyczna postać modułu Object Pascala Programowanie zorientowane obiektowo (OOP) Klasy Typy metod Zasięg deklaracji Zasięg deklaracji jest pojęciem związanym z obowiązywaniem poszczególnych deklaracji w poszczególnych fragmentach programu. I tak, zmienne globalne, deklarowane w programie głównym ( projekcie ) widoczne są w całym programie, podczas gdy zmienne lokalne w procedurze nie są widoczne na zewnątrz niej. Oto prosty przykład: Na uwagę zasługuje tutaj zmienna o identyfikatorze R: wewnątrz procedury oznacza ona jej zmienną lokalną, na zewnątrz zaś zmienną globalną; ta ostatnia jest w ogóle niedostępna w treści procedury, gdyŝ jest przesłonięta (tak to się formalnie nazywa) przez inną zmienną o tym samym identyfikatorze.
Opracował: mgr inŝ. Zbigniew JANIK Strona 2/8 Moduły Moduły (ang. units) stanowią podstawowe jednostki programu, grupujące deklaracje oraz procedury i funkcje, osiągalne z programu głównego, a takŝe nawzajem pomiędzy modułami. KaŜdy moduł składa się, obowiązkowo z następujących elementów: Dyrektywy UNIT, Części publicznej, Części prywatnej, ponadto, w module mogą opcjonalnie wystąpić następujące elementy: Część inicjacyjna, Część kończąca. Schematyczna postać modułu Object Pascala Unit nazwa_modułu; // nagłówek modułu Interface // nagłówek części publicznej Uses Nazwa_modułu_1,..., nazwa_modułu_n; Const Nazwa_zmiennej = wyraŝenie; Type Nazwa_typu = definicja_typu; Var Nazwa_zmiennej : określenie_typu; { w części publicznej znajdują się jedynie nagłówki procedur i funkcji. } procedure proc1; function func1: nazwa_typu; implementation // nagłówek części prywatnej Uses Nazwa_modułu_1,..., nazwa_modułu_n; Const Nazwa_zmiennej = wyraŝenie; Type Nazwa_typu = definicja_typu; Var Nazwa_zmiennej : określenie_typu; procedure proc1; blok procedury; function func1: nazwa_typu; blok funkcji; initialization // nagłówek sekcji inicjacyjnej instrukcje; sekcja nieobowiązkowa { powyŝsze instrukcje wykonywane są jednokrotnie, przed rozpoczęciem programu głównego. } finalization sekcja nieobowiązkowa
Opracował: mgr inŝ. Zbigniew JANIK Strona 3/8 instrukcje; { powyŝsze instrukcje wykonywane są jednokrotnie, przed rozpoczęciem programu głównego. } end. // znacznik końca modułu Dyrektywa UNIT Stanowi ona pierwszą linię modułu i zawiera jego nazwę poprzedzoną słowem UNIT. Nazwa musi być toŝsama z nazwą pliku, w którym się on znajduje. Np: moduł o nazwie MIASTA misi znajdować się w pliku MIASTA.PAS. Część publiczna interface Część publiczna modułu, rozpoczyna się słowem kluczowym interface. Zawiera definicje tych stałych, typów i zmiennych oraz nagłówki tych procedur i funkcji, które jako globalne obowiązywać mają w całym module oraz mają być dostępne dla innych modułów, w szczególności dla programu głównego. W odniesieniu do procedur i funkcji, część publiczna zawiera jedynie ich nagłówki (zapowiedzi), gdyŝ tylko one istotne są dla reszty programu. Szczegółowe definicje (procedur i funkcji znajdują się w części prywatnej modułu. JeŜeli część publiczna modułu odwołuje się do innych modułów, lista tych ostatnich powinna znaleźć się w dyrektywie uses, występującej bezpośrednio po słowie interface. Ogranicznikiem części publicznej modułu jest słowo kluczowe implementation, rozpoczynające część prywatną. Część prywatna implementation Ta część modułu, niewidoczna dla pozostałych modułów, rozpoczyna się od słowa kluczowego implementation i zawiera definicje tych elementów modułu, które mają dla niego znaczenie lokalne. Znajdują się tutaj m.in. kompletne definicje procedur i funkcji, których nagłówki występują w części publicznej. Stałe, typy, zmienne i etykiety deklarowane poza blokami procedur i funkcji dostępne są dla całej części prywatnej modułu mają w niej obrębie znaczenie globalne. Wszystkie moduły, do których odwołuje się część prywatna modułu, powinny wystąpić na liście dyrektywy uses znajdującej się bezpośrednio po słowie kluczowym implementation. Kolejność definiowania poszczególnych elementów części prywatnej zaleŝy wyłącznie od jej specyfiki; w szczególności procedury i funkcje anonsowane w części publicznej mogą być definiowane w dowolnej kolejności. Ogranicznikiem części prywatnej jest jedna z dyrektyw initialization, finalization lub end. (z kropką). Część inicjacyjna initialization Jest to nieobowiązkowa część modułu. Rozpoczyna się od dyrektywy initialization, a kończy dyrektywą end. kończącą równocześnie cały moduł, bądź teŝ słowem finalization. Zawarte w niej instrukcje wykonywane są jednokrotnie, przed rozpoczęciem programu głównego. Kolejność wykonywania części inicjacyjnych poszczególnych modułów zaleŝy od ich wzajemnej zaleŝności wynikającej z zawartości dyrektyw uses w częściach publicznych.
Opracował: mgr inŝ. Zbigniew JANIK Strona 4/8 Część kończąca finalization Ta sekcja modułu równieŝ jest nieobowiązkowa, wystąpić moŝe jednak tylko z sekcją inicjacyjną części modułu. Rozpoczyna się od dyrektywy finalization i kończy dyrektywą end. kończącą zarazem cały moduł. Zawarte w niej instrukcje wykonywane są jednokrotnie, po zakończeniu pracy programu głównego, a ich celem jest z reguły zwolnienie zasobów, zamknięcie plików i wykonanie ew. innych czynności kończących pracę modułu. Kolejność wykonywania części kończących poszczególnych modułów jest odwrotna do kolejności wykonywania części inicjacyjnych. JeŜeli część inicjacyjna danego modułu nie zostanie rozpoczęta na skutek przedwczesnego zakończenia programu, nie zostanie równieŝ wykonana jego część kończąca. Programowanie zorientowane obiektowo Programowanie zorientowane obiektowo (ang. OOP Object Oriented Programming) zyskało sobie w ostatnim dziesięcioleciu rangę niemal kultową. Nic w tym dziwnego po językach algorytmicznych, a następnie programowaniu strukturalnym jest to następna idea, której skutki w rewolucjonizowaniu procesu projektowania oraz programowania są widoczne aŝ nazbyt dobrze. Kiedy Niklas Wirth ponad 20 lat temu przedstawił projekt języka programowania o nazwie Pascal, uderzająca okazała się elegancja i oszczędność zastosowanych środków językowych. Starannie dobrane elementy składniowe, niewielki zasób słów kluczowych, operatorów i standardowych identyfikatorów to wszystko z jednej strony wymuszało pewną dyscyplinę i elegancję programowania, z drugiej stanowiło ograniczenie na rozwiązanie tego samego na przysłowiowy tysiąc sposobów. Nie zabrakło oczywiście i dzisiaj nie brakuje krytyków języka Pascal, piętnujących w nim brak wielu konstrukcji i mechanizmów, obecnych w innych językach. Nie sposób jednak przecenić w informatyce idei programowania strukturalnego, której Pascal był pierwszym uosobieniem: dwa podstawowe elementy programu kod i dane rozpatrywane są jako byty o określonej strukturze, przy wielorakich wzajemnych analogiach. Kiedy prześledzić ponad dwudziestoletnią ewolucję Pascala nie sposób oprzeć się wraŝeniu, Ŝe z pierwotnej postaci, stanowiącej dzisiaj przede wszystkim akademicki wzór elegancji, język ten stał się juŝ dzisiaj szeroko zaakceptowanym, pełnoprawnym narzędziem do tworzenia profesjonalnych aplikacji ogromny sukces najpierw Turbo Pascala, a obecnie Delphi jest tego wyraźnym potwierdzeniem. Kluczowe znaczenie ma tutaj fakt, iŝ wszelkie uŝyteczne rozszerzenia jeŝyka nie zachwiały jak dotąd tym, co stanowiło od początku fundament języka mianowicie jego prostotą i elegancją. Pewnym niedostatkiem idei programowania strukturalnego jest traktowanie kodu i danych programu w swoiście globalny sposób: przy szczegółowym podejściu strukturalnym do obydwu tych aspektów programu, programowanie strukturalne nie przywiązuje zbyt duŝej uwagi do ich wzajemnej współpracy. Zmianę w tym względzie przyniosła dopiero kolejna rewolucyjna idea programowania obiektowego. Zgodnie z nią program jawi się jako współistnienie obiektów, z których kaŝdy stanowi ściśle dobrany zestaw współpracujących ze sobą danych i kodu. Stanowiąc zamkniętą, funkcjonalną całość, obiekty równieŝ mogą stanowić poziom wymiany rozwiązań między aplikacjami: najbardziej koronnym tego przykładem są komponenty Delphi.
Opracował: mgr inŝ. Zbigniew JANIK Strona 5/8 Będąc świadomym ogromnej wiedzy między Object Pascalem a jego pierwowzorem sprzed ponad 20 lat, trudno po raz kolejny oprzeć się wraŝeniu, Ŝe Pascal nie przestał być Pascalem. Klasyczna, modularna forma wymiany informacji bynajmniej jednak z Object Pascala nie zniknęła. Lazarus zawiera szereg modułów, noszących wspólną nazwę biblioteki uruchomieniowej (ang. RTL Runtime Library), zawierających szereg uŝytecznych podprogramów obejmujących róŝnorodne aspekty programowania. Filozofię obiektów określają cztery fundamentalne pojęcia: Dziedziczenie Polimorfizm Enkapsulacja Obiektowość jako pierwotna metoda programowania Dziedziczenie. Tworząc złoŝone aplikacje, nie sposób zauwaŝyć podobieństw między poszczególnymi fragmentami danych i kodu. Stąd pomoc, aby przy definiowaniu nowych typów obiektowych nie zaczynać pracy od początku, lecz wykorzystać cechy obiektów juŝ istniejących. Na bazie istniejących typów musi dać się tworzyć nowe typy; musi się to odbywać na drodze dziedziczenia atrybutów i metod. Polimorfizm oznacza dosłownie występowanie w wielu postaciach. W programowaniu obiektowym termin ten określa zdolność róŝnych obiektów do odpowiadania na ten sam komunikat w róŝny sposób. Domyślnie metody w Delphi są statyczne. Oznacza to, Ŝe odwołanie do danej metody jest równoznaczne z wywołaniem ściśle określonej procedury. Polimorfizm umoŝliwia dynamiczne wywiązanie metod z procedurami w trakcie wykonywania programu. Ta sama metoda moŝe być dowiązana do róŝnych procedur, zaleŝnie od obiektu. Enkapsulacja polega z ścisłym powiązaniu kodu oraz danych słuŝących temu samemu celowi, poprzez zamknięcie ich w ramach jednego bytu typu obiektowego. Inaczej mówiąc; dane i kod programu powinno się umieszczać w pojedynczych obiektach. Obiekt musi zatem zawierać elementy danych (podobnie jak rekord) i procedury (zwane metodami). Procedury zawarte w obiekcie muszą mieć automatycznie zapewniony dostęp do danych obiektu. Obiektowość jako pierwotna metoda programowania Mechanizmy programowania obiektowego powinny być dla danego narzędzia pierwotną metodą tworzenia programu. Nie mogą być uzupełnieniem, dodanym z czasem do istniejącego juŝ produktu. Będąc podstawową metodą tworzenia kodu mechanizmy programowania obiektowego powinny zapewniać wydajność wystarczającą w praktycznych zastosowaniach; w przeciwnym razie naleŝy poddać w wątpliwość jakość narzędzia, którego pierwotna i podstawowa metoda tworzenia programu nie oferuje niezbędnej wydajności.
Opracował: mgr inŝ. Zbigniew JANIK Strona 6/8 Klasy Podstawowym elementem Object Pascala jest typ obiektowy, nazywany obecnie klasą (ang. classes). Konkretny egzemplarz klasy nosi nazwę obiektu (ang. object). Podstawowymi trzema elementami, z których składa się klasa w Object Pascalu są: Pola (ang. Fields) stanowi daną składową obiektu, na wzór pola rekordu z tą róŝnicą, Ŝe klasa nie moŝe zawierać części wariantowej; Metody (ang. Methods) procedury i funkcje słuŝące do wykonania operacji na polach klasy; Właściwości (ang. Properties) wykorzystywane jak pola, lecz zrealizowane w oparciu o metody. Stanowi połączenie koncepcji pola i metody i określa sposób dostępu do pól metod obiektu. Operowanie właściwościami w miejsce operowania polami i metodami pozwala uniezaleŝnić sposób korzystania z obiektu od jego szczegółów implementacyjnych. Ponadto, w przeciwieństwie do tradycyjnych typów języka, klasa moŝe być definiowana wyłącznie na poziomie globalnym modułu lub programu (nie wewnątrz procedury czy funkcji). Nie jest takŝe moŝliwe zdefiniowanie klasy przy okazji deklarowania zmiennej w dyrektywie var klasa musi być zdefiniowana jawnie jako typ. PoniŜej przedstawiono typową postać modułu ze zdefiniowaną klasą TForm1. pole unit Unit1; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs; type Klasa przodka TForm1 = class(tform) Button1: TButton; Label1: TLabel; metoda MainMenu1: TMainMenu; procedure Button1Click(Sender: TObject); private { Private declarations } sum : integer; function Suma(var X:wektor):integer; public { Public declarations } end; var Form1: TForm1; implementation Definicja klasy rozpoczyna się do słowa kluczowego class, po którym wymienione są poszczególne jej elementy (ang. members). Podstawowym mechanizmem związanym z programowaniem obiektowym jest zjawisko dziedziczenia. Polega ono na tym, Ŝe obiekt pochodny dziedziczy po swym obiekcie bazowym wszystkie jego elementy pola metody i właściwości, nie ma zatem potrzeby
Opracował: mgr inŝ. Zbigniew JANIK Strona 7/8 ponownego ich definiowania. Nie ma natomiast moŝliwości wyeliminowania któregokolwiek z elementów klasy bazowej. Definicja klasy zazwyczaj zawarta jest w module Object Pascala: definicje pól, właściwości i nagłówki metod, składające się na definicję klasy umieszczane są z reguły w części publicznej modułu, natomiast kompletne definicje metod znajdują się w części prywatnej. W przeciwieństwie do tradycyjnych typów języka moŝliwe jest dodatkowe określenie stopnia globalności elementów klasy za pomocą dyrektyw private, protected (wym: protektyd), public i published. Wszystkie elementy klasy widoczne są bez ograniczenia w module, w którym klasa została zdefiniowana. Znaczenie powyŝszych dyrektyw jest następujące: Private dyrektywa ta powoduje najwyŝszy stopień ograniczenia globalności: elementy klasy znajdujące się w zasięgu tej dyrektywy widoczne są jedynie w ramach modułu, w którym klasa została zdefiniowana i kompletnie nie widoczne dla innych modułów. Protected elementy znajdujące się w zakresie tej dyrektywy ( chronione ) dostępne są w innych modułach jedynie dla potrzeb definiowania klas pochodnych i mogą wystąpić jedynie w ramach definicji metod i właściwości tych ostatnich. Pod kaŝdym innym względem elementy te traktowane są tak, jak elementy prywatne. UmoŜliwia to definiowanie klasy pochodnej w module innym niŝ ten, w którym zdefiniowano klasę bazową. Public ta dyrektywa oznacz brak ograniczeń na globalność elementów znajdujących się w jej zakresie. Published umieszczenie elementów klasy w zasięgu tej dyrektywy powoduje umieszczenie informacji o nich w ramach specjalnej struktury zawierającej informacje i klasie i dostępnej w czasie wykonania programu, same zaś elementy nazywane są opublikowanymi. Wszystkie właściwości i zdarzenia widoczne w zakresie Inspektora Obiektu naleŝą do elementów tej kategorii. Z dyrektywą published wiąŝą się pewne ograniczenia. (Patrz literatura.) Te elementy, które nie znajdują się w zasięgu Ŝadnej z w/w dyrektyw, traktowane są tak, jak elementy opublikowane (published). Są one jednak traktowane przez Delphi w specyficzny sposób, dlatego teŝ wskazane jest zawsze jawne deklarowanie widoczności elementów klasy. Typy metod W Object Pascalu istnieją cztery typy metod obiektowych o statyczne o wirtualne o dynamiczne o zarządzające komunikatami A oto przykład zebrania metod wszystkich czterech kategorii w ramach jednego typu: TOop = class procedure Statyczna; procedure Wirtualna; virtual; procedure Dynamiczna; dynamic; procedure Komunikacyjna(var Z: TMessage); message wm_somemessage; end;
Opracował: mgr inŝ. Zbigniew JANIK Strona 8/8 Metody statyczne Jest to domyślna postać metody obiektowej. Jej adres znany jest juŝ w czasie kompilacji, a jej wykonanie bardzo efektywne. Procedura statyczna nie daje jednak moŝliwości wykorzystania polimorfizmu. Metody wirtualne Zjawisko dziedziczenia wiąŝe się z moŝliwością predefiniowania (ang. Overriding) metod obiektu. Oznacza to, Ŝe metoda o danej nazwie moŝe mieć zupełnie róŝne działanie dla typu macierzystego i typu pochodnego. Innymi słowy, kompilator, znając nazwę metody nie potrafi określić jej konkretnego adresu, nie znając konkretnego egzemplarza (a właściwie jego typu) na rzecz którego jest ona aktywowana. Zjawisko róŝnego zachowania metod o tej samej nazwie dla róŝnych typów w całym poddrzewie typów pochodnych nosi nazwę polimorfizmu metoda o danej nazwie ma jak gdyby wiele twarzy. Do realizacji polimorfizmu Object Pascal utrzymuje struktury zwane tablicami VMT (ang. Virtual Metod Tables), po jednej dla kaŝdego typu. PoniewaŜ dla kaŝdego typu tablica VMT zawiera adresy wszystkich metod, niezaleŝnie od tego czy metody są przedefiniowane w stosunku do typu macierzystego, metody wirtualne powodują pewien stopień obciąŝalności pamięci, lecz za to są stosunkowo szybkie. Metody dynamiczne Koncepcyjnie metody dynamiczne nie róŝnią się od metod wirtualnych, są jednak w mniejszym stopniu pamięciochłonne. Dla kaŝdego typu posiadającego metody dynamiczne kompilator utrzymuje strukturę zwaną tablicą DMT (ang. Dynamic Metod Table); tablica ta nie zawiera jednak adresów wszystkich metod typu, lecz tylko tych, które w stosunku do typu macierzystego zostały predefiniowane. Skutkuje to mniejszym obciąŝeniem pamięci, lecz znacznie mniej efektywnym wykonaniem, gdyŝ proces poszukiwania właściwego adresu jest bardziej złoŝony niŝ w przypadku tablic VMT. Metody zarządzające komunikatami Metody tej kategorii stanowią ukłon w stronę klasycznego programowania w Windows i słuŝą do niskopoziomowego zarządzania wybranymi kategoriami komunikatów (ang. messages).