Podstawy Programowania semestr drugi. Wykład czternasty



Podobne dokumenty
Wykład 9: Polimorfizm i klasy wirtualne

DIAGRAMY SYNTAKTYCZNE JĘZYKA TURBO PASCAL 6.0

Dziedziczenie jednobazowe, poliformizm

1. Programowanie obiektowe. Wstęp.

Dziedziczenie. Tomasz Borzyszkowski

PARADYGMATY PROGRAMOWANIA Wykład 4

Typy klasowe (klasy) 1. Programowanie obiektowe. 2. Założenia paradygmatu obiektowego:

Wykład 8: klasy cz. 4

TEMAT : KLASY DZIEDZICZENIE

Języki i techniki programowania Ćwiczenia 3 Dziedziczenie

Programowanie strukturalne. Opis ogólny programu w Turbo Pascalu

Podstawy programowania 2. Przygotował: mgr inż. Tomasz Michno

Kurs programowania. Wykład 2. Wojciech Macyna. 17 marca 2016

Wykład 9: Metody wirtualne i polimorfizm

Kurs WWW. Paweł Rajba.

Programowanie obiektowe i zdarzeniowe

Informatyka I. Dziedziczenie. Nadpisanie metod. Klasy abstrakcyjne. Wskaźnik this. Metody i pola statyczne. dr inż. Andrzej Czerepicki

Dziedziczenie jednobazowe, poliformizm, tablice wskaźników na obiekty

Podczas dziedziczenia obiekt klasy pochodnej może być wskazywany przez wskaźnik typu klasy bazowej.

Dziedziczenie. Streszczenie Celem wykładu jest omówienie tematyki dziedziczenia klas. Czas wykładu 45 minut.

Programowanie współbieżne Wykład 8 Podstawy programowania obiektowego. Iwona Kochaoska

Zaawansowane programowanie w C++ (PCP)

Programowanie obiektowe

Programowanie, część I

Java: kilka brakujących szczegółów i uniwersalna nadklasa Object

Podstawy Programowania 2

Konstruktory. Streszczenie Celem wykładu jest zaprezentowanie konstruktorów w Javie, syntaktyki oraz zalet ich stosowania. Czas wykładu 45 minut.

Programowanie obiektowe

Programowanie obiektowe

Programowanie obiektowe - 1.

Polimorfizm. dr Jarosław Skaruz

Zaawansowane programowanie w języku C++ Programowanie obiektowe

Wykład 5: Klasy cz. 3

Język programowania PASCAL

Wprowadzenie do programowanie obiektowego w języku C++

Oracle PL/SQL. Paweł Rajba.

Obiekt klasy jest definiowany poprzez jej składniki. Składnikami są różne zmienne oraz funkcje. Składniki opisują rzeczywisty stan obiektu.

Wykład 5 Okna MDI i SDI, dziedziczenie

PROGRAM: WYSZUKANIE LICZBY MAKSYMALNEJ

Ada-95. Dariusz Wawrzyniak

Programowanie obiektowe Wykład 6. Dariusz Wardowski. dr Dariusz Wardowski, Katedra Analizy Nieliniowej, WMiI UŁ 1/14

Programowanie, część I

Rozdział 4 KLASY, OBIEKTY, METODY

dr inż. Jarosław Forenc

Podstawy Programowania Obiektowego

PHP 5 język obiektowy

C++ - polimorfizm. C++ - polimorfizm. C++ - polimorfizm. C++ - polimorfizm. C++ - polimorfizm POLIMORFIZM

Programowanie obiektowe w języku

Podstawy programowania. Wykład PASCAL. Zmienne wskaźnikowe i dynamiczne. dr Artur Bartoszewski - Podstawy prograowania, sem.

1. Które składowe klasa posiada zawsze, niezależnie od tego czy je zdefiniujemy, czy nie?

Funkcje wirtualne. Wskaźniki do klas pochodnych są podstawą dla funkcji wirtualnych i polimorfizmu dynamicznego.

Instrukcja do pracowni specjalistycznej z przedmiotu. Obiektowe programowanie aplikacji

Technologie i usługi internetowe cz. 2

