Lassen Sie uns über die vollständige technische Lösung sprechen, die in den alten Tagen als Best Practice galt.
Das Problem mit Strukturen ist, dass alles öffentlich ist, so dass keine Daten versteckt sind.
Wir können das beheben.
Sie erstellen zwei Headerdateien. Einer ist die "öffentliche" Header-Datei, die von Clients Ihres Codes verwendet wird. Es enthält Definitionen wie folgt aus:
typedef struct t_ProcessStruct *t_ProcessHandle;
extern t_ProcessHandle NewProcess();
extern void DisposeProcess(t_ProcessHandle handle);
typedef struct t_PermissionsStruct *t_PermissionsHandle;
extern t_PermissionsHandle NewPermissions();
extern void DisposePermissions(t_PermissionsHandle handle);
extern void SetProcessPermissions(t_ProcessHandle proc, t_PermissionsHandle perm);
dann Sie eine private Header-Datei erstellen, die Definitionen wie diese enthält:
typedef void (*fDisposeFunction)(void *memoryBlock);
typedef struct {
fDisposeFunction _dispose;
} t_DisposableStruct;
typedef struct {
t_DisposableStruct_disposer; /* must be first */
PID _pid;
/* etc */
} t_ProcessStruct;
typedef struct {
t_DisposableStruct_disposer; /* must be first */
PERM_FLAGS _flags;
/* etc */
} t_PermissionsStruct;
und dann in Ihrer Implementierung können Sie etwas tun:
static void DisposeMallocBlock(void *process) { if (process) free(process); }
static void *NewMallocedDisposer(size_t size)
{
assert(size > sizeof(t_DisposableStruct);
t_DisposableStruct *disp = (t_DisposableStruct *)malloc(size);
if (disp) {
disp->_dispose = DisposeMallocBlock;
}
return disp;
}
static void DisposeUsingDisposer(t_DisposableStruct *ds)
{
assert(ds);
ds->_dispose(ds);
}
t_ProcessHandle NewProcess()
{
t_ProcessHandle proc = (t_ProcessHandle)NewMallocedDisposer(sizeof(t_ProcessStruct));
if (proc) {
proc->PID = NextPID(); /* etc */
}
return proc;
}
void DisposeProcess(t_ProcessHandle proc)
{
DisposeUsingDisposer(&(proc->_disposer));
}
Was passiert ist, dass Sie Forward-Deklarationen für Ihre Strukturen in Ihren öffentlichen Header-Dateien machen. Jetzt sind Ihre Strukturen undurchsichtig, was bedeutet, dass Kunden nicht mit ihnen schwänzen können. Dann fügen Sie in der vollständigen Deklaration einen Destruktor am Anfang jeder Struktur ein, die Sie generisch aufrufen können. Sie können den gleichen Malloc-Allokator für alle die gleiche Dispose-Funktion verwenden und so. Sie machen öffentliche Set/Get-Funktionen für die Elemente, die Sie anzeigen möchten.
Plötzlich ist Ihr Code viel vernünftiger. Sie können nur Strukturen von Zuweisern erhalten oder diese Anrufverteiler bedienen, was bedeutet, dass Sie die Initialisierung des Engpasses blockieren können. Sie bauen Destruktoren ein, damit das Objekt zerstört werden kann. Und du gehst. Übrigens, ein besserer Name als t_DisposableStruct könnte t_vTableStruct sein, denn genau das ist es. Sie können jetzt virtuelle Vererbung erstellen, indem Sie eine vTableStruct verwenden, bei der es sich um Funktionszeiger handelt. Sie können auch Dinge tun, die Sie in einer reinen oo-Sprache nicht tun können (in der Regel), indem Sie ausgewählte Elemente der vtable im laufenden Betrieb ändern.
Der wichtige Punkt ist, dass ist ein Engineering-Muster für die Herstellung von Strukturen sicher und initialisierbar.
Oh cfront, wie wir dich vermissen. – joeforker
... wie ein schrecklicher brennender Ausschlag. – Randolpho
Und wie behandelt cfront Konstruktor am Anfang? – claf