| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
欢迎加入我们,一同切磋技术
用户名:   
 
密 码:  
共有 1037 人关注过本帖
标题:C接口的另一种设计方法
取消只看楼主 加入收藏
voldemort
Rank: 1
等 级:新手上路
帖 子:40
专家分:0
注 册:2006-3-1
收藏
 问题点数:0 回复次数:9 
C接口的另一种设计方法

现在如果要写一个C的函数库~先写一个头文件,里面定义好一些#define和一些基本的函数,这就是个简单的接口。然后再去根据接口定义的函数去具体的实现。
但是我觉得我们可以从另外一种方式用指针去实现这个接口的功能。

比如,我现在就定义了一个元素的接口 Element.h,当然,在此之前我们还有个小小的常量定义 const.h

/*const.h*/
/*类*/
#ifndef Class
#define Class struct
#endif


/*状态*/
#ifndef Status
#define Status int
#endif
#define STATUS_OK 1
#define STATUS_ERROR 0
#define STATUS_SUCCESS 1
#define STATUS_FAIL 0
#define STATUS_INFEASIBLE -1
#define STATUS_OVERFLOW -2


/*布郎值*/
#ifndef Boolean
#define Boolean int
#endif
#define BOOLEAN_TRUE 1
#define BOOLEAN_FALSE 0


/*空指针或者空类*/
#ifndef NULL
#define NULL 0
#endif


/*不存在*/
#ifndef NOTEXIST
#define NOTEXIST -1
#endif

/*大于*/
#define COMPARE_LARGE 1
/*等于*/
#define COMPARE_EQUAL 0
/*小于*/
#define COMPARE_SMALL -1

搜索更多相关主题的帖子: 接口 设计 
2006-03-02 14:18
voldemort
Rank: 1
等 级:新手上路
帖 子:40
专家分:0
注 册:2006-3-1
收藏
得分:0 

定义Element接口并且实现
/*element.c*/
/*元素值的类型,现在这个元素类的值的类型为int*/
#define ELEMENT_VALUE_TYPE int

/**元素类的定义*/
Class Element{
Class Element *prior;/*前驱节点,链表的时候才用*/
Class Element *next;/*后继节点,链表的时候才用*/
Class Element *this;/*类的实例本身,觉得好象一直很多余,但是还是留着吧*/
ELEMENT_VALUE_TYPE *value;/*元素的值,比较方法、取值、赋值方法和值的类型相关*/
ELEMENT_VALUE_TYPE (*getValue)(Class Element *this);/*获取元素的值*/
Status (*compare)(Class Element *this,Class Element *other);/*元素之间的比较*/
void (*setValue)(Class Element *this,ELEMENT_VALUE_TYPE value);/*元素的赋值方法*/
void (*toString)(Class Element *this,char *string);/*把元素的值转换成为字符串形式*/
void (*destroy)(Class Element *this);/*销毁这个元素*/
};

/*取值方法*/
int Element_GetValue(Class Element *this){
return *(this->value);
}

/*赋值方法*/
void Element_SetValue(Class Element *this,ELEMENT_VALUE_TYPE value){
ELEMENT_VALUE_TYPE *value_p = (int*)malloc(sizeof(ELEMENT_VALUE_TYPE));
*(value_p)=value;
this->value = value_p;
}

/*比较方法,返回值是比较状态Status*/
Status Element_Compare(Class Element *this,Class Element *other){
ELEMENT_VALUE_TYPE this_value,other_value;
this_value = this->getValue(this);
other_value = other->getValue(other);
if(this_value>other_value){
return COMPARE_LARGE;
}else if(this_value<other_value){
return COMPARE_SMALL;
}else{
return COMPARE_EQUAL;
}
}


void Element_ToString(Class Element *this,char *string){
ELEMENT_VALUE_TYPE value = *(this->value);
itoa(value,string,10);/*这里随着ELEMENT_VALUE_TYPE的类型改变而改变*/
}

void Element_Destroy(Class Element *this){
free(this->value);
free(this->this);
}

/*元素类的实例化*/
Class Element *Element_new(ELEMENT_VALUE_TYPE value){
Class Element *element=(Class Element*)malloc(sizeof(Class Element));
element->this = element;
element->getValue = Element_GetValue;
element->setValue = Element_SetValue;
element->compare = Element_Compare;
element->setValue(element,value);
element->destroy = Element_Destroy;
element->toString = Element_ToString;
return element;
}


