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 = NULL;
	return CT_ERROR_NO_ERROR;
}

int AAC_Init()
{
	return RegisterAudioSoftDec(AudioDecType_AAC ,&aacModule);
}

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 = NULL;
	return CT_ERROR_NO_ERROR;
}

int Control(void *this , U32 cmd ,void* param)
{
	return CT_ERROR_NO_ERROR;
}

int MPEG_Init()
{
	return RegisterAudioSoftDec(AudioDecType_MPEG ,&mpegModule);
}

总结:

使用面向对象来设计自己的代码,维护上能够减少很多工作量。在C语言里面还实现了MVC模式等,这部分也是函数指针实现的,实际上只是一个回调。但是代码维护,模块划分上,非常清晰。

C 语言实现多态的原理:函数指针,布布扣,bubuko.com

时间: 2024-08-25 01:58:54

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

【示例】C语言中利用数组存放函数指针

C语言中利用数组存放函数指针,增加函数使用的灵活性.使用时只需提供数组索引,即可调用不同函数. 预备知识: 1.指向函数的指针 一个函数在编译时被分配一个入口地址,这个地址就被称为函数的指针. 例如: int max(int,int); // 声明函数,比较两数大小 int (*p)(); //声明指向函数的指针变量 p=max; //将函数max的入口地址赋给指针变量p int c=(*p)(a,b); //调用函数 2.函数指针作为函数参数 该例子中每次给process函数不同实参(函数名)

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

这篇文章简单的叙述一下函数指针在结构体中的应用,为后面的一系列文章打下基础 本文地址:http://www.cnblogs.com/archimedes/p/function-pointer-in-c-struct.html,转载请注明源地址. 引言 指针是C语言的重要组成部分, 于是深入理解指针并且高效地使用指针可以使程序员写出更加老练的程序.我们要记住指针是一个指向内存地址的变量.指针可以引用如int.char……常见的数据类型,例如: int * intptr; // 声明一个指向整型值的

C++基础8【难】 回顾:数组指针,函数指针,函数指针做函数参数 C语言多态

1,数组指针语法梳理 回顾,如何定义数组数据类型: 回顾,如何定义指针类型数组: 回顾,如何直接定义 一个指向数组类型的指针: 2,函数指针语法梳理 1)如何定义一个函数类型 2)如何定义一个函数指针类型 3)如何定义一个函数指针(指向一个函数的入口地址) [中级程序员 转 高级程序员的 必经之路] 1,函数类型做函数的参数 把函数的入口地址传过来,奇怪的效果:[多态就是这样] 函数指针 做 函数参数 思想剖析 1,数组指针语法梳理 回顾,如何定义数组数据类型: [email protected

Day8 函数指针做函数参数

课堂笔记 课程回顾 多态 virtual关键字 纯虚函数 virtual func() = 0; 提前布局vptr指针 面向接口编程 延迟绑定 多态的析构函数的虚函数. 多继承的二义性 . 重载 重写 重定义. 实现多态的理论基础:函数指针做函数参数. vptr指针与虚函数表. 构造函数不应为虚函数 多态会降低程序的执行速度.不建议所有的函数都是虚函数. 多态时的指针步进. 多继承在项目开发中使用的比较少. linux从2.4内核升级到2.6的时候,做到了电源可以热插拔,提前将电源驱动的接口规划

C++多态:从虚表指针到设计模式

多态是面向对象语言的一种高级特性.无论是底层的实现还是整体架构的设计,多态思想都有着很广泛的应用.学习多态不仅是要学习一种程序设计技术,更应该掌握的是其背后的设计思想.本文从底层讲起,一点一点剖析了多态的来龙去脉,希望能给大家呈现一个真实的多态. 从虚函数说起 虚函数是实现多态的语言基础,我们通过在继承体现中声明虚函数来实现多态技术.这里主要有三个关键点: ①继承体现,多态一定是存在于一个继承体现中的,没有继承就不会有多态发生. ②虚函数,只有声明为virtual的成员函数才能产生多态效果. ③

函数指针玩得不熟,就不要自称为C语言高手(函数指针是解耦对象关系的最佳利器,还有signal)

记得刚开始工作时,一位高手告诉我说,longjmp和setjmp玩得不熟,就不要自称为C语言高手.当时我半信半疑,为了让自己向高手方向迈进,还是花了一点时间去学习longjmp和setjmp的用法.后来明白那不单是跳来跳去那样简单,而是一种高级的异常处理机制,在某些情况下确实很有用. 事实上,longjmp和 setjmp玩得熟不熟与是不是C语言高手,不是因果关系.但是,如果可以套用那位高手的话,我倒想说如果函数指针玩得不熟,就不要自称为C语言高手.为什么这么说呢,函数指针有那么复杂吗?当然不是

C利用可变参数列表统计一组数的平均值,利用函数形式参数栈原理实现指针运算

//描述:利用可变参数列表统计一组数的平均值 #include <stdarg.h> #include <stdio.h> float average(int num, ...);//函数原型:即声明 float average2(int num, ...);//num个数 void add(int num, int x, int y, int z); int main(void){ int a=10; int b=20; printf("a地址:%p b地址:%p\n&

&lt;编译原理 - 函数绘图语言解释器(1)词法分析器 - python&gt;

<编译原理 - 函数绘图语言解释器(1)词法分析器 - python> 背景 编译原理上机实现一个对函数绘图语言的解释器 - 用除C外的不同种语言实现 解释器分为三个实现块: 词法分析器:用于识别一条语句中的关键词是否符合预先定义的规则. 语法分析器:用来确定一条语句是否满足语法规则. 解释器:用来确定满足语法规则的句子,在意思上是否符合要求. 设计思路: 设计记号:词法分析器读取一个序列并根据构词规则把序列转化为记号流 定义一个字典:把所有符合一个模式的保留字.常量名.参数名.函数名等放进字

C#委托与C语言函数指针及函数指针数组

C#委托与C语言函数指针及函数指针数组 在使用C#时总会为委托而感到疑惑,但现在总新温习了一遍C语言后,才真正理解的委托. 其实委托就类似于C/C++里的函数指针,在函数传参时传递的是函数指针,在调用的时候通过指针访问这个函数. 在C语言中函数指针的申明如下: //可以理解为申明一个指着变量 Func ,它的类型是 返回Type(可以为 void )类型的参数,接收 (Type one,Type two,...)类型的//参数(可以不接受参数). Type *Func(Type one,Type