Search Knowledge

© 2026 LIBREUNI PROJECT

C Programming Mastery / Object-Oriented C & Encapsulation

Opaque Pointers and the ADT Pattern

Encapsulation in C

C is a procedural language and lacks native object-oriented classes. However, we can enforce encapsulation and modularity using the Abstract Data Type (ADT) pattern. This pattern prevents client code from reading or writing a data structure’s fields directly, shielding implementation details behind a clean public interface.

Example: The Incomplete Type Pattern

To hide a struct’s layout, we declare the struct as an incomplete type in the public header and define it fully in the private implementation file.

1. Public Header (book.h)

The header exposes only a pointer to the incomplete structure type:

#pragma once

// Incomplete type declaration
struct book;

// Opaque pointer type alias
typedef struct book* book_t;

// Public interface functions
book_t book_create(const char* title, int pages);
int book_get_pages(book_t self);
void book_destroy(book_t self);

2. Private Implementation (book.c)

The layout of the structure is defined only in the implementation file. Client code compiling against book.h cannot dereference book_t because the compiler does not know its size or members at compile time.

#include "book.h"
#include <stdlib.h>
#include <string.h>

struct book {
    char title[32];
    int pages;
};

book_t book_create(const char* title, int pages) {
    book_t self = malloc(sizeof(struct book));
    if (self != NULL) {
        strncpy(self->title, title, sizeof(self->title) - 1);
        self->pages = pages;
    }
    return self;
}

int book_get_pages(book_t self) {
    return self->pages;
}

void book_destroy(book_t self) {
    free(self);
}

UML to C Mapping Rules

When translating UML class diagrams into C source code, apply the following visibility and relationship rules:

Visibility Mapping

  • Public Attributes/Methods (+): Declared in the .h file.
  • Private Attributes/Methods (-): Declared inside the struct definition in the .c file. Helper functions are declared as static inside the .c file so they are invisible to the linker.

Association and Multiplicity

  • Multiplicity 0..1 (Optional Association): Mapped to a single pointer member.
  • Multiplicity 0..N (Collection): Mapped to a fixed-size array of pointers along with a count tracking the active size.
#define MAX_AUTHORS 5

struct book {
    char title[32];
    struct author* authors[MAX_AUTHORS]; // Array of pointers (0..N)
    int author_count;
};

Lifecycles: Composition vs. Aggregation

  • Composition (Filled Diamond): Represents strict ownership. The parent struct owns the child objects. The parent’s destructor must destroy all children.
  • Aggregation (Empty Diamond): Represents a temporary relationship. The child objects exist independently of the parent. The parent’s destructor simply frees its own container, leaving the children intact.

In a system where a Library has a composition relationship with Books, what must the library destructor do?

Define Opaque Pointer Type

#pragma once

struct author_st;

// Create the opaque pointer type mapping to struct author_st
typedef struct author_st* ;

References & Further Reading

  • Kernighan, B. W., & Ritchie, D. M. (1988). The C Programming Language (2nd ed.). Prentice Hall. Section 6.7 (Typedef) and Section 6.2 (Structures and Functions).
  • VIA University College: Embedded Software 1 (ESW1) Lecture Notes - Section 5 (Abstract Data Types).