黑魔法
2006-03-02 14:19
voldemort
Rank: 1
等 级:新手上路
帖 子:40
专家分:0
注 册:2006-3-1
收藏
得分:0 

怎么用这个元素类呢?
这里做个演示,当然这个不是我们要讨论的重点

#include "const.h"
#include "element.c"

int main(void){
Class Element *e = Element_new(100); /*实例化一个Element*/
char string[80];
e->toString(e,string);/*把该元素的值转换成为字符串格式作为统一输出格式*/
e->destroy(e);/*东西用了就要放回,这个习惯一定要有哦*/
printf("%s",string);/*输出这个元素的值*/
getch();
return 0;
}

[此贴子已经被作者于2006-3-2 14:25:55编辑过]


黑魔法
2006-03-02 14:23
voldemort
Rank: 1
等 级:新手上路
帖 子:40
专家分:0
注 册:2006-3-1
收藏
得分:0 

恩~我现在想做的是一个数据结构中的最简单的类型----表----的演示程序
我们知道,表可以是用堆来实现,也可以是用链表来实现。我想一个纯虚的类来定义这个接口

/*List.h*/
#include "Element.c"

/*定义线性表的接口*/
Class List{
Class List *this;/*这个东西...还是不忍心去掉*/
Class Element *elements;/*元素存放的首地址*/
int length;/*表中元素的个数*/
int size;/*表的当前大小*/
int increment;/*自增量的大小*/
int init_size;/*初始表的大小*/
int (*locateElement)(Class List *this,Class Element *element);/*返回表中第一个与element元素相等的元素的索引*/
Status (*destroy)(Class List *this);/*销毁表,返回状态值*/
Status (*clear)(Class List *this);/*销毁表内的所有元素,返回状态值*/
Boolean (*isEmpty)(Class List *this);/*判断是否为空表,返回布郎值*/
Class Element *(*getElement)(Class List *this,int index);/*获取第index个元素,返回元素指针*/
Class Element *(*priorElement)(Class List *this,Class Element *element);/*返回element的前驱元素,返回元素指针*/
Class Element *(*nextElement)(Class List *this,Class Element *element);/*返回element的后继元素,返回元素指针*/
Status (*insert)(Class List *this,int index,Class Element *element);/*在index处插入element,返回状态值*/
Status (*delete)(Class List *this,int index);/*删除index处的元素,返回状态值*/
};


黑魔法
2006-03-02 14:33
voldemort
Rank: 1
等 级:新手上路
帖 子:40
专家分:0
注 册:2006-3-1
收藏
得分:0 

在发这个帖子之前,我已经实现了用堆做的表ArrayList,下面要贴出的这个就是

/*ArrayList.c*/

/*销毁表*/
Status ArrayList_destroy(Class List *this){
this->clear(this);/*先销毁表内的所有元素*/
free(this->this);/*再销毁这个表*/
this=NULL;
return STATUS_SUCCESS;/*删除成功*/
}


/*清除表中的数据*/
Status ArrayList_clear(Class List *this){
int index;
Class Element *element;
if(this->isEmpty(this)==BOOLEAN_TRUE){/*如果为空表。则直接返回*/
return STATUS_SUCCESS;/*清除成功*/
}else{/*如果不是一个空表,则清空所有数据、初始化表后返回*/
for(index=0;index<this->length;index++){/*销毁所有元素中的数据*/
element = this->getElement(this,index);
element->destroy(element);
}
free(this->elements);/*销毁所有元素*/
/*PS:元素中的数据和元素不是一回事,元素中的数据也就是Element_Value_Type *value*/
/*初始化表*/
this->length=0;
this->size=this->init_size;
this->elements=(Class Element*)malloc(sizeof(Class Element)*this->init_size);
return STATUS_SUCCESS;/*清除成功*/
}
}

/*判断队列表是否为空*/
/*空表返回BOOLEAN_TRUE,非空表返回BOOLEAN_FALSE*/
Status ArrayList_isEmpty(Class List *this){
if(this->length==0){
return BOOLEAN_TRUE;/*空表*/
}else{
return BOOLEAN_FALSE;/*非空表*/
}
}

