void*" for your "opaque pointers", you lose all
typechecking, since void* is compatible with almost
everything in C, and because typedef doesn't create a new type in C or
C++, just a new name for an old type.Instead, use forward declared structs...
If you use struct forwards, all the errors will be caught by the
compiler, if you use typedef
/* Declare foo opaque type */
struct foo;
foo* foo_create (void);
void foo_manipulate (foo* f);
void foo_delete (foo* f);
/* Declare bar opaque type */
struct bar;
bar* bar_create (void);
void bar_do_it (bar* b);
void bar_delete (bar* b);
/* use them */
foo* f = foo_create (); /* ok */
bar* b = foo_create (); /* error */
foo_manipulate (f); /* ok */
bar_do_it (f); /* error */
foo_delete (f); /* ok */
bar_delete (f); /* error */
void* the will not be caught.
To other minor style issues with the code in the story: If you make your constructor return the object, you can use it directly when declaring variables of the type:
instead of
foo* f = foo_create ();
The library user save a line, and we avoid having a point in the code
where "
foo* f;
f_create(&f);
f" is uninititalized.
Also, it is a bad idea to hide the fact that it is a pointer with a typedef. This is because the type has pointer semantics, hiding the pointer can make it easier to assume value semantics by accident.
If the abstract datatype is implemented in C++, all the accessor
functions (foo_create, foo_manipulate,
foo_delete) should obviously be declared extern "C" for
use in C code.