Object Pascal/Typy zmiennych

Z Wikibooks, biblioteki wolnych podręczników.
Skocz do: nawigacja, szukaj

Typy zmiennych określają zewnętrzną postać zmiennej, czyli zakres jej wartości i zestaw dozwolonych operacji, które może na niej wykonać programista, a także jej reprezentację wewnętrzną, czyli sposób traktowania je przez inne obiekty programu.

Typ prosty[edytuj]

Porządkowy[edytuj]

Całkowity[edytuj]

Typ predefiniowany.

Typy ogólne[edytuj]
Nazwa typu Zakres Format
Integer typ zależny od typu programowania, najczęściej od -32768 do 32767 ze znakiem, 16 lub 32 lub 64 bitowy (w zależności od platformy na którą programujemy)
Cardinal typ zależny od typu programowania, najczęściej 0..4294967295 bez znaku, 16 lub 32 lub 64 bitowy (w zależności od platformy na którą programujemy)
Typy podstawowe[edytuj]
Nazwa typu Zakres Format
ShortInt –128..127 ze znakiem, 8-bitowy
SmallInt –32768..32767 ze znakiem, 16-bitowy
LongInt –2147483648..2147453647 ze znakiem, 32-bitowy
Int64 –2^64..2^64–1 ze znakiem, 64-bitowy
Byte 0..255 bez znaku, 8-bitowy
Word 0..65535 bez znaku, 16-bitowy
LongWord 0..42849567295 bez znaku, 32-bitowy
QWord 0 .. 18446744073709551615 bez znaku, 64-bitowy
Dodatkowe informacje[edytuj]

Predefiniowane w module System stałe MaxLongint i MaxInt określają maksymalną wartość w typach LongInt i Integer.

Logiczny[edytuj]

Typ predefiniowany.

Nazwa typu Format
Boolean 8 - bitowy
ByteBool 8 - bitowy
WordBool 16 - bitowy
LongBool 32 - bitowy

Wartością zmiennej typu logicznego może być predefiniowana stała FALSE lub TRUE.

Znakowy[edytuj]

Typ predefiniowany.

Typy podstawowe[edytuj]
Nazwa typu Format Uwagi
AnsiChar 8 - bitowy rozszerzony zestaw znaków ASCII (standard 7 bitów)
WideChar 16 - bitowy zestaw znaków Unicode
Typ ogólny[edytuj]
Nazwa typu Format Uwagi
Char 8 - bitowy zgodny z typem AnsiChar w Object Pascal

Wyliczeniowy[edytuj]

Typ niepredefiniowany, wymaga opisu programisty.

Definicja typu[edytuj]
 type  identyfikator-typu = (lista identyfikatorów)  
Przykład[edytuj]
 type samochody = (fiat, polonez, opel, volkswagen);
 //Ord(fiat) = 0
 //Ord(polonez) = 1 itd.
 var
 x,y:samochody;
 begin
   x:=polonez;          //x – 00000001 (liczba 1)
   y:=opel;             //y  – 00000010 (liczba 2)
 end;
Uwagi dotyczące stosowania typów wyliczeniowych[edytuj]
  • Element tego typu zajmuje 8 lub 16 bitów.
  • Identyfikatory na liście muszą być różne, błędna jest na przykład deklaracja
 type znaki = (a,b,b,c)
  • W dwóch różnych typach o tym samym zasięgu nie może wystąpić ten sam identyfikator, np. w zasięgu deklaracji typu samochody błędna jest deklaracja
 type ciezarowki = (opel, volkswagen, scania)
  • Porządek w typie wyliczeniowym jest zgodny z kolejnością wyliczenia w definicji typu.
  • Wartości zmiennych tego typu nie można wypisać standardową procedurą write.
  • Nie można na nich wykonywać operacji arytmetycznych.
  • Maksymalna ilość elementów to 256.

Okrojony[edytuj]

Typ niepredefiniowany, wymaga opisu programisty. Służy do definiowania podzbiorów dowolnego zbioru wartości określonego przez typy porządkowe.

Definicja[edytuj]
 type identyfikator-typu = stala1 .. stala2;

