#include #include /* Eine Liste von allen Typen die wir haben. */ /* Typ-IDs kann man auch dynamisch vergeben */ enum Object_Types{ HASI_OBJECT_TYPEID = 1, OSTER_HASI_OBJECT_TYPEID, }; /* Es folgen Strukturbeschreibungen, * es wird noch kein echter Speicherplatz belegt */ /* Vorab-Typedefs von den hier verwendeten Struct-Typen */ typedef struct _HaSiObjectClass HaSiObjectClass; typedef struct _OsterHaSiObjectClass OsterHaSiObjectClass; typedef struct _HaSiObject HaSiObject; typedef struct _OsterHaSiObject OsterHaSiObject; /* das hier ist die Beschreibung unserer Basisklasse, * alle anderen Klassen sind davon abgeleitet */ struct _HaSiObjectClass { int type_id; /* damit können wir später auf den Typ testen */ HaSiObjectClass *parent_class; /* Ein Funktionspointer für die (einzige) Methode unserer Klasse */ int (*hoppel) (HaSiObject *obj, int schritte); }; /* Eine von HaSiObjectClass abgeleitete Klasse. * Wir müssen als erstes (!) Element einen Struct der Elternklasse einbinden * nicht nur ein Pointer! */ struct _OsterHaSiObjectClass { HaSiObjectClass pklass; /* Das ist eine Methode die in dieser Klasse neu dazukommt */ int (* leg_eier) (OsterHaSiObject *sth, int anzahl); }; /* Nach den Klassenbeschreibungen folgen jetzt die Instanz-Structs */ /* Unser Basis-Objekt. Enthält einen Pointer auf "seine" Klassenbeschreibung */ struct _HaSiObject { HaSiObjectClass *klass; int position; }; /* Wie bei den Klassenbeschreibungen binden wir auch hier * einen Struct des ElternObjekts an erster Stelle ein */ struct _OsterHaSiObject { HaSiObject parent; int eier; }; /* Hilfsfunktion zum Aufruf der "hoppel" Methode: einfacher zu lesen */ int hasi_object_hoppel (HaSiObject *hobj, int schritte) { return hobj->klass->hoppel (hobj, schritte); } /* tatsächliche Methodendefinition für hasi_object_hoppel() * macht die eigentliche Arbeit */ int hasi_object_hoppel_real (HaSiObject *hobj, int schritte) { hobj->position += schritte; printf ("Ein HaSi hoppelt mit %d Hopsern auf Position %d\n\n", schritte, hobj->position); return hobj->position; } /* tatsächliche Methodendefinition für hasi_object_do_it() */ /* macht die eigentliche Arbeit */ int oster_hasi_object_hoppel_real (HaSiObject *hobj, int schritte) { OsterHaSiObject *ohobj = (OsterHaSiObject *) hobj; hobj->position += schritte * 2; printf ("Ein OsterHaSi hoppelt mit %d Riesenhopsern auf Position %d.\n", schritte, hobj->position); printf ("Er hat %d Eier im Korb\n\n", ohobj->eier); return hobj->position; } /* Hilfsfunktion: Methodenaufruf für "leg_eier", macht auch * noch einen Check, ob *wirklich* ein OsterHaSi kommt. */ int oster_hasi_object_leg_eier (OsterHaSiObject *ohobj, int anzahl) { HaSiObject *hobj = (HaSiObject *) ohobj; if (hobj->klass->type_id != OSTER_HASI_OBJECT_TYPEID) { printf ("Huch, ein Programmierfehler!\n" "hier versucht gerade ein normales HaSi Eier zu legen!\n\n"); return -1; } return ((OsterHaSiObjectClass *) hobj->klass)->leg_eier (ohobj, anzahl); } int oster_hasi_object_leg_eier_real (OsterHaSiObject *ohobj, int anzahl) { HaSiObject *hobj = (HaSiObject *) ohobj; ohobj->eier -= anzahl; printf ("Ein OsterHaSi legt %d Eier auf Position %d.\n", anzahl, hobj->position); printf ("Er hat noch %d Eier im Korb\n\n", ohobj->eier); return hobj->position; } /* Initialisierung unseres Objektsystems */ /* Speicherbereich für eine Beschreibung der HaSiObject-Klasse */ HaSiObjectClass HaSiObjectBeschreibung; /* Speicherbereich für eine Beschreibung der SomeThing-Klasse */ OsterHaSiObjectClass OsterHaSiObjectBeschreibung; /* jetzt befüllen wir die Objektbeschreibung mit Methoden */ int hasi_init () { HaSiObjectClass *hklass; OsterHaSiObjectClass *ohklass; /* normalerweise hat man pro Klasse eine Klassen-Initialisierungsfunktion */ /* wir initialisieren hier beide von uns */ /* HaSiClass */ hklass = &HaSiObjectBeschreibung; hklass->type_id = HASI_OBJECT_TYPEID; hklass->parent_class = NULL; /* Das ist unsere Basisklasse */ hklass->hoppel = hasi_object_hoppel_real; /* OsterHaSiClass */ ohklass = &OsterHaSiObjectBeschreibung; hklass = (HaSiObjectClass *) ohklass; hklass->type_id = OSTER_HASI_OBJECT_TYPEID; hklass->parent_class = &HaSiObjectBeschreibung; hklass->hoppel = oster_hasi_object_hoppel_real; ohklass->leg_eier = oster_hasi_object_leg_eier_real; return 0; } /* Konstruktor für ein HaSiObject */ /* mit malloc wird echter Speicher besorgt */ HaSiObject * hasi_object_new () { HaSiObject *hobj = malloc (sizeof (HaSiObject)); hobj->klass = &HaSiObjectBeschreibung; hobj->position = 0; return hobj; } /* Konstruktor für SomeThings */ OsterHaSiObject * oster_hasi_object_new (int anzahl_eier) { /* Speicher bereitstellen */ OsterHaSiObject *ohobj = malloc (sizeof (OsterHaSiObject)); /* Abkürzungspointer für die Basisklasse */ HaSiObject *hobj = (HaSiObject *) ohobj; /* Zuweisung einer "Klassenidentität" */ /* klass ist in der Teilstruktur für die Basisklasse */ /* eigentlich müsste hier der Basisklassen-Konstruktor aufgerufen werden */ hobj->klass = (HaSiObjectClass *) &OsterHaSiObjectBeschreibung; hobj->position = 0; /* Initialisierung der "OsterHaSiObject"-spezifischen Member-Variablen */ ohobj->eier = anzahl_eier; return ohobj; } int main (int argc, char *argv[]) { HaSiObject *hobj; OsterHaSiObject *ohobj; hasi_init (); hobj = hasi_object_new (); ohobj = oster_hasi_object_new (15); hasi_object_hoppel (hobj, 7); hasi_object_hoppel ((HaSiObject *) ohobj, 12); oster_hasi_object_leg_eier (ohobj, 3); oster_hasi_object_leg_eier ((OsterHaSiObject *) hobj, 5); return 0; }