Wstęp do programowania obiektowego, wykład 7

Podobne dokumenty
TEMAT : KLASY POLIMORFIZM

Zaawansowane programowanie w języku C++ Programowanie obiektowe

2.4 Dziedziczenie. 2.4 Dziedziczenie Przykłady programowania w C - kurs podstawowy

TEMAT : KLASY DZIEDZICZENIE

Podczas dziedziczenia obiekt klasy pochodnej może być wskazywany przez wskaźnik typu klasy bazowej.

PARADYGMATY PROGRAMOWANIA Wykład 4

Podstawy algorytmiki i programowania - wykład 4 C-struktury

Wstęp do programowania

Składnia C++ Programowanie Obiektowe Mateusz Cicheński

Podstawy programowania skrót z wykładów:

Techniki Programowania wskaźniki

Wstęp do programowania

Programowanie w C++ Wykład 4. Katarzyna Grzelak. 19 marca K.Grzelak (Wykład 1) Programowanie w C++ 1 / 37

Wykład 9: Polimorfizm i klasy wirtualne

Programowanie proceduralne w języku C++ Funkcje

Programowanie - wykład 4

Wstęp do programowania obiektowego. WYKŁAD 3 Dziedziczenie Pola i funkcje statyczne Funkcje zaprzyjaźnione, this

Informatyka I. Klasy i obiekty. Podstawy programowania obiektowego. dr inż. Andrzej Czerepicki. Politechnika Warszawska Wydział Transportu 2018

Programowanie 2. Język C++. Wykład 9.

Szablony klas, zastosowanie szablonów w programach

Techniki Programowania wskaźniki 2

dr inż. Jarosław Forenc

> C++ wskaźniki. Dane: Iwona Polak. Uniwersytet Śląski Instytut Informatyki 26 kwietnia 2017

C++ - polimorfizm. C++ - polimorfizm. C++ - polimorfizm. C++ - polimorfizm. C++ - polimorfizm POLIMORFIZM

Wyjątki (exceptions)

1 Wskaźniki. 1.1 Główne zastosowania wskaźników

C-struktury wykład. Dorota Pylak

Kurs programowania. Wykład 1. Wojciech Macyna. 3 marca 2016

1. Wartość, jaką odczytuje się z obszaru przydzielonego obiektowi to: a) I - wartość b) definicja obiektu c) typ oboektu d) p - wartość

Struktury Struktura polami struct struct struct struct

Szablony. Szablony funkcji

Podstawy informatyki. Elektrotechnika I rok. Język C++ Operacje na danych - wskaźniki Instrukcja do ćwiczenia

Java - tablice, konstruktory, dziedziczenie i hermetyzacja

Część 4 życie programu

JĘZYKI PROGRAMOWANIA Z PROGRAMOWANIEM OBIEKTOWYM. Wykład 5

Wykład 1: Wskaźniki i zmienne dynamiczne

Dziedziczenie jednobazowe, poliformizm

Składnia C++ Programowanie Obiektowe Mateusz Cicheński

8. Wektory. Przykłady Napisz program, który pobierze od użytkownika 10 liczb, a następnie wypisze je w kolejności odwrotnej niż podana.

Zajęcia nr 2 Programowanie strukturalne. dr inż. Łukasz Graczykowski mgr inż. Leszek Kosarzewski Wydział Fizyki Politechniki Warszawskiej

Programowanie 2. Język C++. Wykład 3.

> C++ dynamiczna alokacja/rezerwacja/przydział pamięci. Dane: Iwona Polak. Uniwersytet Śląski Instytut Informatyki

IMIĘ i NAZWISKO: Pytania i (przykładowe) Odpowiedzi

Programowanie w C++ Wykład 3. Katarzyna Grzelak. 12 marca K.Grzelak (Wykład 1) Programowanie w C++ 1 / 35

Wprowadzenie w dziedziczenie. Klasa D dziedziczy klasę B: Klasa B klasa bazowa (base class), klasa D klasa pochodna (derived class).

Programowanie obiektowe i C++ dla matematyków

JĘZYKI PROGRAMOWANIA Z PROGRAMOWANIEM OBIEKTOWYM. Wykład 6

ZASADY PROGRAMOWANIA KOMPUTERÓW

Funkcje przeciążone, konstruktory kopiujące, argumenty domyślne

Podstawy programowania w języku C++ Zadania - dziedziczenie i polimorfizm

