D   A   T   A   W   O   K





Creation: May 08 2016
Modified: January 28 2023

Inheritance in C

This article is part of a series that addresses the implementation of four of the most fundamental concepts of object-oriented programming using the standard C programming language:

It is assumed that you are already familiar with object-oriented programming. Thus, for each topic, only a brief theoretical introduction is provided.


Inheritance allows new types to be defined by extending existing types. Extending a type mainly means reusing the code of a base type to inherit its behavior and implementation. The principle that always holds with inheritance is that a derived type is a base type.

The C language does not explicit support inheritance, but developers can implement it by utilizing one simple language feature: the first member of the structure is always aligned to the beginning of the structure. As a result, if we include what is intended to be the base class structure as the first member of the derived structure then:

The two properties above effectivelly implement inheritance. That is, we can always use a derived type wherever a base type is expected.

Example

Base class definition, a person

typedef struct person {
    char        *name;
} person_t;

Derived class definition, a student

typedef struct student {
    person_t    super;
    int         number;
} student_t;

Having defined the student_t in this way, every pointer to a student is also a pointer to its first member, a person. A student_t can be safely used wherever a pointer to a person_t is expected.

Base class constructor and destructor.

void person_construct(person_t *person, const char *name)
{
    person->name = malloc(strlen(name) + 1);
    strcpy(person->name, name);
}

void person_destruct(person_t *person)
{
    free(person->name);
    person->name = NULL;
}

Derived class constructor and destructor. Note the construction and destruction of the base class.

void student_construct(student_t *student, const char *name, int number)
{
    person_construct(&student->super, name);
    student->number = number;
}

void student_destruct(student_t *student)
{
    person_destruct(&student->super);
}

Example of a person interface function

void person_print(person_t *person)
{
    printf("name: %s\n", person->name);
}

Usage example

student_t stud;
student_construct(&stud, "Davide", 123456);
person_print((person_t *) &stud);   /* explicit cast to prevent compiler warnings */
student_destruct(&stud);

Example sources download

Proudly self-hosted on a cheap Raspberry Pi