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點了,該睡覺覺羅~~