Funkcje i klasy zaprzyjaźnione
PrzeciąŜanie operatorów
Szablony funkcji
Szablony klas
Funkcje wirtualne
Programowanie obiektowe
1
Są to takie funkcje, które mimo, Ŝe nie są częścią klasy mają dostęp do jej składników czyli innych funkcji, zmiennych i obiektów
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)
};
Programowanie obiektowe
2
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.
Programowanie obiektowe
3
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ć
Programowanie obiektowe
4
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;
Przykład programowy
Program 3.6
Programowanie obiektowe
5
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.
Przykład programowy
Program 3.7
Programowanie obiektowe
6
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
7
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 3.8
Programowanie obiektowe
8
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;
Programowanie obiektowe
9
Przykład jawnego przekazania wskaźnika do parametru
Program 3.9
Przykład uŜycia parametru referencyjnego
Program 3.10
Programowanie obiektowe
10
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
c:
Program 3.11
Programowanie obiektowe
11
Funkcja moŜe zwracać referencję;
W konsekwencji funkcja moŜe występować z lewej strony instrukcji przypisania!
Przykład
Program 3.12
Programowanie obiektowe
12
Referencję moŜna zastosować jako samodzielną 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 3.13
Programowanie obiektowe
13
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
Programowanie obiektowe
14
Ogólna składnia funkcji operatora , będącej składową klasy: zwracany_typ nazwa_klasy::operator#(lista_argumentów)
{
symbol operatora
//operacje
}
Lista argumentów moŜe być pusta (w przypadku operatorów
jednoargumentowych)
Przykład
Program 4.1
Programowanie obiektowe
15
// 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 parametr op2
...
operand przekazywany przez wskaźnik this
Programowanie obiektowe
16
W kolejnym programie przykładowym przeciąŜone zostaną trzy operatory dwuargumentowe (+, −, =) oraz jeden operator jednoargumentowy (++)
Przykład
Program 4.2
Programowanie obiektowe
17
Operatory przyrostowe - przypomnienie
Przykład
#include <stdio.h>
int main(void) {
int i, j;
i = 10;
j = i++;
// Najpierw przypisanie, potem inkrementacja
/* wyświetlenie wartości zmiennych i oraz j */
printf("i = %d",i);
printf(", j= %d", j);
getchar();
return 0;
}
Program 4.3
Programowanie obiektowe
18
Operatory przyrostowe - przypomnienie
Przykład
#include <stdio.h>
int main(void) {
int i, j;
i = 10;
j = ++i;
// Najpierw inkrementacja, potem przypisanie
/* Wyświetlenie wartości zmiennych i oraz j */
printf("i = %d",i);
printf(", j= %d", j);
getchar();
return 0;
}
Program 4.4
Programowanie obiektowe
19
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 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
}
Programowanie obiektowe
20
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 4.5
Programowanie obiektowe
21
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 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!
Programowanie obiektowe
22
Funkcje ogólne 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; Programowanie obiektowe
23
Funkcje ogólne sa podobne do funkcji przeciąŜonych, ale podczas pracy z nimi obowiązuje więcej ograniczeń
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.
Programowanie obiektowe
24
Argumenty są do funkcji wstawiane takie jak przy jej wywołaniu w kodzie, czyli to wtedy jest uŜyty ich właściwy typ i utworzony zgodnie z funkcją jej typ.
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 nazwy mogą wystąpić w tym samym kodzie; naleŜy tylko uwaŜać, aby jeden nie był szczególnym przypadkiem drugiego (wówczas linker wiedział byz którego ma skorzystać)
Programowanie obiektowe
25
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);
Programowanie obiektowe
26
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ć przydomki 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:
template <class bb> inline bb wieksza (bb z1, bb z2)
{
return (z1>z2)? z1:z2;
}
Programowanie obiektowe
27
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 4.6
Programowanie obiektowe
28
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
Programowanie obiektowe
29
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;
Programowanie obiektowe
30
Przykład: stos ogólny
Program 4.7
Przykład: szablon klasy z dwoma typami ogólnymi
Program 4.8
Przykład: szablon klasy: ogólna, bezpieczna tablica
Program 4.9
Programowanie obiektowe
31
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 deklarację 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
Programowanie obiektowe
32
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 4.10
Programowanie obiektowe
33
Atrybut virtual jest dziedziczony
Oznacza to, Ŝe bez względu na to, ile razy jest dziedziczona funkcja wirtualna pozostaje ona funkcją wirtualną
Przykład
Program 4.11
Programowanie obiektowe
34
Funkcje wirtualne są hierarchiczne
Funkcja zadeklarowana w klasie bazowej jako virtual moŜe być przesłonięta w klasie pochodnej lub nie;
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 4.12
Programowanie obiektowe
35
Przykład:
konwersja litrów na galony i temperatury w stopniach Fahrenheita na
stopnie Celsjusza z wykorzystaniem funkcji wirtualnych
Program 4.13
Programowanie obiektowe
36
37