1
Programowanie obiektowe
Wykład 5-6
Konstruktory kopiuj
ą
ce
Klasy zaprzyja
ź
nione
Wska
ź
nik this
Przeci
ąŜ
anie operatorów
Funkcje wirtualne
Szablony funkcji
Szablony klas
2
Programowanie obiektowe
Jedną z najwaŜniejszych postaci konstruktorów przeciąŜonych są tzw.
konstruktory kopiujące
Taki konstruktor tworzy kopię innego, juŜ istniejącego wśród obiektów
danej klasy
Ogólna postać deklaracji konstruktora kopiującego:
klasa::klasa(klasa& obiekt);
lub
klasa::klasa(const klasa& obiekt);
Pozostałe argumenty konstruktora (jeśli występują) są domyślne.
Przykłady deklaracji konstruktorów kopiujących:
X::X(X&);
lub
X::X(X&, float=3.1415, int=0)
;
Konstruktor kopiujący
3
Programowanie obiektowe
Konstruktorem kopiującym w danej klasie jest konstruktor, który moŜna
wywołać z jednym argumentem typu referencja obiektu danej klasy:
klasa::klasa(klasa &)
klasa::klasa(const klasa &)
Konstruktor kopiujący wprowadza obiekty identyczne z juŜ istniejącymi,
czyli ich kopie (konstruowanie obiektu na podstawie wzoru).
Konstruktor kopiujący moŜe być wywołany niejawnie:
1.
W sytuacji gdy do funkcji jest przekazywany przez wartość obiekt
klasy X. Wówczas tworzona jest kopia tego obiektu.
2.
W sytuacji kiedy funkcja zwraca przez wartość obiekt klasy X.
Wtedy takŜe tworzona jest kopia obiektu.
To, Ŝe konstruktor kopiujący podaje obiekt kopiowany przez referencję daje
mu moŜliwość zmiany zawartości obiektu klasy!!
Konstruktor kopiujący
4
Programowanie obiektowe
Nie moŜna pominąć referencji w konstruktorze kopiującym, bo gdyby
konstruktor X wywoływał obiekty swojej klasy X przez wartość, czyli
wytwarzałby swoją kopię, to powstaje nie zamknięta pętla tworzenia kopii.
Konstruktor kopiujący moŜe uszkodzić oryginał!!
Zabezpieczamy się przed taką sytuacją następująco:
X::X(const X& obiekt)
Teraz konstruktor X wie, Ŝe obiekt klasy X jest jest typu const, czyli nie
moŜe zmienić sam siebie.
Konstruktor kopiujący
5
Programowanie obiektowe
Przykład programowy
Program 4.5
Konstruktor kopiujący
6
Programowanie obiektowe
Są to takie funkcje, które mimo, Ŝe nie są składnikami klasy mają dostęp do
jej składników czyli innych funkcji i zmiennych danej klasy
Mają dostęp takŜe do tych składników klasy, które są hermetyzowane
etykietą private
Funkcja zaprzyjaźniona jest wprowadzana słowem kluczowym friend
Sposób stosowania:
class figura{
int x,y;
…….
friend void goniec(figura f)
};
Funkcje zaprzyjaźnione
7
Programowanie obiektowe
Funkcja goniec(figura f) jest zdefiniowana gdzieś w programie w całkowicie
innym miejscu i nie jest funkcją składową klasy figura
W klasie figura {} chcemy z niej skorzystać nawet, jeśli przynaleŜy ona do
innej klasy (wtedy poprawnie jest taką funkcję umieścić w sekcji public w jej
klasie).
Cechy funkcji zaprzyjaźnionych:
Funkcja moŜe być zaprzyjaźniona z kilkoma klasami
Na argumentach jej wywołania moŜe wykonywać operacje zgodnie ze
swoją definicją
MoŜe być napisana w zupełnie innym języku niŜ C++ i dlatego moŜe
nie być funkcją składową klasy.
Funkcje zaprzyjaźnione
8
Programowanie obiektowe
PoniewaŜ funkcja typu friend nie jest składnikiem klasy, to nie ma
wskaźnika this czyli musi się posłuŜyć operatorem jawnego wskaźnika lub
przypisania, aby wykonać działania (takŜe te na składniku klasy, z którą jest
zaprzyjaźniona).
Jest deklarowana w klasie ze słowem kluczowym friend i nie podlega
etykietom hermetyzacji (public, private, protected)
MoŜe być cała zdefiniowana w klasie i wtedy jest typu inline, ale nadal jest
funkcją zaprzyjaźnioną.
Nie musi być funkcją składową Ŝadnej klasy, ale moŜe nią być
Funkcje zaprzyjaźnione
9
Programowanie obiektowe
Klasa moŜe się przyjaźnić z wieloma funkcjami, które są lub nie są
składnikami innych klas;
Funkcje zaprzyjaźnione nie są przechodnie, czyli zaprzyjaźnienie nie
przenosi się
z
klasy do klasy, tzn. zaprzyjaźnienie nie podlega
mechanizmowi dziedziczenia (w tym przypadku „przyjaciel mojego
przyjaciela nie jest moim przyjacielem” );
Z zasady umieszcza się funkcje zaprzyjaźnione na początku wszystkich
deklaracji w klasie;
Dopuszcza się stosowanie słowa kluczowego friend do definiowania klas
zaprzyjaźnionych; w takim przypadku wszystkie funkcje składowe klasy
zaprzyjaźnionej mają dostęp do prywatnych składników drugiej klasy.
Funkcje zaprzyjaźnione
10
Programowanie obiektowe
Przykład programowy
Program 4.6
Funkcje i klasy zaprzyjaźnione
Program 4.7
11
Programowanie obiektowe
Wskaźnik this
Podczas wywoływania funkcji składowej jest do niej automatycznie
przekazywany niejawny wskaźnik do obiektu, na rzecz którego realizowane
jest wywołanie funkcji; wskaźnik ten nazywa się this
Przykład
Program 4.8
Funkcja musi odszukać obiekt, aby wykonać operację na jego rzecz. Robi to
tak, Ŝe korzysta z ukrytego wskaźnika this, który jest inicjowany w
momencie pojawienia się operatora kropki po nazwie obiektu.
Ten wskaźnik pokazuje funkcji na którym egzemplarzu (konkrecie)
obiektów klasy ma wykonać swoje czynności.
12
Programowanie obiektowe
Wskaźnik this
pwr::pwr(double base, int exp)
{
b = base;
e = exp;
val = 1;
if(exp==0) return;
for( ; exp>0; exp--) val = val * b;
}
pwr::pwr(double base, int exp)
{
this->b = base;
this->e = exp;
this->val = 1;
if(exp==0) return;
for( ; exp>0; exp--)
this->val = this->val * this->b;
}
13
Programowanie obiektowe
Referencje
Język C++ posiada dodatkową cechę związana ze wskaźnikami - referencję;
Zasadniczo referencja to niejawny wskaźnik;
MoŜna ja wykorzystywać na trzy sposoby:
1)
jako parametr funkcji,
2)
jako zwracaną wartość,
3)
jako zmienną referencyjną.
14
Programowanie obiektowe
Referencje jako parametry
W momencie wywołania funkcji jej parametry mogą być przekazywane na
dwa sposoby: przez wartość i przez referencję;
Podczas przekazywania parametru przez wartość do funkcji przekazywana
jest kopia argumentu;
Przykład:
Program 4.9a
15
Programowanie obiektowe
Referencje jako parametry
WaŜnym zastosowaniem referencji jest moŜliwość definiowania funkcji,
wykorzystujących mechanizm przekazywania parametrów przez referencję;
Przekazywanie przez referencję polega na przekazaniu do funkcji wskaźnika
do argumentu; moŜna to realizować na dwa sposoby:
jawne przekazanie wskaźnika do parametru;
posłuŜenie się się tzw. parametrem referencyjnym;
16
Programowanie obiektowe
Referencje jako parametry
Przykład jawnego przekazania wskaźnika do parametru
Program 4.10
Przykład uŜycia parametru referencyjnego
Program 4.9
17
Programowanie obiektowe
Przekazywanie obiektów przez referencję
Przekazywanie obiektu jako argumentu funkcji polega na przekazaniu jego
kopii;
Po zakończeniu funkcji kopia jest niszczona i wywoływany jest destruktor
tej kopii;
Jeśli nie chcemy, aby destruktor był uaktywniany, moŜemy przekazać
obiekt do funkcji przez referencję;
Podczas przekazywania obiektu przez referencję kopia obiektu nie jest
tworzona (w konsekwencji nie ma jej niszczenia i nie jest wywoływany
destruktor obiektu);
Przykład
Program 4.11
c:
18
Programowanie obiektowe
Zwracanie referencji
Funkcja moŜe zwracać referencję;
W konsekwencji funkcja moŜe występować z lewej strony instrukcji
przypisania!
Przykład
Program 4.12
19
Programowanie obiektowe
Zmienne referencyjne
Referencję moŜna zastosować jako samodzielna zmienną;
Zmienna referencyjna jest tworzona jako nowa nazwa dla istniejącej
zmiennej (przezwisko);
Podczas tworzenia zmiennej referencyjnej obowiązkowa jest jej inicjacja;
Przykład
Program 4.13
20
Programowanie obiektowe
PrzeciąŜanie operatorów
Z przeciąŜaniem funkcji ściśle związane jest zagadnienie przeciąŜania operatorów
W języku C++ moŜna przeciąŜyć większość operatorów tak, aby wykonywały
zadania charakterystyczne dla danej klasy, np. dla klasy stos operator + moŜe być
wykorzystany do dodawania elementu na stos, a operator – do zdejmowania
elementu ze stosu
Po przeciąŜeniu odpowiednich operatorów moŜna posługiwać się obiektami w
wyraŜeniach tak samo jak zmiennymi typów wbudowanych
Operator moŜna przeciąŜyć tworząc funkcję operatora
Funkcja operatora definiuje, jakie operacje na obiektach wskazanej klasy ma
wykonywać operator
Do tworzenia funkcji operatora słuŜy słowo kluczowe operator
Funkcja operatora moŜe, ale nie musi, być składową klasy
Funkcje operatora nie będące składowymi klasy są najczęściej jej funkcjami
zaprzyjaźnionymi
21
Programowanie obiektowe
PrzeciąŜanie operatorów
Ogólna składnia funkcji operatora, będącej składową klasy:
zwracany_typ nazwa_klasy::operator # (lista_argumentów)
{
//operacje
}
Lista argumentów moŜe być pusta (w przypadku operatorów
jednoargumentowych)
Przykład
symbol operatora
Program 5.1
22
Programowanie obiektowe
PrzeciąŜanie operatorów
// PrzeciąŜenie operatora + dla klasy loc
loc loc::operator+(loc op2) {
loc temp;
temp.longitude = op2.longitude + longitude;
temp.latitude = op2.latitude + latitude;
return temp;
}
int main() {
loc ob1(10, 20), ob2( 20, 30);
ob1.show();
// wyświetla 10 20
ob2.show();
// wyświetla 20 30
ob1 = ob1 + ob2;
...
operand przekazywany przez wskaźnik this
operand przekazywany przez parametr op2
23
Programowanie obiektowe
PrzeciąŜanie operatorów
W kolejnym programie przykładowym przeciąŜone zostaną trzy operatory
dwuargumentowe (+,
−
, =) oraz jeden operator jednoargumentowy (++)
w formie przedrostkowej
Przykład
Program 5.2
24
Programowanie obiektowe
Operatory przyrostowe - przypomnienie
Przykład
#include <iostream>
using namespace std;
int main(void) {
int i, j;
i = 10;
j = i++;
/* wy
ś
wietlenie warto
ś
ci zmiennych i oraz j */
cout << "i=" << i;
cout << ", j=" << j;
getchar();
// Zatrzymanie okna konsoli
return 0;
}
Program 5.3
// Najpierw przypisanie, potem inkrementacja
25
Programowanie obiektowe
Przykład
#include <iostream>
using namespace std;
int main(void) {
int i, j;
i = 10;
j = ++i;
/* Wy
ś
wietlenie warto
ś
ci zmiennych i oraz j */
cout << "i=" << i;
cout << ", j=" << j;
getchar();
// Zatrzymanie okna konsoli
return 0;
}
Program 5.4
Operatory przyrostowe - przypomnienie
// Najpierw inkrementacja, potem przypisanie
26
Programowanie obiektowe
Inkrementacja w formie przedrostkowej
typ operator++() {
// ciało operatora w formie przedrostkowej
}
Inkrementacja w formie przyrostkowej
typ operator++(int x) {
// ciało operatora w formie przyrostkowej
}
Dekrementacja w formie przedrostkowej
typ operator
−−−− −−−−
() {
// ciało operatora w formie przedrostkowej
}
Dekrementacja w formie przyrostkowej
typ operator
−−−− −−−−
(int x) {
// ciało operatora w formie przyrostkowej
}
Formy przedrostkowe i przyrostkowe przeciąŜonych operatorów
inkrementacji i dekrementacji
Program 5.2a
27
Programowanie obiektowe
PrzeciąŜanie operatorów za pomocą funkcji zaprzyjaźnionych
Operator moŜna przeciąŜyć takŜe posługując się funkcjami nie będącymi
składowymi klasy
W tym celu najczęściej stosuje się funkcje zaprzyjaźnione
Funkcje zaprzyjaźnione nie są składowymi klasy, nie jest więc do nich
przekazywany wskaźnik this
Dlatego do zaprzyjaźnionej funkcji operatora operandy przekazywane są w
sposób jawny
Oznacza to, Ŝe funkcja zaprzyjaźniona słuŜąca do przeciąŜania operatora
dwuargumentowego ma dwa parametry, a funkcja zaprzyjaźniona
przeciąŜająca operator jednoargumentowego ma jeden parametr
Podczas przeciąŜania operatora dwuargumentowego za pomocą funkcji
zaprzyjaźnionej lewy operand przekazywany jest jako pierwszy, a prawy –
jako drugi
Przykład
Program 5.5
28
Programowanie obiektowe
Funkcje wirtualne
Polimorfizm jest obsługiwany przez język C++ zarówno na etapie
kompilacji (przeciąŜanie funkcji i operatorów), jak i na etapie wykonania
(dziedziczenie i funkcje wirtualne)
Funkcja wirtualna to metoda składowa zadeklarowana w klasie bazowej
a zdefiniowana w klasie pochodnej
Aby utworzyć funkcję wirtualną naleŜy jej deklaracje w klasie bazowej
poprzedzić słowem kluczowym virtual
Zasadę, pozwalającą funkcjom wirtualnym realizować polimorfizm
określamy w skrócie jako „jeden interfejs, wiele metod”
W klasie bazowej ma miejsce definicja intejfejsu, kaŜda definicja funkcji
wirtualnej w klasie pochodnej to implementacja funkcji specyficznych dla
danej klasy pochodnej
29
Programowanie obiektowe
Funkcje wirtualne
Funkcję wirtualną moŜna wywoływać w „normalny sposób”, tzn.
wykorzystując nazwę obiektu i operator kropki
Do wskazywania obiektów klas pochodnych moŜna wykorzystać wskaźnik
ich klasy bazowej
Wówczas kompilator C++ decyduje o wyborze wersji funkcji na podstawie
typu obiektu wskazywanego przez ten wskaźnik; wybór odbywa się na
etapie wykonania programu
Oznacza to, Ŝe wskazanie róŜnych obiektów spowoduje wskazanie róŜnych
wersji funkcji wirtualnej
Przykład
Program 6.1
30
Programowanie obiektowe
Funkcje wirtualne
Atrybut virtual jest dziedziczony
Oznacza to, Ŝe bez względu na to, ile razy jest dziedziczona funkcja
wirtualna pozostaje funkcją wirtualną
Przykład
Program 6.2
31
Programowanie obiektowe
Funkcje wirtualne
Funkcje wirtualne są hierarchiczne
Funkcja zadeklarowana w klasie bazowej jako virtual moŜe być
przesłonięta (tj. przedefiniowana) w klasie pochodnej, ale nie musi być tak
zawsze
Jeśli w klasie pochodnej funkcja wirtualna nie zostanie przesłonięta, wtedy
obiekty tej klasy odwołujące się do takiej funkcji wirtualnej będą
wykorzystywały funkcję zdefiniowana w klasie bazowej
Przykład
Program 6.3
32
Programowanie obiektowe
Funkcje wirtualne
Przykład: konwersja litrów na galony i temperatury w stopniach Fahrenheita
na stopnie Celsjusza z wykorzystaniem funkcji wirtualnych
Program 6.4
33
Programowanie obiektowe
Szablony
Szablony są jedną z najbardziej wyrafinowanych i najbardziej efektywnych
cech języka C++
Zostały dodane do specyfikacji języka zaledwie kilka lat temu
Dzięki szablonom moŜliwe jest tworzenie tzw. ogólnych definicji funkcji
i klas
W ogólnych funkcjach lub klasach typ danych, na których operuje funkcja
lub klasa jest określany jako parametr
W konsekwencji moŜna stworzyć funkcję lub klasę, przystosowaną do pracy
z kilkoma róŜnymi typami danych, bez konieczności jawnego
redefiniowania specyfikacji dla poszczególnych typów
Funkcja moŜe być zatem w pewnym stopniu inteligentna: moŜe
samodzielnie dobrać zarówno typ argumentów, jak typ wyniku samej
funkcji!
34
Programowanie obiektowe
Szablony funkcji
Funkcję ogólną (szablon funkcji) tworzymy posługując się słowem
kluczowym template
template <class Ttype > typ_zwracany nazwa_funkcji(lista parametrów)
{
// ciało funkcji
}
gdzie:
Ttype – symboliczna nazwa typu danych, wykorzystywanych przez
funkcję (podczas tworzenia konkretnej wersji funkcji kompilator
zamienia ten typ na rzeczywisty typ danych)
class - słowo kluczowe konieczne, aby powstał szablon;
Uwaga:
Jeśli parametrów szablonu jest więcej niŜ jeden, to po przecinku
powtarzamy dla słowo class i podajemy kolejną nazwę parametru;
35
Programowanie obiektowe
Funkcje ogólne są podobne do funkcji przeciąŜonych, ale podczas pracy
z nimi obowiązuje więcej ograniczeń
W odróŜnieniu od funkcji przeciąŜonej funkcja ogólna musi we wszystkich
wersjach wykonywać te same operacje (tyle, Ŝe na zmiennych róŜnych
typów)
Nazwa szablonu musi być zdefiniowana w zakresie globalnym, czyli na
zewnątrz wszystkich funkcji i klas.
Parametr szablonu musi wystąpić jako typ argumentu funkcji definiowanej
tym szablonem.
WNIOSEK: nie moŜna wprost zadać szablonem funkcji o typie innym niŜ
typ jej argumentów; jest to moŜliwe poprzez specjalne obejście ograniczeń
języka.
Parametrem szablonu funkcji moŜe być typ obiektu czyli nazwa klasy.
Definicja szablonu nie powoduje jeszcze utworzenia funkcji szablonowej.
Zostanie ona utworzona dopiero po wystąpieniu w kodzie nazwy tej
funkcji. Utworzenie odbędzie się zgodnie z „recepturą” zapisaną w
szablonie.
Szablony funkcji
36
Programowanie obiektowe
Nazwa funkcji szablonowej nie powinna pokrywać się z innymi nazwami
zmiennych i funkcji globalnych.
Operacja zapisana w funkcji poddana jest takim samym regułom na
poprawność operacji jak we wszystkich innych funkcjach, czyli nie wykona
się na przykład operacja arytmetyczna na zmiennych znakowych.
Parametr szablonu – nazwany podczas deklarowania szablonu – nie musi
mieć tej samej nazwy podczas definiowania szablonu.
Dwa szablony o takiej samej nazwie mogą wystąpić w tym samym kodzie;
naleŜy tylko uwaŜać, aby jeden nie był szczególnym przypadkiem drugiego
(wówczas linker nie wiedziałby, z którego ma skorzystać)
Szablony funkcji
37
Programowanie obiektowe
Szablon wstawiając do wzorca funkcji róŜne typy argumentów realizuje tak
naprawdę przeciąŜenie nazwy funkcji.
Sam szablon teŜ moŜe być przeciąŜony czyli w tym samym zakresie
waŜności moŜe wystąpić dwa lub kilka razy z tą sama nazwą, ale róŜnymi
parametrami, np.:
template <class typ> void funkcja (typ, int);
template <class typ> void funkcja (typ, int, float, char);
Szablony funkcji
38
Programowanie obiektowe
Szablon jest deklarowany globalnie, ale stosowany lokalnie; dlatego nie
powinien uŜywać nazw zmiennych globalnych
UWAGA: szablony ciągle są nowością: w róŜnych środowiskach języka
C++, a szczególnie w zakresie pracy linkerów mogą występować problemy
W szablonie moŜemy stosować kwalifikatory inline, extern, static.
Pamiętajmy jednak, Ŝe słowo to odnosi się ostatecznie nie do szablonu ale
do funkcji, która wg tego szablonu zostanie zbudowana:
Przykład
template <class bb> inline bb wieksza (bb z1, bb z2)
{
return (z1>z2)? z1:z2;
}
Szablony funkcji
39
Programowanie obiektowe
Szablony funkcji
Funkcje ogólne (szablony funkcji) są bardzo uŜyteczne
MoŜna je stosować w tych sytuacjach, kiedy róŜne funkcje wykorzystują
ten sam ogólny algorytm
Przykład: funkcja ogólna, realizująca sortowanie bąbelkowe
Program 6.7
40
Programowanie obiektowe
Sortowanie przez zamianę (bąbelkowe)
44
Klucze
pocz
ą
tkowe
55
i = 2
42
i = 3
18
i = 5
06
94
i = 4
67
44
12
42
18
06
94
67
06
06
K r o k i a l g o r y t m u
12
55
55
18
94
42
67
44
44
55
42
18
67
94
12
12
06
44
55
42
18
67
94
12
06
44
55
42
18
67
94
12
i = 6
06
44
55
42
18
67
94
12
i = 7
06
44
55
42
18
67
94
12
i = 8
41
Programowanie obiektowe
Szablony klas
Oprócz funkcji ogólnych (szablonów funkcji) w języku C++ moŜna takŜe
definiować szablony klas (klasy ogólne)
W takim przypadku tworzona klasa zawiera definicje wszystkich
wykorzystywanych przez nią algorytmów, jednak typ danych, na których
klasa operuje, zostanie przekazany do niej jako parametr dopiero w chwili
tworzenia obiektów
42
Programowanie obiektowe
Szablony klas
Ogólna składnia szablonu klasy:
template <class Ttype > class nazwa_klasy
{
// ciało klasy
}
gdzie Ttype oznacza nazwę typu, który zostanie określony podczas tworzenia
obiektu (egzemplarza klasy)
MoŜna zdefiniować więcej niŜ jeden typ ogólny: wówczas kolejne typy są
oddzielane od siebie przecinkami;
Po utworzeniu klasy ogólnej moŜna stworzyć obiekt (egzemplarz klasy),
posługując się składnią:
nazwa_klasy <typ_rzeczywisty> nazwa_obiektu;
43
Programowanie obiektowe
Szablony klas
Przykład 1: szablon klasy: stos ogólny
Przykład 2: szablon klasy z dwoma typami ogólnymi
Program 6.8
Program 6.9
44
Programowanie obiektowe
Szablony klas
PrzeciąŜanie operatora []
Przykład 3: szablon klasy: ogólna, bezpieczna tablica
Program 6.10a
Program 6.10b
Program 6.10
45
Programowanie obiektowe
Szablony klas
W szablonach klas moŜna posługiwać się takŜe argumentami, które nie
słuŜą do określenia typu
Składnia szablonu, w przypadku uŜycia takiego parametru nie ulega zmianie
Program 6.11
46
Programowanie obiektowe
Szablony klas
W szablonach klas moŜna definiować argumenty domyślne, związane z
typem ogólnym, np.
template <clas X=int> class MojaKlasa( ...
Dopuszcza się takŜe definiowanie wartości domyślnych dla argumentów nie
słuŜących do określania typu
Wartość domyślna jest wykorzystywana wtedy, gdy podczas tworzenia
obiektu (egzemplarza klasy) Ŝadna wartość nie zostanie wyspecyfikowana w
sposób jawny
Wartości domyślne dla argumentów nie słuŜących do określania typu
definiuje się w taki sam sposób, jak dla standardowych argumentów funkcji
Przykład
Program 6.12
47
Programowanie obiektowe