1. Quotations
Today, there are quite a variety of programming languages, some of which have not even been heard or touched. For a programmer, C language is the foundation, C language is a process-oriented programming language, so how to use C language to write object-oriented programs?
The three basic characteristics of object-oriented programming are encapsulation, inheritance and polymorphism.
First use a C++ example, then turn the example into C language.
////////////////////////////Object.h/////////////////////////
//base class
class Object
{
public:
Object(double h);
~Object(){}
virtual double calcuArae() = 0; //Calculating Surface Area
virtual double calcuVolume() = 0;//calculate volume
//Have a common attribute
double height;
};
//cylinder
class Cylinder :public Object
{
public:
Cylinder(double h,double r);
~Cylinder(){}
virtual double calcuArae();
virtual double calcuVolume();
double radius;
};
//Cuboid
class Cuboid :public Object
{
public:
Cuboid(double h,double w,double l);
~Cuboid(){}
virtual double calcuArae();
virtual double calcuVolume();
double weith;
double length;
};
Realization:
///////////////////////////Object.cpp///////////////////////
//Base class constructor
Object::Object(double h)
:height(h)
{
}
/////////////////////////////////////////////////////////
Cylinder::Cylinder(double h, double r)
:Object(h)
,radius(r)
{
}
double Cylinder::calcuArae()
{
return 2*PI*radius*radius + 2*PI*radius*height;
}
double Cylinder::calcuVolume()
{
return (PI*(radius*radius)/4)*height;
}
/////////////////////////////////////////////////////////
Cuboid::Cuboid(double h, double w, double l)
:Object(h)
,weith(w)
,length(l)
{
}
double Cuboid::calcuArae()
{
return length*weith*height;
}
double Cuboid::calcuVolume()
{
return 2*(length*weith+weith*height+length*height);
}
Polymorphism:
QVector<Object*> vec;
vec<< new Cylinder(2,3);
vec<< new Cuboid(2,3,4);
for(int i = 0 ; i < vec.size();i++)
{
qDebug()<<vec.at(i)->calcuArae();
qDebug()<<vec.at(i)->calcuVolume();
}
C++ polymorphism is realized by virtual functions.
2. Packaging
class is used to encapsulate data and methods in C++ and struct is used to encapsulate data and methods in C language. In standard C runtime, a set of functions fopen(), fclose(),fread(), and fwrite() are used to operate FILE structure, and each function will pass in a FILE pointer.
Encapsulation is better
//Abstract object
typedef struct
{
int16_t x;
int16_t y;
} Shape;
//Constructor
Shape *Shape_new(int16_t x, int16_t y)
{
Shape * obj = (Shape*)malloc(sizeof(Shape));
obj->x = x;
obj->y = y;
return obj;
}
//Method
void Shape_moveBy(Shape * const me, int16_t dx, int16_t dy)
{
me->x += dx;
me->y += dy;
}
3. Inheritance
Inheritance in C language is a bit like the combination of C++, subclasses encapsulate the objects of the parent class.
//Specific object
typedef struct
{
Shape super; //This must be at the top of the list.
uint16_t width;
uint16_t height;
} Rectangle;
//Constructor
Rectangle*Rectangle_new(int16_t x, int16_t y,uint16_t width, uint16_t height)
{
Rectangle* r = (Rectangle*)malloc(sizeof(Rectangle));
r->super.x = x;
r->super.y = y;
r->width = width;
r->height = height;
return r;
}
//Method, using the method of base class
Application:
Rectangle* r1 = Rectangle_new(1,1,2,3);
Shape_moveBy((Shape *)r1, -2, 3);//Upcast type conversion, upcast inC++It's safe inside.
4. Polymorphism
- The realization of polymorphism is to create a virtual table and then bind it after implementation. For C language, it is the method of using function pointer.
First package:
//base class
typedef struct
{
struct ObjectVtbl const *vptr;//Fictitious table, this must also be put in the front.
double height;
}Object;
//Virtual table class
struct ObjectVtbl
{
double (*area)(Object * const o);
double (*volume)(Object * const o);
};
//Cylinder subclasses
typedef struct
{
Object super;
double radius;
}Cylinder;
//Cuboid subclass
typedef struct
{
Object super;
double width;
double length;
}Cuboid;
Then all the methods are realized:
These methods only use non-expouse in modules for users
static double cylinder_area(Object * const o)
{
Cylinder * const me = (Cylinder *)o;
double r = (uint)me->radius;
double h = (uint)o->height;
return 2*PI*r*r + 2*PI*r*h;
}
static double cylinder_volume(Object * const o)
{
Cylinder * const me = (Cylinder *)o;
double r = (uint)me->radius;
double h = (uint)o->height;
return (PI*(r*r)/4)*h;
}
/////////////////////////////////////////////////////////////
static double cuboid_volume(Object * const o)
{
Cuboid * const me = (Cuboid *)o;
double w = (uint)me->width;
double h = (uint)o->height;
double l = (uint)me->length;
return l*w*h;
}
static double cuboid_area(Object * const o)
{
Cuboid * const me = (Cuboid *)o;
double w = (uint)me->width;
double h = (uint)o->height;
double l = (uint)me->length;
return 2*(l*w+w*h+l*h);
}
Then the constructor is implemented:
Cuboid * new_Cuboid(double l,double w,double h)
{
//static and const are used here, because all instances use the same set of functions
//And here you should allocate space on rom
static struct ObjectVtbl const vtbl = { &cuboid_area,
&cuboid_volume,
};
Cuboid * c = (Cuboid *)malloc(sizeof(Cuboid));
c->super.vptr = &vtbl;
c->super.height = h;
c->length = l;
c->width = w;
return c;
}
Cylinder * new_Cylinder(double r,double h)
{
static struct ObjectVtbl const vtbl = { &cylinder_area,
&cylinder_volume,
};
Cylinder * c = (Cylinder *)malloc(sizeof(Cylinder));
c->super.vptr = &vtbl;
c->super.height = h;
c->radius = r;
return c;
}
Finally, the post-binding method is implemented:
static double calcu_area(Object * const o)
{
return (*o->vptr->area)(o);
}
static double calcu_volume(Object * const o)
{
return (*o->vptr->volume)(o);
}
Use:
Cylinder *cylinder = new_Cylinder(2,6);
Cuboid *cuboid = new_Cuboid(2,6,5);
Object *table[2];
table[0] = (Object *)cylinder;
table[1] = (Object *)cuboid;
for(int i = 0 ; i < 2 ;i++)
{
qDebug()<<calcu_area(table[i]);
qDebug()<<calcu_volume(table[i]);
}
5. Summary
- Object Oriented Programming is a design method, not a language
- Encapsulation and inheritance, C language can handle easily, but polymorphic words are relatively complex, and without any performance improvement.
- If you are writing frameworks, you can consider using polymorphism to hide details, but not for general applications.
6. Reference
https://www.cs.rit.edu/~ats/books/ooc.pdf
https://www.state-machine.com/doc/AN_OOP_in_C.pdf
https://www.youtube.com/watch?v=d5k_HBPFm0M
https://stackoverflow.com/questions/415452/object-orientation-in-c
http://ldeniau.web.cern.ch/ldeniau/html/oopc.html
https://sourceforge.net/projects/lwoopc/