Cognition -- the core idea of object-oriented in C language

I. Preface

In embedded development, C/C + + language is the most popular. Before C++11 version, their syntax is relatively similar, but C + + provides object-oriented programming.

Although C + + language is developed from C language, today's C + + is no longer an extension of the C language of that year. From the 2011 version, it is more like a brand-new language.

So I didn't think about why I extended C + +? What are the disadvantages of C language that lead to the emergence of C + +?

C + + has solved these problems very well, but with the gradual expansion of language standards, the learning difficulty of C + + language has gradually increased. I haven't developed several projects. I'm sorry to say that I have learned C + +. Those concepts of left value, right value, template, template parameters, variable template parameters and so on can't be mastered in 2 or 3 years.

However, C language also has many advantages:

In fact, the last advantage is the most important: the more people use it, the stronger the vitality. Just like today's society, it is not the survival of the superior, but the survival of the fittest.

In this article, let's talk about how to use the idea of object-oriented programming in C language. Maybe you can't use it in the project, but it's strongly recommended that you take a look, because the director likes to ask questions during the interview.

2, What is object-oriented programming

There is such a formula: program = data structure + algorithm.

C language generally uses process oriented programming, which is to analyze the steps needed to solve the problem, and then call these steps step by step with functions to process the data structure (execute the algorithm) in the functions, that is, the data structure and algorithm are separated.

C + + language encapsulates data and algorithm to form a whole. Whether it is to operate its properties or call its behavior, it is executed through an object, which is the idea of object-oriented programming.

If you use C language to simulate such a programming method, you need to solve three problems:

  1. Data encapsulation

  2. inherit

  3. polymorphic

First question: Encapsulation

Encapsulation describes the organization form of data, which is to organize all attributes (data) belonging to an object. The structure type in C language naturally supports this.

Second question: Inheritance

Inheritance describes the relationship between objects. Subclasses automatically own the properties and behaviors (that is, methods) in the parent class by inheriting the parent class. This problem is not a problem as long as you understand the memory model of C language. As long as you place a parent class structure variable at the position of the first member variable in the child class structure, the child class object inherits the properties in the parent class.

Add another point: to learn any language, you must understand the memory model!

The third question: polymorphism

Literally, polymorphism is "multiple states", which describes a dynamic behavior. In C + +, polymorphism occurs only when calling virtual functions through base class references or pointers, that is, polymorphism occurs during operation, and polymorphism is realized through a virtual table in C + +. Then in C language, we can also implement it according to this idea.

If a language only supports classes and does not support polymorphism, it can only be said that it is object-based rather than object-oriented.

Since there is no problem in thinking, let's simply implement one.

3, First implement a parent class to solve the problem of encapsulation

Animal.h

#ifndef _ANIMAL_H_#define _ANIMAL_H_​// Define parent class structure typedef struct {int age; int weight;} Animal; / / constructor declares void Animal_Ctor(Animal *this, int age, int weight); / / get the parent class attribute declaration int Animal_GetAge(Animal *this);int Animal_GetWeight(Animal *this); ​#endif

Animal.c

#include "Animal.h" / / the parent class constructor implements void animal_ Ctor(Animal *this, int age, int weight){    this->age = age;    this->weight = weight;} ​int Animal_ GetAge(Animal *this){    return this->age;} ​int Animal_ GetWeight(Animal *this){    return this->weight;}

Test:

#include <stdio.h>#include "Animal.h"#include "Dog.h" int main() {/ / create an object Animal a on the stack; / / construct the object animal_ctor (& A, 1, 3); printf ("age =% D, weight =% d \ n", animal_getage (& A), animal_getweight (& A)); return 0;}

It can be simply understood as: there is a space in the code segment to store functions that can handle Animal objects; There is a space in the stack to store the a object.

Compared with C + +: in the method of C + +, the first parameter this pointer is implied. When a method of an object is called, the compiler will automatically pass the address of the object to the pointer.

So, in Animal Let's simulate the function in H. the displayed definition of this pointer actively passes the address of the object to it when calling. In this way, the function can process any Animal object.

4, Implement a subclass to solve the problem of inheritance

Dog.h

#ifndef _DOG_H_#define _DOG_H_​#include "Animal.h"​// Define the subclass structure typedef struct {animal parent; / / place the parent structure int legs in the first position; / / add the subclass's own attribute} dog; / / subclass constructor declares void Dog_Ctor(Dog *this, int age, int weight, int legs); / / subclass attribute declaration int Dog_GetAge(Dog *this);int Dog_GetWeight(Dog *this);int Dog_GetLegs(Dog *this); ​#endif


Dog.c

#include "Dog.h" / / subclass constructor implements void Dog_Ctor(Dog *this, int age, int weight, int legs) {/ / first call the constructor of the parent class to initialize the data inherited from the parent class. Animal_ctor (& this - > parent, age, weight); / / then initialize the data of the child class. This - > legs = legs;} ​int Dog_ Getage (dog * this) {/ / the age attribute is inherited and forwarded to the get attribute function return animal_getage (& this - > parent);} ​int Dog_ GetWeight(Dog *this){    return Animal_GetWeight(&this->parent);} ​int Dog_GetLegs(Dog *this) {/ / the subclass's own attribute. Return this - > legs;}

Test:

 
int main(){ Dog d; Dog_Ctor(&d, 1, 3, 4); printf("age = %d, weight = %d, legs = %d \n",  Dog_GetAge(&d), Dog_GetWeight(&d), Dog_GetLegs(&d)); return 0;}

