编程知识 cdmana.com

Have you mastered the three elements of making C language realize object-oriented?

 send C Language implements three elements of object-oriented , Have you got it ?

 

layout | strongerHuang

WeChat official account | strongerHuang

 

I don't know how many people have known the history of language development , In the early C In fact, the grammatical function of language is relatively simple . As application requirements and scenarios change ,C The grammatical functions of language are constantly upgrading and changing .

 

Although our textbook has such a conclusion :C Language is Process oriented Language ,C++ yes object-oriented Programming language , But the concept of object-oriented is in C The language stage has , And it's been used in a lot of places , For example, some operating system kernels 、 Communication protocol, etc .

 

object-oriented programming , That is to say OOP(Object Oriented Programming) It's not a specific language or tool , It's just a design method 、 design idea , The three most basic characteristics of it are encapsulation 、 Inheritance and polymorphism .

 

Why use C Language implements object-oriented

 

There must be readers who ask questions like this before reading the text : We have C++ Object oriented language , Why use C Language implementation object-oriented ?

 

C Language is a non object oriented language , You can also use object-oriented ideas to write programs . It's just object-oriented C++ Language to implement object-oriented programming will be easier , however C The efficiency of language is incomparable with other object-oriented programming languages .

 

Of course use C Language to achieve object-oriented development is relatively difficult to understand , That's why most people have learned C But I can't understand the language Linux Kernel source code .

 

So this question is very easy to understand , As long as there is a certain amount of C Readers of language programming experience should understand : Process oriented C Language and object-oriented C++ Language comparison , Code efficiency 、 The amount of code varies a lot . In the performance is not very good 、 There are not many resources MCU Use in C Language object-oriented programming is particularly important .

 

Have the conditions

 

Want to use C Language implements object-oriented , First of all, you need to have some basic knowledge . such as :(C In language ) Structure 、 function 、 The pointer , And function pointers ,(C++ Medium ) Base class 、 The derived 、 polymorphic 、 Inheritance, etc .

 

First , It's not just about understanding the basics , But I have some programming experience , Because it says “ Object oriented is a design method 、 design idea ”, If only stay in the literal meaning of understanding , Without this kind of design idea, it can't be .

 

therefore , It is not recommended for beginners to use C Language implements object-oriented , Especially in real projects . It is suggested to practice basic skills well , Reuse .

 

utilize C There are many ways to implement object-oriented language , The following describes the most basic packaging 、 Inheritance and polymorphism .

 

C/C++ Learning skirt of 【 712   two eight four   Seven Zero Five  】, Whether you are Xiaobai or an advanced person , If you want to change your career or join it, you can learn about it and learn from it together ! There are development tools in the skirt , A lot of dry goods and technical information sharing !

 

encapsulation

 

Encapsulation is to package data and functions into a class , In fact, most of them C Language programmers have been exposed to .

 

C In the standard library fopen(), fclose(), fread(), fwrite() The operation object of the function is FILE. The data content is FILE, Reading and writing data is fread()、fwrite(),fopen() It's analogous to a constructor ,fclose() It's a destructor .

 

This seems to be easy to understand , Now let's implement the basic encapsulation features .

#ifndef SHAPE_H
#define SHAPE_H

#include <stdint.h>

// Shape  Properties of 
typedef struct {
    int16_t x; 
    int16_t y; 
} Shape;

// Shape  Operation function of , The interface function 
void Shape_ctor(Shape * const me, int16_t x, int16_t y);
void Shape_moveBy(Shape * const me, int16_t dx, int16_t dy);
int16_t Shape_getX(Shape const * const me);
int16_t Shape_getY(Shape const * const me);

#endif /* SHAPE_H */

 

This is a Shape Declaration of a class , It's simple , Well understood. . Generally, the declaration will be put in the header file “Shape.h”. Take a look Shape Class related definitions , Of course is in “Shape.c” Inside .

#include "shape.h"

