wprowadzenie do programowania w języku c++

39
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++

Upload: dinhkiet

Post on 11-Jan-2017

223 views

Category:

Documents


2 download

TRANSCRIPT

Page 1: Wprowadzenie do programowania w języku C++

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]/~siminski

Autor

Kontakt

Wprowadzenie do programowania Wprowadzenie do programowania w języku C++w języku C++

Page 2: Wprowadzenie do programowania w języku C++

Koncepcja polimorfizmuKoncepcja polimorfizmuPodstawy i języki programowaniaPodstawy i języki programowania

Copyright © Roman Simiński 2Strona :

PolimorfizmJęzyk C++Język C++

poly czyli wiele,

morphos czyli postać.

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ą.

Page 3: Wprowadzenie do programowania w języku C++

Dziedziczenie „produkuje” wiele spowinowaconych klas Dziedziczenie „produkuje” wiele spowinowaconych klas Podstawy i języki programowaniaPodstawy i języki programowania

Copyright © Roman Simiński 3Strona :

Wiele klas tworzących hierarchię rodzinną

PolimorfizmJęzyk C++Język C++

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

. . .

Page 4: Wprowadzenie do programowania w języku C++

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

Copyright © Roman Simiński 4Strona :

PolimorfizmJęzyk C++Język C++

Auto

markamodelrokProdnrRej

. . .

AutoWSerwisie

przebiegnumerKomputerowy

. . .

AutoWStacjiDiagn

dataPrzegladunastepnyPrzegladdiagnosta

. . .

AutoWKomisie

cenadataPrzyjeciawlasciciel

. . .

ScrPixel

minx, minymaxx, maxy

. . .

Pixel

color

. . .

Point

xy

. . .

Point3D

z

. . .

Auto * auto;

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 );

Page 5: Wprowadzenie do programowania w języku C++

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

Copyright © Roman Simiński 5Strona :

PolimorfizmJęzyk C++Język C++

W języku C++ wolno do wskaźnika klasy bazowej przypisać wskazanie obiektu klasy

pochodnej. Analogicznie jest w przypadku referencji.

Obiekt klasy pochodnej jest przecież pewnego rodzaju obiektem klasy bazowej (jest

specjalizacją klasy bazowej), posiada zatem wszystkie pola i funkcje składowe.

Wolno zatem pośrednio odwoływać się do odziedziczonych pól i funkcji składowych.

AutoWKomisie

cenadataPrzyjeciawlasciciel

. . .

Auto

markamodelrokProdnrRej

. . .

Auto * auto;

auto = new AutoWKomisie;auto->rokProd = 2005;. . .delete auto;

Page 6: Wprowadzenie do programowania w języku C++

Zarządzanie grupami spowinowaconych obiektówZarządzanie grupami spowinowaconych obiektówPodstawy i języki programowaniaPodstawy i języki programowania

Copyright © Roman Simiński 6Strona :

Problem

PolimorfizmJęzyk C++Język C++

Należy napisać program wspomagający pracę technologa w firmie produkującej okna. Zadaniem programu jest:

obliczanie łącznego pola powierzchni wszystkich skrzydeł okna,

przybliżonej, łącznej długości profili, użytych do produkcji każdego ze skrzydeł.

Page 7: Wprowadzenie do programowania w języku C++

Obiekty rzeczywiste

Abstrakcyjny model analityczny

Analiza obiektowaAnaliza obiektowaPodstawy i języki programowaniaPodstawy i języki programowania

Copyright © Roman Simiński 7Strona :

PolimorfizmJęzyk C++Język C++

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

Page 8: Wprowadzenie do programowania w języku C++

Analiza obiektowa, cd...Analiza obiektowa, cd...Podstawy i języki programowaniaPodstawy i języki programowania

Copyright © Roman Simiński 8Strona :

PolimorfizmJęzyk C++Język C++

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

Page 9: Wprowadzenie do programowania w języku C++

Figury płaskie raz jeszcze — budujemy hierarchię klasFigury płaskie raz jeszcze — budujemy hierarchię klasPodstawy i języki programowaniaPodstawy i języki programowania

