Funkcje i klasy zaprzyjaźnione
Wskaźnik
i t
h
t is
i
Przeciążanie operatorów
Programowanie obiektowe
1
Są to takie funkcje, które mimo, że nie są metodami klasy mają dostęp do jej składowych, 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:
cl
c a
l ss fig
i ura{
int x,y;
…….
friend void goniec(figura f)
};
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).
Programowanie obiektowe
2
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ą
Nie
i
e m
u
m si
i być
y
ć f
unkcj
c ą
ą s
kła
ł d
a ową
ą ż
a
ż d
a nej
e k
la
l s
a y,
y al
a e
l
e mo
m że
ż
e nią
i
ą b
yć
y
Może być napisana w zupełnie innym języku niż C++
Jest deklarowana w klasie ze słowem kluczowym friend i nie podlega
etykietom hermetyzacji ( public, private, protected)
Może być zdefiniowana w innej klasie i wtedy jest typu inline, ale nadal jest funkcją zaprzyjaźnioną.
Programowanie obiektowe
3
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
me
m c
e h
c an
a iz
i m
z o
m wi dzi
z e
i d
e zi
z c
i z
c e
z n
e ia
i
(w ty
t m
y
pr
p zy
z p
y ad
a k
d u „p
„ r
p z
r y
z j
y ac
a i
c e
i l
e
mo
m j
o eg
e o
przyjaciela nie jest moim przyjacielem” );
Z zasady umieszcza się funkcje zaprzyjaźnione na początku wszystkich deklaracji w klasie;
Programowanie obiektowe
4
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 wszystkich (także prywatnych) składników drugiej klasy.
Programowanie obiektowe
5
Funkcje i klasy zaprzyjaźnione
Przykład programowy
Program 4.1
Program 4.2
Programowanie obiektowe
6
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
Funkcja musi odszukać obiekt, aby wykonać operację na jego rzecz. Robi to tak, że korzysta z niejawnego wskaźnika this, który jest inicjowany w momencie pojawienia się operatora kropki po nazwie obiektu.
Wskaźnik this wskazuje, na którym egzemplarzu (konkrecie) obiektów klasy funkcja ma wykonać swoje czynności.
Przykład
Program 4.3
Programowanie obiektowe
7
pwr::pwr(double base, int exp)
{
b = base;
e = exp;
val = 1;
if(exp==0) return;
for(
r ; ex
e p>0
> ; ex
e p--) 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;
}
Programowanie obiektowe
8
Funkcje zaprzyjaźnione a wskaźnik this
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).
Programowanie obiektowe
9
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ą.
Programowanie obiektowe
10
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 jes
e t kopia
i ar
a g
r ume
m n
e tu
t ;
Przykład:
Program 4.4
Programowanie obiektowe
11
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 ar
a g
r ume
m n
e tu
t ; mo
m żn
ż a to
t rea
e l
a i
l z
i o
z wać
a na dwa sposoby:
y
jawne przekazanie wskaźnika do parametru;
posłużenie się się tzw. parametrem referencyjnym;
Programowanie obiektowe
12
Przykład jawnego przekazania wskaźnika do parametru Program 4.5
Przykład użycia parametru referencyjnego
Program 4.6
Programowanie obiektowe
13
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ś
e li
l nie
i ch
c ce
c m
e y
m ,
y ab
a y des
e tr
t uk
u to
t r był
y uak
a ty
t w
y ni
n a
i n
a y,
y mo
m że
ż m
e y
m prz
r e
z k
e az
a a
z ć
a ob
o ie
i k
e t
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
c:
c:
Program 4.7a
Program 4.7b
Programowanie obiektowe
14
Funkcja może zwracać referencję;
W konsekwencji funkcja może występować z lewej strony instrukcji przypisania!
Przykład
Program 4.8
Programowanie obiektowe
15
Referencję można zastosować jako samodzielna zmienną;
Zmienna referencyjna jest tworzona jako nowa nazwa dla istniejącej zmiennej (tzw. przezwisko);
Podczas tworzenia zmiennej referencyjnej obowiązkowa jest jej inicjacja;
Przy
z k
y ła
ł d
a
Program 4.9
Programowanie obiektowe
16
Z przeciążaniem funkcji ściśle związane jest zagadnienie przeciążania operatorów
W jęz
ę y
z k
y u C+
C +
+
mo
m żn
ż a
pr
p ze
z c
e i
c ą
i ż
ą y
ż ć
y
wi
w ę
i k
ę szo
z ść op
o er
e at
a o
t ró
r w ta
t k
a , ab
a y
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 Programowanie obiektowe
17
Operator można przeciążyć tworząc tzw. funkcję operatora :
będącą składową klasy,
nie będącą składową klasy, ale będącą funkcją zaprzyjaźnioną (z klasą)
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 Programowanie obiektowe
18
Ogólna składnia funkcji operatora , będącej składową klasy: zwracany_typ nazwa_klasy::operator # (lista_argumentów)
{
//operacje
symbol operatora
}
Lista argumentów może być pusta (w przypadku operatorów jednoargumentowych)
Przykład
Program 4.10
Programowanie obiektowe
19
// Przeciążenie operatora + dla klasy loc
loc loc::operator+(loc op2) {
loc temp;
temp.longitude = op2.longitude + longitude;
temp.latitude = op2.latitude + latitude;
ret
e u
t rn te
t m
e p
m ;
}
int main() {
loc ob1(10, 20), ob2( 20, 30);
ob1.show(); // wyświetla 10 20
ob2.show(); // wyświetla 20 30
ob3 = ob1 + ob2;
operand przekazywany przez parametr op2
...
operand przekazywany przez wskaźnik this
Programowanie obiektowe
20
W kolejnym programie przykładowym przeciążone zostaną trzy operatory dwuargumentowe (+, −, =) oraz jeden operator jednoargumentowy (++) w formie przedrostkowej
Przykład
Program 4.11
Programowanie obiektowe
21
Operatory przyrostowe - przypomnienie
Przykład
#include <iostream>
using namespace std;
int main(void) {
int i, j;
i =
1
0
1 ;
0
j = i++; // Najpierw przypisanie, potem inkrementacja
/* wyświetlenie wartości zmiennych i oraz j */
cout << "i=" << i;
cout << ", j=" << j;
getchar(); // Zatrzymanie okna konsoli
return 0;
}
Program 4.12
Programowanie obiektowe
22
Operatory przyrostowe - przypomnienie
Przykład
#include <iostream>
using namespace std;
int main(void) {
int i, j;
i =
1
0
1 ;
0
j = ++i;
// Najpierw inkrementacja, potem przypisanie
/* Wyświetlenie wartości zmiennych i oraz j */
cout << "i=" << i;
cout << ", j=" << j;
getchar(); // Zatrzymanie okna konsoli
return 0;
}
Program 4.13
Programowanie obiektowe
23
Formy przedrostkowe i przyrostkowe przeciążonych operatorów inkrementacji i dekrementacji
Inkrementacja w formie przedrostkowej
typ operator++() {
// ciało operatora w formie przedrostkowej
}
Inkrementacja w formie przyrostkowej
typ operator++(int x) {
// ciało
o op
o e
p rato
t r
o a w f
o
f r
o mi
m e pr
p zyr
y os
o tk
t ow
o ej
}
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
Program 4.14
}
Programowanie obiektowe
24
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 jaw
a ny
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 4.15
Programowanie obiektowe
25
26