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就非常easy了:
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  !!!
"  , __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  !!!
"  , __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模式等,这部分也是函数指针实现的。实际上仅仅是一个回调。

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

原文地址:https://www.cnblogs.com/mqxnongmin/p/10668922.html