typ

Transkrypt

typ
Paradygmaty Programowania
Wykład 3
Typy
dr Robert Kowalczyk, Katedra Analizy
Nieliniowej, WMiI UŁ
1
Typ - definicja
Przez typ rozumieć będziemy pewien zbiór wartości, które mogą być
przyjmowane przez zmienne. W praktyce z każdym typem związanych
jest szereg operacji, które można wykonywać na wartościach z tego
typu. Tak postawiona definicja bliska jest klasycznemu pojęciu zbioru (w
naszym przypadku działamy na zbiorach skończonych gdyż pamięć jest
skończona). Dozwolone operacje na typach, to wszystkie operatory (w
szerokim rozumieniu, czyli również podprogramy, podstawienia itp.),
których dziedziną jest ów typ lub typ z nim zgodny (tu zgodność można
rozumieć jako zawieranie), tj.
operacja(typ1) -> typ2.
Przykładowo, niemal w każdym języku programowania występuje
podstawowy typ związany z liczbami całkowitymi (int, Integer,
integer). Jest to skończony podzbiór zbioru liczb całkowitych Z, na ogół
odpowiadający zakresowi liczb, jakie można przechowywać w jednym
słowie danego komputera. Dozwolone operacje to np. dodawanie,
odejmowanie, mnożenie, dzielenie (całkowite i z resztą).
dr Robert Kowalczyk, Katedra Analizy
Nieliniowej, WMiI UŁ
2
Tworzenie nowych typów
Kilka ogólnych kwestii związanych z tworzeniem nowych typów:
 Typ pierwotny to taki typ, którego w danym języku nie da się
zdefiniować za pomocą innych typów, np. typ prosty. Większość języków
posiada pewien zestaw typów prostych, np. char, int, float (np. w C
lub C++).
 Z typów pierwotnych możemy tworzyć typy złożone, jak np. rekordy,
tablice itp. (np. record i array w Pascal).
Można tworzyć typy wyliczeniowe, czyli listy stałych. Ich ważną cechą
jest to, że definiując typ jednocześnie określamy liniowy porządek na
nim (np. enum w C++ czy Enum Javie).

Powyższe mechanizmy to klasyka języków imperatywnych
zapoczątkowana przez język programowania Algol.

dr Robert Kowalczyk, Katedra Analizy
Nieliniowej, WMiI UŁ
3
Typy a Zbiory
Oto kilka widocznych analogii pomiędzy typami a zbiorami:
 Rekord to iloczyn kartezjański typów składowych (przykład Pascal):
record = typ1 x typ2 x … x typn

Tablica to iloczyn kartezjański odpowiedniej liczby egzemplarzy tego samego typu (przykład C++):
tablica = typ x typ x … x typ
Typ wyliczeniowy to zbiór zawierający wskazane elementy (choć w istocie definiujemy coś więcej: porządek). A zatem jest to
skończony ciąg o ustalonych elementach (przykład Java):

enum typ {element1,element2,…,elementn}
Podtyp jakiegoś typu to jego podzbiór, dokładniej to typ oparty na typie bazowym i narzucający pewne ograniczenia na ten typ
(przykład ADA):

subtype nowytyp is typbazowy range zakres

Typ pochodny to ”kopia typu pod inną nazwą” (przykład C):
typedef nowytyp typbazowy
(W niektórych źródłach przez typ pochodny rozumie się typ rozszerzający dany typ, np. klasę.
Wtedy zachodzi oczywista relacja nadzbioru).
dr Robert Kowalczyk, Katedra Analizy
Nieliniowej, WMiI UŁ
4
Po co właściwie typy?
Kilka powodów potrzeby istnienia typów:
 Na poziomie maszynowym wszelkie dane zapisane są jako
układy bitów, niezależnie od tego, co reprezentują, a zatem typy
to oczywisty sposób nadania znaczenia tym ”anonimowym”
układom bitów.
 Dostajemy możliwość wykrywania wielu powszechnych błędów
(przez sprawdzanie zgodności typów).
 Optymalizacja kodu przez kompilator przez wybór efektywnej
