Panel For Example Panel For Example Panel For Example

Object-Oriented Programming Concepts in C

Author : Adrian December 31, 2025

Overview

C is a procedural language, but its features can be used to simulate object-oriented concepts such as encapsulation, inheritance, and polymorphism by using structs and function pointers. Below are several concrete examples and applications.

 

Encapsulation

Encapsulation groups an object's attributes and methods together and exposes an interface while hiding internal details. In C, structs can define attributes and function pointers can define methods; combining them in a struct creates a class-like type. Example:

#include <stdio.h> #include <stdlib.h> // Define person struct person { // Attributes char *name; int age; // Methods void (*say_hello)(struct person *p); }; // Person's method void say_hello(struct person *p) { printf("Hello, I am %s, %d years old.", p->name, p->age); } // Create an instance of person struct person *create_person(char *name, int age) { struct person *p = malloc(sizeof(struct person)); p->name = name; p->age = age; p->say_hello = say_hello; return p; } // Use person instances int main() { struct person *p1 = create_person("Alice", 20); struct person *p2 = create_person("Bob", 25); p1->say_hello(p1); p2->say_hello(p2); free(p1); free(p2); return 0; }

 

Inheritance

Inheritance lets a subtype reuse and override attributes and methods of a parent type. In C, struct nesting can implement inheritance by placing the parent struct as the first member of the child struct. Example:

#include <stdio.h> #include <stdlib.h> // Define person struct person { // Attributes char *name; int age; // Methods void (*say_hello)(struct person *p); }; // Person's method void say_hello(struct person *p) { printf("Hello, I am %s, %d years old.", p->name, p->age); } // Create person instance struct person *create_person(char *name, int age) { struct person *p = malloc(sizeof(struct person)); p->name = name; p->age = age; p->say_hello = say_hello; return p; } // Define student class struct student { // Inherit from person struct person base; // Attributes char *school; // Methods void (*study)(struct student *s); }; // Define student's method void study(struct student *s) { printf("%s is studying at %s.", s->base.name, s->school); } // Create student instance struct student *create_student(char *name, int age, char *school) { struct student *s = malloc(sizeof(struct student)); s->base.name = name; s->base.age = age; s->base.say_hello = say_hello; // Reuse parent's method s->school = school; s->study = study; return s; } // Use student instances int main() { struct student *s1 = create_student("Charlie", 18, "MIT"); struct student *s2 = create_student("David", 19, "Stanford"); s1->base.say_hello(&s1->base); // Call parent's method s2->base.say_hello(&s2->base); s1->study(s1); // Call child's method s2->study(s2); free(s1); free(s2); return 0; }

 

Polymorphism

Polymorphism enables different object types to use the same interface while performing type-specific behavior. In C, function pointers allow different types to be treated as a common type and invoked via shared function pointers. Example:

#include <stdio.h> #include <stdlib.h> // Define animal struct animal { // Attributes char *name; // Methods void (*make_sound)(struct animal *a); }; // Define dog struct dog { // Inherit from animal struct animal base; // Attributes char *breed; }; // Define cat struct cat { // Inherit from animal struct animal base; // Attributes char *color; }; // Define animal method void make_sound(struct animal *a) { printf("%s is making sound.", a->name); } // Define dog method void dog_make_sound(struct dog *d) { printf("%s is barking.", d->base.name); } // Define cat method void cat_make_sound(struct cat *c) { printf("%s is meowing.", c->base.name); } // Create animal instance struct animal *create_animal(char *name) { struct animal *a = malloc(sizeof(struct animal)); a->name = name; a->make_sound = make_sound; return a; } // Create dog instance struct dog *create_dog(char *name, char *breed) { struct dog *d = malloc(sizeof(struct dog)); d->base.name = name; d->base.make_sound = (void (*)(struct animal *))dog_make_sound; // Override parent's method d->breed = breed; return d; } // Create cat instance struct cat *create_cat(char *name, char *color) { struct cat *c = malloc(sizeof(struct cat)); c->base.name = name; c->base.make_sound = (void (*)(struct animal *))cat_make_sound; // Override parent's method c->color = color; return c; } // Use animal instances int main() { struct animal *a1 = create_animal("Tom"); struct dog *d1 = create_dog("Spike", "Bulldog"); struct cat *c1 = create_cat("Jerry", "Brown"); // Polymorphism: different object types use the same interface to perform different behaviors a1->make_sound(a1); // Call animal method d1->base.make_sound(&d1->base); // Call dog method c1->base.make_sound(&c1->base); // Call cat method free(a1); free(d1); free(c1); return 0; }