首页 > 代码库 > C 语言实现多态的原理:函数指针
C 语言实现多态的原理:函数指针
C语言实现多态的原理:函数指针
何为函数指针?答案:C Programming Language. 可以查阅下,从原理上来讲,就是一个内存地址,跳过去执行对应的代码段。
既然如此,在运行时决定跳到哪个地方去执行特定的代码即可。
一个简单的版本:
以音频解码器作为例子:AAC 解码器,Mpeg解码器,以及其他类型的解码器。
那手动的多态可能会这样实现:
U32 audioHandle = AudioDecOpen(int type) { if(type == aac) return aac_open(); else if(type == mpeg) return mpeg_open(); }
这样的代码不利于扩展,没加入一个新的实例,就得改动AudioDecOpen这个函数。而且封装的不好。
另外一种方法来写:
首先定义三种公有函数的函数指针。
typedef int (*OpenFunc) (void *this); typedef int (*CloseFunc) (void *this); typedef int (*ControlFunc) (void *this, int command, void *param);
定义公共接口结构体 & AudioDecoder 对象:
struct module { OpenFunc Open; CloseFunc Close; ControlFunc Control;}; struct AudioDecoder{ struct module m; int audioType; void* private; };
提供一个表驱动来方便找到对应的入口:
struct AudioPool{ int audioType; struct module* audioModule; }pool[] = { {aac , aac_module}, {mpeg , mpeg_module}, };
int AudioCreate(int type , Handle *handle) { AudioDecoder dec = alloc_audioDec(); foreach(pool , k) { if(k->audioType == type) { dec->m = k->audioModule; } } *handle = (Handle)dec; }这样,当外界去Create一个Audio的对象时,就已经初始化好对应的函数入口了。Open就非常简单了:
int AudioOpen(struct AudioDecoder *dec) { return dec->m->Open(dec); }其中AudioDecoder中的Private 则是在各自的Open中自己申请,自己释放,Close,Control 类似。
今后维护这个表驱动即可(pool),新的对象的支持加入进来就行了,很方便维护。
更好的维护pool
现在的pool依然拓展性不太好,毕竟每次加入新的对象都得改动pool这个表驱动。
这里提供一个更好的方法:
struct AudioPool{ int audioType; struct module* audioModule; }pool[MAX_POOL];
在提供一个Pool_Register(int type , struct module* module); 的功能:
int Pool_Register(int type , struct module* module); { for_each(pool , k) { if(k->type == INVALID_AUDIO_TYPE) { k->type = type; k->audioModule = module; } } if(k == NULL) { return REACH_POOL_END; } return NO_ERROR; }
这样在每个实例中调用 rigister 就可以很优雅的解决这个问题。
附上两个解码器的对象的代码,Mpeg的解码器使用的是 libmad , aac的解码器使用的是 libfaad 库:
AAC代码片段:
. . . static int Close(void *this) { AudioSoftDecoder *ad = (AudioSoftDecoder*)this; if(!ad || !ad->privateData) { syslog(LOG_ERR , "%s(%d):Bad Parameter !!!\n" , __FUNCTION__ , __LINE__ ); return CT_ERROR_BAD_PARAMETER; } AacFaadPrivate *private = (AacFaadPrivate *)ad->privateData; private->exit = TRUE; if(private->decoderPid > 0) { pthread_join(private->decoderPid , NULL); } if(private->hDecoder) { NeAACDecClose(private->hDecoder); } free(private); ad->privateData = http://www.mamicode.com/NULL;>
MPEG代码片段:
. . . int Close(void *this) { AudioSoftDecoder *ad = (AudioSoftDecoder*)this; if(!ad || !ad->privateData) { syslog(LOG_ERR , "%s(%d):Bad Parameter !!!\n" , __FUNCTION__ , __LINE__ ); return CT_ERROR_BAD_PARAMETER; } mpegMadPrivate *private = (mpegMadPrivate *)ad->privateData; private->exit = TRUE; if(private->decoderPid > 0) { pthread_join(private->decoderPid , NULL); } mad_decoder_finish(&private->decoder); if(private->data.buffer) { free(private->data.buffer); } free(private); ad->privateData = http://www.mamicode.com/NULL;>
总结:
使用面向对象来设计自己的代码,维护上能够减少很多工作量。在C语言里面还实现了MVC模式等,这部分也是函数指针实现的,实际上只是一个回调。但是代码维护,模块划分上,非常清晰。
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。