今天继续写模块化C代码与UML类图的转换,所举例子也许粗糙,主要是演示一下思路,时间允许的话我会尽量按正式的产品开发质量要求来完善代码示例。
1.4 抽象类与继承
抽象类是指继承关系树中位于树枝节点的用于被继承的类,如图1.5所示。抽象类具有以下特点:
(1)不能被实例化,所以没有Create或GetInstance方法;
(2)抽象类中方法可以没有实现体,称为抽象方法,它必须被子类重写。
(3)如果类中包含抽象方法,则必须定义为抽象类。
顺便说一下,图中void *privateData是类的私有字段,可以利用这个字段扩展功能或简单忽略之。后面有机会再举例说明。
另外,I_DEV是类DEV实现的一组操作集合,公开给用户,这就是接口,下一节再详细举例说明。
UML示例:
图1.5 抽象类
C代码示例:
///
//inheritance_utils.h
#undef CONTAINING_RECORD
#define CONTAINING_RECORD(address, type, field) \
((type *)( (char *)(address) - (unsigned long)(&((type*)0)->field)))
///
//DEV.h
/* 定义设备操作接口*/
struct I_DEV{
int (*Add)(struct DEV *, int somePara);
int (*Delete)(struct DEV *, int somePara);
int (*Query)(struct DEV *, int somePara);
int (*Reset)(struct DEV *, int somePara);
};
/* 定义设备类*/
struct DEV{
void (*Destroy)(struct DEV *);
void (*Method1)(struct DEV *);
void (*Method2)(struct DEV *);
const struct I_DEV *itf; /* 接口*/
void *privateData;
};
//抽象类不能实例化,没有Create
void DEV_Init(struct DEV *DEV, const struct I_DEV *itf); //注意init方法职责是初始化而非实例化
void DEV_Destroy(struct DEV *self);
void DEV_Method1(struct DEV *self);//Method1是具体方法,DEV.c中实现Method1
//Method2是抽象方法,DEV.c中没有Method2实现体
///
//DEV.c
#include "DEV.h"
void DEV_Init(struct DEV *DEV, const struct I_DEV *itf)
{
assert(DEV != NULL);
memset(DEV, 0, sizeof *DEV);
DEV->itf = itf;
DEV->Method1 = DEV_Method1;
}
void DEV_Destroy(struct DEV *self)
{
if (self != NULL)
{
free(self);
}
}
void DEV_Method1(struct DEV *self)
{
printf("hello, I'm concrete method!\r\n");
}
///
//WASHER_DEV.h
struct WASHER; /* 隐藏具体类的细节*/
struct WASHER *WASHER_Create(int type, int id, char *name);
//…
///
//WASHER.c
#include "DEV.h"
#include “WASHER_DEV.h”
/* 定义WASHER设备类*/
struct WASHER
{
int type;
int id;
char *name;
struct DEV DEV; //继承DEV类
void *moreData;
};
/* 实现I_DEV接口*/
static int WASHER_Add(struct DEV *DEV, int somePara)
{
struct WASHER *WASHER;
WASHER = CONTAINING_RECORD(DEV, struct WASHER, DEV);
DEV->privateData = WASHER;
printf("[WASHER_Add]type = %d, id = %d, name = %s\r\n", WASHER->type, WASHER->id, WASHER->name);
return 0;
}
static int WASHER_Query(struct DEV *DEV, int somePara)
{
struct WASHER *WASHER = (struct WASHER *)DEV->privateData;
printf("[WASHER_Query]type = %d, id = %d, name = %s\r\n", WASHER->type, WASHER->id, WASHER->name);
return 0;
}
struct I_DEV WASHERItf = {
WASHER_Add,
NULL,
WASHER_Query,
NULL,
};
/* 派生类实现基类的抽象方法*/
static void WASHER_DEV_Method2(struct DEV *self)
{
printf("hello, I'm abstract method, implemented by WASHER.\r\n");
}
static void WASHER_setup_DEV(struct WASHER *WASHER)
{
DEV_Init(&WASHER->DEV, &WASHERItf);
WASHER->DEV.Method2 = WASHER_DEV_Method2;
}
static void WASHER_init(struct WASHER *self, int type, int id, char *name)
{
memset(self, 0, sizeof(struct WASHER));
self->type = type;
self->id;
self->name = name;
WASHER_setup_DEV(self);
}
struct WASHER *WASHER_Create(int type, int id, char *name)
{
struct WASHER *WASHER = (struct WASHER *)malloc(sizeof(struct WASHER));
WASHER_init(WASHER, type, id, name);
return WASHER;
}
///
//test_WASHER_DEV.c
#include "WASHER_DEV.h"
TEST(test_DEV_inheritance, test_demo)
{
int type = 3;
int id = 1;
char *name = "WASHER";
struct WASHER * WASHER = WASHER_Create(type, id, name);
// Usually register WASHER first. Here’s just a demo…
//针对接口/抽象编程
struct DEV *DEV = &(WASHER->DEV);
EXPECT_EQ(0, DEV->itf->Add(DEV, 0xff));
EXPECT_EQ(0, DEV->itf->Query(DEV, 0xff));
DEV->Method1(DEV);
DEV->Method2(DEV);
}
//e.g. user: bd = add(type, id, "DEVname"); query(bd, para);
又到11点了,该睡觉觉罗~~