Strukturen

Oft ist es sinnvoll, nicht nur wie in einem Array Daten desselben Datentyps zusammenzufassen, sondern auch Daten verschiedener Datentypen. Das ist mit Klassen möglich, die zusammen mit der objektorientierten Programmierung noch ausführlich behandelt werden. Hier werden (nur) einige Grundbegriffe in Zusammenhang mit sogenannten Strukturen betrachtet.

Der Datentyp struct

Eine mit dem Schlüsselwert struct definierte Klasse ist ein Datentyp, der auch als Struktur bezeichnet wird. Die wie Variablen zwischen den geschweiften Klammern aufgeführten Elemente einer solchen Klasse werden auch als Datenelemente bezeichnet.

Beispiel 1a: Der umgangssprachliche Begriff „Kalenderdatum“ steht für drei Werte, die einen Tag, einen Monat und ein Jahr bezeichnen. Ein solches Datum kann durch die Klasse CDatum mit den Datenelementen Tag, Monat und Jahr dargestellt werden:

struct CDatum 
{int Tag;
 int Monat;
 int Jahr;
}; // Das Semikolon ist hier notwendig.

Mit diesem Datentyp kann man wie mit einem der vordefinierten Datentypen int usw. eine Variable des Datentyps CDatum definieren:

CDatum d;

Gibt man vor dem Semikolon, das eine Klassendefinition abschließt, einen Bezeichner an, ist dieser eine Variable des zugehörigen Klassentyps. Lässt man den Namen der Klasse aus, erhält man eine Variable des Klassentyps. Der Datentyp hat in diesem Fall keinen eigenen Namen.

Beispiel 1b: Die Definition

struct CDatum 
{int Tag;
 int Monat;
 int Jahr;
} d; // d ist eine Variable des Datentyps CDatum.

ist gleichwertig mit den beiden Definitionen aus dem letzten Beispiel. Durch

struct  // Dieser Datentyp hat keinen eigenen Namen.
{int Tag; 
 int Monat;
 int Jahr;
} d; // Der Datentyp von d ist anonym

wird nur eine Variable des Klassentyps definiert. Dieser hat aber keinen eigenen Namen.

Normalerweise wählt man für eine Klasse einen Namen, der genau dem Konzept entspricht, das sie darstellen soll, wie z.B. Datum für ein Kalenderdatum. Da dieser Name aber später noch für eine Variable dieses Typs verwendet werden soll, wurde CDatum gewählt. Mit englischen Namen kann man solche Namenskonflikte durch Groß- und Kleinschreibung umgehen (Date für die Klasse und date für eine Variable des Klassentyps).

Eine Zusammenfassung inhaltlich zusammengehöriger Daten zu einer Klasse kann zur Verständlichkeit eines Programms beitragen und ist generell empfehlenswert.

Beispiel 2: Die Zusammengehörigkeit und Bedeutung der Daten kommt in

struct CKreis
{int x,y,r;
} k1,k2;

unmittelbar zum Ausdruck. Findet man dagegen die Definitionen

int x1, x2, y1, y2, r1, r2;

in einem Programm, das man nicht selbst geschrieben hat, lassen sich nur aus der Verwendung der Variablen Rückschlüsse auf ihre Bedeutung ziehen. Das kann aber bei einem größeren Programm ziemlich aufwendig werden, insbesondere wenn keine zusätzlichen Kommentare die Bedeutung der Daten erklären.

Der etwas höhere Schreibaufwand für Strukturen wird durch die Ersparnis an Kommentaren und die leichtere Verständlichkeit meist kompensiert.

Typische Anwendungen von Strukturen findet man auch in der betriebswirtschaftlichen Datenverarbeitung. Dabei werden oft die einzelnen Zeilen einer Tabelle durch eine Struktur dargestellt, die auch als Datensatz bezeichnet wird. Aus solchen Strukturen werden dann Arrays oder Dateien aufgebaut. Datenbanken sind im Wesentlichen eine mehr oder weniger große Anzahl von Dateien, die alle aus solchen Datensätzen bestehen.

Verschachtelung von Strukturen

Beispiel 3a: Eine Zeile der Tabelle

bck-240.jpg

kann für eine Kontobewegung stehen und durch die folgende Struktur dargestellt werden:

struct Kontobewegung 
{int KontoNr;
 char NameInhaber[20];
 ...
 double Betrag; 
}; 

Dieser Datensatz enthält mit dem Datum einen weiteren Datensatz. Will man dieses Datum unter einem eigenständigen Begriff ansprechen, kann man es innerhalb der Struktur ebenfalls als Struktur definieren:

struct Kontobewegung 
{int KontoNr;
 char NameInhaber[20];
 struct 
 {int Tag;
  int Monat;
  int Jahr;
 } Datum;
 char BewArt;
 double Betrag;
};

Die Verschachtelung von Strukturen kann im Prinzip unbegrenzt fortgesetzt werden. Wenn zuvor ein Name für die Datenstruktur vereinbart wurde, kann auch dieser verwendet werden:

struct Kontobewegung
{int KontoNr;
 char NameInhaber[20];
 CDatum Datum;
 char BewArt;
 double Betrag;
};

Zugriff auf Datenelemente einer Struktur

Eine Variable, deren Datentyp eine Klasse ist, enthält alle Elemente, die bei der Definition der Klasse angegeben wurden. Diese Elemente werden durch den Namen der Variablen angesprochen, auf den ein Punkt und der Name des Elements folgt. Jeder so gebildete Ausdruck ist ein Ausdruck des Datentyps, der bei der Definition des Elements angegeben wurde.

Beispiel 3b: Nach der Definition

Kontobewegung k;

kann man die Elemente der Variablen k folgendermaßen ansprechen:

k.KontoNr // ein Ausdruck des Datentyps int
k.Datum // ein Ausdruck des Datentyps CDatum

Die drei Elemente von K.Datum lassen sich einzeln ansprechen durch

k.Datum.Tag // ein Ausdruck des Datentyps int
k.Datum.Monat
k.Datum.Jahr

Für den Compiler wird durch jede Definition einer Klasse ein neuer Datentyp erzeugt. Deshalb werden durch die beiden Klassendefinitionen in

struct { int i;} s1;
struct { int i;} s2;

zwei verschiedene Datentypen erzeugt, obwohl man auch erwarten könnte, dass die Datentypen von s1 und s2 gleich sind. Da die Datentypen von s1 und s2 verschieden sind, verweigert der Compiler die Übersetzung der Zuweisung

s1=s2; // Fehler: Konvertierung nicht möglich

Verwendet man dagegen denselben Klassennamen bei der Definition von Variablen, haben sie denselben Datentyp und können einander zugewiesen werden. Nach der Definition

Kontobewegung k1;
Kontobewegung k2;

wird die folgende Zuweisung vom Compiler akzeptiert:

k1=k2;

Aufgaben Strukturen