Copyright © Roman Simiński 9Strona :

PolimorfizmJęzyk C++Język C++

class Figure{ public :

Figure() {} double area() const { return 0; } double circumference() const { return 0; }

};

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.

Page 10: Wprowadzenie do programowania w języku C++

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

Copyright © Roman Simiński 10Strona :

PolimorfizmJęzyk C++Język C++

class Square: public Figure{ public :

Square(); Square( double startSide );

void setSide( double newSide ); double getSide();

double area() const; double circumference() const;

private: double side;};

Klasa reprezentująca kwadrat będzie teraz klasą pochodną w stosunku do klasy Figure:

double Square::area() const { return side * side; }

double Square::circumference() const { return 4 * side; }

Redefinicja funkcji area i circumference — obliczenia dla kwadratu:

Page 11: Wprowadzenie do programowania w języku C++

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

Copyright © Roman Simiński 11Strona :

PolimorfizmJęzyk C++Język C++

Klasa reprezentująca prostokąt będzie teraz klasą pochodną w stosunku do klasy Figure:

class Rectangle: public Figure{ public :

Rectangle(); Rectangle( double startWidth, double startHeight );

void setWidth( double newWidth ); void setHeight( double newHeight );

double getWidth() const; double getHeight() const;

double area() const; double circumference() const;

private: double width, height;};

double Rectangle::area() const { return width * height; }double Rectangle::circumference() const { return 2 * width + 2 * height; }

Redefinicja funkcji area i circumference — obliczenia dla prostokąta:

Page 12: Wprowadzenie do programowania w języku C++

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

Copyright © Roman Simiński 12Strona :

PolimorfizmJęzyk C++Język C++

Klasa reprezentująca prostokąt będzie teraz klasą pochodną w stosunku do klasy Figure:

class Triangle: public Figure{ public : Triangle(); Triangle( double startBase, double startHeight ); void setBase( double newBase ); void setHeight( double newHeight ); double getBase() const; double getHeight() const;

double area() const; double circumference() const;

private: double base, height;};

double Triangle::area() const { return 0.5 * base * height; }double Triangle::circumference() const { return sqrt( base * base + height * height ) + base + height; }

Redefinicja funkcji area i circumference — obliczenia dla trójkąta:

Uwaga, zakładamy dla uproszczenia, że

trójkątne szyby będą trójkątami prostokątnymi.

Page 13: Wprowadzenie do programowania w języku C++

Hierarchia klas figur płaskichHierarchia klas figur płaskichPodstawy i języki programowaniaPodstawy i języki programowania

Copyright © Roman Simiński 13Strona :

PolimorfizmJęzyk C++Język C++

Figure

+double area()+double circumference()

Triangle

+double area()+double circumference()

―double base―double width

Square

+double area()+double circumference()

―double side

Rectangle

+double area()+double circumference()

―double height―double width

Page 14: Wprowadzenie do programowania w języku C++

Wykorzystanie wskaźników w hierarchii klasWykorzystanie wskaźników w hierarchii klasPodstawy i języki programowaniaPodstawy i języki programowania

Copyright © Roman Simiński 14Strona :

PolimorfizmJęzyk C++Język C++

Figure * fp;

Załóżmy, że zdefiniowano wskaźnik do klasy bazowej Figure:

Square s( 10 );Rectangle r( 10, 20 );Triangle t( 10,10 );

Załóżmy, że zdefiniowano obiekty klas pochodnych:

fp = &s; // OK

Wiemy już, że można przypisać do wskaźnika fp wskazanie na obiekt klasy pochodnej:

fp = &r; // OK

lub

fp = &t; // OK

lub

Page 15: Wprowadzenie do programowania w języku C++

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

Copyright © Roman Simiński 15Strona :

PolimorfizmJęzyk C++Język C++

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

składowych.

fp = &s;cout << "Pole kwadratu wynosi: " << fp->area() << endl;cout << "Obwod kwadratu wynosi: " << fp->circumference() << endl;

Można zatem:

fp->setSide( 100 ); // Niedozwolone

Ale nie można:

( ( Square * )fp )->setSide( 100 );

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).

