A Delphi programozási nyelv

Típusok, típuskonstrukciók

Típusszerkezet

 A Pascal nyelvben számos előre definiált adattípus létezik. Ezek három csoportba sorolhatók: sorszámozott (ordinal), valós (real) és szöveg (string). A nyelv kibővítése során szükséges volt újabb típusok bevezetése (pl.: LongBool, DateTime, Variant, ...), többek között a Windows operációs rendszerrel való kompatibilitás miatt. Ebben a pontban ezeket vesszük sorra. (Azok kedvéért, akik nem ismerik nagyon a Turbo Pascalt, nem csak az új típusok vannak felsorolva.)

 Felhasználói típust, -szinonímát a type kulcsszó után vezethetünk be név = típusdefiníció; alakban.

Elemi típusok

Diszkrét típusok

 Az ilyen típusok azzal a fontos tulajdonsággal bírnak, hogy értelmezett rajtuk egy rákövetkezési reláció, ami a <, >, =, <= ,>= operátorokkal kérdezhető le, valamint mindannyiukon használható néhány beépített eljárás. Ezek az eljárások a következők:

 

A sorszámozott típusokon használható beépített eljárások

Eljárás

Hatása

Dec

A paraméterként megadott változó értékét eggyel, vagy a második paraméter megadása esetén annak értékével csökkenti.

Inc

A paraméterként megadott változó értékét eggyel, vagy a második paraméter megadása esetén annak értékével növeli.

Odd

True (igaz) értéket ad vissza, ha argumentuma páratlan szám.

Pred

A sorszámozott típusú érték megelőzőjét adja vissza.

Ord

A sorszámozott típusú érték sorszámával tér vissza.

Succ

A sorszámozott típusú érték rákövetkezőjét adja vissza.

Low

A sorszámozott típusban tárolható legkisebb értékkel tér vissza.

High

A sorszámozott típusban tárolható legnagyobb értékkel tér vissza.

  A legfontosabb sorszámozott típusok a következők: egész szám (Integer), logikai típus (Boolean) és a karakter (Char). Az egyes csoportokba több, hasonló jellemzőkkel bíró adattípus tartozik, melyek reprezentációjukban illetve értékkészletükben térnek el egymástól. Ezeken kívül a felhasználónak is van lehetősége új sorszámozott típus megadására.

Egész típusok

   A következő táblázat az egész számok tárolására alkalmas sorszámozott adattípusokat tartalmazza:

 

Egész típusok

ShortInt

Előjeles

8 bit

SmallInt

Előjeles

16 bit

LongInt

Előjeles

32 bit

Int64
Előjeles 64 bit(Delphi 4-től)

Integer

Előjeles

Verziófüggő (Delphi 1 – 16 bit; Delphi 2-től – 32 bit)

Byte

Előjel nélküli

8 bit

Word

Előjel nélküli

16 bit

LongWord

Előjel nélküli

32 bit (Delphi 4-től)

UInt64

Előjel nélküli

64 bit (Delphi 2007-től)

Cardinal

Előjel nélküli

Verziófüggő (Delphi 1 – 16 bit; Delphi 2-től – 32 bit)

 Látható, hogy vannak rendszerfüggő típusok. Ennek oka, hogy ez a két leggyakrabban használt típus, és a hatékonyság érdekében ezek közvetlenül megfelelnek a CPU által használt számoknak.

Logikai típusok

 A logikai típusokat is táblázatban foglaljuk össze:

 

Logikai típusok

Boolean, ByteBool

1 byte

WordBool

2 byte

LongBool

4 byte

 A táblázatban szereplő Boolean felel meg az eredeti Pascal logikai típusának. Az ilyen típusú változó a True (1) vagy False (0) értékek valamelyikét veheti fel. A másik három típust numerikus Boolean típusnak nevezzük, és a Windows API-val való kompatibilitás miatt kerültek a nyelvbe. Rájuk az a jellemző, hogy minden nem 0 értéket True-nak értelmeznek, a különbség a maximális elfogadott szám nagyságában van. Érdekesség, hogy a Delphi 3-tól kezdődően a Visual Basickel és az OLE Automationnel való kompatibilitás miatt a numerikus Boolean típusok az igaz értéket a -1-gyel, a hamis értéket pedig a 0-val jelölik. Egész érték Boolean-ra történő konvertálása 0 esetén False, minden más esetben True lesz.

Karakter típusok

 Delphiben a karakterek ábrázolására két típust használhatunk: az ANSIChar és a WideChar típusokat. Az előbbi a 8 bites karakterek, míg az utóbbi a 16 bites Unicode karakterek tárolására alkalmas. A Pascalból ismert Char típus a Delphi 2009 előtt az ANSIChar-nak, attól kezdve a WideChar-nak felel meg.

Részintervallum típusok (subrange types)

 A részintervallum típus felhasználó által meghatározott típus. Lényege, hogy egy nagyobb intervallumon belüli kisebb intervallumot határozunk meg. A részintervallum típusának meghatározásához nem szükséges a bővebb intervallum megadása, elég abból két konstans érték (az új típus legkisebb és legnagyobb elemének) megadása. A két értéknek természetesen valamely már ismert sorszámozott típusúnak kell lennie, és az új típus is sorszámozott típusú lesz. Példák részintervallum típusra:

