How would one write object-oriented code in C?
While C is not an object-oriented language like C++ or Java, you can write object-oriented code in C by simulating the principles of object-oriented programming (OOP). The core ideas of OOP—encapsulation, inheritance, and polymorphism—can still be implemented using structures, function pointers, and other features of C. Here's how to achieve it:
Understanding the Approach
Object-oriented programming in C involves:
- Encapsulation: Grouping data and functions into a "class-like" structure.
- Inheritance: Reusing code through composition or manually replicating relationships between "classes."
- Polymorphism: Achieving dynamic behavior using function pointers.
Key Steps to Write Object-Oriented Code in C
1. Encapsulation with Structs
Use struct
to represent an object, grouping its data (fields) and behavior (functions).
#include <stdio.h> #include <string.h> // Define a "class" typedef struct { char name[50]; int age; } Person; // Function to initialize an object void Person_init(Person* self, const char* name, int age) { strcpy(self->name, name); self->age = age; } // Function to print object details void Person_display(Person* self) { printf("Name: %s, Age: %d\n", self->name, self->age); }
2. Simulating Methods
Pass the object (struct
) as a parameter to functions to mimic method calls.
int main() { Person person; Person_init(&person, "Alice", 30); Person_display(&person); // Output: Name: Alice, Age: 30 return 0; }
3. Inheritance through Composition
C doesn't support inheritance natively, but you can achieve it using composition—embedding one struct inside another.
// Base class typedef struct { char name[50]; } Animal; // Function for the base class void Animal_init(Animal* self, const char* name) { strcpy(self->name, name); } void Animal_speak(Animal* self) { printf("%s makes a noise\n", self->name); } // Derived class typedef struct { Animal base; // Composition: "inherits" Animal int num_legs; } Dog; // Function for the derived class void Dog_init(Dog* self, const char* name, int num_legs) { Animal_init(&self->base, name); self->num_legs = num_legs; } void Dog_speak(Dog* self) { printf("%s barks with %d legs\n", self->base.name, self->num_legs); } int main() { Dog dog; Dog_init(&dog, "Buddy", 4); Dog_speak(&dog); // Output: Buddy barks with 4 legs return 0; }
4. Polymorphism with Function Pointers
Use function pointers to implement polymorphic behavior (different behaviors for derived types).
// Base class with a virtual function typedef struct { char name[50]; void (*speak)(void* self); // Function pointer for polymorphism } Animal; void Animal_speak_default(void* self) { Animal* animal = (Animal*)self; printf("%s makes a noise\n", animal->name); } // Derived class typedef struct { Animal base; // Inheritance through composition int num_legs; } Dog; void Dog_speak(void* self) { Dog* dog = (Dog*)self; printf("%s barks with %d legs\n", dog->base.name, dog->num_legs); } int main() { // Create a polymorphic array Animal animals[2]; // Initialize a generic Animal Animal generic_animal; strcpy(generic_animal.name, "Some Animal"); generic_animal.speak = Animal_speak_default; animals[0] = generic_animal; // Initialize a Dog Dog dog; strcpy(dog.base.name, "Buddy"); dog.num_legs = 4; dog.base.speak = Dog_speak; // Assign Dog-specific behavior animals[1] = *(Animal*)&dog; // Store Dog as an Animal // Polymorphic behavior for (int i = 0; i < 2; ++i) { animals[i].speak(&animals[i]); } return 0; }
Summary
Object-oriented programming in C involves:
- Encapsulation: Use
struct
to group data and methods. - Inheritance: Use composition to share functionality.
- Polymorphism: Use function pointers for dynamic behavior.
This approach allows you to implement OOP principles while leveraging C's flexibility and performance. For deeper understanding of OOP principles and their application, explore Grokking System Design Fundamentals on DesignGurus.io to learn how to apply these techniques in real-world scenarios.
GET YOUR FREE
Coding Questions Catalog