Page 16: Wprowadzenie do programowania w języku C++

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

Copyright © Roman Simiński 16Strona :

PolimorfizmJęzyk C++Język C++

Wykorzystując wskaźnik do klasy bazowej można odwoływać się w legalny sposób do wszystkich odziedziczonych składowych obiektu pochodnego.

Stosując zwykłe rzutowanie (lub specjalne metody konwersji) można siłowo wymusić dostęp do składowych zdefiniowanych w klasie pochodnej.

Klasa bazowa definiuje zatem „protokół” wykorzystania obiektu klasy pochodnej.

Square

―double side

Figure

+double area()+double circumference()

fp = &s;cout << fp->area() << endl;cout << fp->circumference() << endl;

Page 17: Wprowadzenie do programowania w języku C++

Po co ten cyrk ze wskaźnikami?Po co ten cyrk ze wskaźnikami?Podstawy i języki programowaniaPodstawy i języki programowania

Copyright © Roman Simiński 17Strona :

PolimorfizmJęzyk C++Język C++

Można napisać uniwersalną funkcję wyświetlającą informacje o figurze:

void showFigureInfo( Figure * fp ){ cout << "Pole : " << fp->area() << endl; cout << "Obwod : " << fp->circumference() << endl; cout << endl;}

I wywoływać ją z różnymi obiektami klas pochodnych:

showFigureInfo( &s );showFigureInfo( &r );showFigureInfo( &t );

Page 18: Wprowadzenie do programowania w języku C++

Po co ten cyrk ze wskaźnikami?Po co ten cyrk ze wskaźnikami?Podstawy i języki programowaniaPodstawy i języki programowania

Copyright © Roman Simiński 18Strona :

PolimorfizmJęzyk C++Język C++

Można rozbudować klasy o dodatkową funkcję określającą typ figury:

class Figure{ public : . . . char * getName() const { return "Figura"; }

};

class Square: public Figure{ public : . . . char * getName() const { return "Kwadrat"; }

};

Page 19: Wprowadzenie do programowania w języku C++

Po co ten cyrk ze wskaźnikami?Po co ten cyrk ze wskaźnikami?Podstawy i języki programowaniaPodstawy i języki programowania

Copyright © Roman Simiński 19Strona :

PolimorfizmJęzyk C++Język C++

Można rozbudować klasy o dodatkową funkcję określającą typ figury:

class Rectangle: public Figure{ public : . . . char * getName() const { return "Prostokat"; }

};

class Triangle: public Figure{ public : . . . char * getName() const { return "Trojkat"; }

};

Page 20: Wprowadzenie do programowania w języku C++

Po co ten cyrk ze wskaźnikami?Po co ten cyrk ze wskaźnikami?Podstawy i języki programowaniaPodstawy i języki programowania

Copyright © Roman Simiński 20Strona :

PolimorfizmJęzyk C++Język C++

Nowa wersja funkcji wyświetlającej informacje o figurach:

void showFullFigureInfo( Figure * fp ){ cout << fp->getName() << endl; cout << "Pole : " << fp->area() << endl; cout << "Obwod : " << fp->circumference() << endl; cout << endl;}

Page 21: Wprowadzenie do programowania w języku C++

Zobaczmy w końcu, czy to działa...Zobaczmy w końcu, czy to działa...Podstawy i języki programowaniaPodstawy i języki programowania

Copyright © Roman Simiński 21Strona :

PolimorfizmJęzyk C++Język C++

void showFullFigureInfo( Figure * fp ){ cout << fp->getName() << endl; cout << "Pole : " << fp->area() << endl; cout << "Obwod : " << fp->circumference() << endl; cout << endl;}

Wywołujemy:

showFigureInfo( &s );showFigureInfo( &r );showFigureInfo( &t );

I otrzymujemy...

To nie działa!!!

Page 22: Wprowadzenie do programowania w języku C++

Co się dzieje?Co się dzieje?Podstawy i języki programowaniaPodstawy i języki programowania

Copyright © Roman Simiński 22Strona :

PolimorfizmJęzyk C++Język C++

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).

Page 23: Wprowadzenie do programowania w języku C++

