2016-02-09 8 views
7

Sto scrivendo un programma in C e utilizzando gcc 4.4.6 per compilare. Non voglio usare un compilatore C++.Interfaccia di disaccoppiamento di programmazione C dall'implementazione con la dichiarazione struct forward

Sto implementando un componente e ho intenzione di avere diverse istanze di questo componente dal vivo e di proprietà di altri componenti in fase di esecuzione.

Come mezzo per disaccoppiare la definizione di un'interfaccia dalla sua implementazione e nascondere le strutture interne e i tipi di dati che utilizza in tale implementazione, ho cercato di utilizzare una dichiarazione di struttura in avanti.

file di

Interfaccia: component.h

struct _hidden_implementation_type; 
typedef struct _hidden_implementation_type visible_type_to_clients; 

int component_function1(visible_type_to_clients instance); 

file di implementazione: component.c

struct _hidden_implementation_type 
{ 
    int foo; 
}; 

file del client: main.c

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

Come posso farlo funzionare? Quale altro approccio esiste per consentire l'istanziazione di più componenti e fornire un disaccoppiamento tra l'interfaccia pubblica e l'implementazione in altro modo?

+2

L'approccio comune comporta puntatori * * per strutturare i tipi, in cui i dettagli interni della struttura non sono visibili ai clienti. –

+0

'instance_type' è l'istanza stessa, non un tipo. – Olaf

+0

Quello era un errore di battitura. – Rire1979

risposta

6

Sei quasi arrivato. L'interfaccia deve essere in termini di puntatori al tipo opaco:

struct hidden_implementation_type; 
typedef struct hidden_implementation_type visible_type_to_clients; 

int component_function1(visible_type_to_clients *instance_type); 

e:

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

Questo almeno la compilazione - che non farà niente di utile, però. si sarebbe probabilmente bisogno di una funzione come:

visible_type_to_clients *new_visible(void); 

per creare un valore del tipo e restituire un puntatore, e quindi è possibile utilizzare:

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

In sostanza, i clienti non lo farà essere in grado di creare strutture nello stack (o strutture globali) del tuo tipo perché non hai detto al compilatore quanto è grande il tipo. Ma puoi gestire i puntatori e i puntatori digitati sono molto più sicuri dei puntatori "non tipizzati" void *.

Ho omesso il controllo degli errori per semplicità. Ho rifatto il nome del tag della struttura senza il carattere di sottolineatura principale perché, a tutti gli effetti, i nomi che iniziano con un carattere di sottolineatura sono reserved for the implementation. Vorrei andare con:

typedef struct VisibleType VisibleType; 

dove il tag e il nome del tipo sono gli stessi.

1

Avere strutture nascoste presenta vantaggi e svantaggi. Una struttura nascosta non può mai essere allocata dal client senza costruttore. Una struttura nascosta richiede un distruttore e al client è richiesto di ricordare di chiamarla. Questo è un vantaggio o uno svantaggio a seconda delle tue esigenze.

Qui ci sono due implementazioni per il confronto:

#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(); 
} 
Problemi correlati