optymalizacji (zakresy liczb są znane w czasie kompilacji).
 Typy abstrakcyjne stanowią sposób na modularyzację
programów (typy abstrakcyjne związane są bezpośrednio z
pojęciem programowania obiektowego).
dr Robert Kowalczyk, Katedra Analizy
Nieliniowej, WMiI UŁ
5
Pierwotne typy danych
Podstawowe 4 typy proste (pierwotne):
 Typ całkowity (int, Integer, integer) odpowiada zazwyczaj takiemu
zakresowi liczb, jaki mieści się w jednym słowie maszyny (na ogół 4B). Typ ten
miewa warianty różniące się rozmiarem (byte, short, long) i dopuszczaniem
znaku, tzn. liczb ujemnych (signed/unsigned).
 Typ zmiennopozycyjny (float, double) to prawie zawsze typ obsługiwany
sprzętowo, zgodne ze standardem IEEE 754.
 Typy znakowy (char, character) przez długi czas wykorzystywał kodowanie
ASCII; obecnie coraz częściej używany jest styl kodowania Unicode (2B).
 Typ logiczny (boolean) jest kodowany za pomocą pojedynczych bitów (co jest
oszczędne pamięciowo, ale wolniejsze w dostępie) lub całych bajtów (słów).
 Występują również pierwotne typy stałopozycyjne, czyli liczby z ustaloną w
deklaracji liczbą cyfr i liczbą miejsc po przecinku. Typy takie dobrze nadają się do
obliczeń finansowych, pozwalając uniknąć niektórych problemów z
zaokrągleniami charakterystycznych dla typów zmiennopozycyjnych. Inne
zastosowanie to obliczenia na urządzeniach pozbawionych sprzętowej obsługi
liczb zmiennopozycyjnych, np. przenośne urządzenia do gier.
dr Robert Kowalczyk, Katedra Analizy
Nieliniowej, WMiI UŁ
6
Typ całkowity
W jednym z najpopularniejszych języków programowania C, C++
zdefiniowano 8 typów danych opartych na liczbach całkowitych
przeznaczonych do reprezentacji liczb całkowitych - są to short int,
int, long int, long long int w wersjach ze znakiem (signed) oraz
bez znaku (unsigned). Ich rozmiary w bitach zależą od implementacji.
Standard C99 określa następujące zależności pomiędzy typami:
 int ma minimum 16 bitów,
 long int jest co najmniej takiego rozmiaru, co int,
 long long int ma minimum 64 bity.
W praktyce współczesne kompilatory (takie jak GCC) na maszynach 32bitowych zazwyczaj stosują typy o następujących rozmiarach:
 short int ma 16 bitów,
 int jest równy long int i ma 32 bity,
 long long int ma 64 bity.
dr Robert Kowalczyk, Katedra Analizy
Nieliniowej, WMiI UŁ
7
Typ zmiennopozycyjny
IEEE 754 - standard reprezentacji binarnej i operacji na liczbach zmiennoprzecinkowych (IEEE floating-point
standard), implementowany powszechnie w procesorach i programowaniu obliczeniowym.
Liczbę pojedynczej precyzji w formacie "IEEE-754" zapisujemy za pomocą trzydziestu dwóch bitów. Pierwszym
bitem jest bit znaku S (sign). Jeśli liczba zapisana w kodzie dziesiętnym jest ujemna, oznacza to, iż S przyjmie
wartość 1. Jeśli liczba dziesiętna jest dodatnia - to S przyjmuje 0. Dalej następuje 8 bitów kodujących wykładnik
potęgi 2 (cecha), oraz 23 bity rozwinięcia binarnego (mantysa), przy czym pomija się wiodący, niezerowy bit. Daje
to około 7-8 dziesiętnych miejsc znaczących i zakres od około ±1.18·10-38 do około ±3.4·1038. Zakres taki często
jest wystarczający w prostych obliczeniach.
Oprócz tego zdefiniowano szczególne przypadki:
 +0 - wszystkie bity są zerami,
 -0 - bit znaku jest ustawiony, reszta jest zerami,
 liczby małe (tj. bliskie zera) - wykładnik równy zero, mantysa różna od 0, nie zakłada się wiodącego