type Positive = 1..High(Integer); // pozitív számok tárolására alkalmas típust definiál //(felső határa megegyezik az Integer típus felső  határával) UpperCase = 'A' .. 'Z'; // nagybetűk tárolására alkalmas típust definiál
Felsorolás típusok

 Ez is gyakran használt, felhasználó által meghatározott adattípus. Magunk is készíthetünk felsorolás típust, ha a típusértékeket felsorolva adjuk meg, illetve természetesen, ha meglévő felsorolás típus altípusát készítjük el. Minden felsorolás típusból készített altípus is felsorolás típus, tehát a részintervallumai, illetve tetszőleges kiválogatott elemei is. Példa:

type Napszak = (Hajnal, Reggel, Délelőtt, Dél, Délután, Este, Éjjel);

 Az egyes értékek sorrendje egyértelműen meghatározott, az első érték indexe nulla, következő az egy és így tovább. (Ezeket az értékeket adja vissza az Ord függvény.)

 A megszámlálható típusoknak többféle ábrázolása létezik Delphiben. Alapállapotban az ábrázolási mód 8 bites, feltéve, ha 256 elemnél kevesebbet tartalmaz az adott típus. Emellett létezik 16 bites és 32 bites ábrázolási mód is, amire érdemes odafigyelni, mert a C++ könyvtárak általában 32 bites ábrázolást használnak. Nagyobb ábrázolási módot a {$Z+} fordítási direktívával kérhetünk.

Valós típusok

 A valós számokat a Delphi lebegőpontosan ábrázolja, különböző méretekben.

 

Valós típusok

Típus

Intervallum

Szignifikáns számjegyek

Méret (byte)

Real48

2,9 * 10-39 .. 1,7 * 1038

11-12

6

Single

1,5* 45..3.4*1038

7-8

4

Double

5,0*10-324..1,7*10308

15-16

8

Extended

3,4*10-4932..1,1*10493

19-20

10

Comp

-2^63+1 .. 2^63-1

19-20

8

Currency

-922337203685477.5808 .. 922337203685477.5807

19-20

8

 A Single, Double és az Extended az IEEE nemzetközi lebegőpontos szabványnak megfelelő típusok. Ezek a matematikai koprocesszor által támogatottak, így alkalmazásukkal a lehető leggyorsabb kód hozható létre. A Real48 típus nem felel meg ennek a szabványnak, így használata nem ajánlott. Csak a Pascallal való kompatibilitás miatt maradt a nyelv része. A Comp gyakorlatilag az Int64-nek felel meg, viszont nem rendelkezik az egész típusukra értelmezett műveletekkel. A Currency négy tizedes jeggyel rendelkező fixpontos érték.

A Real típusnév fordítótól függően a Real48 vagy a Double típusnak felel meg, figyeljünk erre oda, ha ezt a típust használjuk.

Mutató és referencia típusok

 A mutató típus olyan változót határoz meg, amely egy adott memóriaterületre mutat. Példa:

type PointerTípusNév = ^TipusNev; // az adott típusra mutató pointertípust deklarálhatunk így var p: PointerTípusNév; // a p egy PointerTípusNév típusú mutató

 A fenti deklaráció hatására a p változó értéke NIL. Ez azt jelenti, hogy a mutató sehova sem mutat. Ezután hozzárendelhetünk egy neki megfelelő típusú változót az @ operátor segítségével, vagy a heap memóriában új változót hozhatunk létre a New eljárással. Ekkor a memória felszabadítását is nekünk kell elvégezni, ha a változóra többé nincs szükségünk. Ezt a Dispose eljárás segítségével tehetjük meg.

 A Delphiben lehetőség van típus nélküli mutató létrehozására is. (Ez hasonló, mint a C nyelvben a void* .) Ekkor azonban memóriaterületet nem a New, hanem a GetMem eljárással foglalhatunk, melynek meg kell adni a foglalni kívánt memória méretét, a felszabadítás pedig a FreeMem-mel történik.

Műveletek mutatókkal

Object Pascalban kétféle mutatónk van: típusos és típus nélküli. Ezek deklarációja a következőképp történik:

var ip: ^byte; //típusos p: pointer; // típus nélküli

Mindkét mutatótípusra értelmezett az értékadás, pl:

p := nil; ip := p;

A típusos mutató esetén a ^ postfix operátorral érhetjük el a mutatott objektumot:

ip^ := 4;

Ha az $X direktíva be van kapcsolva, akkor tömbre vagy rekordra mutató pointernél a mutatott objektum elemeinek eléréséhez nem kell a ^ jelet kiírni.

