C实现多态

源码:https://github.com/baitxaps/CPointer



typedef void (*fptrSet)(void *,int);

typedef int (*fptrGet)(void *);

typedef void(*fptrDisPlay)();

/*

 1.C++多态是建立在基类及派生类之间继承关系的基础上的,C不支持继承,所以得模拟结构体之间的继承

   定议和使用两个结构体来说明多态行为:Shape结构体表示基,而Rectangle结构表示从基类Shape派生的类

   结构体的变量分配顺序对这个技术的工作原理影响很大,当创建一个派生类/结构体的实例时,会先分配基类/结构体的

   变量,也需要考虑打算覆盖的函数

 2.Shape结构体持有函数指针,接着是xy的坐标整数

 3.vFunctions结构体:由一系列函数指针组成.fptrSetfptrGet函数指针为整数类型数据定义了典型的gettersetter

   函数,用来获取和设置ShapeRectanglexy值,fptrDisplay函数指针定义了一个参数为空,返回值为空的函数

   会用这个打印函数解释多态行为

 4.当一个类/结构体执行函数时,其行为取决它作用的对象是什么,如对Shpae调用打印函数

   就会显示一个Shape,对Rectangle调用打印函数就会显示Rectangle.在面向对象编程中这通常通过虚表(VTable)

   实现,vFunctions结构就是用来实现这种功能

 */

typedef struct _functions{

    fptrSet setX;

    fptrGet getX;

    fptrSet setY;

    fptrGet getY;

    fptrDisPlay display;

}vFunctions;



typedef struct _shape{

    vFunctions functions;

    int x;

    int y;

}Shape;


/*

 看起来实现Shape结构体这么做有点大费周章,但是从Shape派生出一个Rectangle结构体,就会看到这么做

 强大的能力

 */

typedef struct _rectangle{

    Shape base;

    int width;

    int height;

}Rectangle;


void shapeDisplay(Shape *shape){

    printf("Shape\n");

}


void shapeSetX(Shape *shape,int x){

    shape->x = x;

}

int  shapeGetX(Shape *shape){

    return  shape->x;

}

void shapeSetY(Shape *shape,int y){

    shape->y= y;

}

int shapeGetY(Shape *shape){

    return shape->y;

}


void rectangleSetX(Rectangle *rectangle,int x){

    rectangle->base.x= x;

}


void rectangleSetY(Rectangle *rectangle,int y){

    rectangle->base.y= y;

}

int rectangleGetX(Rectangle *rectangle){

   return rectangle->base.x;

}


int rectangleGetY(Rectangle *rectangle){

   return  rectangle->base.y;

}


void rectangleDisplay(){

    printf("Rectangle\n");

}

/*

 为对象分配内存,然后为其设置函数

 */


Shape *getShapeInstance(){

    Shape *shape = (Shape *)malloc(sizeof(Shape));

    shape->functions.display =shapeDisplay;

    shape->functions.setX  = (void *)shapeSetX;

    shape->functions.getX  = (void *)shapeGetX;

    shape->functions.setY  = (void *)shapeSetY;

    shape->functions.getY  = (void *)shapeGetY;

    

    shape->x = 100;

    shape->y = 100;

    return shape;

}


Rectangle *getRectangleInstance(){

    Rectangle *rectangle = (Rectangle *)malloc(sizeof(Rectangle));

    rectangle->base.functions.display =rectangleDisplay;

    rectangle->base.functions.setX  = (void *)rectangleSetX;

    rectangle->base.functions.getX  = (void *)rectangleGetX;

    rectangle->base.functions.setY  = (void *)rectangleSetY;

    rectangle->base.functions.getY  = (void *)rectangleGetY;

    

    rectangle->base.x200;

    rectangle->base.y200;

    rectangle->width  = 300;

    rectangle->height = 500;

    return rectangle;

}


int main(int argc,constchar * argv[]) {

//    Shape *sptr = getShapeInstance();

//    sptr->functions.setX(sptr,35);

//    sptr->functions.display();

//    printf("%d\n",sptr->functions.getX(sptr));

//    

//    

//    Rectangle *rptr = getRectangleInstance();

//    rptr->base.functions.setX(rptr,65);

//    rptr->base.functions.display();

//    printf("%d\n",rptr->base.functions.getX(rptr));

    

    /*

     1.创建一个Shape指针的数组,然后初始化。当把Rectangle赋给shapes[1]时,没有必要非得把它转成(Shape*),

       但是不强转会产生警告

     2.创建Shape指针的数组过程中,创建一个Rectangle实例并将其赋给数组的第二个元素,当for循环中打印元素时,

       它倒用Rectangle的函数行为而不是Shape的,这就是一种多态行为。display函数的行为取决于它所执行的对象

     3.我们把它当成Shape来访问,因此不应该试图用shape[i]来访问其宽度和高度,原因是这个元素可能引用一个Rectangle

       也可能不是。如果不这么做,就可能访问shapes的其他内存,那些内存并不代表宽度和高度信息,会导致不可预期的结果

     4.也可以再从Shape中派生一个结构,如Circle,把它加入数组,而不需要大量修改代码。我们也需要为这个结构体创建函数

     5.如给基结构Shape增加一个函数,如getArea,就可以为每一个类实现一个唯一的getArea函数,在循环中,可以轻易地把所有ShapeShape派生的结构体的面积累加,而不需要先判断处理的是什么类型的Shape.

     6.如果ShapegetArea实现足够了,那么就不需要为其他结构增加函数了。这样很容易维护和扩展一个应用程序

     */

    

    Shape *shape[3];

    shape[0] = getShapeInstance();

    shape[0]->functions.setX(shape[0],5);

    

    shape[1] =getRectangleInstance();

    shape[1]->functions.setX(shape[1],15);

    

    shape[2] = getShapeInstance();

    shape[2]->functions.setX(shape[2],25);

    

    

    for (int i =0; i<3; i++) {

        shape[i]->functions.display();

        printf("%d\n",shape[i]->functions.getX(shape[i]));

    }

    return 0;

 }   


输出结果:

Shape

5

Rectangle

15

Shape

25

Program ended with exit code: 0


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值