niezerowego bitu; są to liczby zbyt małe aby mogły być reprezentowane z taką samą precyzją jak "zwykłe" liczby,
 ±∞ - ustawione wszystkie bity wykładnika, mantysa równa 0, może się pojawić np. jako wynik dzielenia przez 0,
 NaN (z ang. Not a Number) ustawione wszystkie bity wykładnika, mantysa różna od 0, może się pojawić np.
jako wynik pierwiastkowania liczby ujemnej.
Zobacz: http://eff10.internetdsl.tpnet.pl/programowanie/kurs_sc/liczby/pages/14.htm
dr Robert Kowalczyk, Katedra Analizy
Nieliniowej, WMiI UŁ
8
Typ znakowy
W językach C i C++ typ ten jest po prostu jednobajtową liczbą całkowitą
(może być ona ze znakiem, w przypadku signed char lub bez znaku, dla
unsigned char w przypadku nie podania kwalifikatora signed/unsigned
rodzaj liczby zależy od implementacji). W Pascalu natomiast typ znakowy nie
jest typem liczbowym (do konwersji używa się funkcji Chr). Wewnętrznie
jednak znak jest zawsze reprezentowany przez jego kod, w zależności od
implementacji będzie to ASCII, czy Unicode itp. Zapis konkretnej wartości
typu znakowego w kodzie źródłowym dokonuje się za pomocą literału
znakowego.
Typy znakowe w językach programowania:
 C/C++ - char, signed char, unsigned char,
 Pascal - Char,
 Fortran - character,
 Java - char, Character,
 Ada - Character,
 itp.
dr Robert Kowalczyk, Katedra Analizy
Nieliniowej, WMiI UŁ
9
Typ logiczny
Typ logiczny to typ obejmujący dwie wartości: false i true. Każda
zmienna logiczna zajmuje w pamięci komputera 1 bajt. Wartość zmiennej
jest przechowywana w najmłodszym bicie. Pozostałe 7 bitów jest
niewykorzystywane.
C/C++ - bool (lub typ całkowity),
 Pascal - Boolean,
 Java - boolean,
 Ada - Boolean jako Enumeration typ,
 itp.

dr Robert Kowalczyk, Katedra Analizy
Nieliniowej, WMiI UŁ
10
Złożone typy danych
Omówimy teraz główne złożone typy danych (typy budowane
w oparciu o typy pierwotne), tj:
 napisy (teksty, łańcuchy),
 tablice,
 tablice asocjacyjne (mapy, słowniki),
 rekordy (struktury),
 wskaźniki (referencje),
 typy abstrakcyjne (klasy).
dr Robert Kowalczyk, Katedra Analizy
Nieliniowej, WMiI UŁ
11
Napisy (teksty, łańcuchy)
Typ napisowy, to typ powstały w oparciu o typ znakowy (char). W
niektórych językach programowania typ napisowy może być typem
pierwotnym (np. w Javie klasa String). W wielu językach, np. w C napisy to
szczególne rodzaje tablic, a zatem nie są typem pierwotnym:
char[] napis = ”ala”;
napis[0]=’a’, napis[1]=’l’, napis[2]=’a’, napis[3]=’\0’
Cechy napisów o zmiennej długości:
 Napisy statyczne, tj. po zadeklarowaniu nie można zmienić ich długości
oraz zawartości (np. w Javie obiekty klasy String).
 Napisy dynamiczne o długości ograniczonej statycznie, tj. deklarujemy
napis o ustalonej długości (np. tablica znakowa w C czy C++).
 Napisy w pełni dynamiczne, czyli długość może się zmieniać bez
ograniczeń (np. napisy w Perlu).
dr Robert Kowalczyk, Katedra Analizy
Nieliniowej, WMiI UŁ
12
Tablice - implementacja
Tablica to zestaw elementów takiego samego typu, gdzie dostęp do
poszczególnych elementów jest poprzez indeksowanie. Wymaga to dynamicznego
wyliczania adresu elementu (chyba że indeks jest stałą znaną w czasie kompilacji).
Problemy napotykane podczas implementacji, to:
 Kiedy i skąd alokowana jest pamięć dla tablicy? Generalnie tak jak dla zwykłych