//  Constructors 
void Shape_ctor(Shape * const me, int16_t x, int16_t y)
{
    me->x = x;
    me->y = y;
}

void Shape_moveBy(Shape * const me, int16_t dx, int16_t dy) 
{
    me->x += dx;
    me->y += dy;
}

//  Get property value function 
int16_t Shape_getX(Shape const * const me) 
{
    return me->x;
}
int16_t Shape_getY(Shape const * const me) 
{
    return me->y;
}

 

Let's take a look at main.c

#include "shape.h"  /* Shape class interface */
#include <stdio.h>  /* for printf() */

int main() 
{
    Shape s1, s2; /* multiple instances of Shape */

    Shape_ctor(&s1, 0, 1);
    Shape_ctor(&s2, -1, 2);

    printf("Shape s1(x=%d,y=%d)\n", Shape_getX(&s1), Shape_getY(&s1));
    printf("Shape s2(x=%d,y=%d)\n", Shape_getX(&s2), Shape_getY(&s2));

    Shape_moveBy(&s1, 2, -4);
    Shape_moveBy(&s2, 1, -2);

    printf("Shape s1(x=%d,y=%d)\n", Shape_getX(&s1), Shape_getY(&s1));
    printf("Shape s2(x=%d,y=%d)\n", Shape_getX(&s2), Shape_getY(&s2));

    return 0;
}

 

After the compilation , See the results :

Shape s1(x=0,y=1)
Shape s2(x=-1,y=2)
Shape s1(x=2,y=-3)
Shape s2(x=0,y=0)

 

The whole example , It's simple , Very easy to understand . When you write code later , Think more about the standard library files IO operation , To develop object-oriented thinking in this way .

 send C Language implements three elements of object-oriented , Have you got it ?

 

Inherit

 

Inheritance is to define a new class based on an existing class , This helps reuse code , Better organization of code . stay C In language , It's also very simple to implement single inheritance , Just put the base class in the position of the first data member of the inherited class .

 

for example , We're going to create a Rectangle class , We just have to inherit Shape Class's existing properties and operations , Adding is different from Shape Properties and operations to Rectangle in .

 

Here is Rectangle Statement and definition of :

#ifndef RECT_H
#define RECT_H

#include "shape.h" //  Base class interface 

//  Properties of rectangles 
typedef struct {
    Shape super; //  Inherit  Shape

    //  Own attributes 
    uint16_t width;
    uint16_t height;
} Rectangle;

//  Constructors 
void Rectangle_ctor(Rectangle * const me, int16_t x, int16_t y,
                    uint16_t width, uint16_t height);

#endif /* RECT_H */
#include "rect.h"

//  Constructors 
void Rectangle_ctor(Rectangle * const me, int16_t x, int16_t y,
                    uint16_t width, uint16_t height)
{
    /* first call superclass’ ctor */
    Shape_ctor(&me->super, x, y);

    /* next, you initialize the attributes added by this subclass... */
    me->width = width;
    me->height = height;
}

 

Let's take a look Rectangle The inheritance relationship and memory layout of :

 send C Language implements three elements of object-oriented , Have you got it ?

 

Because of this memory layout , So you can safely pass a point to Rectangle Object to an expected pass in Shape Object in the function of the pointer , The parameter of a function is “Shape *”, You can pass in “Rectangle *”, And it's very safe . In this case , All properties and methods of the base class can be inherited by the inherited class !

#include "rect.h"  
#include <stdio.h> 

