C语言之“面向对象编程”
面向对象编程(OOP)四大特征:抽象、封装、继承、多态。主流的面向对象编程语言(如C++、Java、C#等)都有完善的面向对象实现机制。C语言是面向过程编程语言,但可以通过结构体和指针实现类似的面向对象语言功能。所以,我更倾向于将其理解为一种编程思想,而不是面向对象编程语言仅有的特性。
本文基于一个实例,演示如何在C语言中实现多态。
1 定义函数指针
//基类函数成员
typedef int (*fptrSet)(void *, int);
typedef int (*fptrGet)(void *);
typedef void (*fptrDisplay)(void *);//派生类新增函数成员
typedef double (*fptrGetArea)(void *);
2 定义Shape基类
(1)定义“基类”,包含数据成员和函数成员,其中函数成员用函数指针定义。
(2)实现函数成员,定义为独立的函数,参数为结构体指针。
(3)实现“构造函数”,以参数形式将数据成员传递进来,直接用(2)中定义的函数给函数成员赋值。
//定义基类Shape
typedef struct _shape
{//定义基类函数成员struct{fptrSet setX;fptrGet getX;fptrSet setY;fptrGet getY;fptrDisplay display;};//定义基类数据成员int x;int y;
} Shape;//函数成员的实现,独立函数还未绑定
void shapeDisplay(Shape *shape)
{printf("Shape\n");
}
void shapeSetX(Shape *shape, int x)
{shape->x = x;
}
void shapeSetY(Shape *shape, int y)
{shape->y = y;
}
int shapeGetX(Shape *shape)
{return shape->x;
}
int shapeGetY(Shape *shape)
{return shape->y;
}
//定义构造函数:数据成员以参数传值,绑定独立的函数(为函数成员赋值)
Shape *shapeConstructor(int x, int y)
{Shape *shape = (Shape *)malloc(sizeof(Shape));shape->x = x;shape->y = y;shape->display = shapeDisplay;shape->setX = shapeSetX;shape->setY = shapeSetY;shape->getX = shapeGetX;shape->getY = shapeGetY;return shape;
}
3 定义Rectangle派生类
(1)基于C++及Java等面向对象程序设计语言中派生类的特性来实现该派生类。
(2)测试以下几点:派生类覆盖基类函数成员display;派生类新增数据成员width、height;派生类新增函数成员func1。
//定义派生类
typedef struct _rectangle
{//维护一个基类成员变量,必须为变量,不能用指针Shape base;//派生类额外的函数成员fptrGetArea func1;//派生类额外的数据成员int width;int height;
} Rectangle;//覆盖基类的dispalay方法
void rectangleDisplay(Rectangle *rectangle)
{printf("Rectangle\n");
}//实现派生类额外的函数成员
double getArea(Rectangle *rectangle)
{return rectangle->width * rectangle->height;
}//定义构造函数
Rectangle *rectangleConstructor(int width, int height, int x, int y)
{Rectangle *rectangle = (Rectangle *)malloc(sizeof(Rectangle));//初始化派生类中额外的成员rectangle->width = width;rectangle->height = height;rectangle->func1 = getArea; //此处初始化新增函数成员//初始化派生类中的基类变量rectangle->base = (Shape){.x = x,.y = y,.display = rectangleDisplay, //此处覆盖基类函数成员.setX = shapeSetX,.setY = shapeSetY,.getX = shapeGetX,.getY = shapeGetY};return rectangle;
}
4 测试
用基类指针指向派生类对象,调用基类方法时,可选择调用基类或派生类的方法实现,原理在于shapes[1]- >display会访问实际函数地址,如果该函数已被派生类覆盖,则调用派生类的版本。
int main()
{//构造三个对象Shape *shapes[3];shapes[0] = shapeConstructor(0, 0);shapes[1] = rectangleConstructor(100, 200, 50, 50);shapes[2] = shapeConstructor(600, 600);//输出三个对象for (int i = 0; i < 3; i++){shapes[i]->display(shapes[i]);printf("%d\n", shapes[i]->getX(shapes[i]));}//输出shapes[1]中display函数的地址,两者相等,是该多态访问成功的基础printf("%p\n", ((Rectangle *)shapes[1])->base.display);printf("%p\n", shapes[1]->display);//输出shapes[1]的面积,对于派生类特有的函数,应该转变为派生类指针后再访问printf("area=%lf\n", ((Rectangle *)shapes[1])->func1(shapes[1]));return 0;
}

本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
