C Encapsulation and Abstraction Object-Oriented Programming

Encapsulation and abstraction

Encapsulation is one of the three major characteristics of object-oriented programming (encapsulation, inheritance, polymorphism), but it is also the most important characteristic. The combination of encapsulation + abstraction can provide a low-coupling module to the outside world.

Data encapsulation is a mechanism that bundles data and functions that operate on the data. Data abstraction is a mechanism that only exposes the interface to users and hides specific implementation details.

In C language, data encapsulation can start with a structure, which can contain data members and function pointer members for operating data. Of course, the structure can also contain only the data to be manipulated.

A simple example is used as a demonstration below.

Design a software module. The object to be operated in the module is a rectangle. The interfaces that need to be provided to the outside are:

1. Create a rectangular object;
2. Set the length and width;
3. Get the rectangular area;
4. Print the rectangular information (length, width, height);
5. Delete the rectangular object.

Let's complete this demo code together. First, let’s think about what our interface naming should be? In fact, there are rules to follow. Let’s see how the object-oriented interface of RT-Thread is designed.
Insert image description here

Insert image description here

We also imitate this naming form to name several interfaces of our demo:

1、shape_create
2、shape_set
3、shape_getArea
4、shape_display
5、shape_delete

We create a header file rect.h, where we declare several interfaces we provide to the outside world. At this time our header file can be designed as:

typedef struct _fun_ptr
{
    
    
    int (*area)(void);
}fun_ptr;

typedef struct _Shape
{
    
    
    char* object_name;
    int length;
    int width;
    fun_ptr fptr;
}Shape, *pShape;

/* 对象操作 */
HandleShape shape_create(const char* object_name);
void shape_set(HandleShape shape, int length, int width);
int shape_getArea(HandleShape shape);
void shape_display(HandleShape shape);
void shape_delete(HandleShape shape);

There is nothing wrong with doing this. However, the data is not hidden well enough. What we provide for external use must be as simple as possible.
We can think about it, for file operations in C language, what kind of file operation interface does the C language library provide us? like:

FILE *fopen(const char *pathname, const char *mode);
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);

We will create a file handle (descriptor), and then we only need to operate this file handle. We don't need to care about how FILE is implemented.

What is a handle? Take a look at Baidu Encyclopedia’s explanation:
Insert image description here

We can also create our object handle, and only expose our object handle in the externally provided header file without exposing the specific implementation. The above header file rect.h code can be modified as:

#ifndef __SHAPE_H
#define __SHAPE_H

#ifdef __cplusplus
extern "C" {
    
    
#endif

/* 对象句柄 */
typedef void* HandleShape;

/* 对象操作 */
HandleShape shape_create(const char* object_name);
void shape_set(HandleShape shape, int length, int width);
int shape_getArea(HandleShape shape);
void shape_display(HandleShape shape);
void shape_delete(HandleShape shape);

#ifdef __cplusplus
}
#endif

#endif

Void* is used here, which is an untyped pointer. Void * can point to any type of data. Then the specific structure to be operated can be implemented in .c:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "CShape.h"

typedef struct _fun_ptr
{
    
    
    int (*area)(void);
}fun_ptr;

typedef struct _Shape
{
    
    
    char* object_name;
    int length;
    int width;
    fun_ptr fptr;
}Shape, *pShape;

Below we implement the above five functions in sequence:

HandleShape shape_create(const char* object_name)
{
    
    
    printf(">>>>>>>>>> %s: %s (line: %d) <<<<<<<<<<\n", __FILE__, __FUNCTION__, __LINE__);
    /* 给shape结构体变量分配内存 */
    pShape shape = (pShape)malloc(sizeof(Shape));
    if (NULL == shape)
    {
    
    
        printf("shape memory malloc failed!\n");
        abort();
    }
    /* 给shape->object_name字符串申请内存 */
    shape->object_name = (char*)malloc(strlen(object_name) + 1);
    if (NULL == shape->object_name)
    {
    
    
        printf("shape->object_name memory malloc failed!\n");
        abort();
    }

    /* 给结构体各成员进行初始化 */
    strncpy(shape->object_name, object_name, strlen(object_name) + 1);
    shape->length = 0;
    shape->width = 0;
    
    return ((HandleShape)shape);
}

void shape_set(HandleShape shape, int length, int width)
{
    
    
    printf(">>>>>>>>>> %s: %s (line: %d) <<<<<<<<<<\n", __FILE__, __FUNCTION__, __LINE__);
    if (shape)
    {
    
    
        ((pShape)shape)->length = length;
        ((pShape)shape)->width = width;
    }
}

int shape_getArea(HandleShape shape)
{
    
    
    return ( ((pShape)shape)->length * ((pShape)shape)->width );
}

void shape_display(HandleShape shape)
{
    
    
    printf(">>>>>>>>>> %s: %s (line: %d) <<<<<<<<<<\n", __FILE__, __FUNCTION__, __LINE__);
    if (shape)
    {
    
    
        printf("object_name = %s\n", ((pShape)shape)->object_name);
        printf("length = %d\n", ((pShape)shape)->length);
        printf("width = %d\n", ((pShape)shape)->width);
        printf("area = %d\n", shape_getArea(shape));
    }
}

void shape_delete(HandleShape shape)
{
    
    
    printf(">>>>>>>>>> %s: %s (line: %d) <<<<<<<<<<\n", __FILE__, __FUNCTION__, __LINE__);
    if (shape)
    {
    
    
        // free(((HandleShape)shape)->object_name);
        // ((HandleShape)shape)->object_name = NULL;
        // free(shape);
        // shape = NULL;
    }
}

Guess you like

Origin blog.csdn.net/weixin_44280688/article/details/122373694