There is a space in the code segment to store functions that can handle Dog objects; There is a space in the stack to store d objects. Since the first parameter in the Dog structure is an Animal object, from the memory model, the subclass contains the attributes defined in the parent class.

The first part of Dog's memory model automatically includes members in Animal, that is, Dog inherits the attributes of Animal.

5, Using virtual function to solve the problem of polymorphism

In C + +, if a virtual function is defined in a parent class, the compiler will open up a space in this memory to place the virtual table. Each item in this table is a function pointer, and then put a virtual table pointer in the memory model of the parent class to point to the above virtual table.

The above description is not very accurate. It mainly depends on the processing methods of various compilers, but most C + + processors do so. We can think so.

After the subclass inherits the parent class, it will open up a space in memory to place the subclass's own virtual table, and then let the inherited virtual table pointer point to the subclass's own virtual table.

Since C + + does this, we use C to manually simulate this behavior: creating virtual tables and virtual table pointers.

1. Animal.h is the parent class animal, adding virtual table and virtual table pointer

 
#ifndef _ANIMAL_H_#define _ANIMAL_H_​struct AnimalVTable; // Pre declaration of parent virtual table / / parent structure typedef struct {struct animalvtable * VPTR; / / virtual table pointer int age; int weight;} Animal; / / virtual table struct animalvtable {void (* say) (animal * this); / / virtual function pointer}; / / the virtual function void animal implemented in the parent class_ Say(Animal *this); ​#endif

2. Animal.c

 
#include <assert.h>#include "Animal.h" / / the concrete implementation of the virtual function in the parent class static void_ Animal_ Say (animal * this) {/ / because the parent class animal is an abstract thing and should not be instantiated. / / the virtual function in the parent class should not be called, that is, the subclass must implement the virtual function. / / it is similar to the pure virtual function in C + +. assert(0);} / / parent constructor void Animal_Ctor(Animal *this, int age, int weight) {/ / first define a virtual table static struct AnimalVTable animal_vtbl = {_Animal_Say}// Let the virtual table pointer point to the above virtual table this - > VPTR = & animal_ vtbl;  this->age = age;  this->weight = weight;} / / test polymorphism: the parameter type passed in is the parent class pointer void Animal_Say(Animal *this) {/ / if this actually points to a subclass Dog object, the virtual table pointer of this - > VPTR points to the virtual table of the subclass itself. / / therefore, this - > VPTR - > say will call the functions in the virtual table of the subclass. This - > VPTR - > say (this);}

A virtual function table animal is defined in the stack space_ VTBL, each item in this table is a function pointer. For example, the function pointer say points to the function in the code segment_ Animal_Say(). > the first member vptr of object a is a pointer to the virtual function table animal_vtbl.

3. dog H constant

4. Dog. Define the virtual table of subclass in C

 
#include "Dog.h" / / concrete implementation of virtual function in subclass static void_ Dog_ Say(Dog *this){ printf("dag say \n");} / / subclass constructor void Dog_Ctor(Dog *this, int age, int weight, int legs) {/ / call the parent class constructor first. Animal_ctor (& this - > parent, age, weight); / / define the virtual function table static struct AnimalVTable dog_vtbl = {_Dog_Say}// Point the virtual table pointer inherited from the parent class to the virtual table this - > parent vptr = &dog_ vtbl; //  Initialize the subclass's own attribute this - > legs = legs;}

5. Test it

 
int main(){ // Create a subclass dog object dog D in the stack; Dog_ Ctor(&d, 1, 3, 4); / / assign the subclass object to the parent class pointer animal * PA = & D; / / passing the parent class pointer will call the virtual function implemented in the child class. Animal_Say(pa);}

The memory model is as follows:

In object d, the virtual table pointer vptr inherited from the parent class points to dog_vtbl.

Executing Animal_ When say (pa), although the parameter type is a pointer to the parent class Animal, the pa actually passed in is an object pointing to the subclass dog. The virtual table pointer vptr in this object points to the virtual table dog defined by the subclass itself_ VTBL, the function pointer say in this virtual table points to the virtual function redefined in the subclass_ Dog_Say, so this - > vptr - > say (this) finally calls the function_ Dog_Say.

Basically, the idea of object-oriented development in C is the above. This code is very simple. Just knock it with your own hand.

6, Application of C object-oriented idea in project

1. Linux kernel

Take a look at several structures of socket:

 
struct sock { ...}​struct inet_sock { struct sock sk; ...};​struct udp_sock { struct sock sk; ...};

Sock can be regarded as a parent class, inet_sock and UDP_ The first member of the sock is the sock type. From the memory model, it is equivalent to inheriting all the attributes in the sock.

2. glib Library

Take the simplest string processing function as an example:

GString *g_string_truncate(GString *string, gint len)GString *g_string_append(GString *string, gchar *val)GString *g_string_prepend(GString *string, gchar *val)

The first parameter of the API function is a GString object pointer, pointing to the string object to be processed.

 
GString *s1, *s2;s1 = g_string_new("Hello");s2 = g_string_new("Hello");​g_string_append(s1," World!");g_string_append(s2," World!");

3. Other items

Some other projects, although not object-oriented in terms of function parameters, are also object-oriented in terms of data structure design, such as:

1. libmodbus, an open source library of Modbus Protocol
2. Wireless communication protocol ZWave for home automation
3. BREW, Qualcomm's mobile development platform long ago

Conclusion: C language is a low-level language, master ability and go further.

Tags: C++

Posted by johnc71 on Tue, 19 Apr 2022 08:00:18 +0930