2016-02-09 8 views
7

Ich schreibe ein C-Programm und mit gcc 4.4.6 zu kompilieren. Ich möchte keinen C++ Compiler verwenden.C-Programmierung Entkopplung Schnittstelle von der Implementierung mit Struktur Vorwärtsdeklaration

Ich bin eine Komponente implementieren und ich beabsichtige, mehrere Instanzen dieser Komponente zur Laufzeit von anderen Komponenten leben und besitzen.

Um die Definition einer Schnittstelle von ihrer Implementierung zu entkoppeln und die internen Strukturen und Datentypen zu verbergen, die in dieser Implementierung verwendet werden, habe ich versucht, eine Forward-Struct-Deklaration zu verwenden.

Schnittstelle Datei: component.h

struct _hidden_implementation_type; 
typedef struct _hidden_implementation_type visible_type_to_clients; 

int component_function1(visible_type_to_clients instance); 

Implementierungsdatei: component.c

struct _hidden_implementation_type 
{ 
    int foo; 
}; 

Client-Datei: main.c

int main(int argc, char** argv) 
{ 
    visible_type_to_clients a; 
    return component_function1(a); 
} 

Wie mache ich das? Welcher andere Ansatz gibt es, um die Instantiierung mehrerer Komponenten zu ermöglichen und andernfalls eine Entkopplung zwischen der öffentlichen Schnittstelle und der Implementierung zu erreichen?

+2

Der üblicher Ansatz beinhaltet * Zeiger * Typen zu strukturieren, wobei die internen Details der Struktur sind für die Kunden nicht sichtbar. –

+0

'instance_type' ist die Instanz selbst, kein Typ. – Olaf

+0

Das war ein Tippfehler. – Rire1979

Antwort

6

Sie sind fast da. Ihre Schnittstelle hat in Bezug auf die Zeiger auf die undurchsichtige Art sein:

struct hidden_implementation_type; 
typedef struct hidden_implementation_type visible_type_to_clients; 

int component_function1(visible_type_to_clients *instance_type); 

und:

int main(void) 
{ 
    visible_type_to_clients *a = 0; 
    return component_function1(a); 
} 

Dies wird zumindest kompilieren - es wird nichts tun, nützlich, though. Sie würden vermutlich eine Funktion benötigen, wie:

visible_type_to_clients *new_visible(void); 

Wert des Typs zu schaffen und einen Zeiger darauf zurückkommen, und dann können Sie verwenden:

int main(void) 
{ 
    visible_type_to_clients *a = new_visible(); 
    return component_function1(a); 
} 
Grundsätzlich

, die Kunden werden nicht in der Lage sein, Strukturen auf dem Stack (oder globalen Strukturen) Ihres Typs zu erstellen, weil Sie dem Compiler nicht mitgeteilt haben, wie groß der Typ ist. Aber Sie können mit Zeigern umgehen - und getippte Zeiger sind erheblich sicherer als "untypisierte" void * Zeigern.

Ich habe Fehlerprüfung für Einfachheit weggelassen. Ich habe den Struktur-Tag-Namen ohne den führenden Unterstrich neu geschrieben, weil für alle praktischen Zwecke Namen, die mit einem Unterstrich beginnen, reserved for the implementation sind. Ich würde gehen mit:

typedef struct VisibleType VisibleType; 

wo die tag und der typname sind die gleichen.

1

Strukturen versteckt haben Vor- und Nachteile. Eine versteckte Struktur kann vom Client niemals ohne Konstruktor zugewiesen werden. Eine versteckte Struktur benötigt einen Destruktor und der Client muss sich erinnern, ihn aufzurufen. Je nach Anforderung ist dies ein Vorteil oder ein Nachteil.

Hier sind zwei Ausführungen zum Vergleich:

#include <stdio.h> 
#include <stdlib.h> 

/*VIVIBLE.h*/ 
typedef struct 
{ 
    int number; 
}VISIBLE; 
void VISIBLE_INIT(VISIBLE * me, int num); 
void VISIBLE_PRINT(const VISIBLE * me); 

/*VIVIBLE.c*/ 
void VISIBLE_INIT(VISIBLE * me, int num) { if(me) me->number = num; } 
void VISIBLE_PRINT(const VISIBLE * me) { if(me) printf("%i\n", me->number); } 

/*SECRET.h*/ 
struct CLIENT; 
void CLIENT_CTOR(struct CLIENT ** me, int num); 
void CLIENT_DTOR(struct CLIENT ** me); 
void CLIENT_PRINT(const struct CLIENT * me); 

/*SECRET.c*/ 
typedef struct CLIENT 
{ 
    int number; 
}CLIENT; 
void CLIENT_CTOR(CLIENT ** me, int num) 
{ 
    if (me) 
    { 
     *me = (CLIENT*)malloc(sizeof(CLIENT)); 
     (*me)->number = num; 
    } 
} 
void CLIENT_DTOR(CLIENT ** me) 
{ 
    if (me && *me) free(*me); 
    *me = 0; 
} 
void CLIENT_PRINT(const CLIENT * me) { if(me) printf("%i\n", me->number); } 

/*main.c*/ 
void visible() 
{ 
    VISIBLE vis; // client can allocate memory 
    VISIBLE_INIT(&vis, 4); 
    VISIBLE_PRINT(&vis); 
    //if there is no need for a destructor the client does not need to call one 
} 

void hidden() 
{ 
    CLIENT * hidden; 
    CLIENT_CTOR(&hidden, 3); 
    CLIENT_PRINT(hidden); 
    CLIENT_DTOR(&hidden); //Client is never allowed to forget the destructor 
} 

int main() 
{ 
    visible(); 
    hidden(); 
} 
Verwandte Themen