• 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模式等,这部分也是函数指针实现的。实际上仅仅是一个回调。

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

  • 相关阅读:
    新线程 handler
    解决获取View的width和Height为0的4种方法
    回调深入理解 同步回调 以android中View.OnClickListener为列
    回调函数
    android:layout_weight
    studio rendering problems
    android:exported属性
    Codeforces 1264C/1265E Beautiful Mirrors with queries (概率期望、DP)
    Codeforces 1254C/1255F Point Ordering (交互题)
    Codeforces 576D Flights for Regular Customers (图论、矩阵乘法、Bitset)
  • 原文地址:https://www.cnblogs.com/mqxnongmin/p/10668922.html
Copyright © 2020-2023  润新知