Object Oriented Programming in C part IV: Inheritance
In OOP, inheritance is a foundational concept that enables classes to inherit attributes and methods from others. Let's explore how this is achieved in C.
1. Basic about inheritance
Inheritance, a fundamental concept enabling classes to inherit attributes and methods from others, fosters hierarchical relationships in object-oriented programming. While C lacks the class concept, it allows for implementing inheritance through clever techniques, laying the groundwork for the powerful concept of polymorphism.
2. Apply inheritance in C
In the previous blog OOP: Object Blog we talked about how to create an object with OPP style. Let鈥檚 explore how we can create a base object type and implement inheritance in a derived type using C. Look at to this example, we have a base object type person that contains base attributes like name, age, along with base methods like talk() and work():
1
2
3
4
5
6
7
8
9
10
11
12
typedef struct {
    char name[MAX_LENGTH];
    char language[MAX_LENGTH];
    int age;
} person_t;
int person_init(person_t *self, const char *name);
int person_deinit(person_t *self);
/* Pubic methods. */
int person_talk(person_t *self, const char *speech);
int person_work(person_t *self);
Now assume that we want to define an employee object type, also an employee is a person 馃槢, and we don鈥檛 want to re-code all person鈥檚 methods, attributes. So here we consist the person_t as a property of employee_t:
1
2
3
4
5
6
7
8
9
typedef struct
{
    char company[];
    int salary;
    person_t person;
} employee_t;
int employee_init(employee_t *self, const char *name);
int employee_deinit(employee_t *self);
To create and destroy base object:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
int employee_init(employee_t *self, const char *name)
{
    memset(self, 0, sizeof(employee_t));
    person_init(&self->person, name);
    /* Init another employee's components ... */
    return 0;
}
int employee_deinit(employee_t *self)
{
    person_deinit(&self->person);
    return 0;
}
For using base type attributes and methods in application code, we have two choices:
- Access the person attributes, methods directly (Public Inheritance). - 1 2 3 4 5 6 7 8 9 10 11 12 - int main() { employee_t John = {0}; employee_init(&John, "John"); printf("Employee name: %s\n", John.person.name); printf("Employee age: %s\n", John.person.age); person_talk(&John.person, "Hi, I'm John!"); employee_init(&John); } 
- Wrapping them by employee methods (Private Inheritance). - 1 2 3 4 5 6 7 8 9 - const char *employee_get_name(employee_t *self) { return (const char *)self->person.name; } int employee_talk(employee_t *self, const char *speech) { return person_talk(&self->person, speech); } - In the application code: - 1 2 3 4 5 6 7 8 9 10 - int main() { employee_t John = {0}; employee_init(&John, "John"); printf("Employee name: %s\n", employee_get_name(&John)); employee_talk(&John, "Hi, I'm John!"); employee_init(&John); } 
3. Summary
Inheritance simplifies code reuse, establishes relationships between objects, and, most importantly, forms the foundation of polymorphism, enhancing code flexibility and generality for user applications.