One way to achieve high encapsulation for ADTs is to publish “opaque pointers” in the public header files. The usage of opaque pointers also improves binary compatibility. 1.
The mechanism is quite simple. Suppose that we want to publish an
opaque ADT to the user: pdf_foo_t. A first approximation would
be to mark the full definition of pdf_foo_t as public in the
header file, like:
/* -*- mode: C -*-
*
* File: pdf-foo.h
...
*/
...
/* BEGIN PUBLIC */
struct pdf_foo_s
{
int a;
int b;
};
typedef struct pdf_foo_s *pdf_foo_t;
/* END PUBLIC */
...
Despite the user is not supposed to access the internal structure of
pdf_foo_t, she can actually do it using the exported
structure struct pdf_foo_s.
An additional problem is that the user can allocate pdf_foo_s
structs in the stack, and thus the binary compatibility would be break
if the binary links with a more recent version of the library
exporting more fields (like a third integer c).
The solution to both problems is to export a “opaque pointer”: we simply do not export the details about the structure:
/* -*- mode: C -*-
*
* File: pdf-foo.h
...
*/
...
/* BEGIN PUBLIC */
typedef struct pdf_foo_s *pdf_foo_t;
/* END PUBLIC */
struct pdf_foo_s
{
int a;
int b;
};
...
[1] this technique is also known as the PIMPL idiom. See http://en.wikipedia.org/wiki/Pimpl_idiom