Jakie wiązanie stosuje kompilator?Jakie wiązanie stosuje kompilator?Podstawy i języki programowaniaPodstawy i języki programowania

Copyright © Roman Simiński 23Strona :

PolimorfizmJęzyk C++Język C++

Figure * fp;. . .fp = &s;cout << "Pole kwadratu wynosi: " << fp->area() << endl;cout << "Obwod kwadratu wynosi: " << fp->circumference() << endl;

Wywołanie odbywa się za pośrednictwem wskaźnika do typu Figure. Kompilator „przygląda” się definicji klasy i deklaracji wywoływanej funkcji:

class Figure{ . . . char * getName() const { return "Figura"; } double area() const { return 0; } double circumference() const { return 0; }};

Wywoływane funkcje są „zwykłymi” funkcjami.

Takie funkcje są łączone statycznie. Kompilator wstawia wywołanie funkcji zdefiniowanych w klasie występującej w deklaracji wskaźnika fp.

Wywoływane są zatem funkcje z klasy Figure, niezależnie od klasy wskazywanego obiektu.

Page 24: Wprowadzenie do programowania w języku C++

Wiązanie statyczne (wczesne)Wiązanie statyczne (wczesne)Podstawy i języki programowaniaPodstawy i języki programowania

Copyright © Roman Simiński 24Strona :

PolimorfizmJęzyk C++Język C++

O tym która funkcja jest wywoływana decyduje kompilator na etapie kompilacji.

Wywołanie ma taką samą postać jak wywołanie klasycznych funkcji w języku C.

O tym która funkcja zostanie wywołana decyduje typ występujący w deklaracji zmiennej wskaźnikowej.

+double area()+double circumference()

―double side

Square

Figure

+double area()+double circumference()

Figure * fp;Square s( 10 );

fp = &s;cout << fp->area() << endl;cout << fp->circumference() << endl;

Mimo iż klasa Square przedefiniowała obie funkcje i posiada ich własne wersje, nie zostaną one wywołane.

Page 25: Wprowadzenie do programowania w języku C++

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

Copyright © Roman Simiński 25Strona :

PolimorfizmJęzyk C++Język C++

O tym która funkcja jest wywoływana decyduje kompilator na etapie kompilacji.

Wywołanie ma taką samą postać jak wywołanie klasycznych funkcji w języku C.

O tym która funkcja zostanie wywołana decyduje typ występujący w deklaracji zmiennej wskaźnikowej.

void showFullFigureInfo( Figure * fp ){ cout << fp->getName() << endl; cout << "Pole : " << fp->area() << endl; cout << "Obwod : " << fp->circumference() << endl; cout << endl;}

showFigureInfo( &s );showFigureInfo( &r );showFigureInfo( &t );

class Figure{ . . . char * getName() const { return "Figura"; } double area() const { return 0; } double circumference() const { return 0; }};

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

parametru fp: void showFullFigureInfo( Figure * fp )

Page 26: Wprowadzenie do programowania w języku C++

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

Copyright © Roman Simiński 26Strona :

PolimorfizmJęzyk C++Język C++

Dokonujemy drobnej modyfikacji deklaracji funkcji składowych klasy Figure:

class Figure{ public :

Figure() {} virtual double area() const { return 0; } virtual double circumference() const { return 0; } virtual char * getName() const { return "Figura"; }

};

Rekompilujemy, uruchamiamy i ...

Funkcja showFullInfo działa teraz poprawnie

Page 27: Wprowadzenie do programowania w języku C++

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

Copyright © Roman Simiński 27Strona :

PolimorfizmJęzyk C++Język C++

O tym która funkcja jest wywoływana decyduje kompilator na etapie kompilacji.

Wywołanie ma taką samą postać jak wywołanie klasycznych funkcji w języku C.

O tym która funkcja zostanie wywołana decyduje typ występujący w deklaracji zmiennej wskaźnikowej.

void showFullFigureInfo( Figure * fp ){ cout << fp->getName() << endl; cout << "Pole : " << fp->area() << endl; cout << "Obwod : " << fp->circumference() << endl; cout << endl;}