int main() 
{
    Rectangle r1, r2;

    //  Instantiate objects 
    Rectangle_ctor(&r1, 0, 2, 10, 15);
    Rectangle_ctor(&r2, -1, 3, 5, 8);

    printf("Rect r1(x=%d,y=%d,width=%d,height=%d)\n",
           Shape_getX(&r1.super), Shape_getY(&r1.super),
           r1.width, r1.height);
    printf("Rect r2(x=%d,y=%d,width=%d,height=%d)\n",
           Shape_getX(&r2.super), Shape_getY(&r2.super),
           r2.width, r2.height);

    //  Be careful , There are two ways , One is the strong transition type , The second is to use the member address directly 
    Shape_moveBy((Shape *)&r1, -2, 3);
    Shape_moveBy(&r2.super, 2, -1);

    printf("Rect r1(x=%d,y=%d,width=%d,height=%d)\n",
           Shape_getX(&r1.super), Shape_getY(&r1.super),
           r1.width, r1.height);
    printf("Rect r2(x=%d,y=%d,width=%d,height=%d)\n",
           Shape_getX(&r2.super), Shape_getY(&r2.super),
           r2.width, r2.height);

    return 0;
}

 

Output results :

Rect r1(x=0,y=2,width=10,height=15)
Rect r2(x=-1,y=3,width=5,height=8)
Rect r1(x=-2,y=5,width=10,height=15)
Rect r2(x=1,y=2,width=5,height=8)

 

polymorphic

 

C++ Language polymorphism is the use of virtual functions . stay C In language , Polymorphism can also be achieved .

 

Now? , Let's add another circle , And in Shape To extend functionality , We need to increase area() and draw() function . however Shape Equivalent to an abstract class , I don't know how to calculate my area , I don't know how to draw myself . and , The area calculation method of rectangle and circle is also different from geometric image .

 

Now let's restate Shape class :

#ifndef SHAPE_H
#define SHAPE_H

#include <stdint.h>

struct ShapeVtbl;
// Shape  Properties of 
typedef struct {
    struct ShapeVtbl const *vptr;
    int16_t x; 
    int16_t y; 
} Shape;

// Shape  The virtual table of 
struct ShapeVtbl {
    uint32_t (*area)(Shape const * const me);
    void (*draw)(Shape const * const me);
};

// Shape  Operation function of , The interface function 
void Shape_ctor(Shape * const me, int16_t x, int16_t y);
void Shape_moveBy(Shape * const me, int16_t dx, int16_t dy);
int16_t Shape_getX(Shape const * const me);
int16_t Shape_getY(Shape const * const me);

static inline uint32_t Shape_area(Shape const * const me) 
{
    return (*me->vptr->area)(me);
}

static inline void Shape_draw(Shape const * const me)
{
    (*me->vptr->draw)(me);
}


Shape const *largestShape(Shape const *shapes[], uint32_t nShapes);
void drawAllShapes(Shape const *shapes[], uint32_t nShapes);

#endif /* SHAPE_H */

 

Take a look at the class diagram after adding virtual functions :

 send C Language implements three elements of object-oriented , Have you got it ?

 

5.1 Virtual tables and virtual pointers

Virtual table (Virtual Table) Is the collection of function pointers to all virtual functions of this class .

 

Virtual pointer (Virtual Pointer) Is a pointer to a virtual table . This virtual pointer must exist in every object instance , Will be inherited by all subclasses .

 

stay 《Inside The C++ Object Model》 In the first chapter of the article , There are these introductions .

 

5.2 Set... In the constructor vptr

In each object instance ,vptr Must be initialized to point to it vtbl. The best place to initialize is in the class constructor . in fact , In the constructor ,C++ The compiler implicitly creates an initialized vptr. stay C In language , We have to show the initialization of vptr.

 

Let's show you , stay Shape In the constructor of , How to initialize this vptr.

static inline uint32_t Shape_area(Shape const * const me) {    return (*me->vptr->area)(me);}

 

5.3 Inherit vtbl and heavy load vptr

As mentioned above , The base class contains vptr, Subclasses automatically inherit . however ,vptr Need to be reassigned by the virtual table of the subclass . also , This must also happen in the subclass constructor . Here is Rectangle Constructor for .

#include "rect.h"  
#include <stdio.h> 