Előre-hátra léptetésre van lehetőség az Inc() és Dec() függvények segítségével. Csak a típusos mutatókat tudjuk léptetni, annyi bájttal, amennyi a mutatott típusnak megfelelő adatméret.
Azonos típusú mutatók esetén használhatjuk az = és <> összehasonlító műveleteket. A nil konstans és a pointer típusú mutatók bármilyen típusú mutatóval összehasonlíthatók.
A mutatók típusa típuskonverzióval megváltoztatható. Ilyen módon a pointer típusú mutatókhoz is rendelhetünk típust.
Az Addr() függvény és a @ operátor segítségével bármely Pascal objektum (függvény, változó, stb.) címét lekérdezhetjük, és egy mutatónak értékül adhatjuk.
A Ptr() és az Assigned() utasítással egész értékeket alakíthatunk pointer típusú mutatóvá:

function Ptr(memaddr: Integer): Pointer;

A könyvtári függvények nil értékű mutatóval térnek vissza hiba esetén, ezért használatukkor erre mindig figyelni kell!

Memória-kezelő függvények és eljárások

Object Pascalban a pointer típussal általános mutatót (mint pl. C-ben a void*) deklarálhatunk. Mivel az így létrehozott mutató nem rendelkezik konkrét típussal, ezért a new() eljárást nem használhatjuk memóriafoglalásra. Ebben a esetben adott bájtnyi memóriát a GetMem() eljárás segítségével foglalhatunk le, és a FreeMem() eljárás segítségével szabadíthatunk fel. Ezek az eljárások a System unitban találhatóak.

procedure GetMem(var p: pointer; size: Integer); procedure FreeMem(var p: pointer[; size: Integer]);

Dinamikus memóriaterületet a Sysutils modulban található AllocMem függvény segítségével is foglalhatunk, ekkor a lefoglalt memóriaterület 0-kkal lesz feltöltve. A visszatérési érték a lefoglalt területre mutató pointer.

function AllocMem(size: cardinal): pointer;

A fenti alprogramok segítségével lefoglalt memóriablokk mérete a ReallocMem eljárással megváltoztatható:

procedure ReallocMem(var p: pointer; newsize: integer);

Az alkalmazás által lefoglalt memóriablokkok számát az AllocMemCount, a lefoglalt memória összméretét pedig az AllocMemSize Integer típusú globális változók tartalmazzák.

Variáns típus (variant)

 A variáns típusnak az a kellemes jellegzetessége, hogy nem kell a változó deklarálás időpontjában eldönteni, milyen legyen a típusa, hanem Variant típusúra deklaráljuk, és a változónak a program során adhatunk bármilyen értéket, számértéket, karakterest, tömböt, de még objektum is lehet. Attól függően, hogy mit adtunk neki értékül, olyan típusúvá válik (legalábbis amíg meg nem változtatjuk a tartalmát más típusra). Kompatibilis lesz a benne lévő érték típusával, bírja annak a műveleteit, értékül adható olyan váltózónak, melynek ilyen a típusa. Például a következő programsorok működnek:

procedure VariantPelda; var  V: Variant;  I: Integer;  S: String; begin V:='42'; // a Variant-ba egy stringet teszünk  I:=Integer(V)*2;  // a Stringet tartalmazó Variantot Integerré konvertáljuk  V:=N; // a Variantba most Integert teszünk  S:=V; // az Integert tartalmazó variantot egy Stringnek adjuk értékül end;

 A fenti sorokból is látszik, hogy a Variant igen rugalmasan használható adattípus. Azonban a fentihez hasonló kód írása rengeteg veszélyt rejt magában. Például ha a V változónak kezdetben nem számot tartalmazó Stringet adunk értékül, akkor azt a Delphi nem tudja Integerré konvertálni, és ez kivételt vált ki. Ezért ha tehetjük, inkább használjunk egyéb Delphi adattípusokat. Másik hátránya a Variant típus használatának a lassúsága. A Variant típusa és értéke mindig futás közben dől el, ezért az ilyen változókat tartalmazó kódrészletek szinte interpretált (futás közben értelmezett) kódrészleteknek is tekinthetők, és ez nagymértékben lassítja a programunk futását.

Alprogram típusok

 A Pascalban létezik egy alprogram típus, amely a C-beli függvénymutatóhoz hasonlóan működik. Az alprogram típusok létrehozásakor meg kell adni a paraméterek listáját és függvény esetén a visszatérési érték típusát is. Példák:

type  ProcTípusNév = procedure(a_1: Típus_1, a_2: Típus_2); var  p: ProcTípusNév;

A fenti sorok definiálnak egy adott számú és típusú paraméterrel rendelkező eljárástípust, és egy ilyen típusú változót. Ezután a változóknak értékül adhatunk ilyen fejléccel rendelkező eljárást. A változóhoz a NIL értéket is rendelhetjük. Ez nagyon hasznos, akkor, ha egy definiált eseményt bizonyos esetben le akarunk tiltani, vagy hol ezt, hol azt akarunk végrehajtani valamilyen eseményére.

Metódusreferencia típus

Ez a típus hasonló az alprogram típushoz, de az alprogram címén kívül tartalmazza annak az objektumnak a címét is, amelyre a metódust meg kell hívni. Deklarációjakor az alprogram típus deklarációját ki kell egészítenünk az of object kulcsszavakkal.