/*获取队列表中的第index个元素*/
/*成功则返回该位置*/
/*不成功则返回NULL*/
Class Element *ArrayList_getElement(Class List *this,int index){
if(index<0 || index>this->length){/*检查index的值是否在范围之内*/
/*PS.其实我一直挺郁闷,到底一个函数应该是专心实现它的功能而把检查参数交给调用它的函数好呢*/
/*还是应该两者都实现的好...,这里我是让函数实现了检查参数的功能*/
return NULL;/*参数非法,返回空指针*/
}else{
return this->elements+index;/*参数合法,返回元素指针*/
}
}


/*返回该元素在队列表中第一次出现的位置*/
/*成功则返回该位置*/
/*不成功则返回NULL*/
int ArrayList_locateElement(Class List *this,Class Element *element){
int index;
Class Element *element_x;
for(index=0;index<this->length;index++){/*遍历整张表,从中找出与参数给出的元素的值相等的元素*/
element_x = this->getElement(this,index);
if(element_x->compare(element_x,element)==COMPARE_EQUAL){/*这里为了屏蔽元素类的实现,用了元素自身的判断方法*/
return index;/*如果找到则返回位置*/
}
}
return NOTEXIST;/*找不到...返回不存在*/
}

/*返回给定元素的前驱元素*/
/*成功则返回该元素*/
/*如果给定元素不存在返回NULL*/
/*如果给定元素为顶元素返回NULL*/
Class Element *ArrayList_priorElement(Class List *this,Class Element *element){
int index;
if((index=this->locateElement(this,element))==NOTEXIST){
return NULL;
}
if(index==0){
return NULL;
}
return this->getElement(this,index-1);
}

/*返回指定元素的后继元素*/
/*成功则返回该元素*/
/*如果给定元素不存在返回NULL*/
/*如果给定元素为尾元素返回NULL*/
Class Element *ArrayList_nextElement(Class List *this,Class Element *element){
int index;
if((index=this->locateElement(this,element))==NOTEXIST){
return NULL;
}
if(index==this->length-1){
return NULL;
}
return this->getElement(this,index+1);
}

/*在index插入一个元素*/
/*如果index无效则返回STATUS_FAIL*/
Status ArrayList_insert(Class List *this,
int index,Class Element *element){
int i;
if(this->isEmpty(this)==BOOLEAN_FALSE){/*如果不是空表*/
if(index>this->length){/*检查参数index*/
return STATUS_FAIL;/*index不合法*/
}
for(i=this->length-1;i>=index;i--){/*从第index元素开始到最后一个元素为止,所有元素向后移动一格*/
this->elements[i+1]=this->elements[i];
}
}
this->elements[index]=*element;/*元素赋值*/
this->length++;/*表中元素个数++*/
if(this->length==this->size){/*如果表的空间不够,因为是堆嘛~所以总会有个长度。*/
/*如果length超过了size,那么我们就认为这表溢出,为了避免这种情况发生*/
/*令length==size的时候就重新改变这表的大小,让表的长度在原来基础上增加一个自增量的长度*/
this->elements=(Class Element*)realloc
(this->elements,(this->size+this->increment)*sizeof(Class Element));
this->size+=this->increment;/*表的当前大小也因此改变*/
}
return STATUS_SUCCESS;/*插入操作成功*/
}

/*删除index指定的元素*/
/*如果index无效则返回STATUS_FAIL*/
Status ArrayList_delete(Class List *this,int index){
int i;
Class Element *element;
if(this->isEmpty(this)==BOOLEAN_TRUE){
return STATUS_FAIL;
}else if(index>this->length-1){
return STATUS_FAIL;
}else{
element = this->getElement(this,index);
element->destroy(element);
for(i=index;i<this->length;i++){
this->elements[i]=this->elements[i+1];
}
this->length--;
return STATUS_SUCCESS;
}

}

/*....这个是表的实例化...*/
Class List *ArrayList_new(int init_size,int increment){
Class List *list=(Class List*)malloc(sizeof(Class List));
list->this=list;
list->length=0;
list->size=init_size;
list->init_size=init_size;
list->increment=increment;
list->destroy=ArrayList_destroy;
list->clear=ArrayList_clear;
list->isEmpty=ArrayList_isEmpty;
list->getElement=ArrayList_getElement;
list->locateElement=ArrayList_locateElement;
list->priorElement=ArrayList_priorElement;
list->nextElement=ArrayList_nextElement;
list->insert=ArrayList_insert;
list->delete=ArrayList_delete;
list->elements=(Class Element*)malloc(sizeof(Class Element)*init_size);
return list;
}


黑魔法
2006-03-02 15:01
voldemort
Rank: 1
等 级:新手上路
帖 子:40
专家分:0
注 册:2006-3-1
收藏
得分:0 