showFigureInfo( &s );showFigureInfo( &r );showFigureInfo( &t );

class Figure{ . . . virtual double area() const { return 0; } virtual double circumference() const { return 0; } virtual char * getName() const { return "Figura"; }};

Mimo, iż typ występujący w deklaracji wskaźnika to Figure, wywołane zostaną funkcje

należące do klasy obiektu wskazywanego przez wskaźnik fp. Przy wiązaniu dynamicznym istotny jest typ obiektu wskazywanego!

Page 28: Wprowadzenie do programowania w języku C++

Funkcje wirtualneFunkcje wirtualnePodstawy i języki programowaniaPodstawy i języki programowania

Copyright © Roman Simiński 28Strona :

PolimorfizmJęzyk C++Język C++

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.

Page 29: Wprowadzenie do programowania w języku C++

Wiązanie dynamiczne (późne)Wiązanie dynamiczne (późne)Podstawy i języki programowaniaPodstawy i języki programowania

Copyright © Roman Simiński 29Strona :

PolimorfizmJęzyk C++Język C++

O tym która funkcja jest wywoływana decyduje typ obiektu wskazywanego.

Funkcja wiązana dynamicznie musi być zadeklarowana jako wirtualna.

Wystarczy, że słowo kluczowe virtual wystąpi w deklaracji klasy bazowej.

+double area()+double circumference()

―double side

Square

Figure

+double area()+double circumference()

Figure * fp;Square s( 10 );

fp = &s;cout << fp->area() << endl;cout << fp->circumference() << endl;

Klasa Square przedefiniowała obie funkcje wirtualne. To one właśnie zostaną wywołane a nie funkcje z klasy bazowej.

Page 30: Wprowadzenie do programowania w języku C++

Jak wykorzystać późne wiązanie?Jak wykorzystać późne wiązanie?Podstawy i języki programowaniaPodstawy i języki programowania

Copyright © Roman Simiński 30Strona :

PolimorfizmJęzyk C++Język C++

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

Page 31: Wprowadzenie do programowania w języku C++

Jak reprezentować informacje o oknie?Jak reprezentować informacje o oknie?Podstawy i języki programowaniaPodstawy i języki programowania

Copyright © Roman Simiński 31Strona :

PolimorfizmJęzyk C++Język C++

const int itemNo = 4;

Figure * win[ itemNo ];

50 70

50100

win

50

50

70

50

50

100

70

100

Kwadrat Prostok tą Prostok tą Prostok tą

0 1 2 3

Page 32: Wprowadzenie do programowania w języku C++

Definiowanie elementów okna, obliczenia, sprzątanieDefiniowanie elementów okna, obliczenia, sprzątaniePodstawy i języki programowaniaPodstawy i języki programowania

Copyright © Roman Simiński 32Strona :

PolimorfizmJęzyk C++Język C++

// Okre lenie liczby elementówśconst int itemNo = 4;

// Tablica wka ników na elementy oknaźFigure * win[ itemNo ];

// Przydział pami ci dla elementów oknaęwin[ 0 ] = new Square( 50 );win[ 1 ] = new Rectangle( 50, 70 );win[ 2 ] = new Rectangle( 50, 100 );win[ 3 ] = new Rectangle( 70, 100 );

// Oblicz co trzeba i wyprowadz do str.wyj ciowegoścalcAndShowWinInfo( win, 4 );

// Zwolnij pami ć przydzielon elementom okna ę ąfor( int i = 0; i < itemNo; delete win[ i++] ) ;

Page 33: Wprowadzenie do programowania w języku C++

Jak to wygląda w pamięci operacyjnej?Jak to wygląda w pamięci operacyjnej?Podstawy i języki programowaniaPodstawy i języki programowania

Copyright © Roman Simiński 33Strona :

PolimorfizmJęzyk C++Język C++

win

Square

+double area()+double circumference()

―double side: 50

Rectangle

+double area()+double circumference()

―double height: 50―double width: 70

Rectangle

+double area()+double circumference()

―double height: 50―double width: 100

Rectangle

+double area()+double circumference()

―double height: 70―double width: 100

0 1 2 3