Wykład V. Programowanie II - semestr II Kierunek Informatyka. dr inż. Janusz Słupik. Wydział Matematyki Stosowanej Politechniki Śląskiej

Ok. Rozbijmy to na czynniki pierwsze, pomijając fragmenty, które już znamy:

C++ - przeciążanie operatorów. C++ - przeciążanie operatorów. C++ - przeciążanie operatorów. C++ - przeciążanie operatorów

Podstawy Programowania Obiektowego

Przeciążenie (przeładowanie nazw) funkcji

C-struktury wykład. Dorota Pylak

Laboratorium nr 10. Temat: Funkcje cz.2.

typ y y p y z łoż o on o e n - tab a lice c e w iel e owym m ar a o r we, e stru r kt k ury

W dowolnym momencie można zmienić typ wskaźnika.

Polimorfizm, metody wirtualne i klasy abstrakcyjne

Języki Programowania. Prowadząca: dr inż. Hanna Zbroszczyk. tel: Konsultacje: piątek:

KLASA UCZEN Uczen imię, nazwisko, średnia konstruktor konstruktor Ustaw Wyswietl Lepszy Promowany

Programowanie, część I

4. Funkcje. Przykłady

Algorytmika i programowanie. Wykład 2 inż. Barbara Fryc Wyższa Szkoła Informatyki i Zarządzania w Rzeszowie

1 Wskaźniki i zmienne dynamiczne, instrukcja przed zajęciami

referencje Wykład 2. Programowanie (język C++) Referencje (1) int Num = 50; zdefiniowano zmienną Num (typu int) nadając jej wartość początkową 50.

Wskaźniki i dynamiczna alokacja pamięci. Spotkanie 4. Wskaźniki. Dynamiczna alokacja pamięci. Przykłady

Plik klasy. h deklaracje klas

Programowanie obiektowe i zdarzeniowe

Wstęp do informatyki- wykład 11 Funkcje

Strona główna. Strona tytułowa. Programowanie. Spis treści. Sobera Jolanta Strona 1 z 26. Powrót. Full Screen. Zamknij.

KLASA UCZEN Uczen imię, nazwisko, średnia konstruktor konstruktor Ustaw Wyswietl Lepszy Promowany

Konwersje napis <-> liczba Struktury, unie Scanf / printf Wskaźniki

Wykład 1. Program przedmiotu. Programowanie Obiektowe (język C++) Literatura. Program przedmiotu c.d.:

Wstęp do informatyki- wykład 9 Funkcje

Wykład 8: klasy cz. 4

Kurs programowania. Wykład 2. Wojciech Macyna. 17 marca 2016

Programowanie obiektowe w języku C++ Zarządzanie procesami. dr inż. Jarosław Forenc. Przeładowanie (przeciążanie) operatorów

Techniki programowania INP001002Wl rok akademicki 2017/18 semestr letni. Wykład 4. Karol Tarnowski A-1 p.

Funkcje. Deklaracja funkcji. Definicja funkcji. Wykorzystanie funkcji w programie.

C++ - klasy. C++ - klasy. C++ - klasy. C++ - klasy. C++ - klasy INNE SPOSOBY INICJALIZACJI SKŁADOWYCH OBIEKTU

W2 Wprowadzenie do klas C++ Klasa najważniejsze pojęcie C++. To jest mechanizm do tworzenia obiektów. Deklaracje klasy :

Informacje ogólne. Karol Trybulec p-programowanie.pl 1. 2 // cialo klasy. class osoba { string imie; string nazwisko; int wiek; int wzrost;

Programowanie strukturalne i obiektowe. Funkcje

Wstęp do informatyki- wykład 12 Funkcje (przekazywanie parametrów przez wartość i zmienną)

Do czego służą klasy?

Techniki programowania INP001002Wl rok akademicki 2018/19 semestr letni. Wykład 4. Karol Tarnowski A-1 p.

Dariusz Brzeziński. Politechnika Poznańska, Instytut Informatyki

Klasa jest nowym typem danych zdefiniowanym przez użytkownika. Najprostsza klasa jest po prostu strukturą, np

C++ Przeładowanie operatorów i wzorce w klasach

Deklaracja struktury w C++

Programowanie Obiektowe i C++

METODY I JĘZYKI PROGRAMOWANIA PROGRAMOWANIE STRUKTURALNE. Wykład 02

Enkapsulacja, dziedziczenie, polimorfizm

