- Verbund (Datentyp)
-
Ein Verbund (engl. object composition) ist ein aus Komponenten verschiedener Datentypen zusammengesetzter Datentyp. Da die Komponenten eines Verbunds wieder Verbünde sein können, können so auch komplexe Datenstrukturen definiert werden.
Es gibt grundlegend zwei verschiedene Möglichkeiten der Anordnung der Komponenten in einem Verbund: Die Komponenten werden entweder nacheinander im Speicher angeordnet (beispielsweise als struct in der Programmiersprache C bzw. als record in Pascal bezeichnet), oder alle Komponenten sind überlappend im Speicher angeordnet und jede Komponente hat die gleiche Anfangsspeicheradresse (beispielsweise als union in der Programmiersprache C bzw. als variant record in Pascal bezeichnet). Letzteres hat den Vorteil, dass der gesamte Verbund weniger Speicher verbraucht, er jedoch nur für einzelne Szenarien zweckmäßig ist.
In einigen rein objektorientierten Sprachen, wie beispielsweise Smalltalk, sind Verbünde daher nicht vorgesehen. Dadurch, dass auf ihre Elemente normalerweise direkt zugegriffen werden kann, wird gegen das Prinzip der Kapselung verstoßen. Andere rein objektorientierte Sprachen, wie zum Beispiel Oberon oder Component Pascal verwenden erweiterte Verbünde, bei denen auf sehr einfache Art und Weise Methoden und Sichtbarkeitsregeln (Exportkennzeichnungen) definiert werden können, um Vererbung zu modellieren.
Ein Datensatz ist eine Instanz eines Verbunds.
Inhaltsverzeichnis
Struct
C/C++-Strukturen
Strukturen werden in der Programmiersprache C sowie C++ auf folgende weise deklariert:
-
struct Verbundname {
-
type attribut;
-
type attribut2;
-
[...]
-
} instanz1, instanz2, ...;
Die Deklarierung einer Struktur erwartet nach dem Schlüsselwort struct einen eindeutigen Namen der Struktur, der anschließend (bei C++) im gesamten Namensraum bzw. (bei C) global gültig ist, um Instanzen der Struktur zu erzeugen. Eine oder mehrere Instanzen können auch direkt nach der Auflistung der Attribute erzeugt werden, wie im Beispiel mit instanz1, instanz2 angedeutet.
Strukturen dürfen sowohl in C als auch in C++ auch keine Attribute beinhalten (leere Struktur), in diesem Fall erzeugen die meisten Compiler automatisch ein Attribut des Datentypes char.
Strukturen dürfen auch andere Strukturen enthalten, jedoch nicht sich selbst, weil die Größe einer Struktur damit undefiniert wäre. Ein Zeiger auf sich selbst ist jedoch möglich – auf diese Weise werden beispielsweise verkettete Listen erzeugt.
Implementierung in Component Pascal
Ein Verbund vom Datentyp Person für die beiden Instanzen Mustermann1 und Mustermann2 könnte in Component Pascal zum Beispiel folgendermaßen definiert und verwendet werden, und nur Instanzen desselben Datentyps sind in dieser Programmiersprache zuweisungskompatibel:
MODULE Personen; IMPORT Dates; TYPE Person = RECORD Vorname, Name, Wohnort: ARRAY 256 OF CHAR; Geburtstag: Dates.Date; END; VAR Mustermann1, Mustermann2: Person; BEGIN Mustermann1.Vorname := "Hans"; Mustermann1.Name := "Mustermann"; Mustermann1.Wohnort := "Musterstadt"; Mustermann1.Geburtstag.day := 1; Mustermann1.Geburtstag.month := 1; Mustermann1.Geburtstag.year := 1900; Mustermann2 := Mustermann1; (* Zwei Variablen vom selben Datentyp sind zuweisungskompatibel *) END Personen.
Der importierte im Modul Dates definierte Datentyp Dates.Date ist wiederum ein Verbund mit den ganzzahligen Elementen day (Tag), month (Monat) und year (Jahr).
Union
Die Komponenten einer Union teilen sich einen Speicherbereich. Die Anfangsadresse jeder Komponente im Speicher ist identisch, das heißt die Speicherbereiche der Komponenten haben einen Überlapp.
Der Speicherbedarf einer Union u mit k Komponenten ist definiert als , wobei ci die i-te Komponente der Union u bezeichnet.
Unions sind in verschiedenen Programmiersprachen entweder als tagged-Unions oder untagged-Unions implementiert.
Eine tagged-Union ordnet jeder Komponente einen tag zu. Beim Schreiben einer Komponente wird der tag dieser Komponente in der Union-Variable gespeichert. Bei Lesezugriffen auf Komponente einer Union wird der tag der zu lesenden Komponente mit dem tag der letzten geschriebenen Komponente verglichen. Unterscheiden sich die tags ist ein Typfehler festgestellt. Somit sind tagged-Unions typsicher.
Untagged-Unions verwenden keine tags und sind deswegen typunsicher. D.h. es liegt in der Verantwortung des Programmierers, dass der letzte Schreibzugriff einer Union die gleiche Komponente verändert hat, die auch der darauf folgende Lesezugriff ausliest. Neben unbeabsichtigten Typfehlern bei der Verwendung von untagged-Unions existieren aber auch Anwendungsfälle für die Seiteneffekte von untagged-Unions. Beispielsweise eine Union aus einer IEEE-Gleitkommazahl und einer struct, deren Komponenten den Zugriff auf Vorzeichen, Mantisse und Exponent erlauben.
Beispiel: tagged-Union
Beispiel der Deklaration einer tagged-Union in Haskell.
data Tree a = Br (Tree a) (Tree a) | Leaf a | Nil
Tree ist ein algebraischer Datentyp und die Konstruktoren des Datentyps sind die tags. Die tags der Union sind also Br, Leaf und Nil.
Beispiel: untagged-Union
Die Programmiersprachen C sowie C++ implementieren untagged-Unions:
union endian { int i; char c; }; union endian e; e.i = 1; if (e.c) puts("litte endian"); else puts("big endian");
Je nach Rechnerarchitektur überlappen sich das least- bzw. most-significant Byte des Integer-Komponente i und die 1-Byte große Komponente c.
Siehe auch
-
Wikimedia Foundation.