Page 34: Wprowadzenie do programowania w języku C++

Funkcja calcAndShowWinInfo Funkcja calcAndShowWinInfo Podstawy i języki programowaniaPodstawy i języki programowania

Copyright © Roman Simiński 34Strona :

PolimorfizmJęzyk C++Język C++

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(); }

// Wyprowadzanie wyników obliczeń cout << "Powierzchnia szyb : " << totalArea << endl; cout << "Dlugosc profili : " << totalCircum << endl; cout << endl;}

Page 35: Wprowadzenie do programowania w języku C++

Iteracja zliczającaIteracja zliczającaPodstawy i języki programowaniaPodstawy i języki programowania

Copyright © Roman Simiński 35Strona :

PolimorfizmJęzyk C++Język C++

for( int i = 0; i < numOfSash; i++ ){ totalArea += window[ i ]->area(); totalCircum += window[ i ]->circumference();}

win

Square

+double area()+double circumference()

―double side: 50

Rectangle

+double area()+double circumference()

―double height: 50―double width: 70

Rectangle

+double area()+double circumference()

―double height: 50―double width: 100

Rectangle

+double area()+double circumference()

―double height: 70―double width: 100

i 0

0 1 2 3

double Square::area() const { return side * side; }double Square::circumference() const { return 4 * side; }`

Page 36: Wprowadzenie do programowania w języku C++

Iteracja zliczającaIteracja zliczającaPodstawy i języki programowaniaPodstawy i języki programowania

Copyright © Roman Simiński 36Strona :

PolimorfizmJęzyk C++Język C++

for( int i = 0; i < numOfSash; i++ ){ totalArea += window[ i ]->area(); totalCircum += window[ i ]->circumference();}

win

Square

+double area()+double circumference()

―double side: 50

Rectangle

+double area()+double circumference()

―double height: 50―double width: 70

Rectangle

+double area()+double circumference()

―double height: 50―double width: 100

Rectangle

+double area()+double circumference()

―double height: 70―double width: 100

i 1

0 1 2 3

double Rectangle::area() const { return width * height; }double Rectangle::circumference() const { return 2 * width + 2 * height; }

Page 37: Wprowadzenie do programowania w języku C++

Iteracja zliczającaIteracja zliczającaPodstawy i języki programowaniaPodstawy i języki programowania

Copyright © Roman Simiński 37Strona :

PolimorfizmJęzyk C++Język C++

for( int i = 0; i < numOfSash; i++ ){ totalArea += window[ i ]->area(); totalCircum += window[ i ]->circumference();}

win

Square

+double area()+double circumference()

―double side: 50

Rectangle

+double area()+double circumference()

―double height: 50―double width: 70

Rectangle

+double area()+double circumference()

―double height: 50―double width: 100

Rectangle

+double area()+double circumference()

―double height: 70―double width: 100

i 2

0 1 2 3

double Rectangle::area() const { return width * height; }double Rectangle::circumference() const { return 2 * width + 2 * height; }

Page 38: Wprowadzenie do programowania w języku C++

Iteracja zliczającaIteracja zliczającaPodstawy i języki programowaniaPodstawy i języki programowania

Copyright © Roman Simiński 38Strona :

PolimorfizmJęzyk C++Język C++

for( int i = 0; i < numOfSash; i++ ){ totalArea += window[ i ]->area(); totalCircum += window[ i ]->circumference();}

win

Square

+double area()+double circumference()

―double side: 50

Rectangle

+double area()+double circumference()

―double height: 50―double width: 70

Rectangle

+double area()+double circumference()

―double height: 50―double width: 100

Rectangle

+double area()+double circumference()

―double height: 70―double width: 100

i 3

0 1 2 3

double Rectangle::area() const { return width * height; }double Rectangle::circumference() const { return 2 * width + 2 * height; }

Page 39: Wprowadzenie do programowania w języku C++

Polimorfizm — krótkie podsumowaniePolimorfizm — krótkie podsumowaniePodstawy i języki programowaniaPodstawy i języki programowania

Copyright © Roman Simiński 39Strona :

PolimorfizmJęzyk C++Język C++

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.