Obszar statyczny dane dostępne w dowolnym momencie podczas pracy programu (wprowadzone słowem kluczowym static),

Klasy abstrakcyjne i interfejsy

Programowanie obiektowe. Literatura: Autor: dr inŝ. Zofia Kruczkiewicz

.NET Klasy, obiekty. ciąg dalszy

Dariusz Brzeziński. Politechnika Poznańska, Instytut Informatyki

Informacje ogólne. Karol Trybulec p-programowanie.pl 1. 2 // cialo klasy. class osoba { string imie; string nazwisko; int wiek; int wzrost;

Podstawy programowania. Wykład PASCAL. Wstęp do programowania obiektowego. dr Artur Bartoszewski - Podstawy programowania, sem.

Programowanie obiektowe

Java - tablice, konstruktory, dziedziczenie i hermetyzacja

Klasy abstrakcyjne, interfejsy i polimorfizm

Jeśli chcesz łatwo i szybko opanować podstawy C++, sięgnij po tę książkę.

Kurs programowania. Wstęp - wykład 0. Wojciech Macyna. 22 lutego 2016

Polimorfizm, metody wirtualne i klasy abstrakcyjne

Szablony klas, zastosowanie szablonów w programach

Język C++ Programowanie obiektowe

Mechanizm dziedziczenia

C++ - [4-7] Polimorfizm

Programowanie obiektowe

Dziedziczenie. dr Jarosław Skaruz

Aplikacje w środowisku Java

Programowanie w Javie 1 Wykład i Ćwiczenia 3 Programowanie obiektowe w Javie cd. Płock, 16 października 2013 r.

Podstawy programowania 2. Temat: Wprowadzenie do wskaźników. Przygotował: mgr inż. Tomasz Michno

Wprowadzenie do systemu Delphi

Programowanie w Internecie. Java

Zapis programu z wykorzystaniem modułu (Podstawy Delphi 2.1, 2.2, 2.3 str11 )

Język Java część 2 (przykładowa aplikacja)

Podstawy programowania 2. Przygotował: mgr inż. Tomasz Michno

TEMAT : KLASY POLIMORFIZM

2. Klasy cz. 2 - Konstruktor kopiujący. Pola tworzone statycznie i dynamicznie - Funkcje zaprzyjaźnione - Składowe statyczne

C++ - dziedziczenie. C++ - dziedziczenie. C++ - dziedziczenie. C++ - dziedziczenie. C++ - dziedziczenie C++ - DZIEDZICZENIE.

Programowanie w Turbo Pascal

PROGRAMOWANIE OBIEKTOWE W C++ cz. 2. Dziedziczenie, operacje wej cia-wyj cia, przeładowanie operatorów.

Interfejsy i klasy wewnętrzne

Klasa jest nowym typem danych zdefiniowanym przez użytkownika. Najprostsza klasa jest po prostu strukturą, np

Wstęp do Programowania potok funkcyjny

Informatyka I. Klasy i obiekty. Podstawy programowania obiektowego. dr inż. Andrzej Czerepicki. Politechnika Warszawska Wydział Transportu 2018

Pascal. 1. Pliki tekstowe. Przykład 1.1. Zapis do pliku tekstowego

Zaawansowane programowanie w C++ (PCP)

Strona główna. Strona tytułowa. Programowanie. Spis treści. Sobera Jolanta Strona 1 z 26. Powrót. Full Screen. Zamknij.

Wykład V. Programowanie II - semestr II Kierunek Informatyka. dr inż. Janusz Słupik. Wydział Matematyki Stosowanej Politechniki Śląskiej

Wstęp do programowania 2

Procedury i funkcje - powtórzenie i uzupełnienia. Przykład funkcji potęgowanie przy wykładniku naturalnym

INSTRUKCJA PUSTA. Nie składa się z żadnych znaków i symboli, niczego nie robi. for i := 1 to 10 do {tu nic nie ma};

Wskaźniki. Informatyka

Programowanie 2. Język C++. Wykład 3.

Programowanie obiektowe. Wykład 03. Maciej Wołoszyn 17 marca Polimorfizm oraz wczesne i późne wiazanie

