Polimorfizm Część piąta Niniejsze opracowanie zawiera skrót treści wykładu, lektura tych materiałów nie zastąpi uważnego w nim uczestnictwa. Opracowanie to jest chronione prawem autorskim. Wykorzystywanie jakiegokolwiek fragmentu w celach innych niż nauka własna jest nielegalne. Dystrybuowanie tego opracowania lub jakiejkolwiek jego części oraz wykorzystywanie zarobkowe bez zgody autora jest zabronione. Roman Simiński [email protected]www.us.edu.pl/~siminski Autor Kontakt Wprowadzenie do programowania Wprowadzenie do programowania w języku C++ w języku C++
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Polimorfizm
Część piąta
Niniejsze opracowanie zawiera skrót treści wykładu, lektura tych materiałów nie zastąpi uważnego w nim uczestnictwa.Opracowanie to jest chronione prawem autorskim. Wykorzystywanie jakiegokolwiek fragmentu w celach innych niż nauka własna jest nielegalne.
Dystrybuowanie tego opracowania lub jakiejkolwiek jego części oraz wykorzystywanie zarobkowe bez zgody autora jest zabronione.
Słowo polimorfizm pochodzi od dwóch greckich słów:
Polimorfizm oznacza zatem wielopostaciowość. Polimorfizm w programowaniu obiektowym oznacza zdolność obiektów do różnych zachowań, w zależności od bieżącego kontekstu wykonania programu.
Polega to zwykle na tym, że obiekt―zleceniodawca usługi przesyła komunikat do obiektu-wykonawcy usługi, który w odpowiedzi wykonuje odpowiednią w danym kontekście akcję. To jaka ma być wykonana akcja, ustalane jest na etapie wykonania programu, a wykonywane akcje mogą być różne.
W języku C++ wykonanie akcji polega na wywołaniu odpowiedniej funkcji. Polimorfizm w tym języku polega na tym, że wywoływane mogą być różne wersje tej samej funkcji.
Różne wersje tej samej funkcji powstają w trakcie dziedziczenia, kiedy to klasy pochodne w specjalny sposób redefiniują pewną funkcję składową.
Dziedziczenie „produkuje” wiele spowinowaconych klas Dziedziczenie „produkuje” wiele spowinowaconych klas Podstawy i języki programowaniaPodstawy i języki programowania
Zdyscyplinowane stosowanie zasad abstrakcji, hermetyzacji i dziedziczenia prowadzi do powstania, często rozbudowanych, hierarchii klas.
Obiekty takich klas są często do siebie podobne, ale nie jednakowe.
Problem: jak spójnie i wygodnie zarządzać grupami obiektów różnych klas należących do tej samej hierarchii, zdefiniowanej dziedziczeniem?
Auto
markamodelrokProdnrRej
. . .
AutoWSerwisie
przebiegnumerKomputerowy
. . .
AutoWStacjiDiagn
dataPrzegladunastepnyPrzegladdiagnosta
. . .
AutoWKomisie
cenadataPrzyjeciawlasciciel
. . .
ScrPixel
minx, minymaxx, maxy
. . .
Pixel
color
. . .
Point
xy
. . .
Point3D
z
. . .
Obiekty spowinowacone mogą być traktowane w specjalny sposóbObiekty spowinowacone mogą być traktowane w specjalny sposóbPodstawy i języki programowaniaPodstawy i języki programowania
auto = new AutoWKomisie;auto->rokProd = 2005;. . .delete auto;
auto = new AutoWSerwisie;auto->rokProd = 1999;. . .delete auto;
void showPointInfo( Point & p ){ cout << "X = " << p.getX() << endl; cout << "Y = " << p.getY() << endl;}. . .
Pixel p1( 10, 10, Red );Point3D p2( 1, 1, 1 );
showPointInfo( p1 );showPointInfo( p2 );
Obiekty spowinowacone mogą być traktowane w specjalny sposóbObiekty spowinowacone mogą być traktowane w specjalny sposóbPodstawy i języki programowaniaPodstawy i języki programowania
Stosując zasadę abstrakcji wyodrębniamy najistotniejsze cechy obiektów dla rozpatrywanego zagadnienia — szyby to figury geometryczne a okno to ich złożenie.
Łączna powierzchnia okna to, w przybliżeniu, suma pól figur opisujących szyby,
Łączna długość profili to, w przybliżeniu, suma obwodów figur opisujących szyby.
Kwadrat
Prostokąt
Trójkąt
Prostokąt
Analiza obiektowa, cd...Analiza obiektowa, cd...Podstawy i języki programowaniaPodstawy i języki programowania
Realizacja programu sprowadza się do obliczeń pól powierzchni i obwodów obiektów, będących złożeniem elementarnych figur płaskich.
Utworzyliśmy już klasy reprezentujące figury płaskie,
Nie wiemy jak reprezentować ich złożenia.
Kwadrat
Prostokąt
Trójkąt
Prostokąt
KwadratProstokąt
Trójkąt
Prostokąt
Figury płaskie raz jeszcze — budujemy hierarchię klasFigury płaskie raz jeszcze — budujemy hierarchię klasPodstawy i języki programowaniaPodstawy i języki programowania
Rozpoczynamy od utworzenia nieco dziwnej klasy — reprezentującej abstrakcyjną figurę geometryczną. Wyposażamy ją w funkcje obliczania pola i obwodu.
Klasa Figure służyć będzie jak klasa bazowa dla specjalizowanych klas pochodnych, reprezentujących konkretne figury geometryczne.
Jej istotą jest stwierdzenie, że każda figura geometryczna powinna umieć wyznaczać swoje pole i obwód, w charakterystyczny dla siebie sposób.
Zatem każda z klas pochodnych, powinna redefiniować funkcje area i circumference, w odpowiedni dla tych klas sposób.
Figury płaskie raz jeszcze — budujemy hierarchię klas, klasa SquareFigury płaskie raz jeszcze — budujemy hierarchię klas, klasa SquarePodstawy i języki programowaniaPodstawy i języki programowania
Redefinicja funkcji area i circumference — obliczenia dla kwadratu:
Figury płaskie raz jeszcze — budujemy hierarchię klas, klasa SquareFigury płaskie raz jeszcze — budujemy hierarchię klas, klasa SquarePodstawy i języki programowaniaPodstawy i języki programowania
Redefinicja funkcji area i circumference — obliczenia dla prostokąta:
Figury płaskie raz jeszcze — budujemy hierarchię klas, klasa TriangleFigury płaskie raz jeszcze — budujemy hierarchię klas, klasa TrianglePodstawy i języki programowaniaPodstawy i języki programowania
Wiemy już, że można przypisać do wskaźnika fp wskazanie na obiekt klasy pochodnej:
fp = &r; // OK
lub
fp = &t; // OK
lub
Wykorzystanie wskaźników w hierarchii klas, cd...Wykorzystanie wskaźników w hierarchii klas, cd...Podstawy i języki programowaniaPodstawy i języki programowania
W języku C++ wolno do wskaźnika klasy bazowej przypisać wskazanie obiektu klasy pochodnej. Wolno zatem pośrednio odwoływać się do odziedziczonych pól i funkcji
Choć można dokonać „wymuszenia” stosując brutalne rzutowanie typów:
W C++ istnieją inne, bezpieczniejsze metody konwersji typów (np. static_cast, dynamic_cast).
Wykorzystanie wskaźników w hierarchii klas, cd...Wykorzystanie wskaźników w hierarchii klas, cd...Podstawy i języki programowaniaPodstawy i języki programowania
Przypisanie konkretnego ciała funkcji do wywołania nazywa się wiązaniem (ang. binding).
W języku C++ występują dwa rodzaje wiązania:
Wczesne wiązanie (ang. early binding) polega na przypisaniu konkretnej funkcji każdemu wywołaniu już na etapie kompilacji programu. Inna nazwa — wiązanie statyczne (ang. static binding).
Późne wiązanie (ang. late binding) polega na przypisaniu konkretnej funkcji każdemu wywołaniu dopiero na etapie wykonania programu, w zależności od typu obiektu, którego wywołanie dotyczy. Inna nazwa to dynamiczne wiązanie (ang. dynamic binding).
Jakie wiązanie stosuje kompilator?Jakie wiązanie stosuje kompilator?Podstawy i języki programowaniaPodstawy i języki programowania
Mimo iż klasa Square przedefiniowała obie funkcje i posiada ich własne wersje, nie zostaną one wywołane.
Wiązanie statyczne przyczyną problemów z showFullInfo Wiązanie statyczne przyczyną problemów z showFullInfo Podstawy i języki programowaniaPodstawy i języki programowania
Mimo, że funkcja wywoływana jest dla obiektów klas potomnych względem Figure, kompilator wstawi wywołanie funkcji zgodnie z typem występującym w deklaracji
Co trzeba zrobić, aby wszystko działało tak, jak się spodziewamy?Co trzeba zrobić, aby wszystko działało tak, jak się spodziewamy?Podstawy i języki programowaniaPodstawy i języki programowania
Dlaczego teraz działa? Bo kompilator stosuje wiązanie dynamiczneDlaczego teraz działa? Bo kompilator stosuje wiązanie dynamicznePodstawy i języki programowaniaPodstawy i języki programowania
Wiązanie dynamiczne jest realizowane w języku C++ za pomocą funkcji wirtualnych.
Funkcja wirtualna posiada w swojej deklaracji słowo kluczowe virtual.
Jeżeli w klasie pochodnej funkcja wirtualna nie zostanie przedefiniowana, wszystko działa jak w przypadku innych funkcji.
Jeżeli w klasie pochodnej funkcja wirtualna zostanie przedefiniowana, to zostanie ona wywołana zamiast funkcji przedefiniowanej — w przypadku gdy wskaźnik do klasy bazowej wskazuje na obiekt klasy pochodnej.
W przypadku funkcji wirtualnych nie jest istotny typ wskaźnika, wywoływana jest funkcja zdefiniowana w klasie obiektu wskazywanego.
Wiązanie dynamiczne (późne)Wiązanie dynamiczne (późne)Podstawy i języki programowaniaPodstawy i języki programowania
Zadany jest układ okna oraz wymiary jego ościeżnic. Jedna ościeżnica jest kwadratowa (bok 50cm), pozostałe trzy prostokątne (70x50 cm, 50x100 cm i 70x100 cm).
Należy wyznaczyć łączną powierzchnię szyb i długość profili.
50 7050
100
Jak reprezentować informacje o oknie?Jak reprezentować informacje o oknie?Podstawy i języki programowaniaPodstawy i języki programowania
Definiowanie elementów okna, obliczenia, sprzątanieDefiniowanie elementów okna, obliczenia, sprzątaniePodstawy i języki programowaniaPodstawy i języki programowania
void calcAndShowWinInfo( Figure * window[], int numOfSash ){ // Tutaj ł czna powierzchnia szyb i długo ć profilią ś double totalArea = 0, totalCircum = 0;
// Zliczanie powierzchni i długo ciś for( int i = 0; i < numOfSash; i++ ) { totalArea += window[ i ]->area(); totalCircum += window[ i ]->circumference(); }
Polimorfizm zakłada, że jedna funkcja składowa występować może we wielu wersjach.
Wersje te definiowane są w klasach pochodnych, polimorfizm zakłada zatem wykorzystanie dziedziczenia.
Wysłanie do obiektu komunikatu o określonej nazwie (np. area) może spowodować wykonanie różnych akcji (wywołanie różnych wersji funkcji składowej) w zależności od kontekstu wywołania.
Kontekst wywołania zależy od tego, na obiekt jakiej klasy wskazuje zmienna wskaźnikowa, albo z jakim obiektem skojarzona jest referencja.
W języku C++ polimorfizm jest realizowany z wykorzystaniem funkcji wirtualnych i dostępny jest przy wykorzystaniu odwołań wskaźnikowych lub referencyjnych.
Funkcje wirtualne wywoływane są na zasadzie wiązania dynamicznego.
C++ jest hybrydowym językiem programowania. Zawiera mechanizmy obiektowe ale nie wymusza ich wykorzystania. Pozostawia również programiście wybór, czy stosować wiązanie styczne czy dynamiczne.