今天继续写模块化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点了,该睡觉觉罗~~