Recommended Advanced Books ↑↑↑
Recommended Reading
C Language Dynamic Memory Management: From Beginner to Pro, Understand It All in One Article
C Language Pointers: From Beginner to Pro, Understand It All in One Article
C Language File Operations: From Beginner to Pro, Understand It All in One Article
Top Ten Sorting Algorithms in C Language, Master Them All in One Article
C Language Structures: From Beginner to Pro, Understand It All in One Article
Main Content
Implementing Object-Oriented Programming (OOP) in C language is a very practical skill, especially in embedded systems, low-level development, or scenarios that require interaction with C++. Although C language does not natively support the three main features of OOP (Encapsulation, Inheritance, Polymorphism), these features can be effectively simulated through mechanisms such as structures (<span>struct</span>), function pointers (<span>function pointer</span>), and pointer operations.
1. Encapsulation
1.1 Concept
Encapsulation is the binding of data (attributes) and the functions (methods) that operate on the data together, hiding implementation details and exposing only the interface.
1.2 Implementation in C Language
In C language, use <span>struct</span> to define data structures and function pointers to simulate methods. By defining structures in <span>.c</span> files, external access to the object can only be done through the function interfaces provided in the header files.
1.3 Example: Encapsulating a Rectangle Class
<span>Rectangle.h</span>
#ifndef RECTANGLE_H
#define RECTANGLE_H
typedef struct Rectangle Rectangle;
// Constructor
Rectangle* rectangle_create(double width, double height);
// Destructor
void rectangle_destroy(Rectangle* rect);
// Get area
double rectangle_area(const Rectangle* rect);
// Print information
void rectangle_print(const Rectangle* rect);
#endif // RECTANGLE_H
<span>Rectangle.c</span>
#include "Rectangle.h"
#include <stdio.h>
#include <stdlib.h>
// Actual structure definition
struct Rectangle {
double width;
double height;
};
Rectangle* rectangle_create(double width, double height) {
Rectangle* rect = (Rectangle*)malloc(sizeof(Rectangle));
if (rect) {
rect->width = width;
rect->height = height;
}
return rect;
}
void rectangle_destroy(Rectangle* rect) {
free(rect);
}
double rectangle_area(const Rectangle* rect) {
return rect->width * rect->height;
}
void rectangle_print(const Rectangle* rect) {
printf("Rectangle: width = %.2f, height = %.2f, area = %.2f\n",
rect->width, rect->height, rectangle_area(rect));
}
<span>main.c</span>
#include "Rectangle.h"
int main() {
Rectangle* rect = rectangle_create(5.0, 3.0);
rectangle_print(rect);
rectangle_destroy(rect);
return 0;
}
Encapsulation Effect: External access to
<span>width</span>and<span>height</span>members is not possible; they can only be manipulated through interfaces like<span>rectangle_area()</span>and<span>rectangle_print()</span>.
2. Inheritance
2.1 Concept
Inheritance is when one class (subclass) inherits the properties and methods of another class (superclass) in object-oriented programming.
2.2 Implementation in C Language
C language does not support inheritance syntax, but inheritance can be simulated through structure nesting. The base class is the first member of the subclass structure, thus achieving an “is-a” relationship.
2.3 Example: Inheriting the Shape Class
<span>Shape.h</span>
#ifndef SHAPE_H
#define SHAPE_H
typedef struct Shape Shape;
// Constructor
Shape* shape_create();
// Destructor
void shape_destroy(Shape* shape);
// Virtual function: Print information
void shape_print(const Shape* shape);
#endif // SHAPE_H
<span>Shape.c</span>
#include "Shape.h"
#include <stdio.h>
#include <stdlib.h>
struct Shape {
void (*print)(const Shape*);
};
void shape_print(const Shape* shape) {
printf("This is a Shape.\n");
}
Shape* shape_create() {
Shape* shape = (Shape*)malloc(sizeof(Shape));
if (shape) {
shape->print = shape_print;
}
return shape;
}
void shape_destroy(Shape* shape) {
free(shape);
}
<span>Rectangle.h</span> (Inheriting Shape)
#ifndef RECTANGLE_H
#define RECTANGLE_H
#include "Shape.h"
typedef struct Rectangle {
Shape base; // Base class member
double width;
double height;
} Rectangle;
Rectangle* rectangle_create(double width, double height);
void rectangle_destroy(Rectangle* rect);
void rectangle_print(const Rectangle* rect);
#endif // RECTANGLE_H
<span>Rectangle.c</span>
#include "Rectangle.h"
#include <stdio.h>
#include <stdlib.h>
static void rectangle_print_internal(const Shape* shape) {
const Rectangle* rect = (const Rectangle*)shape;
printf("Rectangle: width = %.2f, height = %.2f\n", rect->width, rect->height);
}
Rectangle* rectangle_create(double width, double height) {
Rectangle* rect = (Rectangle*)malloc(sizeof(Rectangle));
if (rect) {
rect->base.print = rectangle_print_internal;
rect->width = width;
rect->height = height;
}
return rect;
}
void rectangle_destroy(Rectangle* rect) {
free(rect);
}
<span>main.c</span>
#include "Rectangle.h"
int main() {
Rectangle* rect = rectangle_create(5.0, 3.0);
rect->base.print((Shape*)rect); // Polymorphic call
rectangle_destroy(rect);
return 0;
}
Inheritance Effect:
<span>Rectangle</span>inherits the<span>print()</span>method from<span>Shape</span>and overrides it.
3. Polymorphism
3.1 Concept
Polymorphism refers to the same interface having different behaviors on different objects.
3.2 Implementation in C Language
Polymorphism is implemented through function pointers and virtual function tables (vtable). Each object maintains a pointer to an array of function pointers that stores the addresses of all its methods.
3.3 Example: Polymorphism Implementation (Shape, Rectangle, Circle)
<span>Shape.h</span>
#ifndef SHAPE_H
#define SHAPE_H
typedef struct Shape Shape;
// Virtual function table
typedef struct {
void (*print)(const Shape*);
} ShapeVTable;
// Base class
struct Shape {
const ShapeVTable* vtable;
};
// Constructor
Shape* shape_create();
// Destructor
void shape_destroy(Shape* shape);
// Virtual function call
void shape_print(const Shape* shape);
#endif // SHAPE_H
<span>Shape.c</span>
#include "Shape.h"
#include <stdio.h>
#include <stdlib.h>
static void shape_print_default(const Shape* shape) {
printf("This is a Shape.\n");
}
// Default virtual function table
static const ShapeVTable shape_vtable = {
.print = shape_print_default
};
Shape* shape_create() {
Shape* shape = (Shape*)malloc(sizeof(Shape));
if (shape) {
shape->vtable = &shape_vtable;
}
return shape;
}
void shape_destroy(Shape* shape) {
free(shape);
}
void shape_print(const Shape* shape) {
shape->vtable->print(shape);
}
<span>Rectangle.h</span>
#ifndef RECTANGLE_H
#define RECTANGLE_H
#include "Shape.h"
typedef struct Rectangle {
Shape base;
double width;
double height;
} Rectangle;
Rectangle* rectangle_create(double width, double height);
void rectangle_destroy(Rectangle* rect);
void rectangle_print(const Rectangle* rect);
#endif // RECTANGLE_H
<span>Rectangle.c</span>
#include "Rectangle.h"
#include <stdio.h>
#include <stdlib.h>
static void rectangle_print(const Shape* shape) {
const Rectangle* rect = (const Rectangle*)shape;
printf("Rectangle: width = %.2f, height = %.2f\n", rect->width, rect->height);
}
// Virtual function table
static const ShapeVTable rectangle_vtable = {
.print = rectangle_print
};
Rectangle* rectangle_create(double width, double height) {
Rectangle* rect = (Rectangle*)malloc(sizeof(Rectangle));
if (rect) {
rect->base.vtable = &rectangle_vtable;
rect->width = width;
rect->height = height;
}
return rect;
}
void rectangle_destroy(Rectangle* rect) {
free(rect);
}
<span>Circle.h</span>
#ifndef CIRCLE_H
#define CIRCLE_H
#include "Shape.h"
typedef struct Circle {
Shape base;
double radius;
} Circle;
Circle* circle_create(double radius);
void circle_destroy(Circle* circle);
void circle_print(const Circle* circle);
#endif // CIRCLE_H
<span>Circle.c</span>
#include "Circle.h"
#include <stdio.h>
#include <stdlib.h>
static void circle_print(const Shape* shape) {
const Circle* circle = (const Circle*)shape;
printf("Circle: radius = %.2f\n", circle->radius);
}
// Virtual function table
static const ShapeVTable circle_vtable = {
.print = circle_print
};
Circle* circle_create(double radius) {
Circle* circle = (Circle*)malloc(sizeof(Circle));
if (circle) {
circle->base.vtable = &circle_vtable;
circle->radius = radius;
}
return circle;
}
void circle_destroy(Circle* circle) {
free(circle);
}
<span>main.c</span>
#include "Rectangle.h"
#include "Circle.h"
int main() {
Shape* shapes[] = {
(Shape*)rectangle_create(5.0, 3.0),
(Shape*)circle_create(4.0)
};
for (int i = 0; i < 2; i++) {
shape_print(shapes[i]);
shape_destroy(shapes[i]);
}
return 0;
}
Execution Result:
Rectangle: width = 5.00, height = 3.00
Circle: radius = 4.00
Polymorphism Effect: When calling
<span>shape_print()</span>, it will invoke different<span>print</span>methods based on the actual type of the object (<span>Rectangle</span>or<span>Circle</span>).
4. Conclusion
4.1 Core Techniques for Implementing OOP in C Language
| Feature | Implementation Method |
|---|---|
| Encapsulation | <span>struct</span> + function pointers + static functions |
| Inheritance | <span>struct</span> nesting |
| Polymorphism | Virtual function table (<span>vtable</span>) + function pointers |
4.2 Advantages
- High Flexibility: Can be used on any platform that supports C.
- Good Performance: No runtime overhead.
- Strong Compatibility: Easy to integrate with C++, embedded systems, etc.
4.3 Disadvantages
- Complex Manual Management: Requires manual implementation of constructors, destructors, inheritance, etc.
- Poor Readability: Compared to C++, the code is more verbose and has a lower level of abstraction.
- Lack of Compiler Support: No syntax support, prone to errors.
5. References
- CSDN Blog: Implementing Object-Oriented Programming in C Language
- Worktile Community: Implementing OOP in C Language
- Juejin: Implementing OOP in C
- The C Programming Language