Automatyczne tworzenie operatora = Integer2& operator=(const Integer& prawy) { zdefiniuje. Integer::operator=(ri);

Programowanie obiektowe. Materiały przygotował: mgr inż. Wojciech Frohmberg

Lab 10. Funkcje w argumentach funkcji metoda Newtona. Synonimy nazw typów danych. Struktury. Tablice struktur.

wykład IV uzupełnienie notatek: dr Jerzy Białkowski Programowanie C/C++ Język C, a C++. wykład IV dr Jarosław Mederski Spis Język C++ - wstęp

Projektowanie klas c.d. Projektowanie klas przykład

Transkrypt:

Wstęp do programowania obiektowego, wykład 7 Klasy i funkcje abstrakcyjne Przeciążanie funkcji Definiowanie i interpretacja złożonych typów danych w C++ Wskaźniki do funkcji 1

KLASA ABSTRAKCYJNA 2

Klasa abstrakcyjna Klasa abstrakcyjna klasa w której co najmniej jedna metoda nie jest zdefiniowana, a tylko zadeklarowana. Takie metody powinny być wirtualne - w dziedziczących klasach muszą być dostarczone konkretne implementacje tych metod, aby można było tworzyć ich obiekty. Obiektów samej klasy abstrakcyjnej tworzyć nie można, bo klasa nie jest całkowicie zdefiniowana. Klasa abstrakcyjna służy zwykle jako definicja interfejsu, czyli zbioru metod jakie występują w klasach dziedziczących. 3

Metoda czysto wirtualna (abstrakcyjna) Metoda, która nie jest zdefiniowana, a tylko zadeklarowana to tzw. metoda czysto wirtualna (inaczej metoda abstrakcyjna). W C++ deklaruje się taką metodę, pisząc po nawiasie kończącym listę argumentów =0, np. : virtual double liczpole() = 0; Wystarczy jedna deklaracja metody abstrakcyjnej, aby cała klasa była abstrakcyjna (nawet jeżeli posiada zdefiniowane inne metody). W C++ można metodę abstrakcyjną zdefiniować (zdefinować jej ciało), ale klasa tak czy inaczej będzie abstrakcyjna. Do takiej definicji odwołujemy się przez specyfikator zakresu ::. Jest to niepolecane. 4

Klasa konkretna / polimorfizm Przeciwieństwem klasy abstrakcyjnej jest klasa konkretna taka, której wszystkie metody zostały zaimplementowane i można tworzyć jej obiekty. Do obiektów klas pochodnych można się odnosić poprzez wskaźniki i referencje o typie statycznym klasy bazowej (w szczególności również abstrakcyjnej) jest to jeden z warunków polimorfizmu. 5

Przykład: figury (UML) #int kolor Figura +Figura(int kk) +double liczpole() +double liczobwod() +double bok Kwadrat +Kwadrat(int kk, double bb) +double liczpole() +double liczobwod() Kolo +double promien +Kolo(int kk, double pp) +double liczpole() +double liczobwod() +double a +double b +double c Trojkat +Trojkat(int kk, double aa, double bb, double cc) +double liczpole() +double liczobwod() Na diagramach UML klasy i metody abstrakcyjne oznaczamy kursywą. 6

Przykład: figury (kod 1/2) class Figura { protected: int kolor; public: Figura(int kk):kolor(kk){} virtual double liczpole() = 0; virtual double liczobwod() = 0; }; class Kwadrat : public Figura { double bok; public: Kwadrat(int kk, double bb) : Figura(kk), bok(bb) { } double liczpole() { return bok*bok; } double liczobwod() { return 4*bok; } }; class Koło :public Figura {... 7

Przykład: figury (kod 2/2) int main(void) { Figura* tab[] = { new Kolo(1.5), new Kwadrat(1.9), new Kolo(2.25), new Trojkat(3, 2.4, 5.2) }; for (int i = 0; i <= 4; i++) { if (tab[i]!= NULL){ } cout << "Pole figury numer "<< i << "to" << tab[i]-> liczpole() << endl; cout << Obwód figury numer "<< i << "to" << tab[i]-> liczpole() << endl; } 8

Klasa Figura jest tu abstrakcyjna, bo zawiera metody czysto wirtualne; trudno byłoby rozsądnie zaimplementować metody takie jak liczpole czy liczobwód dla nieznanych figur geometrycznych. Dopiero dla konkretnych figur, jak kwadrat czy koło, można to policzyć. Dopiero w klasach dziedziczących z klasy Figura, definiujemy implementacje metod wirtualnych. Każda klasa konkretna musi mieć zaimplementowane wszystkie odziedziczone metody (uprzednio) abstrakcyjne. Różne figury przechowujemy za pomocą wskaźników o typie statycznym Figura, a różnych typach dynamicznych. Wywołania metod są polimorficzne (wirtualne). 9

PRZECIĄŻANIE FUNKCJI 10

W C++ możliwe jest zadeklarowanie dwóch lub więcej funkcji o tej samej nazwie. Nazywa się to przeciążeniem. Zdefiniowanie metod o tej samej nazwie i sygnaturze w dwóch klasach powiązanych dziedziczeniem to jest tzw. przesłonięcie, a nie przeciążenie. Kompilator określa, do której funkcji odnosi się każde wywołanie na podstawie typów parametrów formalnych i aktualnych z ewentualnymi konwersjami 11

Kryteria rozstrzygania najlepiej pasującej funkcji przeciążonej Typ wartości zwracanej przez funkcję nie jest uwzględniany. Poszukiwanie najlepiej pasującej funkcji odbywa się według kryteriów przedstawionych poniżej w podanej kolejności: Dokładne dopasowanie (brak konwersji lub konwersje trywialne, np. tablicy do wskaźnika) Dopasowanie z użyciem promocji (bool do int, char do int, float do double etc.) Dopasowanie z użyciem konwersji standardowych (int do double, double do int etc.) Dopasowanie z użyciem konwersji zdefiniowanych przez użytkownika Dopasowanie z użyciem wielokropka (...) - zmienna ilość argumentów funkcji 12

DEFINIOWANIE I INTERPRETACJA ZŁOŻONYCH TYPÓW DANYCH W C++ 13

Przez typy złożone rozumiemy takie, które są złożeniami typów różnego rodzaju: na przykład tablica wskaźników, odnośnik do tablicy albo wskaźnik do wskaźnika do tablicy wskaźników itp. Definiowanie typów pochodnych może czasem prowadzić do skomplikowanych wyrażeń. Czym na przykład są x, y, z, f po następujących deklaracjach: int tab[] = {1,2,3}; int (&x)[3] = tab; int *y[3] = {tab,tab,tab}; int *(&z)[3] = y; int &(*f)(int*,int&); Linia 1 określa oczywiście, że tab jest typu 'trzyelementowa tablica zmiennych typu int', co w wyrażeniach w sposób naturalny konwertowane jest do typu int*. Pozostałe deklaracje mogą sprawiać kłopoty. 14

Ogólne zasady interpretacji złożonych typów 1. zaczynamy od nazwy deklarowanej zmiennej, 2. patrzymy w prawo: jeśli jest tam nawias otwierający okrągły '(', to będzie to funkcja (odczytujemy liczbę i typ parametrów); jeśli będzie tam nawias otwierający kwadratowy '[', to będzie to tablica (odczytujemy rozmiar), 3. jeśli po prawej stronie nic nie ma lub jest nawias okrągły zamykający ')', to przechodzimy na lewo i czytamy następne elementy kolejno od prawej do lewej aż do końca lub do napotkania nawiasu otwierającego, 4. jeśli napotkaliśmy nawias okrągły otwierający, to wychodzimy z całego tego nawiasu i kontynuujemy znów od jego prawej strony, 5. gwiazdkę (*) czytamy jest wskaźnikiem do, 6. ampersand (&) czytamy jest odniesieniem do, 7. po odczytaniu liczby i typu parametrów funkcji dalszy ciąg określa typ zwracany tej funkcji, 8. po odczytaniu wymiaru tablicy dalszy ciąg określa typ elementów tablicy. 15

Przykład 1 int (&x)[3] = tab; x jest: na prawo nawias zamykający, więc patrzymy na lewo: ODNOŚNIKIEM DO, patrzymy dalej w lewo, napotykamy nawias otwierający; wychodzimy zatem z nawiasu, patrzymy na prawo: jest nawias otwierający kwadratowy, więc: TABLICY TRZYELEMENTOWEJ, przechodzimy na lewo: ZMIENNYCH TYPU int. Ponieważ x jest odnośnikiem (referencją), musieliśmy od razu dokonać inicjalizacji - widać, że jest ona prawidłowa, bo tab właśnie jest trzyelementową tablicą int-ów. 16

Przykład 2 int *y[3] = {tab,tab,tab}; y jest: na prawo nawias kwadratowy otwierający, więc: TRZYELEMENTOWĄ TABLICĄ, patrzymy w lewo i czytamy do końca w lewo, bo nie ma już żadnych nawiasów: WSKAŹNIKÓW DO ZMIENNYCH TYPU int. Tu nie musieliśmy od razu dokonywać inicjalizacji, ale ta której dokonaliśmy jest prawidłowa, bo tab standardowo jest konwertowana do typu int*. Wszystkie elementy tablicy y wskazują na ten sam adres, a mianowicie na pierwszy element tablicy tab. 17

Przykład 3 int *(&z)[3] = y; z jest: 1. na prawo nawias okrągły zamykający, więc patrzymy na lewo: ODNOŚNIKIEM DO, 2. na lewo nawias okrągły otwierający, więc wychodzimy z całego nawiasu i przechodzimy na prawo: TRZYELEMENTOWEJ TABLICY, 3. patrzymy w lewo i czytamy do końca w lewo, bo nie ma już żadnych nawiasów: WSKAŹNIKÓW DO ZMIENNYCH TYPU int. Tu znów musieliśmy od razu dokonać inicjalizacji - do jej wykonania użyliśmy tablicy y z poprzedniego przykładu. 18

WSKAŹNIKI DO FUNKCJI 19

Funkcje a pamięć Wartość zmiennej zapisana jest gdzieś w pamięci komputera, a zatem ma określony adres, który można przechowywać we wskaźnikach. Podobnie funkcja, w postaci binarnego kodu, jest zapisana gdzieś w pamięci komputera. Posiada więc też adres. Stąd wynika pojęcie wskaźnika do funkcji (inaczej wskaźnika funkcyjnego) jest to wskaźnik wskazujący na adres kodu funkcji. 20

Wskaźniki do funkcji a arytmetyka wskaźników Wskaźniki do zmiennych są typowane: określając typ zmiennej wskazywanej dla zwykłego wskaźnika określamy jednocześnie rozmiar (i format zapisu) pojedynczego wskazywanego przez ten wskaźnik obiektu. Takie obiekty możemy układać w pamięci kolejno jeden po drugim tworząc tablice. Jeśli znamy adres pierwszego z nich, to znając rozmiar pojedynczego obiektu znamy położenie drugiego, trzeciego i, ogólnie, n-tego. W przypadku funkcji jest inaczej. Każda funkcja może być inna i jej binarny kod może mieć inny rozmiar. Stąd: wskaźniki do funkcji nie obsługują arytmetyki wskaźników. 21

Typ wskaźnika Informacja o typie wskaźnika do zmiennej jest potrzebna: aby prawidłowo interpretować binarną reprezentację danej (4B int-a to co innego niż 4B float-a), aby kontrolować poprawność operacji na niej (tzw. sprawdzanie zgodności typów wykonywane przez kompilator). W przypadku funkcji kompilator sprawdza czy ich wywołanie jest zgodne ze specyfikacją wyrażoną w definicji (po uwzględnieniu konwersji). W przypadku wskaźników funkcyjnych trzeba określać nie tylko adres funkcji, ale też typy i liczbę parametrów oraz typ zwracanej wartości. 22

Przykład wskaźnika do funkcji int (*pfun)(int); Czytamy zgodnie z zasadami o złożonych typach danych: ZMIENNA pfun JEST - na prawo nawias zamykający, więc patrzymy w lewo - WSKAŹNIKIEM DO - wychodzimy z nawiasu, patrzymy w prawo - FUNKCJI Z JEDNYM PARAMETREM TYPU int ZWRACAJĄCEJ - patrzymy znów w lewo - WARTOŚĆ TYPU int. Wniosek: zmienna pfun jest zmienną wskaźnikową przystosowaną do przechowywania adresów funkcji, które pobierają jeden argument typu int i zwracają wartość typu int. 23

Nawiasy wokół wskaźników do funkcji Nie można było opuścić nawiasów wokół *pfun. Po opuszczeniu otrzymalibyśmy: int *pfun(int); co przeczytalibyśmy tak: ZMIENNA fun JEST - na prawo nawias otwierający - FUNKCJĄ Z JEDNYM PARAMETREM TYPU int ZWRACAJĄCĄ - patrzymy w lewo - WSKAŹNIK DO - dalej w lewo - ZMIENNEJ TYPU int. A zatem byłaby to deklaracja funkcji pfun, a nie wskaźnika do funkcji. 24

Wartość początkowa wskaźnika Po definicji int *k; zmienna wskaźnikowa k istnieje, ale na razie nie zawiera żadnego użytecznego adresu. Podobnie: wskaźnik do funkcji fun już istnieje, ale nie zawiera adresu żadnej konkretnej funkcji. 25

Ustalanie wartości wskaźnika do funkcji Podobnie jak do wskaźnika p typu int* wpisujemy adres istniejącej zmiennej k typu int pisząc p = &k; tak na zmienną pfun można przypisać pfun = &fun; gdzie fun jest nazwą pewnej funkcji o nazwie fun odpowiedniego typu. Konwersja od fun do &fun jest konwersją trywialną, tak więc równie dobrze w przypisaniu możemy pominąć operator wyłuskania adresu i napisać po prostu: pfun = fun; Należy pamiętać, że nie piszemy nawiasów po nazwie funkcji - nawiasy pełnią rolę operatora wywołania funkcji, tak więc: pfun = fun(); spowodowałoby wywołanie funkcji fun i próbę przypisania rezultatu do zmiennej pfun. 26

Przykładowy program #include <iostream> #include <cmath> using namespace std; // funkcje matematyczne const double PI = 4*atan(1.); double nasza(double); int main(void) { double (*f)(double); //deklaracja wskaźnika do funkcji f = sin; //ustawienie wskaźnika na funkcję sin cout << "sin(pi/2) = " << (*f)(pi/2) << endl; //wywołanie f = &cos; //ustawienie wskaźnika na funkcję cos cout << " cos(pi) = " << f(pi) << endl; //wywołanie } f = nasza; //ustawienie wskaźnika na funkcję nasza cout << " nasza(3) = " << f(3) << endl; //wywołanie double nasza(double x) { return x*x; } 27

Wskaźnik funkcyjny może być parametrem funkcji Deklaracja takiego parametru wygląda tak samo jak deklaracja wskaźnika do funkcji: double fun( double (*f)(double), double a, double b) { return f(a) + f(b); } Jest to definicja funkcji fun, której pierwszym parametrem jest funkcja pobierająca i zwracająca double, a dwoma następnymi są zwykłe parametry typu double. W treści funkcji f jest wywoływana kolejno dla argumentu a i b. Wywyłanie w programie na przykład tak (funkcja atan oznacza biblioteczną funkcję arcus tangens): #include <cmath> const double PI = 4*atan(1.); //... double result = fun(sin, 0, PI/2); 28

Definiowanie własnych typów Można uprościć skomplikowany zapis wprowadzając synonim (alias) skomplikowanego typu za pomocą instrukcji typedef. W naszym przypadku moglibyśmy zdefiniować synonim następującego typu: wskaźnik do funkcji z jednym parametrem typu double zwracającej double: typedef double (*FUNDtoD)(double); i użyć go potem w deklaracji naszej funkcji fun: double fun( FUNDtoD, double, double); lub w deklaracjach/definicjach funkcyjnych zmiennych wskaźnikowych #include <cmath> //... FUNDtoD f = sin; //... f = atan; //... 29

Interpretacja złożonych typów: przykład 4 double (*fun[3])(double); Czytamy: ZMIENNA fun JEST: 1. na prawo nawias kwadratowy otwierający - TRZYELEMENTOWĄ TABLICĄ 2. przechodzimy na lewo - WSKAŹNIKÓW DO 3. wychodzimy z nawiasu, patrzymy w prawo - FUNKCJI Z JEDNYM PARAMETREM TYPU double ZWRACAJĄCEJ 4. patrzymy znów w lewo - WARTOŚĆ TYPU double. Wniosek: zmienna fun jest tablicą trzech wskaźników do funkcji. 30

Interpretacja złożonych typów: przykład 5 int &(*f)(int*,int&); f jest: 1. na prawo nawias okrągły zamykający, więc patrzymy na lewo: WSKAŹNIKIEM DO, 2. na lewo nawias okrągły otwierający, więc wychodzimy z całego nawiasu i przechodzimy na prawo: FUNKCJI O DWÓCH PARAMETRACH, PIERWSZYM TYPU int*, DRUGIM ODNOŚNIKOWYM TYPU int&, 3. patrzymy w lewo i czytamy do końca w lewo, bo nie ma już żadnych nawiasów: ZWRACAJĄCEJ ODNIESIENIE DO int. 31