zmiennych, choć języki obiektowe skłaniają się do alokowania tablic dynamicznie, ze
sterty (np. Java).
 Jakiego typu mogą być indeksy? Generalnie są one podtypu typu całkowitego ale
mogą też być typu dającego się odwzorować na zakres liczb całkowitych, np. typu
znakowego czy typu wyliczeniowego.
 Czy dopuszczamy tablice wielowymiarowe?
 Czy dopuszczamy operacje indukowane z operacji na elementach? W pewnych
sytuacjach takie operacje byłyby naturalne, np. dodawanie dwóch macierzy za
pomocą naturalnego operatora ”+”. Tego typu operacje oferuje Fortran. W C, czy C++
można odpowiednio przeciążać operatory ”+”, ”-” itp.
dr Robert Kowalczyk, Katedra Analizy
Nieliniowej, WMiI UŁ
13
Tablice - implementacja
Tłumacząc instrukcje z odwołaniami do elementów tablicy kompilator
generuje kod wyliczający adres elementów. Odbywa się to następująco:
 Dla tablic jednowymiarowych tab (n elementów) adres elementu tab[i]
otrzymujemy następująco:
(adres elementu tab[0]) + i * (rozmiar elementu)
przy założeniu indeksowania od 0.
 Dla tablic wielowymiarowych tab (m x n elementów) (rozumianych jako
tablice tablic jednowymiarowych, w dwóch możliwych wariantach, tj.
ułożonych wierszami lub kolumnami) adres elementu tab[i][j] (przy
założeniu, że ułożenie występuje wierszami) otrzymujemy następująco:
(adres elementu tab[0][0]) + (i*n+j) * (rozmiar elementu)
przy założeniu indeksowania od 0 obu wymiarów.
dr Robert Kowalczyk, Katedra Analizy
Nieliniowej, WMiI UŁ
14
Tablice asocjacyjne (mapy, słowniki)
Tablica asocjacyjna to nieuporządkowany zestaw elementów (wartości)
identyfikowanych za pomocą kluczy. Istotą rzeczy jest to, że klucze mogą
pochodzić z obszernego zbioru możliwych wartości (zwykle są to dowolne
napisy). Nie ma zatem prostego odwzorowania kluczy na adresy elementów
tablicy. Tablice asocjacyjne są użyteczne tam, gdzie potrzebny jest
swobodny (nieuporządkowany) dostęp do elementów. Tam, gdzie
potrzebujemy pętli przetwarzającej wszystkie elementy po kolei, bardziej
efektywna jest zwykła tablica. Typowy przykład tablic asocjacyjnych pojawia
się w Perlu, Python i PHP. Również w Javie takim przykładem mogą być
mapy, tj. HashMap lub TreeMap.
Implementacja tablicy asocjacyjnej musi przechowywać nie tylko wartości
elementów, ale również ich klucze. Typowy sposób implementacji to użycie
funkcji haszującej do odwzorowania kluczy na adresy.
dr Robert Kowalczyk, Katedra Analizy
Nieliniowej, WMiI UŁ
15
Rekordy (struktury)
Rekord to zestaw elementów dowolnych typów. Elementy rekordu zwane są polami.
Większość języków stosuje zapis „z kropką” na oznaczenie dostępu do pól rekordu. Rekordy
przechowywane są w pamięci w kolejnych komórkach, choć architektura sprzętu może
narzucać wymóg umieszczania niektórych pól pod adresami będącymi wielokrotnością np.
czterech. To może powodować luki pomiędzy polami.
Typowe kwestie i trudności związane z implementacją rekordu, to:
 Czy potrzeba jest pamiętać o położeniu pól rekordów? Położenie pól w obrębie rekordu