Techniki programowania INP001002Wl rok akademicki 2017/18 semestr letni. Wykład 4. Karol Tarnowski A-1 p.

Transkrypt:

Wykład czternasty 1. Polimorfizm Ostatni wykład zakończyliśmy stwierdzeniem, że możemy obiektowi dowolnej klasy przypisa ć obiekt klasy dziedziczącej po tej klasie. Przypisanie takie obejmuje jednak jedynie wartości pól wspólnych dla klas obu obiektów. Może by ć ono dokonywane zarówno poprzez jawne użycie instrukcji przypisania, jak i za pośrednictwem przekazania przez warto ść. Technika obiektowa pozwala na bardziej wyrafinowane korzystanie z obiektów, ale wymaga użycia wskaźników i zapoznania si ę z dwoma nowymi pojęciami: metodami wirtualnymi i konstruktorami. Własno ść instrukcji przypisania, która dotyczy obiektów klas należących do jednej hierarchii dziedziczenia jest zachowana równie ż w przypadku wskaźników, co oznacza, że wskaźnik klasy bazowej może przechowywa ć adres obiektu dowolnej klasy pochodnej. Ta własność okazuje si ę by ć bardzo przydatna w połączeniu z późnym wią zaniem adresów metod. Dotychczas adres metody, która ma by ć wywołana by ł ustalany na etapie kompilacji. Język Object Pascal pozwala na odroczenie określenia tego adresu do czasu wykonania programu, co nazywane jest późnym lub dynamicznym wiązaniem i ma ścisły związek z tzw. polimorficznym zachowaniem metod. Aby adres metody by ł ustalany na etapie wykonania programu za jej deklaracj ą należy umieści ć słowo kluczowe virtual. Tak zadeklarowana metoda jest nazywana metod ą wirtualn ą lub metod ą polimorficzn ą. Polimorficzne zachowanie metody polega na tym, że kiedy na obiekt klasy pochodnej wskazuje wskaźnik klasy bazowej i przy pomocy tego wskaźnika wywoływana jest metoda, to zostanie wywołana metoda właściwa dla klasy obiektu, a nie dla klasy wskaźnika. By ten mechanizm zadziała ł konieczne jest, aby ta metoda była zadeklarowana w klasie bazowej i to jako metoda wirtualna. Jeśli metoda została zadeklarowana w klasie bazowej jako wirtualna, to w klasach pochodnych nie można jej deklaracji zmieni ć z powrotem na statyczn ą (pomin ąć słowo kluczowe virtual), natomiast odwrotna sytuacja jest możliwa. Nie jest bezpośrednio możliwe wywołanie, przy pomocy wskaźnika klasy bazowej metod, które w tej klasie nie zostały zadeklarowane, a s ą dodane do klas pochodnych. Ten problem można jednak rozwiąza ć i rozwiązanie to zostanie przedstawione w dalszej części wykładu. Adresy metod wirtualnych s ą ustalane na podstawie tablicy metod wirtualnych ( ang. VMT = Virtual Method Table). Jest to specjalna tablica umieszczana w segmencie danych po uruchomieniu programu. Warunkiem stworzenia tej tablicy jest zadeklarowanie w klasie specjalnej metody, która nazywana jest konstruktorem. Deklaracja tej metody określona jest następującym schematem: constructor nazwa; Konstruktor w języku Object Pascal może si ę nazywa ć dowolnie, zazwyczaj jednak nazywa si ę go init lub inicjuj. Może on równie ż by ć metod ą pust ą, ale zazwyczaj s ą w nim umieszczane instrukcje związane z inicjalizacj ą pól obiektu. Konstruktor jest jedyn ą metod ą, która nie może by ć wirtualna, gdy ż jest on odpowiedzialny za powiązanie VMT z obiektem 1. Wirtualna tablica metod jest tworzona dla każdej klasy, która zawiera konstruktor. W przypadku, kiedy taka klasa nie posiada metod wirtualnych, to rozmiar tej tablicy wynosi 8 bajtów i przechowuje ona między innymi rozmiar obiektu klasy oraz zanegowany rozmiar obiektu klasy. Każda metoda wirtualna powoduje zwiększenie rozmiaru tej tablicy o 4 bajty, w których jest zapisywany adres tej metody. Kiedy tworzony jest obiekt konstruktor dokonuje inicjalizacji dwubajtowego pola tego obiektu, które przechowuje adres (dokładniej: tylko offset) VMT. Pole to jest tworzone niejawnie przez kompilator. Możemy ustalić jakiej faktycznie klasy jest wskazywany przez wskaźnik obiekt posługując si ę funkcj ą TypeOf, która zwraca adres wirtualnej tablicy metod właściwej klasy obiektu. Dzięki temu możemy obiekt rzutowa ć na wskaźnik odpowiedniej klasy i wywoła ć metody, które s ą obecne w tej klasie, ale nie s ą obecne w klasie bazowej. Do tego zagadnienia wrócimy na przyszłych wykładach. Oto przykład ilustrujący działanie mechanizmu polimorfizmu: 1 program Uniwersum; 2 uses cn; 3 type Wszechswiat=object 4 procedure drukuj(ob:pcialoniebieskie); 5 end; 6 var 7 ws:wszechswiat; 8 gw:gwiazda; 9 pl:planeta; 10 11 procedure Wszechswiat.drukuj(ob:PCialoNiebieskie); 12 begin 13 ob^.drukuj; 14 end; 15 16 begin 17 pl.inicjuj; 18 gw.inicjuj; 19 ws.drukuj(@gw); 20 ws.drukuj(@pl); W programie zdefiniowano cztery klasy: CialoNiebieskie (CiałoNiebieskie), Planeta, Gwiazda i Wszechswiat (Wszechświat). Przyjrzyjmy si ę najpierw klasom w module. Tworz ą one drzewo dziedziczenia, którego korzeniem jest klasa CialoNiebieskie - dwie pozostałe dziedzicz ą po niej. Każda z tych klas posiada konstruktor. W klasie CialoNiebieskie jest on metod ą pust ą, w pozostałych wywołuje inne metody odpowiedzialne za nadawanie wartości poszczególnym polom odpowiednich klas. Każda klasa pochodna oprócz pól i metod dziedziczonych po klasie bazowej posiada równie ż własne pola oraz metody je obsługujące. Jedn ą z metod wspólnych dla wszystkich klas jest metoda drukuj. To co j ą odróżnia od pozostałych jest to, że jest metod ą wirtualn ą. Ta metoda jest nadpisywana w kolejnych klasach, tak aby obsługiwała pola charakterystyczne dla tych klas. Jeśli jej nie nadpisalibyśmy, to będzie si ę zachowywała tak jak metoda z klasy bazowej, gdy ż te ż podlega dziedziczeniu. W pliku zawierającym blok główny programu stworzono jeszcze jedn ą klas ę. Ta klasa zawiera tylko jedną metod ę, która przez parametr pobiera wskaźnik do obiektu klasy CialoNiebieskie. W bloku głównym programu tworzony jest obiekt tej klasy i wywoływana jest metoda drukuj tego obiektu. W wierszu 18 jest jej przekazany przez parametr adres obiektu klasy Gwiazda, a w wierszu 19 adres obiektu klasy Planeta. Okazuje si ę, że w metodzie drukuj obiektu klasy Wszechswiat zostały wywołane metody drukuj właściwe dla klas obiektów, których adresy zostały przekazane tej metodzie. Jeśli zmienilibyśmy t ę metod ę w ten sposób, że będzie korzystała nie ze wskaźnika, ale z parametru klasy CialoNiebieskie przekazującego przez warto ść, to program będzie zachowywa ł si ę podobnie do programu z poprzedniego wykładu, który nie korzysta ł z mechanizmu polimorfizmu. 21 end. 1 Robi to w sposób niejawny, czyli od strony programisty nie wymaga to dodatkowych zabiegów, poza stworzeniem takiej metody, która, jak to ju ż wcześniej napisano, może by ć metod ą pust ą. 1

