在 C 系语言中,struct 占用的内存是连续的,我们可以利用这个 struct分配的内存是连续的 这个特性来实现虚函数表

只需要给每个结构体头部加上一个虚函数表指针就可以了,因为指针在 C 系语言中占用的内存固定八字节,所以我们可以将基类的方法放到基类的虚函数表里

子类继承父类时,让子类实现对应的方法,并把方法绑定到对应虚函数表内的函数指针上,然后除去从父类继承的内存而言,其余的派生方法和参数都是放置在虚函数表内存后面排列

而取派生前面的那串连续的内存,结构上和父类是一摸一样的,所以可以强制转换.(多态)

#include<stdio.h>

typedef struct Point{
int x,y;
}Point;

typedef struct Shape { // 基类
struct Methods* methods; // 指向 "虚函数表"
}Shape;

struct Methods { // 将 C++ 对应类中所有虚函数都封装到一个结构体里
// 函数指针 函数返回值类型 (* 指针变量名) (函数参数列表);
float (*getPerimeter)(Shape *shape);
float (*getArea)(Shape * shape);
char* (*getShape)(Shape *shape);
};

typedef struct Rectangle{
struct Methods *methods; // 包含继承 Shape 后的成员函数结构体的指针
Point leftTop; //Shape 之外派生的成员变量
Point rightBottom; // 派生
} Rectangle;

float Rectangle_getPerimeter (Shape *shape){// 计算矩形周长
Rectangle *r = (Rectangle*) shape;
return (float)(r->rightBottom.x - r->leftTop.x + r->rightBottom.y - r->leftTop.y) * 2;
}

float Rectangle_getArea (Shape * shape) // 计算矩形面积
{
Rectangle * r = (Rectangle *) shape;
return (float)(r->rightBottom.x - r->leftTop.x) * (r->rightBottom.y - r->leftTop.y);
}

char* Rectangle_getShape(Shape * shape)
{
return “Rectangle”;
}

struct Methods rectangleMethods = {
&Rectangle_getPerimeter,
&Rectangle_getArea,
&Rectangle_getShape,
};

// 圆形
typedef struct Circle {
struct Methods *methods;
Point center;
float radius;
}Circle;
float Circle_getPerimeter (Shape *shape){ // 计算圆周长
Circle *c = (Circle*) shape;
return (float)2*3.14*c->radius;
}
float Circle_getArea(Shape *shape){
Circle *c = (Circle*)shape;
return (float)3.14*(c->radius)*(c->radius);
}

char* Circle_getShape(Shape *shape){
return “Circle”;
}

struct Methods circleMethods = {
&Circle_getPerimeter,
&Circle_getArea,
&Circle_getShape
};

Shape* shapes[2];
Shape* new_rectangle(Point a,Point b){
struct Rectangle* r = (Rectangle*)malloc(sizeof(Rectangle));
r->methods = &rectangleMethods;
r->leftTop = a;
r->rightBottom = b;
return (Shape*)r;
}

Shape* new_circle (Point a, float r) // 创建 Circle 对象
{
struct Circle* c = (Circle*)malloc(sizeof(Circle));
c->methods = &circleMethods;
c->center = a;
c->radius = r;
return (Shape*)c;
}

int main(){
Point c = {0,0};
shapes[0] = new_circle(c,10);
Point a ={2,3};
Point b = {9,8};
shapes[1] = new_rectangle(a, b);
int i=0;
for(i=0;i<2;i){
printf("%s’s permeter is: %f \n",(*shapes[i]->methods->getShape)(shapes[i]),
(*shapes[i]->methods->getPerimeter)(shapes[i]));
}
for (i = 0; i < 2; i
)
printf("%s’s area is: %f\n", (*shapes[i]->methods->getShape)(shapes[i]),
(*shapes[i]->methods->getArea)(shapes[i]));
getchar();

return 0;

}