下面我们来实际用一下这个实现了List接口的ArrayList类
首先我们用一个函数来“生产”ArrayList类,为什么这么做呢?这是因为程序以后要再实现一个ChainList类。ChainList类是用链表实现List接口的,而ArrayList是用堆来实现。

生产List的ListFactory函数

/*ListFac.c*/
#include "List.h"
#include "ArrList.c"

#define LISTTYPE int
#define LISTTYPE_ARRAY 0
#define LISTTYPE_CHAIN 1

Class List *ListFactory(int init_size,
int increment,LISTTYPE listType){
if(listType==LISTTYPE_ARRAY){/*生产一个ArrayList*/
return ArrayList_new(init_size,increment);
}else if(listType==LISTTYPE_CHAIN){
return NULL;
}else{
return NULL;
}
}

[此贴子已经被作者于2006-3-2 15:08:44编辑过]


黑魔法
2006-03-02 15:08
voldemort
Rank: 1
等 级:新手上路
帖 子:40
专家分:0
注 册:2006-3-1
收藏
得分:0 

接下来是主程序

#include "const.h"
#include "ListFac.c"


/*******全局变量*******/
Class List *list = NULL;
/**********************/

/*******功能区域*******/

/*欢迎界面*/
void welcome(){
printf("\n欢迎使用List演示程序!\n");
printf("作者:voldemort\n");
printf("输入help可以得到帮助\n\n");
}

/*销毁一个list*/
void destroy(){
if(list==NULL){
printf("错误!不能销毁一个空表!\n\n");
}else{
list->destroy(list);
list=NULL;
printf("销毁表成功。\n\n");
}
}

/*程序退出*/
void quit(){
if(list!=NULL){
destroy();
}
printf("\n再见!\n");
}

/*清屏*/
void cls(){
int i=25;
while(printf("\n"),i--);
}

/*创建一个List*/
void create(){
int init_size,increment,listType;
if(list!=NULL){
printf("错误!只能创建一个表。\n\n");
}else{
printf("<创建表>\n");
while(1){
printf("输入表的初始大小: ");scanf("%d",&init_size);
if(init_size<=0){
printf("错误!初始大小必须是一个大于0的整数!\n");
}else{
break;
}
}
while(1){
printf("输入自增量:");scanf("%d",&increment);
if(increment<=0){
printf("错误!自增量必须是一个大于0的整数!\n");
}else{
break;
}
}
while(1){
printf("输入表的类型(0-数组表/1-链式表):");
scanf("%d",&listType);
if(listType!=0 && listType!=1){
printf("错误!表的类型只能是0或者1!\n");
}else{
break;
}
}
list = ListFactory(init_size,increment,listType);
if(list==NULL){
printf("错误!创建表失败!\n");
}else{
printf("创建表成功。\n\n");
}
}
}

/*插入一个数据*/
void insert(){
int index;
int value;
Status status;
Class Element *element = NULL;
if(list==NULL){
printf("错误!不能插入一个元素到一个空表中!\n\n");
}else{
printf("<插入元素>\n");
while(1){
printf("输入插入的位置(0~%d):",list->length);scanf("%d",&index);
if(index<0){
printf("错误!插入的位置必须是一个不小于0的整数!\n");
}else if(index>list->length){
printf("错误!插入的位置不能大于 %d\n",list->length);
}else{
break;
}
}
printf("输入元素的值:");scanf("%d",&value);
element = Element_new(value);
if(element==NULL){
printf("错误!创建元素失败!插入操作失败!\n");
}else{
status = list->insert(list,index,element);
if(status==STATUS_FAIL){
printf("错误!插入操作失败!\n");
}else{
printf("插入操作成功!\n\n");
}
}
}
}

/*描述list表*/
void describe(){
if(list==NULL){
printf("错误!不能描述一个空表\n\n");
}else{
printf("<描述表>\n");
printf("+-----------------+----------------+\n");
printf("| 内存地址 | %-15p|\n",list);
printf("+-----------------+----------------+\n");
printf("| 元素存储地址 | %-15p|\n",list->elements);
printf("+-----------------+----------------+\n");
printf("| 元素个数 | %-15d|\n",list->length);
printf("+-----------------+----------------+\n");
printf("| 当前大小 | %-15d|\n",list->size);
printf("+-----------------+----------------+\n");
printf("| 自增量大小 | %-15d|\n",list->increment);
printf("+-----------------+----------------+\n\n");
}
}