jest znane w czasie kompilacji, zatem nie jest potrzebne przechowywanie informacji o
położeniu pól w trakcie wykonania.
 Jak zinterpretować znak ”=” dla dwóch rekordów? Naturalna wydaje się implementacja
operatora równości rekordów rozumianej jako koniunkcja równości poszczególnych pól.
Zauważmy, że z uwagi na luki między polami nie można tego zrealizować jako porównanie
bloków pamięci. Co zrobić z napisami o zmiennej długości; trzeba porównywać jedynie
faktycznie wykorzystywaną część napisu. Jak traktować pola będące wskaźnikami; czy aby
nie chcielibyśmy, by porównania dotyczyły wskazywanych obiektów, a nie samych
wskaźników (czy też referencji)?
 Czy rekordy to aby nie klasy? Struktury w C są zwykłymi rekordami, natomiast w C++ są w
istocie klasami (jest mała różnica w widoczności pól). Istotna staje się tutaj bliskość tego
typu do typu klasowego.
dr Robert Kowalczyk, Katedra Analizy
Nieliniowej, WMiI UŁ
16
Wskaźniki (referencje)
Typ wskaźnikowy obejmuje wartości, które mogą wskazywać inne
wartości w pamięci, oraz dodatkową wartość ”pustą”, która jest inna
niż jakikolwiek ”prawdziwy” wskaźnik. Wartość ”pusta” bywa często
oznaczana jako null lub nil. Z technicznego punktu widzenia
wskaźniki są to adresy komórek pamięci. Różnica między
wskaźnikiem a adresem to dodatkowa informacja o typie
wskazywanych obiektów, którą posiada kompilator (i wykorzystuje do
sprawdzania zgodności typu).
Motywacją do używania wskaźników jest możliwość dynamicznego
zarządzania pamięcią oraz elastyczność, jaką daje adresowanie
pośrednie. W szczególności, wskaźniki są jedynym sposobem
korzystania ze zmiennych alokowanych dynamicznie na stercie.
dr Robert Kowalczyk, Katedra Analizy
Nieliniowej, WMiI UŁ
17
Operacje na wskaźnikach
Pewne aspekty operacji wykonywanych na wskaźnikach:
 Potrzebne jest przypisanie i dereferencja wskaźnika, czyli dostęp do elementu
wskazywanego przez wskaźnik (na ogół *).
 Do zarządzania pamięcią potrzebny jest mechanizm alokacji, np. new, malloc.
Adresowanie pośrednie wymaga posiadania operatora pobrania adresu (wskazania)
zmiennej (operator & w języku C).

Arytmetyka na wskaźnikach, czyli możliwość swobodnego przesuwania wskaźnika,
daje programiście duże możliwości, ale jest niebezpieczna: łatwo sięgnąć do ”nie
swojej” pamięci (np. w C i C++).
 Bez możliwości przesuwania wskaźnika przez co mechanizm staje się
bezpieczniejszy (np. Java).

Oczywiste problemy pojawiąjące się podczas takich operacji, to:
 Wiszący wskaźnik, tj. wskaźnik odnoszący się do zmiennej, która została już
zdealokowana. Ten problem nie występuje w Javie, gdzie nie ma jawnej dealokacji.
 Zgubiona zmienna, tj. zmienna na stercie do której nie mamy żadnego wskaźnika.