type TMethod = procedure of object; TNotifyEvent = procedure(Sender: TObject) of object; var MainForm: TMainForm; OnClick: TNotifyEvent

Ha a TMainForm osztály rendelkezik egy ButtonClick nevű metódussal, amelynek egy TObject típusú paramétere van, akkor az alábbi értékadás érvényes:

OnClick := MainForm.ButtonClick;
Osztályreferencia típus

 Az osztályreferencia típus arra való, hogy megmondjuk a létrehozott osztály nevét és ősét, de nem deklaráljuk még a többi részt, mert azt később is ráérünk, vagy egyszerűen még nem akarjuk, illetve még nincs pontosan meg. (pl.: csoportmunka és azt a típust más írja, de mi fel szeretnénk már használni). Illetve ez arra is jó, ha fordítási időben nem tudjuk még milyen típusú lesz a deklarálni kívánt változó, megadjuk az ős referenciatípusát, és tetszőleges altípusát hozhatjuk majd a programban létre.

type Típusnév = class of Ősosztály;
THandle

 A Windows operációs rendszerrel való kompatibilitás érdekében szükséges volt egészen új adattípusok bevezetésére is (Pl.: DWORD, UINT). Ezek közül a legfontosabb az úgynevezett handle (kezelő). A típus neve THandle, és a következőképpen van definiálva:

type THandle = Integer;

A handle adattípusokat tehát úgy használjuk, mintha számok lennének, de nem szabad elfelejtenünk, hogy valójában nem azok. Ezek a Windows által a belső adatszerkezetekhez hozzárendelt azonosítók. A Windows alatt minden ablaknak, ikonnak, erőforrásnak saját, egyedi azonosítója van, melyet a rendszer a létrehozásakor automatikusan hozzárendel. A későbbiekben ezzel a számmal (handle-lel) hivatkozhatunk rá. (Pl.: ablak mozgatása, láthatóvá tétele, stb.) Az Integer típushoz hasonlóan a THandle típus nagysága is más a 16 illetve 32 bites Windowsban, ezért a Delphiben is.

Típuskonstrukciók

Tömb típus (array type)

 array[Felsorolás_Típus] of Típus

 Több dimenziós tömb megadásának többféle szintaktikája is van, de ezek szemantikailag nem különböznek. array [felsorolás_típus_1, felsorolás_típus_2,... felsorolás_típus_n] of típusnév ugyanaz a tömb, mint ha azt mondanánk: array [felsorolás_típus_1] of array[felsorolás_típus_2] of... of array [felsorolás_típus_n] of típusnév. A tömb elemeire való hivatkozás lehetséges formái: a[1,2,3,12,5,9,...] vagy a[1][2][3][12]....

Dinamikus tömb

A memória dinamikus elérését dinamikus tömbök segítségével is megtehetjük, ezt az Object Pascal a Delphi 4 verziótól kezdve támogatja. A dinamikus tömbök méretét nem a fordítás, hanem a futtatás közben adhatjuk meg. Az egyszerű, egydimenziós dinamikus tömb deklarációja csak a tömb nevét és típusát tartalmazza:

var A:  array of Integer;

A deklaráció során csak egy mutató jön létre, magát a tömböt futás közben a SetLength() eljárás segítségével hozhatjuk létre, pl:

SetLength(A, 10);

Ezen utasítás hatására létrejön a 10 darab egész elemet tartalmazó tömb, melynek elemeire ugyanúgy hivatkozhatunk, mint statikus esetben. A tömb csupa 0-t fog tartalmazni. A SetLength() eljárást nem csak létrehozásra, hanem átméretezésre is használhatjuk, ekkor a tömb értékei megmaradnak bővítés esetén. A Copy utasítás segítségével egy dinamikus tömb adott indexű elemétől kezdődően, megadott számú elemet átmásolhatunk egy új dinamikus tömbbe. Azonos típusú dinamikus tömbök között értelmezett az értékadás művelete is, melyen eredménye az lesz, hogy a bal oldalon álló dinamikus tömb mutatója ugyanoda fog mutatni, mint a jobb oldalon álló dinamikus tömbé. Dinamikus tömbök esetében a Length() függvény a tömb elemeinek számát adja vissza. Lekérdezhetjük még a az alsó és felső indexhatárt a Low() illetve a High() függvény segítségével. Az alsó indexhatár mindig 0, üres tömb esetén a felső indexhatár-1. A dinamikus tömbök felszabadításáról referenciaszámláló mechanizmus gondoskodik. A felszabadítást kikényszeríthetjük az alábbi módokon: nil –re állítjuk a tömböt, SetLength() segítségével 0 hosszúvá tesszük a tömböt, vagy a Finalize eljárás meghívásával.

Többdimenziós dinamikus tömböket dinamikus tömbök dinamikus tömbjeként állíthatunk elő, pl:

var B: array of array of integer;

A SetLength() eljáráshívásban ekkor meg lehet adni mind a két kiterjedést. Ugyanakkor többdimenziós esetben lépésenként is megadhatjuk a tömb méreteit, így ’kesztyűszerű’ tömböket is létre tudunk hozni, pl:

SetLength(B,5,5);

Többdimenziós tömbök törlése ugyanúgy történhet, mint az egydimenziós esetben.

Állománytípusok

 Ez egy tipikusan Pascal típus. Egy új file adattípust a következő sorral definiálhatunk:

type  TIntFile = file of Integer;  // egy Integer értékekből álló fájltípust határoz meg var  MyFile: TIntFile;  // egy Integer értékeket tartalmazó fájlra hivatkozó fájlváltozót deklaráltunk

 Ezután a MyFile változót hozzárendelhetjük egy fizikai állományhoz, majd értékeket olvashatunk belőle, vagy írhatunk bele.

Létezik típus nélküli fájl típus is (file). Ezeknek a fájloknak kézzel kell beállítanunk egy rekordméretet, valamint blokkosan olvashatjuk rekordonkénti olvasás helyett. A standard könyvtár tartalmaz egy TextFile (Pascalban Text) típust, amellyel karakterenként vagy soronként kezelhetünk szöveges fájlokat.

Szöveges típusok

 A Delphiben a stringek kezelése ugyanolyan egyszerű, mint Pascalban volt. A hagyományos Pascal stringen kívül a Delphi bevezet két új string típust is: a Windows rendszerrutinok által használt "C-típusú" nullával lezárt stringet, illetve az alapértelmezett hosszú string típust. Ebben a pontban sorra vesszük ezeket, és megnézzük a köztük lévő különbségeket, használatuk alapjait, és a velük kapcsolatos problémákat.

A hagyományos Pascal stringek

 A Pascalhoz hasonlóan a Delphi 16 bites verziójában is a string adattípus egy karaktersorozat, amely a string nulladik elemében (első bájt) tárolja a string hosszát. Az ilyen stringek fix méretűek, maximálisan 255 karakter hosszúak. Ez a legjelentősebb hátrányuk. A string hasonlóan viselkedik a tömb típushoz, ezért is hivatkozhatunk a string egyes elemeire szögletes zárójelek közötti indexeléssel:

var  Name:String;  FirstChar:Char;

Ezen deklaráció mellett írhatjuk a következőt:

 FirstChar:=Name[1];
A Delphi hosszú stringjei

 A hagyományos string hátrányainak kiküszöbölése érdekében a 32 bites Delphi három új stringet vezetett be:

  1. ShortString: Ez a típus felel meg a hagyományos Pascal stringnek, amelyről az előző pont szól.
  2. ANSIString: Ez az új, változó hosszúságú string típus neve. Az ilyen típusú stringek számára dinamikusan foglalódik a memória, így méretük szinte korlátlan lehet (maximum 2 GB) . A string elemei ANSIChar típusúak.
  3. WideString: COM-kompatibilis string típus. A Windows memóriakezelő foglalja le, WideChar típusú karakterekből áll. Indexelése nem megbízható (az i. elem nem mindig ugyanaz, mint az i. karakter).
  4. UnicodeString: A Unicode-ot támogató Delphi verziókban ez az alapértelmezett string típus. Hasonlóan viselkedik, mint az AnsiString (főleg teljesítmény szempontjából), de Unicode karakterek tárolására is alkalmas. A WideString csak a COM-kompatibilitás miatt maradt meg.

 Figyelem: különböző Delphi verziók esetén eltérő lehet az alapértelmezett karakter mérete, így elromolhatnak olyan régi kódok, amelyek a string típust használják és feltételezik, hogy a karakterek mérete 1 bájt.

 A dinamikus memóriafoglalás nem csak a méret növelhetőségét jelenti, hanem azt is, hogy ha egy stringet megduplázunk, akkor az új string helyett csak egy mutató másolódik le, amely az eredeti stringre mutat. Ha bármelyik stringet megváltoztatjuk, akkor az egész string megduplázódik. A Delphi a hosszú stringjeit hivatkozásszámlálási mechanizmussal kezeli, azaz számon tartja, hogy az egyes stringekre hány változó hivatkozik. Amikor ez a szám nullára csökken, a string által lefoglalt memóriát a rendszer felszabadítja.

 Amikor egy string méretét növeljük, és az már nem fér el az adott helyén, akkor a teljes string átmásolódik egy nagyobb helyre. Ez időigényes művelet, ezért lehetőségünk van a string számára megfelelő nagyságú memóriát előre lefoglalni: (Ez különösen fontos, ha a stringet egy API függvénynek adjuk át a megfelelő konvertálás után.)

 SetLength (StringNeve, 1000);  // a StringNeve stringnek 1000 bájtnyi helyet foglaltunk

 A 32 bites Delphi String típusa a $H fordítási direktívától függően ShortString ($H-) vagy ANSIString / UnicodeString ($H+ alapbeállítás).

 A hosszú stringek elemeire is indexeléssel hivatkozhatunk, első elemre az egyes indexszel. Van azonban egy különbség. Míg a hagyományos Pascal stringek méretét lekérdezhettük (sőt be is állíthattuk,) a string nulladik elemén keresztül, erre hosszú stringek esetén nincs mód. (Egyszerűen azért, mert a méret nincs a nulladik elemben eltárolva.) Ehelyett használjuk a Length függvényt a méret lekérdezésére, a SetLength eljárást pedig a méret beállítására.