1 unit cn; 2 interface 3 uses crt; 4 type 5 6 PCialoNiebieskie = ^CialoNiebieskie; 7 8 CialoNiebieskie = object 9 private 10 nazwa:string; 11 masa:integer; 12 x,y,z:real; 13 function podajmase:integer; 14 function podajnazwe:string; 15 function podajx:real; 16 function podajy:real; 17 function podajz:real; 18 public 19 constructor inicjuj; 20 procedure ustawnazwe(const n:string); 21 procedure ustawwspolrzedne(x1,y1,z1:real); 22 procedure ustawmase(m:integer); 23 procedure drukuj; virtual; 24 end; 25 26 Planeta = object(cialoniebieskie) 27 private 28 atmosfera:boolean; 29 public 30 constructor inicjuj; 31 function podajatmosfere:boolean; 32 procedure ustawatmosfere(a:boolean); 33 procedure drukuj; virtual; 34 end; 35 36 Gwiazda = object(cialoniebieskie) 37 private 38 temperaturapowierzchni:integer; 39 public 40 constructor inicjuj; 41 function podajtemperaturepowierzchni:integer; 42 procedure ustawtemperaturepowierzchni(t:integer); 43 procedure drukuj; virtual; 44 end; 45 2

46 implementation 47 48 function CialoNiebieskie.podajMase:integer; 49 begin 50 podajmase:=masa; 51 end; 52 53 function CialoNiebieskie.podajNazwe:string; 54 begin 55 podajnazwe:=nazwa; 56 end; 57 58 function CialoNiebieskie.podajZ:real; 59 begin 60 podajz:=z; 61 end; 62 63 function CialoNiebieskie.podajY:real; 64 begin 65 podajy:=y; 66 end; 67 68 function CialoNiebieskie.podajX:real; 69 begin 70 podajx:=x; 71 end; 72 73 procedure CialoNiebieskie.ustawNazwe(const n:string); 74 begin 75 nazwa:=n; 76 end; 77 78 procedure CialoNiebieskie.ustawWspolrzedne(x1,y1,z1:real); 79 begin 80 x:=x1; 81 y:=y1; 82 z:=z1; 83 end; 84 85 procedure CialoNiebieskie.ustawMase(m:integer); 86 begin 87 Masa:=m; 88 end; 89 90 constructor CialoNiebieskie.inicjuj; 3

