C语言实现多态的原理:函数指针

何为函数指针?答案:C Programming Language. 能够查阅下,从原理上来讲,就是一个内存地址。跳过去运行相应的代码段。
既然如此,在运行时决定跳到哪个地方去运行特定的代码就可以。

一个简单的版本号:

以音频解码器作为样例:AAC 解码器,Mpeg解码器。以及其它类型的解码器。

那手动的多态可能会这样实现:
  1. U32 audioHandle = AudioDecOpen(int type)
  2. {
  3. iftype == aac
  4. return aac_open();
  5. else if(type == mpeg)
  6. return mpeg_open();
  7. }
这种代码不利于扩展,没增加一个新的实例。就得修改AudioDecOpen这个函数。并且封装的不好。

第二种方法来写:

首先定义三种公有函数的函数指针。
  1. typedef int (*OpenFunc) (void *this);
  2. typedef int (*CloseFunc) (void *this);
  3. typedef int (*ControlFunc) (void *this, int command, void *param);

定义公共接口结构体 &
AudioDecoder 对象:
  1. struct module
  2. { OpenFunc Open; CloseFunc Close; ControlFunc Control;};
  3. struct AudioDecoder{
  4. struct module m;
  5. int audioType;
  6. void* private;
  7. };
提供一个表驱动来方便找到相应的入口:
  1. struct AudioPool{
  2. int audioType;
  3. struct module* audioModule;
  4. }pool[] = {
  5. {aac , aac_module},
  6. {mpeg , mpeg_module},
  7. };

  1. int AudioCreate(int type , Handle *handle)
  2. {
  3. AudioDecoder dec = alloc_audioDec();
  4. foreach(pool , k)
  5. {
  6. if(k->audioType == type)
  7. {
  8. dec->m = k->audioModule;
  9. }
  10. }
  11. *handle = (Handle)dec;
  12. }

这样,当外界去Create一个Audio的对象时,就已经初始化好相应的函数入口了。Open就非常easy了:

  1. int AudioOpen(struct AudioDecoder *dec)
  2. {
  3. return dec->m->Open(dec);
  4. }

当中AudioDecoder中的Private 则是在各自的Open中自己申请,自己释放,Close,Control 相似。

今后维护这个表驱动就可以(pool),新的对象的支持增加进来就可以了,非常方便维护。

更好的维护pool

如今的pool依旧拓展性不太好,毕竟每次增加新的对象都得修改pool这个表驱动。
这里提供一个更好的方法:
  1. struct AudioPool{
  2. int audioType;
  3. struct module* audioModule;
  4. }pool[MAX_POOL];

在提供一个Pool_Register(int type , struct module* module); 的功能:
  1. int Pool_Register(int type , struct module* module);
  2. {
  3. for_each(pool , k)
  4. {
  5. if(k->type == INVALID_AUDIO_TYPE)
  6. {
  7. k->type = type;
  8. k->audioModule = module;
  9. }
  10. }
  11. if(k == NULL)
  12. {
  13. return REACH_POOL_END;
  14. }
  15. return NO_ERROR;
  16. }

这样在每一个实例中调用 rigister 就能够非常优雅的解决问题。

附上两个解码器的对象的代码,Mpeg的解码器使用的是 libmad , aac的解码器使用的是 libfaad 库:
AAC代码片段:
  1. .
  2. .
  3. .
  4. static int Close(void *this)
  5. {
  6. AudioSoftDecoder *ad = (AudioSoftDecoder*)this;
  7. if(!ad || !ad->privateData)
  8. {
  9. syslog(LOG_ERR , "%s(%d):Bad Parameter !!!\n" , __FUNCTION__ , __LINE__ );
  10. return CT_ERROR_BAD_PARAMETER;
  11. }
  12. AacFaadPrivate *private = (AacFaadPrivate *)ad->privateData;
  13. private->exit = TRUE;
  14. if(private->decoderPid > 0)
  15. {
  16. pthread_join(private->decoderPid , NULL);
  17. }
  18. if(private->hDecoder)
  19. {
  20. NeAACDecClose(private->hDecoder);
  21. }
  22. free(private);
  23. ad->privateData = NULL;
  24. return CT_ERROR_NO_ERROR;
  25. }
  26. int AAC_Init()
  27. {
  28. return RegisterAudioSoftDec(AudioDecType_AAC ,&aacModule);
  29. }

MPEG代码片段:
  1. .
  2. .
  3. .
  4. int Close(void *this)
  5. {
  6. AudioSoftDecoder *ad = (AudioSoftDecoder*)this;
  7. if(!ad || !ad->privateData)
  8. {
  9. syslog(LOG_ERR , "%s(%d):Bad Parameter !!!\n" , __FUNCTION__ , __LINE__ );
  10. return CT_ERROR_BAD_PARAMETER;
  11. }
  12. mpegMadPrivate *private = (mpegMadPrivate *)ad->privateData;
  13. private->exit = TRUE;
  14. if(private->decoderPid > 0)
  15. {
  16. pthread_join(private->decoderPid , NULL);
  17. }
  18. mad_decoder_finish(&private->decoder);
  19. if(private->data.buffer)
  20. {
  21. free(private->data.buffer);
  22. }
  23. free(private);
  24. ad->privateData = NULL;
  25. return CT_ERROR_NO_ERROR;
  26. }
  27. int Control(void *this , U32 cmd ,void* param)
  28. {
  29. return CT_ERROR_NO_ERROR;
  30. }
  31. int MPEG_Init()
  32. {
  33. return RegisterAudioSoftDec(AudioDecType_MPEG ,&mpegModule);
  34. }

