C interface decoupling programming from implementation with forward declaration

I am writing a C program and use gcc 4.4.6 to compile. I do not want to use the C ++ compiler.

I am implementing a component, and I intend to have multiple instances of this component in real time and owned by other components at runtime.

As a means of decoupling the definition of an interface from its implementation and to hide the internal structures and data types that it uses in this implementation, I looked for the use of a direct structure declaration.

Interface File: component.h

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

Implementation File: component.c

 struct _hidden_implementation_type { int foo; }; 

Client file: main.c

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

How do I do this job? What other approach allows you to instantiate multiple components and provide a decoupling between the open interface and the implementation otherwise?

+7
c
source share
2 answers

You are almost there. Your interface should be in the form of pointers to an opaque type:

 struct hidden_implementation_type; typedef struct hidden_implementation_type visible_type_to_clients; int component_function1(visible_type_to_clients *instance_type); 

and

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

It will at least be compiled - but nothing useful will be. You will probably need a function, for example:

 visible_type_to_clients *new_visible(void); 

to create a type value and return a pointer, and then you can use:

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

Basically, clients will not be able to create structures on the stack (or global structures) of your type, because you did not tell the compiler how large this type is. But you can deal with pointers - and typed pointers are much safer than untyped void * pointers.

I have lost error checking for simplicity. I delete the name of the structure tag without the main underscore, because for all practical purposes, names starting with the underscore are reserved for implementation . I would go with:

 typedef struct VisibleType VisibleType; 

where the tag and type name match.

+6
source share

The presence of hidden structures has its advantages and disadvantages. A hidden structure can never be allocated by a client without a constructor. A hidden structure requires a destructor, and the client must remember what it calls. This is an advantage or disadvantage depending on your requirement.

Here are two comparison options:

 #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(); } 
+1
source share

All Articles