PChar Típus

 Ez igazából egy karakterre (karakter sorozatra) mutató pointer (^AnsiChar vagy ^WideChar), úgy is fogalmazhatunk, hogy ez úgynevezett "C-típusú" string. Ez azért lényeges, mert számos Windows API függvény PChar típusú paramétert feltételez. Ahhoz, hogy egy eljárásnak átadjunk egy ilyen típusú változót, először memóriát kell foglalnunk számára a GetMem vagy a NewStr függvénnyel. (Ez esetben ne felejtsük el a memóriát felszabadítani a Dispose eljárással, ha már nincs szükségünk rá.)

 Delphiben a nulla indexhatárú karaktertömbök kompatibilisek (ha az "extended language syntax" engedélyezve van - alapbeállítás) a PChar típussal, így egyszerűen hozhatunk létre ilyen típusú stringeket:

var  PéldaString: array[0..50] of Char;

Ezután ezt a tömböt feltöltjük, majd tetszőleges API függvénynek átadhatjuk. (Természetesen a string végét 0-nak kell zárnia.) Nullavégű stringekre csak a SysUtils-ban definiált stringkezelő függvényeket használhatjuk ( pl. := helyett StrCopy ). Ilyen stringek használatakor az X direktívának bekapcsolt állapotban kell lennie.

 Harmadik, és talán legegyszerűbb módszer a Delphi hosszú stringek használata. Ezek nullával lezárt stringek, ezért kompatibilisek a Windows "C-típusú" stringjeivel. Amennyiben egy hosszú Pascal stringet szeretnénk PChar típusúvá konvertálni, (pl. egy API függvény paramétereként) típusmegfeleltetést kell alkalmazni. Az ellentétes irányú konverzióhoz még ez sem szükséges.

procedure TForm1.Button1Click(Sender: TObject); var  S1: String; // deklarálunk egy hosszú Pascal stringet begin  SetLength(S1, 100);  // a string hosszát 100-ra állítjuk  GetWindowText(Handle, PChar(S1), Length(S1));  // átadjuk a stringet PChar-rá konvertálva egy API függvénynek  Edit1.Text:=S1;  // egy hosszú Pascal string típusú változónak (tulajdonságnak) adjuk értékül end;

 A fenti konverzió működik, ám mégis léphetnek fel problémák. Ez azért lehetséges, mert az átalakítás után a Delphi nem kezeli a stringet, annak tartalmáért mi felelünk. Módosítsuk az előző példát! Szúrjunk be a következő sort az API függvényhívás után:

 S1:=S1 + ' van az ablak fejlécében.';

Ha újrafordítás után futtatjuk a programot, azt tapasztaljuk, hogy az editboxban csak a form fejléce látszik (mint az előbb). Mi is történt itt? Amikor a Windows a stringbe írt, nem állította be a Delphi hosszú string hosszúságát. (A nulla lezárást persze megfelelően kezelte.) Ennek ellenére a Delphi megtalálja a string végét a nulla byte miatt, de a megfelelő hosszt ő sem állítja be, hisz konvertálás után nem felel a stringért. Így amit a string után írtunk, az a nulla lezárás után került, ezért nem íródott ki. Persze a problémának van megoldása. A Delphit utasítani kell, hogy az API függvény által visszaadott stringet konvertálja Pascal hosszú stringgé. (Azaz állítsa be a hosszúságát a valóságnak megfelelően.) Ha azonban a következő sorral próbálkozunk:

 S1:=String(S1);

akkor semmi sem történik, mert ezt a sort a fordító figyelmen kívül hagyja, mondván egy típust a saját típusába konvertálni felesleges dolog, ezért a stringet ezért PCharrá alakítjuk, majd azt vissza Pascal stringgé:

 S1:=String(PChar(S1));

A string átalakítás el is hagyható, mert a PChar - String konverzió automatikus a Delphiben, azaz a végső megoldás:

 S1:=PChar(S1);

Direkt szorzat típus

 A Delphiben a rekord a szokásos:

type rekordTípusNév = record  mező_1: típus_1;   ...  mező_n: típus_n; end; var rekord: rekordTípusNév;

A tagokat a . operátorral érhetjük el:

rekord.mező_1 := 5;

A rekordokra értelmezett az értékadás. Név szerinti ekvivalencia vonatkozik rájuk. Nem adható paraméter a rekordnak. A kezdőérték szintaxisa az alábbi:

var rek: rekordTípusNév = (mező_1:4; mező_2:'abc'; ... mező_n:6);

Ez a szintaxis csak változó és konstans deklarásakor használható, utasításban nem. A Pascal egy egyedi lehetősége, hogy a with rekord do utasítás szerkezettel az utasításban úgy használhatjuk a rekord mezőit, mintha azok lokális változók lennének:

with rekord do begin mező_1 := 6; mező_2 := 'hello'; end;