总结:

使用面向对象来设计自己的代码。维护上能够降低非常多工作量。

在C语言里面还实现了MVC模式等,这部分也是函数指针实现的。实际上仅仅是一个回调。

可是代码维护,模块划分上,非常清晰。

C 语言实现多态的原理:函数指针的更多相关文章

  1. C语言结构体中的函数指针

      这篇文章简单的叙述一下函数指针在结构体中的应用,为后面的一系列文章打下基础 本文地址:http://www.cnblogs.com/archimedes/p/function-pointer-in ...

  2. 【嵌入式开发】C语言 结构体相关 的 函数 指针 数组

    . 作者 : 万境绝尘 转载请注明出处 : http://www.hanshuliang.com/?post=30 . 结构体概述 : 结构体是 多个 变量的集合, 变量的类型可以不同; -- 可进行 ...

  3. 复习C语言系列二:动态调用函数指针数组

    a:用call_fun_ptr调用afun(),b:用call_fun_ptr调用bfun() a 请输入给您指定的函数输调用的参数 afun_par ------------------------ ...

  4. C语言复杂的函数指针声明

    复习C语言ING,发现复杂的函数指针声明看不懂,百度半天终于略知一二. 讲的比较详细的一篇blog: http://blog.csdn.net/megaboy/article/details/4827 ...

  5. Day8 函数指针做函数参数

    课堂笔记 课程回顾         多态 virtual关键字 纯虚函数 virtual func() = 0;         提前布局vptr指针 面向接口编程 延迟绑定 多态的析构函数的虚函数. ...

  6. C++ 类的多态三(多态的原理--虚函数指针--子类虚函数指针初始化)

    //多态的原理--虚函数指针--子类虚函数指针初始化 #include<iostream> using namespace std; /* 多态的实现原理(有自己猜想部分) 基础知识: 类 ...

  7. c++语言虚函数实现多态的原理(更新版)

    自上一个帖子之间跳过了一篇总结性的帖子,之后再发,今天主要研究了c++语言当中虚函数对多态的实现,感叹于c++设计者的精妙绝伦 c++中虚函数表的作用主要是实现了多态的机制.首先先解释一下多态的概念, ...

  8. 2014 0416 word清楚项目黑点 输入矩阵 普通继承和虚继承 函数指针实现多态 强弱类型语言

    1.word 如何清除项目黑点 选中文字区域,选择开始->样式->全部清除 2.公式编辑器输入矩阵 先输入方括号,接着选择格式->中间对齐,然后点下面红色框里的东西,组后输入数据   ...

  9. Atitit java方法引用(Method References) 与c#委托与脚本语言js的函数指针

    Atitit java方法引用(Method References) 与c#委托与脚本语言js的函数指针   1.1. java方法引用(Method References) 与c#委托与脚本语言js ...

随机推荐

  1. [转载+补充][PY3]——环境配置(2)——windows下安装pycharm并连接Linux的python环境

    原文地址:<你所会用到的Python学习环境和工具> 1. 下载安装Pycharm专业版 具体方法略.Pycharm5激活方法参考http://www.cnblogs.com/snsdzj ...

  2. CF520B——Two Buttons——————【广搜或找规律】

    J - Two Buttons Time Limit:2000MS     Memory Limit:262144KB     64bit IO Format:%I64d & %I64u Su ...

  3. 设置 mysql允许外网访问

    mysql的root账户,我在连接时通常用的是localhost或127.0.0.1,公司的测试服务器上的mysql也是localhost所以我想访问无法访问,测试暂停. 解决方法如下: 1,修改表, ...

  4. c#中的程序集

     程序集:一些相关类的包,比如三层中Model层都是一些数据库表的实体类.我们所用到的类都是位于各个程序集中,若需要调用某个类,就必须引用其所在的程序集. 访问级别:程序集中的类有四种访问级别,int ...

  5. 06.密封类 sealed

    sealed   修饰 密封类是不能被继承的. 密封类是可以去继承别的类. namespace _07.密封类 { class Program { static void Main(string[] ...

  6. linux创建日期文件名

    linux创建文件名添加当前系统日期时间的方法 使用`date +%y%m%d` Example: mkdir `date +%y%m%d` tar cfvz /tmp/bak.`date +%y%m ...

  7. hdu1385 最短路字典序

    http://blog.csdn.net/ice_crazy/article/details/7785111 http://blog.csdn.net/shuangde800/article/deta ...

  8. 在mysql语句中为什么要加反引号

    在MySQL语句中我们有时候经常会遇到反引号(``),刚开始的时候不知道什么意思,他是什么作用呢? Select * from `member` order by posts desc limit 0 ...

  9. 远程连接Redis服务器

    建立了一个redis服务器,那么其他主机应该怎么连接上呢? /** * * 修改redis.conf配置文件 * */ // 1. 注释掉bind绑定配置 // 2. 搜索并修改为 protected ...

  10. 一个对inner jion ...on 的sql多表联合查询的练习

    create database practiceSql; use practiceSql; -- create table student( `id` bigint not null auto_inc ...