/*清除表中所有元素*/
void clear(){
if(list==NULL){
printf("错误!不能清除一个空表的内容!\n\n");
}else{
list->clear(list);
printf("清除成功!\n\n");
}
}


/*删除元素*/
void delete(){
int index;
Status status;
if(list==NULL){
printf("错误!不能从一个空表中删除元素!\n\n");
}else if(list->isEmpty(list)){
printf("错误!元素集合为空!\n\n");
}else{
while(1){
printf("输入要删除元素的位置(0~%d):",list->length-1);scanf("%d",&index);
if(index<0){
printf("错误!被删除元素的位置必须是不小于0的整数!\n");
}else if(index>=list->length){
printf("错误!被删除元素的位置不能大于%d\n",list->length-1);
}else{
break;
}
}
status = list->delete(list,index);
if(status==STATUS_FAIL){
printf("错误!删除失败!\n\n");
}else{
printf("删除成功!\n\n");
}
}
}


/*列出所有元素*/
void show(){
int index;
Class Element *element=NULL;
char string[80];
if(list==NULL){
printf("错误!不能从一个空表中列出元素!\n\n");
}else if(list->isEmpty(list)){
printf("该表中无元素。\n\n");
}else{
printf("<列出表中所有元素>\n");
printf("+----------+----------+----------+----------+\n");
printf("| 元素地址 | 元素序列 | 值地址 | 元素值 |\n");
printf("+----------+----------+----------+----------+\n");
for(index=0;index<list->length;index++){
element = list->getElement(list,index);
element->toString(element,string);
printf("| %-8p | %-8d | %-8p | %-8s |\n",element,index,element->value,string);
printf("+----------+----------+----------+----------+\n");
}
printf("<统计>\n");
printf("元素个数:%d\n\n",list->length);
}
}


/*帮助*/
void help(){
printf("<帮助命令>\n");
printf("+----------+--------------------+\n");
printf("| 命令 | 说明 |\n");
printf("+----------+--------------------+\n");
printf("| help | 帮助 |\n");
printf("| cls | 清屏 |\n");
printf("| destroy | 销毁表 |\n");
printf("| create | 创建表 |\n");
printf("| delete | 删除元素 |\n");
printf("| quit | 退出程序 |\n");
printf("| welcome | 欢迎界面 |\n");
printf("| describe | 描述一个表 |\n");
printf("| insert | 插入一个元素 |\n");
printf("| show | 列出所有元素 |\n");
printf("| clear | 清除表中所有元素 |\n");
printf("+----------+--------------------+\n");
printf("\n\n");
}
/**********************/

int main(void){
char command[80];
welcome();
while(1){
printf("CMD#> ");scanf("%s",command);
if(!strcmp(command,"cls")){
cls();
}else if(!strcmp(command,"quit")||!strcmp(command,"exit")){
quit();
return 0;
}else if(!strcmp(command,"welcome")){
welcome();
}else if(!strcmp(command,"create")){
create();
}else if(!strcmp(command,"destroy")){
destroy();
}else if(!strcmp(command,"insert")){
insert();
}else if(!strcmp(command,"describe")){
describe();
}else if(!strcmp(command,"clear")){
clear();
}else if(!strcmp(command,"delete")){
delete();
}else if(!strcmp(command,"show")){
show();
}else if(!strcmp(command,"help")){
help();
}else{
printf("错误命令\n\n");
}
}
return 0;
}


黑魔法
2006-03-02 15:10
voldemort
Rank: 1
等 级:新手上路
帖 子:40
专家分:0
注 册:2006-3-1
收藏
得分:0 
这个是源程序代码和编译好了的程序,推荐使用C-Free来编译,因为这样可以在程序中使用中文。
[attach]5417[/attach]

黑魔法
2006-03-02 15:13
voldemort
Rank: 1
等 级:新手上路
帖 子:40
专家分:0
注 册:2006-3-1
收藏
得分:0 
现在的问题是,谁来用链表实现一下List接口??

黑魔法
2006-03-02 15:32
voldemort
Rank: 1
等 级:新手上路
帖 子:40
专家分:0
注 册:2006-3-1
收藏
得分:0 

顶起,没人尝试一下吗?


黑魔法
2006-03-02 20:46
快速回复:C接口的另一种设计方法
数据加载中...
 
   



关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.032691 second(s), 8 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved