c / expert
Snippet
Dynamischer Schnittstellenaufruf mittels virtueller Methodentabellen
Objektorientierte dynamische Methodenaufrufe können in Standard-C sauber implementiert werden, indem eine Basisstruktur geschachtelt wird, die einen Zeiger auf eine virtuelle Methodentabelle (VTable) enthält. Unterstrukturen platzieren die Basisstruktur als erstes Element, wodurch die Speicheranordnung ein sicheres Casting vom Basistyp auf abgeleitete Typen und somit Laufzeit-Polymorphie ermöglicht.
snippet.c
c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include <stdio.h>struct Shape;typedef struct {double (*area)(const struct Shape *self);} ShapeVTable;typedef struct Shape {const ShapeVTable *vtable;} Shape;typedef struct {Shape base;double radius;} Circle;static double circle_area(const Shape *self) {const Circle *c = (const Circle *)self;return 3.1415926535 * c->radius * c->radius;}static const ShapeVTable circle_vtable = { .area = circle_area };void circle_init(Circle *c, double r) {c->base.vtable = &circle_vtable;c->radius = r;}
Erklärung
1
typedef struct { double (*area)(const struct Shape *self); } ShapeVTable;
Definiert die VTable mit Funktionszeigern für polymorphe Operationen.
2
typedef struct Shape { const ShapeVTable *vtable; } Shape;
Äquivalent einer Basisklasse, das einen unveränderlichen Zeiger auf ihre Laufzeit-Methodentabelle hält.
3
typedef struct { Shape base; double radius; } Circle;
Abgeleitete Struktur, die Shape base als erstes Element platziert, um identischen Speicher-Offset zu garantieren.
4
const Circle *c = (const Circle *)self;
Führt ein sicheres Downcasting des Basiszeigers auf den abgeleiteten Typ basierend auf C-Speichergarantien durch.
5
static const ShapeVTable circle_vtable = { .area = circle_area };
Erstellt eine geteilte, schreibgeschützte VTable-Instanz speziell für Circle-Implementierungen.