// Rectangle  Virtual functions 
static uint32_t Rectangle_area_(Shape const * const me);
static void Rectangle_draw_(Shape const * const me);

//  Constructors 
void Rectangle_ctor(Rectangle * const me, int16_t x, int16_t y,
                    uint16_t width, uint16_t height)
{
    static struct ShapeVtbl const vtbl = 
    {
        &Rectangle_area_,
        &Rectangle_draw_
    };
    Shape_ctor(&me->super, x, y); //  Call the constructor of the base class 
    me->super.vptr = &vtbl;           //  heavy load  vptr
    me->width = width;
    me->height = height;
}

// Rectangle's  Virtual function implementation 
static uint32_t Rectangle_area_(Shape const * const me) 
{
    Rectangle const * const me_ = (Rectangle const *)me; // Display conversion 
    return (uint32_t)me_->width * (uint32_t)me_->height;
}

static void Rectangle_draw_(Shape const * const me) 
{
    Rectangle const * const me_ = (Rectangle const *)me; // Display conversion 
    printf("Rectangle_draw_(x=%d,y=%d,width=%d,height=%d)\n",
           Shape_getX(me), Shape_getY(me), me_->width, me_->height);
}

 

5.4 Virtual function call

With the front virtual watch (Virtual Tables) And virtual pointer (Virtual Pointers) The foundation of , Virtual call ( Late binding ) You can use the following code to achieve .

uint32_t Shape_area(Shape const * const me)
{
    return (*me->vptr->area)(me);
}

This function can be put into .c In the document , However, there is a disadvantage that each virtual call has additional call overhead . To avoid this shortcoming , If the compiler supports inline functions (C99). We can put the definition in the header file , It's like this :

static inline uint32_t Shape_area(Shape const * const me) 
{
    return (*me->vptr->area)(me);
}

 

If it's an older compiler (C89), We can do it with macro functions , Similar to the following :

#define Shape_area(me_) ((*(me_)->vptr->area)((me_)))

 

Take a look at the invocation mechanism in the example :

 send C Language implements three elements of object-oriented , Have you got it ?

 

5.5 main.c

#include "rect.h"  
#include "circle.h" 
#include <stdio.h> 

int main() 
{
    Rectangle r1, r2; 
    Circle    c1, c2; 
    Shape const *shapes[] = 
    { 
        &c1.super,
        &r2.super,
        &c2.super,
        &r1.super
    };
    Shape const *s;

    //  Instantiate a rectangular object 
    Rectangle_ctor(&r1, 0, 2, 10, 15);
    Rectangle_ctor(&r2, -1, 3, 5, 8);

    //  Instantiate a circular object 
    Circle_ctor(&c1, 1, -2, 12);
    Circle_ctor(&c2, 1, -3, 6);

    s = largestShape(shapes, sizeof(shapes)/sizeof(shapes[0]));
    printf("largetsShape s(x=%d,y=%d)\n", Shape_getX(s), Shape_getY(s));

    drawAllShapes(shapes, sizeof(shapes)/sizeof(shapes[0]));

    return 0;
}

Output results :

largetsShape s(x=1,y=-2)
Circle_draw_(x=1,y=-2,rad=12)
Rectangle_draw_(x=-1,y=3,width=5,height=8)
Circle_draw_(x=1,y=-3,rad=6)
Rectangle_draw_(x=0,y=2,width=10,height=15)

 

 send C Language implements three elements of object-oriented , Have you got it ?

 

summary

 

Or that sentence , Object oriented programming is a way , It's not limited to one programming language . use C Language implementation encapsulation 、 Single inheritance , It's easier to understand and implement , Polymorphism is a little more complicated , If you plan to use polymorphism widely , Or is it recommended to go to C++ Language , After all, this layer of complexity is encapsulated in the language , You just need to use it simply . But it doesn't mean ,C Languages can't implement polymorphism .

 

版权声明
本文为[Three ah three water]所创,转载请带上原文链接,感谢

Scroll to Top