91 begin 92 end; 93 94 procedure CialoNiebieskie.drukuj; 95 begin 96 clrscr; 97 writeln('nazwa: ',podajnazwe); 98 writeln('masa: ',podajmase); 99 writeln('współrzędne: ',podajx, ',', podajy, ',', podajz); 100 end; 101 102 constructor Planeta.inicjuj; 103 begin 104 ustawmase(2000); 105 ustawwspolrzedne(1,0,0); 106 ustawnazwe('ziemia'); 107 ustawatmosfere(true); 108 end; 109 110 procedure Planeta.ustawAtmosfere(a:boolean); 111 begin 112 atmosfera:=a; 113 end; 114 115 function Planeta.podajAtmosfere:boolean; 116 begin 117 podajatmosfere:=atmosfera; 118 end; 119 120 procedure Planeta.drukuj; 121 begin 122 inherited drukuj; 123 if podajatmosfere=true then writeln('atmosfera: tak') else 124 writeln('atmosfera: nie'); 125 readln; 126 end; 127 128 constructor Gwiazda.inicjuj; 129 begin 130 ustawmase(20000); 131 ustawwspolrzedne(0,0,0); 132 ustawnazwe('słońce'); 133 ustawtemperaturepowierzchni(5000); 134 end; 135 4

136 procedure Gwiazda.ustawTemperaturePowierzchni(t:integer); 137 begin 138 temperaturapowierzchni:=t; 139 end; 140 141 function Gwiazda.podajTemperaturePowierzchni:integer; 142 begin 143 podajtemperaturepowierzchni:=temperaturapowierzchni; 144 end; 145 146 procedure Gwiazda.drukuj; 147 begin 148 clrscr; 149 inherited drukuj; 150 writeln('temperatura powierzchni: ', podajtemperaturepowierzchni); 151 readln; 152 end; 153 end. Modu ł cn jest równie ż wykorzystywany w krótkim programie, który wypisuje cz ęść zawartości tablicy metod wirtualnych na ekran: 1 program tablica_vmt; 2 uses crt,cn; 3 type Rek = record 4 SizePoz,SizeNeg,Pom1,Pom2:Word; 5 Adr_Metody_1:Pointer; 6 end; 7 var 8 pl:planeta; 9 gw:gwiazda; W programie tym stworzony zosta ł typ rekordowy opisujący elementy tablicy metod wirtualnych. Typ ten jest używany przez procedurę display_vmt, która dokonuje rzutowania danych wskazywanych przez wskaźnik bez określonego typu na ten typ rekordowy i wyświetlenia na ekran zawartości pól tego rekordu (chodzi tu o nadanie określonej formy danym, które zostały pobrane wprost z pamięci operacyjnej). Adresy VMT poszczególnych klas s ą uzyskiwane dzięki wcześniej wspomnianej funkcji TypeOf. Program napisano na podstawie skryptu Zofii Kruczkiewicz pt.: Metody programowania obiektowego. 10 11 wsk:pointer; 12 13 procedure display_vmt(adr:pointer); 14 begin 15 with rek(adr^) do 16 begin 17 writeln('rozmiar obiektu: ',SizePoz); 18 writeln('rozmiar zanegowany: ',SizeNeg); 19 writeln('pom1: ',Pom1, ' Pom2: ',Pom2); 20 writeln('adres drukuj:',seg(adr_metody_1^),':',ofs(adr_metody_1^)); 21 end; 22 end; 23 24 begin 5

