Syntax A:
TYPE TypenName [EXTENDS Mutterklasse] [FIELD = Zahl]
var1 [AS Datentyp]
[var2 [AS Datentyp] ]
[...]
END TYPE
Syntax B:
TYPE TypenName[EXTENDS Mutterklasse] [FIELD = Zahl]
[ AS Datentyp] var1 [, var2 [, ...] ]
[[AS Datentyp] var3 [, var4 [, ...] ]
[...]
END TYPE
Syntax C:
TYPE TypenName AS Datentyp
Typ: Anweisung
Kategorie: Speicherverwaltung
TYPE wird verwendet, um UDTs (user defined types, also benutzerdefinierte Datentypen) zu erstellen, die mehrere Variablen/Arrays enthalten können.
- 'var1', 'var2', ... sind Bezeichner von Variablen, die in diesem UDT verwendet werden. Sie werden als Records bezeichnet. Die Records können auch durch Kommata voneinander getrennt sein. Wie bei DIM darf der Teil AS Datentypen auch zu Beginn einer Zeile stehen.
- 'Datentyp' ist der Typ, den die Records besitzen sollen. Jeder Record darf einen anderen Datentypen besitzen, sie können jedoch auch denselben Datentyp besitzen. Auch Arrays, Strings fester und variabler Länge, Pointer (Zeiger) und andere UDTs sind erlaubt.
- 'EXTENDS' kann verwendet werden, um den eigenen Datentypen die Records eines anderen UDTs erben zu lassen.
- 'FIELD = Zahl' bestimmt, auf welche Größe das Feld "ausgestreckt" werden soll ("Padding"). Aus Geschwindigkeitsgründen werden alle Werte standardmäßig als 32bit-Werte (4 Bytes) gespeichert. Sie können die Daten aber mit dem Parameter "FIELD = 1" auf ihre echte Größe komprimieren. Das kann allerdings zu Problemen führen, wenn angenommen wird, dass die Daten komprimiert vorliegen, obwohl sie es nicht sind. Derartige Probleme können beispielsweise bei externen Bibliotheken und DLLs auftreten. Wenn Sie ein Feld mit drei BYTE-Records also auf 4 padden, wird es dennoch vier Bytes lang sein. Wenn Sie ein Feld mit fünf BYTE-Records auf 4 padden, wird es acht Bytes lang sein. Wird dieser Parameter ausgelassen, nimmt FreeBASIC automatisch 4 an.
Ein mit TYPE erstellter Datentyp kann einer Variable mit DIM, REDIM, COMMON oder STATIC (Anweisung) zugewiesen werden. Auf die einzelnen Records wird dann über die Syntax Variable.Record zugegriffen (siehe auch WITH, TYPE (Funktion)).
Beispiel:
TYPE clr
AS UBYTE red, green, blue
END TYPE
TYPE AnotherUDT
IntVal AS INTEGER
fStrVal AS STRING * 7
vStrVal AS STRING
Array(5) AS clr
UdtPtr AS clr PTR
END TYPE
DIM a AS clr
DIM b AS AnotherUDT
a.red = 255
a.green = 128
a.blue = 64
PRINT a.red, a.green, a.blue
PRINT
b.IntVal = 10023
b.fStrVal = "abcdefg"
b.vStrVal = "abcdefghijklmnopqrstuvwxyz"
b.Array(0).green = 255
b.UdtPtr = @a
PRINT b.IntVal
PRINT b.fStrVal
PRINT b.vStrVal
PRINT b.Array(0).green
PRINT b.UdtPtr->blue
SLEEP
Wollen Sie eine Reihe von Ganzzahlen in einem UDT speichern, die in einem relativ kleinen Wertebereich liegen, können Sie das über ein Bitfeld erreichen. Siehe dazu Bitfelder.
Die Syntax für ein Bitfeld ist:
TYPE BitFeldName [FIELD = Zahl]
Bit1Name : Bits AS INTEGER
Bit2Name : Bits AS INTEGER
...
END TYPE
- 'Bit1Name', Bit2Name', ... sind dabei die Bezeichner, über den der Record angesprochen werden kann.
- 'Bits' ist eine INTEGER-Konstante, die angibt, wie viele Bits für diesen Record verwendet werden sollen.
- 'AS INTEGER' ist ein fester Bestandteil dieser Syntax-Struktur.
- Für das Padding gelten dieselben Regeln wie bei normalen Feldern.
Beispiel: Checkbox-Verwaltung mit Bitfeldern:
TYPE CheckBoxenType
CB1 : 1 AS INTEGER
CB2 : 1 AS INTEGER
CB3 : 1 AS INTEGER
END TYPE
DIM CheckBoxen AS CheckBoxenType
' Status setzen:
CheckBoxen.CB1 = 1 ' aktiv
CheckBoxen.CB2 = 0 ' nicht aktiv
CheckBoxen.CB3 = 1 ' aktiv
' ... Programmcode ...
' Status abfragen:
IF CheckBoxen.CB1 THEN '...
IF CheckBoxen.CB2 THEN '...
IF CheckBoxen.CB3 THEN '...
Die letzte Verwendungsmöglichkeit erlaubt es, eine Variable direkt wie einen eingebauten Datentypen zu verwenden:
Type myDatatype As Integer
Der Vorteil dieser Methode ist, dass man den Datentypen nur an einer Stelle ändern muss, statt an jeder Stelle, an der ein Datentyp verwendet wird.
FreeBASIC erlaubt für diese Syntaxform, neben den allgemeinen Datentypen, auch Pointer auf Prozeduren (Callbacks). Dies hat die Vorteile, dass einerseits die Deklaration verkürzt wird, was Schreibaufwand ersparen kann und andererseits, im Gegensatz zur normalen Deklaration, auch Pointer auf Callbackfunktionen ermöglicht werden:
'Beispielfunktionen
Function testAufruf() As Integer
Return 1
End Function
Function testAufrufPointer() As Integer Ptr
Return Cast(Integer Ptr, 2)
End Function
'Callbackfunktionen
Dim func As Function() As Integer
Dim pointerFunc As Function() As Integer Ptr
'Pointer für Callbackfunktionen
Type pointerFunc_Type As Function() As Integer
Dim pointerPointerFunc As pointerFunc_Type Ptr
'Funktionszuweisungen
func = @testAufruf 'Callback auf die erste Funktion
pointerFunc = @testAufrufPointer 'Callback auf die zweite Funktion
pointerPointerFunc = @func 'Pointer auf das Callback der ersten Funktion
Print "Funktionsadressen:", func, pointerFunc, pointerPointerFunc
Print "Funktionsaufrufe:", func(), pointerFunc(), *pointerPointerFunc()
Sleep
Objekte in FreeBASIC:
Seit Version 0.17 bietet FreeBASIC objektorientierte Ansätze, die beispielsweise Methoden, Konstruktoren und Destruktoren in UDTs erlauben. Hierzu gibt es im Portal mehrere Tutorials, unter anderem dieses hier: Das UDT-Tutorial.
Beispiel für objektorientierte Programmierung:
'Vektorklasse
Type Vector
W as Integer
H as Integer
Declare Constructor (nW as Integer, nH as Integer)
End Type
Constructor Vector (nW as Integer, nH as Integer)
W = nW
H = nH
End Constructor
'Klasse zur Erstellung eines Objekts
Type AObject
Private:
X as Integer
Y as Integer
Movement as Vector Pointer
Public:
'Öffentliche Methoden inklusive eines Konstruktors und eines Destruktors
Declare Constructor (nX as Integer, nY as Integer)
Declare Destructor ()
Declare Sub SetMotion (Motion as Vector Pointer)
Declare Sub Move ()
Declare Property GetX as Integer
End Type
'Initialwerte setzen
Constructor AObject (nX as Integer, nY as Integer)
X = nX
Y = nY
End Constructor
'Allozierten Speicher freigeben
Destructor AObject ()
Delete Movement
End Destructor
'Bewegungsvektor setzen
Sub AObject.SetMotion (Motion as Vector Pointer)
Movement = Motion
End Sub
'Das Objekt anhand seines Bewegungsvektors bewegen
Sub AObject.Move ()
X += Movement->W
Y += Movement->H
End Sub
'Rückgabe von X, welches sonst nicht zugänglich wäre
Property AObject.GetX as Integer
Return X
End Property
'Hauptprogramm
'Eine neue Instanz von 'AObject' an den Koordinaten 100, 100 erstellen
Dim Player as AObject = Type<AObject>(100, 100)
/'Ein neues Vektorobjekt dynamisch allozieren
und dessen Position um 10 nach links und 5 nach unten verschieben'/
Player.SetMotion(new Vector (-10, 5))
'Die Position von 'Player' aktualisieren
Player.Move()
'Den neuen Wert von X (90) anzeigen
Print Player.GetX
/'Weil 'Player' eine lokale Variable ist, wird sein Destruktor
am Ende des Scopes automatisch aufgerufen'/
'Vor Programmende auf Tastendruck warten
Sleep
Alle UDTs besitzen Standard-Konstruktoren und -Destruktoren, falls keine anderen definiert wurden, die diese überschreiben. Diese können jederzeit explizit aufgerufen werden. Dies gilt allerdings auch für selbsterstellte Konstruktoren und Destruktoren.
Type myType
x As Integer
End Type
Dim As myType Ptr myVar = New myType
myVar->Constructor
myVar->Destructor
Delete myVar
Sleep
Unterschiede zu QB:
- Strings fester Länge besitzen im Gegensatz zu QB ein zusätzliches Zeichen am Ende, wodurch UDTs mit diesen Strings nicht kompatibel zu QB sind, wenn es bei Dateioperationen verwendet wird.
- FreeBASIC unterstützt auch Bitfelder.
Plattformbedingte Unterschiede:
- Das Standardpadding unter Linux und DOS ist 4 Byte.
- Das Standardpadding unter Windows ist 8 Byte.
Unterschiede zu früheren Versionen von FreeBASIC:
- Bitfelder existieren erst seit FreeBASIC v0.13.
- Methoden in UDTs existieren erst seit v0.17.
Unterschiede unter den FB-Dialektformen:
- Methoden in UDTs gibt es nur in -lang "fb".
- Das Standardpadding in -lang "fb" und -lang "fblite" hängt von der Plattform ab, während in -lang "qb" kein Padding durchgeführt wird.
Siehe auch:
TYPE (Funktion), TYPE (Forward Referencing), UNION, ENUM, DIM, OPERATOR, LEN, SIZEOF, OFFSETOF, VARPTR, FIELD, WITH, Bitfelder, CONSTRUCTOR, DESTRUCTOR, PROPERTY, OBJECT, EXTENDS