Ez főleg akkor hasznos, ha a rekord egy bonyolult kifejezéssel érhető csak el.

A Delphi az {$A} direktíva állapotától függően igazítja a rekord mezőit, hogy gyorsabb legyen az elérés. Ha nem szeretnénk állítani a direktívát, de egy adott rekordtípus esetén szükséges az igazítás kikapcsolása (pl. hálózati kommunikáció), akkor packed record-ként definiáljuk.

Az újabb Delphi verziókban a rekordoknak lehetnek osztályjellegű tulajdonságai: konstruktorai, metódusai, jellemzői (property), ezek „osztály”-szintű megfelelői, valamint beágyazott típusai. Viszont ettől nem válnak valódi osztállyá, pl. megmarad az érték szerinti átadás, a konstruktor nélküli létrehozás, operátor-túlterhelés, a variáns rekord (ld. unió típus) lehetősége, és nem támogatják az öröklődést, virtuális metódusokat, a destruktorokat és az interfészek megvalósítását.

Unió típus

A rekordok egy speciális tulajdonsága, hogy tartalmazhatnak variáns részt, ezáltal unió típust valósítanak meg. Az uniónak megadható szétválasztó mező, de ennek ellenére mindig elérhetjük az unió összes ágát.

type Személy = record Vezetéknév, Keresztnév: string; SzülDátum: TDate; case Állampolgár: Boolean of True: (SzülHely: string); False: (Ország: string; BelépésiHely: string; BelépésDátum, KilépésDátum: TDate); end;

Halmaz típus

A Delphiben a halmaz nyelvi elemként is létezik. Csak olyan típusból lehet halmazt készíteni, amely felsorolás típus, azaz rákövetkezési relációval bír.

Hátránya: maximum 256 db eleme lehet, és ezek sorszámának a 0..255 intervallumba kell esnie.

Példa:

type  Digits= set of 0..9;  Letters=set of['A'..'Z','a'..'z'];  Day= (Sun, Mon, Tue, Wed, Thu, Fri, Sat);  Days= set of Day;
Az Include és Exclude eljárás

  A két eljárás használatával egyszerűen megoldható a halmazhoz egy elem hozzáadása (Include) vagy egy elem elvétele (Exclude). A két eljárás paramétere egy T típusú halmaz, valamint egy T típussal kompatibilis kifejezés (pl. Include(h,'a')).

Halmazkonstruktorok

Halmaz típusú konstanst a halmazkonstruktor segítségével állítunk elő: szögletes zárójelek között vesszővel elválasztva felsoroljuk a halmaz elemeit. Az egyes elemek mellett intervallumok is szerepelhetnek benne.

['A'..'Z', 'a'..'z', Chr(Digit + 48)]

Típuskonverzió

Az Object Pascal erősen típusos nyelv, így alapértelmezésben nincs lehetőség típuskonverzióra. Ha azonban mégis erre lenne szükség, két lehetőség kínálkozik:

Az egyik, hogy a szabványos könyvtári függvények segítségével végezzük el az átalakítást, pl:

round() // valós -> egész

trunc() // valós -> egész

ord() // char -> egész

chr() // egész -> char

A másik lehetőség, hogy explicit típuskényszerítést használunk, amely ránézésre olyan, mintha a típus nevét használnánk függvényként. Ez a módszer csak akkor működik, ha az érték és a kívánt típus azonos méretű, és nem keverjük az egész és valós számokat (arra ott vannak a könyvtári függvények).

Integer('A');

Típusidentitás

Két típus azonos, ha egy típusazonosító egy másik típusazonosítóval van definiálva:

type T1 = Integer; T2 = T1; T3 = Integer; T4 = T2;

Itt T1, T2, T3, T4 és Integer ugyanazt a típust jelölik. A típuskonstrukciók különböző típusokat hoznak létre még akkor is, ha ugyanaz a konstrukció:

type TS1 = set of Char; TS2 = set of Char; var S1: string[10]; S2: string[10];

TS1 és TS2 különböző típusok, valamint S1 és S2 különböző típusú változók. Két azonos típusú változót így hozhatunk létre:

var S1, S2: string[10];

vagy:

type SajátString = string[10]; var S1: SajátString; S2: SajátString;

Típuskompatibilitás

Minden típus kompatibilis saját magával. Két típus kompatibilis, ha az alábbiak közül legalább egy teljesül: A típuskompatibilitás nem mindig jelent értékadás szerinti kompatibilitást.

Változók, konstansok

Változó és konstans csak az eljárások, függvények deklarációs részében, valamint a globális hatáskörben definiálható. Változóra láthattunk példákat a fenti kódrészletekben.

Konstans definiálása: a const kulcsszó után tetszőleges kifejezés megadható, amelynek típusa egyértelmű és a fordítás pillanatában kiértékelhető, vagy mi magunk is megadhatjuk a típust:

const A = 2; // Integer B = pi/2; // Extended C = (2*A+4) div 2; // Integer D : Extended = 2; // Extended E = Abs(Trunc(4/2)); // Integer (!) F = Int64(42) // Int64