dr Robert Kowalczyk, Katedra Analizy
Nieliniowej, WMiI UŁ
18
Wskaźniki a referencje
W wielu językach nie ma wskaźników ale są referencje, które
częściowo pełnią podobną rolę do wskaźników. Generalnie przez
typy referencyjne rozumiemy typy wskaźnikowe o ograniczonych
możliwościach.
Na większości maszyn wskaźniki mają rozmiar jednego słowa.
Oczywiście referencje to to samo co wskaźniki w sensie odwołania
do komórek pamięci.
W wielu językach w których są referencje a nie ma wskaźników.
dealokacja odbywa się na ogół za pomocą mechanizmu zbierania
śmieci (garbage collector) . Polega to na tym, że przeglądamy stertę
w poszukiwania obiektów do których nie ma referencji i zwalniania
bloków do których nie ma żadnych odwołań.
dr Robert Kowalczyk, Katedra Analizy
Nieliniowej, WMiI UŁ
19
Abstrakcyjny typ danych (klasa)
Abstrakcja to reprezentacja pewnego bytu, w której
pominięto nieistotne w danym kontekście szczegóły.
Pozwala nam to grupować byty według ich wspólnych cech i w
zależności od potrzeby (kontekstu) i pozwala nam to albo
zajmować się całymi grupami (czyli owymi wspólnymi
cechami), albo bytami wewnątrz grupy (czyli szczegółami
różniącymi byty w grupie). Chodzi oczywiście o to, by poradzić
sobie ze złożonością problemów.
dr Robert Kowalczyk, Katedra Analizy
Nieliniowej, WMiI UŁ
20
Od czego właściwie abstrahujemy?
Abstrakcja procesu - abstrakcjami procesów są
podprogramy. Pozwalają wskazać (przez ich wywołanie),
że pewna czynność ma być wykonana, bez
wskazywania jak ma być wykonana. Szczegóły znajdują
się w treści podprogramu, której wywołujący nie musi
znać.
Abstrakcja danych - czyli zamknięta całość obejmująca
reprezentację pewnego typu danych wraz z
podprogramami, umożliwiającymi działanie na tych
danych.
dr Robert Kowalczyk, Katedra Analizy
Nieliniowej, WMiI UŁ
21
Czym jest abstrakcyjny typ danych?
Abstrakcyjny typ danych, to konstrukcja języka programowania, w
której definiujemy typ (w dotychczasowym rozumieniu) oraz operacje
na nim w taki sposób, że inne byty w programie nie mogą
manipulować danymi inaczej niż za pomocą zdefiniowanych przez
nas operacji. Istotą rzeczy jest tu oddzielenie części ”prywatnej” typu
(czyli szczegółów reprezentacji danych i implementacji
poszczególnych operacji) od części ”publicznej” (tego, co można
wykorzystywać w innych miejscach programu).
Rozdzielenie składników abstrakcyjnego typu danych na część
prywatną i publiczną jest możliwe za pomocą zawartych w języku
programowania mechanizmów sterowania dostępem. Dane w typie
abstrakcyjnym zwane są właściwościami lub danymi składowymi;
używa się też określeń pole lub po prostu zmienna. Operacje zwane
są metodami lub funkcjami składowymi.
dr Robert Kowalczyk, Katedra Analizy
Nieliniowej, WMiI UŁ
22
Abstrakcyjny typ danych - przykłady
Wbudowane w języki programowania typy proste
można uznać za abstrakcyjne: nie mamy dostępu do
reprezentacji wewnętrznej, więc możemy posługiwać się
jedynie tym, co dostarcza język.
 Zdefiniowany w Pascalu typ rekordowy i kilka procedur
na nim działających nie stanowi abstrakcyjnego typu
danych. Ktokolwiek zadeklaruje rekord tego typu, będzie
mógł działać bezpośrednio na tym rekordzie z
pominięciem ”oficjalnych” procedur.
 Sztandarowy przykład to klasa np. z Javy lub C++.
Dane schowane w części prywatnej klasy nie są
dostępne na zewnątrz, stąd nie da się wykonywać
żadnych operacji bezpośrednio.

dr Robert Kowalczyk, Katedra Analizy
Nieliniowej, WMiI UŁ
23
Czym jest obiekt?
Obiekt, to instancja abstrakcyjnego typu danych, czyli
pojedynczy ”egzemplarz” tego typu zaalokowany na
stercie (najczęściej), na stosie lub statycznie (najrzadziej).
Sam abstrakcyjny typ danych w większości języków
zwany jest klasą.
Każdy obiekt ma trzy charakterystyczne cechy:
 tożsamość, czyli cechę umożliwiającą jego identyfikację
i odróżnienie od innych obiektów,
 stan, czyli aktualny stan danych składowych,
 zachowanie, czyli zestaw metod wykonujących operacje
