模块化C代码与UML对象模型之间的映射(2)——抽象类与继承

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


 

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值