void*封装struct结构体 | 隐藏结构体内部实现 | 句柄Handle的实现
本文章面向已有一定c语言基础的读者,如果您还不懂c语言中结构体以及指针类型的概念,请提前做好准备。
-
struct结构体
struct Point{
int x;
int y;
};
struct Rect{
int left;
int top;
int right;
int bottom;
};
这里定义了两个结构体,也是Windows.h代码中所写的。
-
结构体对应的处理函数
我们有一些函数用于接受这些类型的变量然后进行处理,这里以Add函数为例。
struct Point* PointAdd(struct Point* a, struct Point* b) {
struct Point* ret = malloc(sizeof(struct Point));
ret->x = a->x + b->x;
ret->y = a->y + b->y;
return ret;
}
struct Rect* RectAdd(struct Rect* a, struct Rect* b) {
struct Rect* ret = malloc(sizeof(struct Rect));
ret->left = a->left + b->left;
ret->top = a->top + b->top;
ret->right = a->right + b->right;
ret->bottom = a->bottom + b->bottom;
return ret;
}
在这里提供给用户函数接口同时,也像用户暴露了结构体的内部细节。
-
Handle句柄类型的定义
在很多场合中,我们不希望暴露过多的细节,以此达到代码分离的效果。因此,我们可以创建一个句柄类型用于结构的统一传参。
typedef struct HandleInstance {
int typeId; // 可为枚举类型
void* pointer;
} *Handle;
typeId存储定义的类型所对应的枚举类型,例如定义struct Point类型ID为1,struct Rect类型ID为2。而pointer则用于维护真正所需的结构体指针。
enum TypeId {
PointType = 1,
RectType,
OtherType
// ...
};
-
结构体细节的封装
那么之前的函数接口便可以封装为:
// 原版:
// struct Point* PointAdd(struct Point* a, struct Point* b);
// struct Rect* RectAdd(struct Rect* a, struct Rect* b);
// 封装后:
Handle PointAdd(Handle a, Handle b);
Handle RectAdd(Handle a, Handle b);
这样看起来,便无法知道结构体的具体细节了。
下面我们还需要增加几个有关Handle的注册和认证功能,以便函数能正确的使用Handle。
// Handle的注册
Handle RegisterHandle(enum TypeId type, void* pointer) {
Handle ret = malloc(sizeof(struct HandleInstance));
ret->typeId = type;
ret->pointer = pointer;
return ret;
}
// Handle的认证
bool CheckHandle(enum TypeId type, Handle handle) {
if(!handle) {
fprintf(stderr, "error 传入句柄为空\n");
return false;
}
if(handle->typeId != type) {
fprintf(stderr, "error 传入句柄类型错误\n");
return false;
}
if(!handle->pointer) {
fprintf(stderr, "error 句柄不应维护空指针\n");
return false;
}
return true;
}
这样一来,使用注册句柄函数RegisterHandle便可以创建句柄,使用认证函数CheckHandle便可以检查类型是否错误。
最终函数实现便可修改为:
Handle PointAdd(Handle a, Handle b) {
if(!CheckHandle(PointType, a)) {
// 异常处理
}
if(!CheckHandle(PointType, b)) {
// 异常处理
}
struct Point* pa = a->pointer;
struct Point* pb = b->pointer;
struct Point* ret = malloc(sizeof(struct Point));
ret->x = pa->x + pb->x;
ret->y = pa->y + pb->y;
return RegisterHandle(PointType, ret);
}
Handle RectAdd(Handle a, Handle b) {
if(!CheckHandle(RectType, a)) {
// 异常处理
}
if(!CheckHandle(RectType, b)) {
// 异常处理
}
struct Rect* pa = a->pointer;
struct Rect* pb = b->pointer;
struct Rect* ret = malloc(sizeof(struct Rect));
ret->left = pa->left + pb->left;
ret->top = pa->top + pb->top;
ret->right = pa->right + pb->right;
ret->bottom = pa->bottom + pb->bottom;
return RegisterHandle(RectType, ret);
}