na tych danych.
dr Robert Kowalczyk, Katedra Analizy
Nieliniowej, WMiI UŁ
24
Jaki powinien być abstrakcyjny typ danych?
Deklaracja części publicznej (interfejsu), czyli danych i
podprogramów przeznaczonych do wykorzystania przez inne
byty w programie, powinna mieścić się w jednej jednostce
syntaktycznej.
Pozostała część, czyli ciała podprogramów publicznych
(implementacja) oraz dane i podprogramy przeznaczone do
wewnętrznego użytku, może mieścić się w tej samej lub innej
jednostce syntaktycznej. Inne byty w programie mogą tworzyć
zmienne definiowanego typu abstrakcyjnego. Jedynymi
bezpośrednimi operacjami (także w sensie dostępu do
zmiennych) na obiektach tego typu są te zawarte w części
publicznej.
dr Robert Kowalczyk, Katedra Analizy
Nieliniowej, WMiI UŁ
25
Mechanizmy danego języka
Mechanizmy języka do tworzenia abstrakcyjnych typów:
 Jednostka syntaktyczna mieszcząca definicję typu abstrakcyjnego.
 Sposób wyszczególnienia danych i podprogramów publicznych.
 Kilka podstawowych, wbudowanych operacji na obiektach z typu,
np. podstawienie, sprawdzenie równości, wypisywanie reprezentacji
obiektu.
 Pewne operacje są potrzebne niemal w każdym typie, są jednak
zależne od szczegółów tego typu. Muszą zatem być
implementowane przez programistę. Są to np. konstruktory,
destruktory, iteratory.
 Język może oferować abstrakcyjne typy danych wprost (C++, C#,
Java) lub może mieć bardziej ogólne konstrukcje (np. Ada).
dr Robert Kowalczyk, Katedra Analizy
Nieliniowej, WMiI UŁ
26
Ada - przykład implementacji
package Stos is
type typ_stosowy is limited private;
maks_rozmiar: constant := 1000;
function pusty(st: in typ_stosowy) return Boolean;
procedure poloz(st: in out typ_stosowy; elem: in Integer);
procedure zdejmij(st: in out typ_stosowy);
function wierzcholek(st: in typ_stosowy) return Integer;
private
type typ_listowy is array (1..maks_rozmiar) of Integer;
type typ_stosowy is record
list: typ_listowy;
wsk_stosu: Integer range 0..maks_rozmiar := 0;
end record;
end Stos;
dr Robert Kowalczyk, Katedra Analizy
Nieliniowej, WMiI UŁ
27
C++ - przykład implementacji
class stos {
private:
int *baza;
int maks_rozmiar, wsk_stosu;
public:
stos() {
baza = new int [1000];
maks_rozmiar = 999;
wsk_stosu = -1;
}
~stos() {delete [] baza;}
void poloz(int elem) {...}
void zdejmij() {...}
int wierzcholek() {...}
bool czypusty() {...}
};
dr Robert Kowalczyk, Katedra Analizy
Nieliniowej, WMiI UŁ
28
Java - przykład implementacji
class Stos {
private int baza[];
private int maks_rozmiar, wsk_stosu;
public Stos() {
baza = new int[1000];
maks_rozmiar = 999;
wsk_stosu = -1;
}
public void poloz(int elem) {...}
public void zdejmij() {...}
public int wierzcholek() {...}
public boolean czyPusty() {...}
}
dr Robert Kowalczyk, Katedra Analizy
Nieliniowej, WMiI UŁ
29
C# - przykład implementacji
class Stos {
private int[] baza;
private int maks_rozmiar, wsk_stosu;
public Stos() {
baza = new int[1000];
maks_rozmiar = 999;
wsk_stosu = -1;
}
public void poloz(int elem) {...}
public void zdejmij() {...}
public int wierzcholek() {...}
public bool czyPusty() {...}
}
dr Robert Kowalczyk, Katedra Analizy
Nieliniowej, WMiI UŁ
30
Dziękuję za Uwagę!!!

dr Robert Kowalczyk, Katedra Analizy
Nieliniowej, WMiI UŁ
31

Podobne dokumenty