25 clrscr; 26 pl.inicjuj; 27 gw.inicjuj; 28 wsk:=typeof(pl); 29 display_vmt(wsk); 30 wsk:=typeof(gw); 31 display_vmt(wsk); 32 readln; 33 end. 2. Podsumowanie Polimorfizm jest bardzo pożytecznym mechanizmem w programowaniu obiektowym. Pełni ę jego możliwości będziemy mogli wykorzysta ć po zapoznaniu si ę z obiektami tworzonymi dynamicznie. Czasem, aby ułatwi ć wywoływanie metod z klas pochodnych, do klas bazowych dodaje si ę wszystkie metody jakie mog ą wystąpi ć w ich klasach pochodnych i umieszcza si ę w nich instrukcj ę abstract, która powoduje błąd czasu wykonania, jeśli metoda j ą zawierająca zostanie wywołana. Takie metody nazywa si ę metodami abstrakcyjnymi, a klasy które je zawieraj ą klasami abstrakcyjnymi. Dosy ć często używa si ę takich klas w innym celu aby uczyni ć model obiektowy bardziej odpowiadającym rzeczywistemu. Klasami abstrakcyjnymi mog ą by ć klasy reprezentujące takie pojęcia jak: figura geometryczna, czy ssak. Problem metod i klas abstrakcyjnych zostanie szerzej omówiony na następnym wykładzie. W wyżej zaprezentowanym programie należy zwróci ć uwag ę na użycie operatora @. Potencjalnie ten operator jest niebezpieczny, poniewa ż kompilator nie sprawdza typu wskaźnika, jaki on zwraca, co oznacza, że za jego pomoc ą do metody drukuj klasy Wszechś wiat możemy przekaza ć wskaźnik na dowoln ą zmienn ą, nawet tak ą, która nie jest obiektem (np.: wskaźnik na zmienn ą typu integer). Aby pozby ć si ę tego operatora możemy zastąpi ć przekazanie wskaźnika do metody przekazaniem przez zmienn ą, tzn. przekształci ć nagłówek metody drukuj na procedure drukuj(var ob:cialoniebieskie); i zmieni ć w ciele tej metody ob^.drukuj na ob.drukuj. Przekazanie przez zmienn ą jest przekazaniem wskaźnika, ale w sposób bezpieczny (z kontrol ą typów). Przekazanie przez zmienn ą nazywane jest równie ż przekazaniem przez referencj ę. Rol ę referencji, czyli bezpiecznego wskaźnika pełni parametr poprzedzony słowem kluczowym var. 6