很多开发工程师都是从学习C语言的"Hello world!"开始的,都知道C语言中的指针是1把利剑,1不留意就伤了自个。但其C语言绝对是1个宗师级语言,这是不可否认的。
由于我们开发的需要在多个平台上运行且需要面向对象的1些特性、所以特写此文章。权当抛砖引玉。
1、概述
C语言是1种面向进程的程序设计语言、而C++在语言级别上添加了很多新机制(继承,多态等)
因此这里说说使用C语言实现封装,继承和多态的方法。
2、基本知识
1、结构体
在C语言中,常把1个对象用结构体进行封装,这样便于对对象进行操作,比如:1
strcut Point{
int x;
int y;
};
结构体可以嵌套。因此可以把1个结构体当做另外一个结构体的成员:
struct Circle {
struct Point point_;
int radius;
};
该结构体与以下定义完全1样(包括内存布置都1样):
struct Circle {
int x;
int y;
int radius;
};
2、函数指针
函数指针是指针的1种,它指向函数的首地址(函数的函数名即为函数的首地址),可以通过函数指针来调用函数。
如函数:
int func(int a[], int n);
可以这样声明函数指针:
int (*pFunc)(int a[], int n);
这样使用:
pFunc = func;
(*pFunc)(a, n);【或PFunc(a, n)】
可以用typedef定义1个函数指针类型,如:
typdef int (*FUNC)(int a[], int n)
可以这样使用:
int cal_a(FUNC fptr, int a[], int n)
{
//实现体...
}
3、extern与static
extern和static是C语言中的两个修饰符,extern可用于修饰函数或变量,表示该变量或函数在其他文件中进行了定义;
static也可用于修饰函数或变量,表示该函数或变量只能在该文件中使用。可利用它们对数据或函数进行隐藏或限制访问权限。
3、封装
在C语言中,可以用结构+函数指针来摹拟类的实现,而用这类结构定义的变量就是对象。
封装的主要含义是隐藏内部的行动和信息,使用者只用看到对外提供的接口和公然的信息。
有两种方法实现封装:
1、利用C语言语法。在头文件中声明,在C文件中真正定义它。
这样可以隐藏内部信息,由于外部不知道对象所占内存的大小,所以不能静态的创建该类的对象,只能调用类提供的创建函数才能创建。这类方法的缺点是不支持继承,由于子类中得不到任何关于父类的信息。如:
/**
* Point的头文件Point.h(对外提供接口)
*/
#ifndef POINT_H
#define POINT_H
extern const void * Point; /* new(Point, x, y); */
void move(void * point, int dx, int dy);
struct Point {
const void * base; //继承Base类,基类指针,放在第1个位置,const是避免修改
int x, y;
//坐标
};
#define point_x(p)(((const struct Point *)(p)) -> x)
#define point_y(p)(((const struct Point *)(p)) -> y)
#endif
//Point的源文件Point.c
#include <stdio.h>
#include "Point.h"
#include "cnew.h"
#include "Base.h"
/**********Point类自己的构造函数***********/
static void * Point_New(void * _self, va_list * app) {
struct Point * self = _self;
self->x = va_arg(*app, int);
self->y = va_arg(*app, int);
printf("Point_New self = %p
", self);
return self;
}
/**********Point类自己的析构函数***********/
static void* Point_Delete(void * _self) {
printf("call Point_Delete self =%p
", _self);
printf("@@@@@@@@@@@@@@@@@@@@@@@@@@@@
");
return NULL;
}
/**********Point类自己的绘图函数***********/
static void Point_Draw(const void * _self) {
const struct Point * self = _self;
printf("Point_Draw at %d,%d
", self->x, self->y);
}
void move(void * _self, int dx, int dy) {
struct Point * self = _self;
printf("call move self =%p
", _self);
self->x += dx;
self->y += dy;
}
static const struct Base _Point = { sizeof(struct Point), Point_New, Point_Delete, Point_Draw };
const void * Point = &_Point;
4、继承
在C语言中,可以利用“结构在内存中的布局与结构的声明具有1致的顺序”这1事实实现继承。
比如我们要设计1个作图工具,其中可能触及到的对象有Point(点),Circle(圆),由于圆是由点组成的,所有可以看成Circle继承自Point。另外,Point和Circle都需要空间申请,空间释放等操作,所有他们有共同的基类Base。
#ifndef C_NEW_H
#define C_NEW_H
/**
* 内存管理类头文件cnew.h(对外提供接口)
*/
void * cnew(const void * base, ...);
void cdelete(void * item);
void draw(const void * self);
#endif /* C_NEW_H */
/**
* 内存管理类的源文件:cnew.c
*/
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <stdarg.h>
#include "cnew.h"
#include "Base.h"
void * cnew(const void * _class, ...) {
const struct Base * base = _class;
void * p = calloc(1, base->size);
assert(p);
*(const struct Base **) p = base;
if (base->constructor) {
va_list ap;
va_start(ap, _class);
p = base->constructor(p, &ap);
va_end(ap);
}
return p;
}
void cdelete(void * self) {
const struct Base ** cp = self;
if (self && *cp && (*cp)->destroy)
self = (*cp)->destroy(self);
free(self);
}
void draw(const void * self) {
const struct Base * const * cp = self;
assert(self && *cp && (*cp)->draw);
(*cp)->draw(self);
}
/**
* 基类Base的内部头文件Base.r,对外隐藏
*/
#ifndef BASE_R
#define BASE_R
#include <stdarg.h>
struct Base {
size_t size;
void * (*constructor)(void * self, va_list * app); //构造函数
void * (*destroy)(void * self);
//析构函数
void (*draw)(const void * self);//作图函数
};
#endif
/**
* Point的头文件Point.h(对外提供接口)
*/
#ifndef POINT_H
#define POINT_H
extern const void * Point; /* new(Point, x, y); */
void move(void * point, int dx, int dy);
struct Point {
const void * base; //继承Base类,基类指针,放在第1个位置,const是避免修改
int x, y;
//坐标
};
#define point_x(p)(((const struct Point *)(p)) -> x)
#define point_y(p)(((const struct Point *)(p)) -> y)
#endif
//Point的源文件Point.c
#include <stdio.h>
#include "Point.h"
#include "cnew.h"
#include "Base.h"
/**********Point类自己的构造函数***********/
static void * Point_New(void * _self, va_list * app) {
struct Point * self = _self;
self->x = va_arg(*app, int);
self->y = va_arg(*app, int);
printf("Point_New self = %p
", self);
return self;
}
/**********Point类自己的析构函数***********/
static void* Point_Delete(void * _self) {
printf("call Point_Delete self =%p
", _self);
printf("@@@@@@@@@@@@@@@@@@@@@@@@@@@@
");
return NULL;
}
/**********Point类自己的绘图函数***********/
static void Point_Draw(const void * _self) {
const struct Point * self = _self;
printf("Point_Draw at %d,%d
", self->x, self->y);
}
void move(void * _self, int dx, int dy) {
struct Point * self = _self;
printf("call move self =%p
", _self);
self->x += dx;
self->y += dy;
}
static const struct Base _Point = { sizeof(struct Point), Point_New, Point_Delete, Point_Draw };
const void * Point = &_Point;
/**
* Circle的头文件Circle.h(对外提供接口)
*/
#ifndef CIRCLE_H
#define CIRCLE_H
#include "Point.h"
extern const void * Circle; /* new(Circle, x, y, rad) */
struct Circle {
const struct Point pbase; //继承Point类,需放在第1位
int radius;
int (*area)(void *self);// 面积,扩大方法
};
#define circle_area(p) (((const struct Circle *)(p)) -> area(p))
#endif
/**
* Circle的源文件Circle.c
*/
#include <stdio.h>
#include "Circle.h"
#include "cnew.h"
#include "Base.h"
/**********Circle类自己的扩大函数***********/
static int Circle_Area(void * _self) {
const struct Circle * self = _self;
printf("call Circle_Area self =%p
", _self);
return self->radius * self->radius;
}
/**********Circle类自己的构造函数***********/
static void * Circle_New(void * _self, va_list * app) {
struct Circle * self = ((const struct Base *) Point)->constructor(_self, app);
self->radius = va_arg(*app, int);
self->area = Circle_Area;
printf("call Circle_New self =%p
", _self);
return self;
}
/**********Circle类自己的构造函数***********/
static void* Circle_Delete(void * _self) {
printf("call Circle_Delete self =%p
", _self);
printf("@@@@@@@@@@@@@@@@@@@@@@@@@@@@
");
return NULL;
}
/**********Circle类自己的绘图函数***********/
static void Circle_Draw(const void * _self) {
const struct Circle * self = _self;
int x = point_x(self);
int y = point_y(self);
printf("Circle_Draw at %d,%d rad %d
", x, y, self->radius);
}
static const struct Base _Circle = { sizeof(struct Circle), Circle_New, Circle_Delete, Circle_Draw };
const void * Circle = &_Circle;
/**
* 测试函数
*/
#include "Circle.h"
#include "cnew.h"
int oo_main(int argc, char ** argv) {
void * p;
int i;
for (i = 0; i < 2; i++) {
if (i == 0) {
p = cnew(Circle, 1, 2, 3);
circle_area(p);
} else {
p = cnew(Point, 1, 2);
}
draw(p);
move(p, 10, 20);
draw(p);
cdelete(p);
}
return 0;
}
/***********************************
* 测试结果:
*
* Point_New self = 0x50a1d8
* call Circle_New self =0x50a1d8
* Circle_Draw at 1,2 rad 3
* call move self =0x50a1d8
* Circle_Draw at 11,22 rad 3
* call Circle_Delete self =0x50a1d8
*
* Point_New self = 0x5096a0
* Point_Draw at 1,2
* call move self =0x5096a0
* Point_Draw at 11,22
* call Point_Delete self =0x5096a0
*
************************************/
5、多态
可以是用C语言中的万能指针void* 实现多态,接上面的例子:
//测试main.c
int oo_main(int argc, char ** argv) {
void * p;
int i;
for (i = 0; i < 2; i++) {
if (i == 0) {
p = cnew(Circle, 1, 2, 3);
circle_area(p);
} else {
p = cnew(Point, 1, 2);
}
draw(p);
move(p, 10, 20);
draw(p);
cdelete(p);
}
return 0;
}
6、总结
C语言能够摹拟实现面向对象语言具有的特性,包括:多态,继承,封装等,现在很多开源软件都了用C语言实现了这几个特性,包括大型开源数据库系统postgreSQL,可移植的C语言面向对象框架GObject,无线2进制运行环境BREW。采取C语言实现多态,继承,封装,能够让软件有更好的可读性,可扩大性。
全部的测试代码:
http://download.csdn.net/detail/andyhuabing/8475335
上一篇 单臂路由与三层交换
下一篇 HTML常用标签之格式标签