Z każdym typem okrojonym związany jest bazowy, macierzysty typ porządkowy i obie stałe muszą być tego typu, przy czym ord(stala1) <= ord(stala2). Pierwsze wyrażenie stałe nie może zaczynać się od ‘(‘.

Przykład[edytuj]
 const      
   a = 5;
   b = 2;
 type
   sam = fiat .. opel;                // typ bazowy samochody
   znaki = '!' .. '+';                // typ bazowy Char
   zakres1 = 2+5 .. 2*5;                // typ bazowy Byte
   zakres2 = b+a .. b*a;                // typ bazowy Integer

Rzeczywisty[edytuj]

Typ predefiniowany. W odróżnieniu od typów całkowitych pozwala na operacje zmiennoprzecinkowe.

Typy podstawowe[edytuj]

Nazwa typu Zakres Znaczące cyfry Format
Real48 2.9 x 10^–39 .. 1.7 x 10^38 11–12 48-bitowy
Single 1.5 x 10^–45 .. 3.4 x 10^38 7–8 32-bitowy
Double 1.5 x 10^–309 .. 1.7 x 10^309 15–16 64-bitowy
Extended 3.6 x 10^–4951 .. 1.1 x 10^4932 19–20 80-bitowy
Comp –2^63 .. 2^63 –1 19–20 64-bitowy
Currency –922337203685477.5808 .. 922337203685477.5807 19–20 64-bitowy

Typ ogólny[edytuj]

Nazwa typu Zakres Znaczące cyfry Format
Real 5.0 x 10^–324 .. 1.7 x 10^308 15–16 64-bitowy

Dodatkowe informacje[edytuj]

  • Typ Extended zapewnia najlepszą precyzję, nie jest jednak zalecany, gdy aplikacja ma być uruchamiana na różnych platformach.
  • Typ Comp służy do pamiętania dużych liczb całkowitych, nie jest jednak typem porządkowym (nie można go np. inkrementować), zachowany dla zgodności z wersjami wcześniejszymi, zaleca się używać typu Int64.
  • Typ Currency ma zastosowanie do obliczeń pieniężnych.

Typ łańcuchowy[edytuj]

Typ łańcuchowy służy do reprezentowania ciągów znaków.

Łańcuchowy krótki[edytuj]

  • string - w zasięgu takiej dyrektywy {$H-},
  • string[zakres] - zakres mniejszy lub równy od 255,
  • shortstring

Łańcuchowy długi[edytuj]

  • string - w zasięgu dyrektywy {$H+} (ustawienie standardowe)
  • ansistring;

Łańcuch znaków dwubajtowych[edytuj]

  • widestring

Typ strukturalny[edytuj]

Tablicowy[edytuj]

Typ przeznaczony do struktur składających się z wielu elementów konkretnego typu.

Tablice statyczne[edytuj]

Deklaracja typu tablicowego:

 type identyfikator_typu = array [typy_indeksowe] of  typ_bazowy;

gdzie:

  • typy_indeksowe – oddzielone przecinkami opisy typów porządkowych;
  • typ_bazowy – dowolny typ prosty lub strukturalny.

Przykłady:

 type
   Kolor = (bialy, zielony, czarny);
   Ttab1 = array [5..8] of array [Boolean] of array [Kolor] of real;
   Ttab2 = array [5..8, Boolean] of array [Kolor] of real;
   Ttab3 = array [5..8] of array [Boolean, Kolor] of real;

Deklaracja zmiennej w typie tablicowym:

 var
   liczba: array [1..100] of integer;

W nawiasach kwadratowych zapisywany jest zakres indeksów tablicy w postaci: od..do. Indeks tablicy musi należeć do typu porządkowego, ograniczenia (od i do) nie mogą być zmiennymi. Ograniczeniom nie podlega zakres indeksów (jedyny warunek to indeks od musi być mniejszy od indeksu do. Typ_bazowy może być typem prostym, ale także typu strukturalnego.

Istnieją również tablice wielowymiarowe, np. dwuwymiarowa:

 var
   liczba: array[1..10] of array[1..10] of integer;

albo dla skrócenia zapisu:

 var
   liczba: array[1..10,1..10] of integer;

Nie ma ograniczeń na liczbę wymiarów tablicy, najczęściej stosuje się tablice jedno- i dwuwymiarowe.

Tablice dynamiczne[edytuj]

Deklaracja:

 type 
   identyfikator_typu = array of typ_bazowy;             //tablica jednowymiarowa
 type 
   identyfikator_typu = array of array of typ_bazowy     //tablica 2-wymiarowa

Informacje:

  • Zmienne tego typu zajmują 32 bity pamięci.
  • Pamięć na tablicę alokowana jest w wyniku wykonania procedury SetLength (zmienna, indeksy) lub w wyniku przypisania.
  • Pamięć jest zwalniana w wyniku przypisania zmienna := nil; lub w wyniku wykonania procedury Finalize (zmienna).

Rekordowy[edytuj]

Typem rekordowym nazywamy złożoną strukturę danych, której elementy (pola), mogą być różnych typów (prostych i strukturalnych).

Deklaracja typu rekordowego[edytuj]

 type identyfikator_typu = record
   {lista_deklaracji_pól};
 end;

gdzie lista_deklaracji_pól ma postać:

 lista_identyfikatorów_pól : opis-typu;

Ważne informacje[edytuj]

  • Ostatnie pole może być polem wariantowym postaci:
 case pole_wyróżnikowe of wykaz_wariantów;
    • Pole_wyróżnikowe może być identyfikatorem typu porządkowego lub deklaracją zmiennej porządkowej.
    • wykaz_wariantów ma postać:
 lista-etykiet-wyboru : (lista-deklaracji-pól)
  • Pola muszą mieć różne identyfikatory.
  • Żadne pole wariantowe nie może być:
    • typu łańcuchowego długiego,
    • typu tablicy dynamicznej,
    • typu wariantowego,
    • typu łącza programowego.

Przykład:[edytuj]

 type
   Data = record
     Dzien: 1..31;                      
     Miesiac: 1..12;
     Rok: integer;
 end;

Zbiorowy[edytuj]

Typ zbiorowy jest zbiorem potęgowym typu porządkowego o maksymalnie 256 elementach.

Deklaracja typu[edytuj]

 type identyfikator_typu = set of typ_porządkowy;

Wartościami zmiennych typu zbiorowego są dowolne podzbiory zbioru bazowego, łącznie ze zbiorem pustym. Konstruktor zbioru ma postać [ ].

Przykłady:[edytuj]

 type Samochody = (fiat, polonez, opel, volkswagen);
 var 
   A : set of samochody;           
   B : set of 0..3;                                        
   C : set of 'a'..'z';
 begin           
   A:= [ ];
   A:= [opel];
   B:= [1,3];
   C:= ['a'..'f'];
 end.

Na zmiennych zbiorowych można wykonywać:

  • operacje mnogościowe,
  • operacje porównań,
  • operację należenia do zbioru in,
  • procedury:
  include(zb, el)  zb:=zb+[el]
  exclude(zb, el)  zb:=zb-[el]

Plikowy[edytuj]

Klasowy[edytuj]

Typ klasowy jest podobny do typu rekordowego, posiada jednak dodatkowo metody (procedury i funkcje). Słowo class, oznacza taką strukturę, która posiada konstruktory (słowo kluczowe constructor) i destruktor (destructor), deklarowane podobnie jak inne metody. Zwyczajowo konstruktory są nazywane Create a destruktory Destroy. Konstruktora używa się do przydzielania zasobów (pamięci, obiektów zagnieżdżonych, itd.) dla klasy oraz do inicjalizowania pól klasy (np. zerowanie pól). Można utworzyć dowolną liczbę konstruktorów ale tylko jeden destruktor. Jeśli klasa posiada kilka konstruktorów, to muszą się one różnić liczbą i/lub typami przekazywanych argumentów. Destruktor służy do zwalniania zasobów, przydzielonych w konstruktorze lub w trakcie działania obiektu danej klasy. Destruktor nie pobiera żadnych argumentów. Do usuwania niepotrzebnych już w programie obiektów, zaleca się stosowanie metody Free, która sama wywołuje destruktor, wcześniej sprawdzając czy obiekt jeszcze istnieje (jeśli obiekt już nie istnieje, to destruktor nie jest wtedy wywoływany). Zapobiega to powstawaniu przypadkowych błędów w programie, związanych z błędnym gospodarowaniem pamięcią używaną przez obiekt (oczywiście o ile destruktor nie zawiera błędów).

Przykład Object[edytuj]

 type
   Data = object(TObject)
     Dzien: 1..31;                      
     Miesiac: 1..12;
     Rok: integer;
     procedure Drukuj;
 end;
 
 procedure Data.Drukuj;
 begin
   writeln(Dzien,'.',Miesiac,'.',Rok)
 end;

Przykład Class[edytuj]

Deklaracja oraz użycie konstruktora i destruktora

 type
   TData = class(TObject)
   private
     FDzien: 1..31;                     
     FMiesiac: 1..12;
     FRok: integer;
   public
     constructor Create;
     destructor Destroy;
     procedure Drukuj;
   end;
 
 constructor TData.Create;
 begin
   FDzien := 1;
   FMiesiac := 5;
   FRok := 2013;
 end;
 
 destructor TData.Destroy;
 begin
    // nic nie robi, bo nie przydzielano klasie żadnych zasobów
 end;
 
 procedure TData.Drukuj;
 begin
   Writeln(FDzien, '-', FMiesiac, '-', FRok)
 end;
 
 var
   Data1: TData;
 
 begin
   Data1 := TData.Create;
   {...}
   Data1.Free;
 end.

Odwołania do klasy[edytuj]

Łącza programowego[edytuj]

Typ wskaźnikowy[edytuj]

Wskaźnik zawiera adres zmiennej. Deklaracja zmiennych typu wskaźnikowego zawiera operator ^ przed nazwą typu, na który ma wskazywać. Kiedy chcemy uzyskać adres zmiennej, poprzedzamy ją operatorem @. Kiedy chcemy się odwołać do elementu wskazywanego przez wskaźnik, piszemy po nazwie wskaźnika ^. Można też tworzyć nowe zmienne dynamiczne, np. procedurą new(wskaźnik) i usuwać je, np. procedurą dispose(wskaźnik).

Przykłady:[edytuj]

 program wsk;
 
 var
   wsk1, wsk2: ^integer;
   i: integer;
 
 begin
   i := 1;
   wsk1 := @i;
   if @wsk1^ = wsk1 then
     writeln('tak');   {drukuje tak}
   writeln(wsk1^);   {drukuje 1}
   wsk1^ := 2;
   wsk1 := nil;
   if wsk1 = nil then
     writeln('tak');   {drukuje tak}
   writeln(i);  {drukuje 2}
   new(wsk2);
   wsk2^ := 3;
   writeln(wsk2^);   {drukuje 3}
   dispose(wsk2);
   new(wsk1);
   wsk2 := wsk1;
   wsk1^ := 4;
   writeln(wsk1^);   {drukuje 4}
   readln;
   dispose(wsk1);
   {dispose(wsk2); - to byłby błąd}
   if wsk2 = nil then
     writeln('tak');   {nic nie drukuje}
   readln;
 end.

Typ proceduralny[edytuj]

Typ wariantowy[edytuj]

Zgodność typów[edytuj]

Identyczność typów[edytuj]

Dwa typy a i b są identyczne, jeżeli:

  • posiadają ten sam identyfikator typu
  • dają się wywieźć od tego samego identyfikatora za pomocą konstrukcji: a=b.

Zgodność operacyjna[edytuj]

Dwa typy są zgodne operacyjne, jeśli są m.in.:

  • identyczne,
  • typami całkowitymi,
  • typami rzeczywistymi,
  • jeden jest typem okrojonym drugiego,
  • są typami okrojonymi tego samego typu bazowego,
  • typami zbiorowymi o zgodnych typach bazowych
  • jeden jest typem Pointer, a drugi dowolnym typem wskaźnikowym,
  • są typami proceduralnymi o identycznych typach wyników, jednakowej liczbie parametrów i identycznych typach odpowiadających sobie parametrów.

Zgodność w sensie przypisania[edytuj]

Instrukcja przypisania z := w jest poprawna, o ile typ a zmiennej z i typ b wyrażenia w spełniają jeden z warunków:

  • są typami rzeczywistymi,
  • są typami łańcuchowymi,
  • a i b są identyczne, ale nie są typami plikowymi, ani nie zawierają odwołań do typu plikowego,
  • a i b są zgodnymi typami porządkowymi i wartość w jest jedną z możliwych wartości typu a,
  • a jest typem rzeczywistym, a b typem całkowitym,
  • a jest typem łańcuchowym, a b jest typem znakowym,
  • są zgodnymi operacyjnie typami zbiorowymi,
  • są zgodnymi operacyjnie typami wskaźnikowymi,
  • są zgodnymi operacyjnie typami proceduralnymi.

Inne podziały typów[edytuj]

Predefiniowalność[edytuj]

  • standardowe – są one predefiniowane i nie wymagają opisu programisty.
  • niestandardowe – nie są predefiniowane i muszą być opisane przez programistę.

Uzależnienie od procesora i systemu operacyjnego[edytuj]

  • podstawowe – są niezależne od procesora i systemu operacyjnego.
  • ogólne – zależą od procesora i systemu operacyjnego.