Tangwx

Tangwx

博客网站

Encapsulation, Inheritance, and Polymorphism in C Language

Understanding how to implement encapsulation, inheritance, and polymorphism in C#

1. Introduction#

Encapsulation, inheritance, and polymorphism are important features of object-oriented programming. They allow us to make our code more cohesive and loosely coupled, increasing its safety, readability, and maintainability. So, can we implement encapsulation, inheritance, and polymorphism in a procedural programming language like C to improve the quality of our code? The answer is yes. In the process of studying the Linux kernel code, we can see that C is widely used to implement encapsulation, inheritance, and polymorphism. This article will analyze how to implement these object-oriented features in C, laying the foundation for understanding and writing high-quality code.

2. Encapsulation#

Encapsulation is the process of packaging the properties and corresponding methods of an abstract entity into a class and changing the internal state through internal methods. The essence of encapsulation is the process of hiding information, preventing direct access and modification of the internal state of an object by the outside world.

Encapsulation has the following advantages:

  • Improves code security by allowing data to be accessed only in specified ways, avoiding misuse and illegal access.
  • Improves code reusability by allowing the same or similar data types to be used multiple times.
  • Improves code maintainability by only requiring modifications in one place when the data type changes.

In C, there is no concept of classes, but we can use structures to implement encapsulation. The important significance of encapsulation is that it integrates functions (methods) and data (properties) together. This way, we can access all the data and operate all the functions through a simple structure pointer.

Here is a specific example of encapsulation:

#include <stdio.h> 

typedef struct human
{ 
    int age; 
    char sex; 
    void (*set_age)(struct human *p, int age);
    int (*get_age)(struct human *p);
    void (*set_sex)(struct human *p, char sex);
    char (*get_sex)(struct human *p);
} Human; 

void set_age(Human *p, int age) 
{ 
    p->age = age; 
} 

int get_age(Human *p) 
{ 
    return p->age; 
} 

void set_sex(Human *p, char sex)
{ 
    p->sex = sex; 
} 

char get_sex(Human *p) 
{ 
    return p->sex; 
} 

int main() 
{ 
    Human p; 
    p.set_age = set_age; 
    p.set_age(&p, 18); 
    p.set_sex = set_sex; 
    p.set_sex(&p, 'M');
    p.get_age = get_age; 
    printf("age: %d\n", p.get_age(&p));
    p.get_sex = get_sex;  
    printf("sex: %c\n", p.get_sex(&p)); 

    return 0; 
}

We have defined a structure called "human" which contains the members "age" and "sex", as well as the functions "set_age", "get_age", "set_sex", and "get_sex" for setting and getting the age and sex. This is encapsulation. The data and functions of the structure can implement the properties and method operations of a human. In addition, the structure's data can only be modified through the operation functions in the structure.

3. Inheritance#

Inheritance is the process of creating a new class (subclass or derived class) based on an existing class (parent class or base class). The subclass or derived class can access the data and functions of the parent class, avoiding the need to rewrite the same code. The subclass can also add its own properties and data.

Inheritance has the following advantages:

  • Improves code reusability by avoiding the need to rewrite the same code.
  • Improves code extensibility by supporting adjustments based on existing classes.
  • Improves code readability by making the code more concise and clear.

In C, we can implement class inheritance (single inheritance, without considering multiple inheritance) through nested structures, but we need to ensure that the reference to the parent class structure is placed in the first position of the child class structure member. This way, there will be no problems with data access or type casting.

Here is a specific example of inheritance:

#include <stdio.h>
#include <stdlib.h>

typedef struct human {
    int age;
    char sex;
} Human;

typedef struct person{
    Human human;
    char *name;
} Person;

Person* create_person(int age, char sex, char *name) {
    Person* cperson = (Person*) malloc(sizeof(Person));
    cperson->human.age = age;
    cperson->human.sex = sex;
    cperson->name = name;
    return cperson;
}

int main() {
    Person* cperson = create_person(18, 'w', "lucy");
    printf("(%d, %c) - name: %s\n", cperson->human.age, cperson->human.sex, cperson->name);
    free(cperson);
    return 0;
}

In the above code, we have defined two structures "Human" and "Person". "Person" contains the "Human" structure and a member variable "name". We use the function "create_person()" to construct a "Person" structure and assign values to its "Human" member and "name" member. When we need to use the features of inheritance elsewhere, we can use a similar nested structure approach to implement it.

4. Polymorphism#

Polymorphism is the most important concept in object-oriented programming. It allows us to perform the same operation on different objects, achieving flexible processing of operations.

Polymorphism has the following advantages:

  • Improves code extensibility by supporting different types of objects, making the program more flexible.
  • Improves code maintainability by only requiring modifications to the corresponding classes when types change.
  • Improves code readability by making the code more concise and readable.

In C, we can implement polymorphism by using function pointers and using the same interface to process different data. Functions with different functionalities can use the same function name, allowing different functionalities to be called using the same function name.

Here is a specific example of polymorphism:

#include <stdio.h>

typedef struct shape {
    void (*draw)(struct shape*);
} Shape;

typedef struct {
    int x;
    int y;
    int radius;
    Shape base;
} Circle;

typedef struct {
    int x1;
    int y1;
    int x2;
    int y2;
    Shape base;
} Line;

void drawCircle(Shape* shape) {
    Circle* circle = (Circle*) shape;
    printf("Circle at (%d, %d) with radius %d\n", circle->x, circle->y, circle->radius);
}

void drawLine(Shape* shape) {
    Line* line = (Line*) shape;
    printf("Line from (%d, %d) to (%d, %d)\n", line->x1, line->y1, line->x2, line->y2);
}

int main() {
    int i; 

    Circle circle = {
        .x = 1,
        .y = 5,
        .radius = 10,
        .base = { .draw = drawCircle }
    };

    Line line = {
        .x1 = 2,
        .y1 = 3,
        .x2 = 7,
        .y2 = 9,
        .base = { .draw = drawLine }
    };
    
    /* //The above two code segments are equivalent to the following operations
	Circle circle;
    circle.x = 1;
    circle.y = 5;
    circle.radius = 10;
    circle.base.draw = drawCircle;

    Line line;
    line.x1 = 2;
    line.y1 = 3;
    line.x2 = 7;
    line.y2 = 9;
    line.base.draw = drawLine; 
	*/

    Shape* shapes[2];
    shapes[0] = (Shape*)&(circle.base);
    shapes[1] = (Shape*)&(line.base);

    for (i = 0; i < 2; i++) {
        shapes[i]->draw(shapes[i]);
    }

    return 0;
}

In the above example, we have defined a structure "Shape" and its member function "draw". We have also defined two child structures "Circle" and "Line" derived from "Shape" and implemented their own "draw" functions.

By declaring the "draw" function as a function pointer in "Shape" that points to a function with a "void*" parameter, we can dynamically process different types of child structures in the "draw" function.

We use "typedef" to name the structures as "Shape" so that we can use them in the "Circle" and "Line" structures. Finally, we create a "Circle" and a "Line" object in the main function and store them in an array of type "Shape*". We use a loop to iterate through the array and call the "draw" function of each shape object to process it, achieving the effect of polymorphism.

Loading...
Ownership of this post data is guaranteed by blockchain and smart contracts to the creator alone.