Wykład 4

Funkcje i klasy zaprzyjaźnione

PrzeciąŜanie operatorów

Szablony funkcji

Szablony klas

Funkcje wirtualne

Programowanie obiektowe

1

Funkcje zaprzyjaźnione

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

Funkcje zaprzyjaźnione

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

Funkcje zaprzyjaźnione

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

Funkcje zaprzyjaźnione

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

Klasy zaprzyjaźnione

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

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

Programowanie obiektowe

7

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 3.8

Programowanie obiektowe

8

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;

Programowanie obiektowe

9

Referencje jako parametry

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

Zwracanie referencji

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

Zmienne referencyjne

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

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

Programowanie obiektowe

14

PrzeciąŜanie operatorów

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ąŜ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 parametr op2

...

operand przekazywany przez wskaźnik this

Programowanie obiektowe

16

PrzeciąŜanie operatorów

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

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

Szablony funkcji

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

Szablony funkcji

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

Szablony funkcji

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

Szablony funkcji

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

Szablony funkcji

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

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 4.6

Programowanie obiektowe

28

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

Programowanie obiektowe

29

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;

Programowanie obiektowe

30

Szablony klas

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

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

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 4.10

Programowanie obiektowe

33

Funkcje wirtualne

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

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

Funkcje wirtualne

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

Programowanie obiektowe

37