Progtwigción en C de la interfaz de desacoplamiento de la implementación con la statement forward

Estoy escribiendo un progtwig en C y usando gcc 4.4.6 para comstackr. No quiero usar un comstackdor de c ++.

Estoy implementando un componente y pretendo tener varias instancias de este componente en vivo y propiedad de otros componentes en tiempo de ejecución.

Como medio de desacoplar la definición de una interfaz de su implementación y ocultar las estructuras internas y los tipos de datos que utiliza en esa implementación, busqué usar una statement de estructura hacia adelante.

Archivo de interfaz: component.h

struct _hidden_implementation_type; typedef struct _hidden_implementation_type visible_type_to_clients; int component_function1(visible_type_to_clients instance); 

Archivo de implementación: component.c

 struct _hidden_implementation_type { int foo; }; 

Archivo de cliente: main.c

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

¿Cómo hago este trabajo? ¿Qué otro enfoque existe para permitir la creación de instancias de múltiples componentes y proporcionar un desacoplamiento entre la interfaz pública y la implementación de otro modo?

Ya casi estás ahí. Su interfaz debe ser en términos de punteros 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); 

y:

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

Esto al menos comstackrá, aunque no hará nada útil. Probablemente necesitarías una función como:

 visible_type_to_clients *new_visible(void); 

para crear un valor del tipo y devolverle un puntero, y luego puede usar:

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

Básicamente, los clientes no podrán crear estructuras en la stack (o estructuras globales) de su tipo porque no le ha dicho al comstackdor qué tan grande es el tipo. Pero puede manejar los punteros, y los punteros typescripts son mucho más seguros que los punteros ” void * tipo”.

Dejé fuera de error la comprobación de la simplicidad. Rediseñé el nombre de la etiqueta de estructura sin el guión bajo porque, para todos los propósitos prácticos, los nombres que comienzan con un guión bajo están reservados para la implementación . Yo iria con

 typedef struct VisibleType VisibleType; 

donde la etiqueta y el nombre del tipo son los mismos.

Tener estructuras ocultas tiene ventajas y desventajas. Una estructura oculta nunca puede ser asignada por el cliente sin el constructor. Una estructura oculta requiere un destructor y el cliente debe recordar haberla llamado. Esto es una ventaja o una desventaja dependiendo de su requerimiento.

Aquí hay dos implementaciones para la comparación:

 #include  #include  /*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(); }