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.
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