Bizonyos beépített függvények használhatók konstans kifejezések megadásában (lásd E változó): Abs, High, Low, Pred, Succ, Chr, Length, Odd, Round, Swap, Hi, Lo Ord, SizeOf, Trunc. Kétféle konstans létezik: valódi konstans (<név> = <érték>) és típusos konstans (<név> : <típus> = <érték>). Minden valódi konstans fordításkor szövegszerűen helyettesítődik az értékével, míg a típusos konstans értéke megváltoztatható, ha a {$J+} fordítói direktíva adott (nem javasolt, csak visszafelé kompatibilitás miatt van). A változóknak is adható kezdőérték a típusos konstans szintaxisával.

Stringek esetén van egy további lehetőségünk: a resourcestring részben deklarált konstansok a Windows végrehajtható fájl erőforrás (resource) részében kapnak helyet, így a program többi részének újrafordítása nélkül is megváltoztathatók.

Kifejezések, operátorok

A legegyszerűbb kifejezés a változó vagy konstans. Kifejezésekből felépíthetünk összetettebb kifejezéseket az operátorokkal, függvényhívásokkal, halmazkonstruktorokkal, indexeléssel és típuskényszerítéssel.

Aritmetikai operátorok

A Delphi aritmetikai operátorai: +, -, *, /, div, mod, not, and, or, xor, shl, shr. A +, -, * (ebből a +, - lehet unáris is) egész és valós számokra is működnek. Ha legalább az egyik argumentum valós, akkor az eredmény is valós. Egyébként az eredmény típusa Int64, ha van ilyen típusú argumentum. A többi egész típusra az eredmény Integer. A / osztás eredménye mindig valós, a div-é pedig egész (abszolút értékben lefelé kerekítve). A mod operátor az osztási maradékot adja meg: x mod y = x - (x div y) * y. A not, and, or, xor egész argumentum(ok)ra bitenként végzik el a megfelelő logikai műveletet. Az shr, shl a bitenkénti jobbra ill. balra léptetés művelete (az shr figyelembe veszi az előjelet, az shl nem).

Logikai operátorok

not, and, or, xor. Az and és or kiértékelése a $B direktívától függ: {$B-} állapotban (alapértelmezés) a kiértékelés rövidzáras, {$B+} állapotban teljes. Ez alól kivétel, ha az egyik argumentum Variant típusú: ekkor mindenképpen teljesen kiértékelődik a kifejezés.

Összehasonlító operátorok

=, <>, <, >, <=, >=. Fontos megjegyezni, hogy az összehasonlító operátorok precedenciája itt alacsonyabb, mint a logikai műveleteké (a Delphiben csak 4 precedenciaszint van), így pl. az a = b and c > d helytelen kifejezés, (a = b) and (c > d) alakban kell leírni.

Halmazműveletek

 A halmaz típus bír annak a szokásos műveleteivel: in (eleme-e), + (unió), -(különbség), * (metszet), illetve lehet halmazok egyenlőségét lekérdezni (=), és van halmazok közti <=, >=, <>; (A <= B igaz, ha A részhalmaza B-nek).

Stringműveletek

A stringekre értelmezettek az összehasonlító műveletek (lexikografikus rendezés karakterkód szerint), valamint a +, amely konkatenációt jelent. Stringet lehet konkatenálni karakterrel, de ha az WideChar, akkor a string csak AnsiString, UnicodeString vagy WideString lehet. Ha a konkatenáció eredménye hosszabb, mint 255, és ShortString-nek akarjuk értékül adni, akkor a string csonkolódik. Nem lehet stringhez számot stb. konkatenálni (csak explicit konverziós függvényekkel).

Pointerműveletek

Lekérdezhetjük két pointer egyenlőségét vagy különbözőségét. Az = és <> csak a címek egyenlőségét ellenőrzik. Típusos pointer esetén a ^ postfix operátorral érhetjük el a mutatott objektumot. Karakterpointereknél (csak ha a beépített PAnsiChar vagy PWideChar típust használjuk) működik a többi összehasonlító művelet, a pointerhez hozzáadhatunk vagy kivonhatunk egész számot, valamint képezhetjük két pointer különbségét, így könnyebben járhatjuk be egy string karaktereit.

Egyéb operátorok

A @ prefix operátor egy tetszőleges változó, eljárás, függvény vagy metódus esetén visszaad egy pointert, amely az adott dologra mutat. Változó esetén visszaadja a változó címét, típusa a {$T-} (alapértelmezett) állapotban Pointer, {$T+} állapotban a változó típusának megfelelő pointer. Eljárás, függvény, metódus (ez utóbbi esetén kötelező kiírni az osztály nevét) esetén a visszaadott pointer az alprogram belépési pontjára mutat, típusa Pointer.

Osztályokra értelmezett két operátor. Az objektum is Osztály kifejezés megmondja, hogy egy objektum az adott osztályból (vagy egy leszármazottjából) való-e. Az as egy objektumot konvertál a megadott osztály vagy interfész típusra ellenőrzéssel: ha az ellenőrzés sikertelen, kivétel váltódik ki.