c实现"对象"

来源:互联网 发布:python readline 编辑:程序博客网 时间:2024/06/05 14:33

后来看到了此博客http://blog.csdn.net/ghostyu/article/details/7921179

也是通过c结构体相互引用来实现的。


标题不好取,所以再啰嗦补充下,等以后想到好的表述了再更改。

在dvr项目中,不同的chip初始化和设置也是不同的,例如gm8187/gm8210等。这些初始化都是以以库的形式出现的,所以用c来实现。之前没有融入"对象"的概念之前,

一般的实现就是if/else或者switch/case来兼容不同的产品,每次有新的设置都会在有差异的地方修改代码。


一、c的"对象"

大概形态,要包含函数指针

{

int a;

void (*pfunc)(void);

}


二、实际实现

就是参考的ffmpeg里的enc/dec 注册来实现的。

待续

接上,给出精彩的代码。

#ifdef __cplusplusextern "C"{#endif#include <stdio.h> #include <string.h> #include <stdlib.h>#include <unistd.h>#include <sys/ioctl.h>#include <sys/time.h>#include <fcntl.h>#if1//来自ffmpeg,祛除了些变量typedef int offset_t;#ifdef ENOENT#undef ENOENT#endif#define ENOENT 2#ifdef ENOMEM#undef ENOMEM#endif#define ENOMEM 12#define URL_RDONLY 0#define URL_WRONLY 1#define URL_RDWR   2#define INT_MAX 2147483647#define FFMAX(a,b) ((a) > (b) ? (a) : (b))void *av_malloc(unsigned int size){    void *ptr;    if (size > INT_MAX)        return NULL;    ptr = malloc(size);    return ptr;}void *av_realloc(void *ptr, unsigned int size){    if (size > INT_MAX)        return NULL;    return realloc(ptr, size);}void av_free(void *ptr){    if (ptr)        free(ptr);}//具体和抽象通过指针互相引用来建立联系//对客户/调用角度来看,只关心抽象(URLProtocol)即可//具体的实现都可以封装为.a,详情看本demo代码//抽象typedef struct URLContext{    struct URLProtocol *prot;    int flags;    int max_packet_size; // if non zero, the stream is packetized with this max packet size    void *priv_data;    char filename[1]; // specified filename} URLContext;//具体typedef struct URLProtocol{    const char *name;    int(*url_open)(URLContext *h, const char *filename, int flags);    int(*url_read)(URLContext *h, unsigned char *buf, int size);    int(*url_write)(URLContext *h, unsigned char *buf, int size);    offset_t(*url_seek)(URLContext *h, offset_t pos, int whence);    int(*url_close)(URLContext *h);    struct URLProtocol *next;} URLProtocol;#endif/////////////////////////////////以下以应用代码来演示,为了方便,就放在一个.c中了//抽象typedef struct DVRContext{    struct DVRProduct *prot;    int flags;    int max_packet_size; // if non zero, the stream is packetized with this max packet size    void *priv_data;int type;    char dvrname[1]; // specified filename} DVRContext;//具体typedef struct DVRProduct{    const char *name;    int(*dvr_open)(DVRContext *h, const char *filename, int flags);    int(*dvr_read)(DVRContext *h, unsigned char *buf, int size);    int(*dvr_write)(DVRContext *h, unsigned char *buf, int size);    int(*dvr_close)(DVRContext *h);    struct DVRProduct *next;} DVRProduct;//带gm8210的单独放在gm8210.c中,其他gmxx仿写gm8210即可//gm8210_open/gm8210_read等沿用了ffmpeg里的URLProtocol,仅demostatic int gm8210_open(DVRContext *h, const char *filename, int flags){printf("gm8210_open,%s jiu zheyang bei ni open\n",h->dvrname);    int access;    int fd;access = O_CREAT | O_TRUNC | O_RDWR;fd = open(filename, access, 0666);    if (fd < 0)    {    return  - ENOENT;    }//可以看出,priv_data就是具体对象的私有数据,此处为fd//不同的具体对象可以用不同的私有数据,依赖自己的应用    h->priv_data = (void*)(size_t)fd;    return 0;}static int gm8210_read(DVRContext *h, unsigned char *buf, int size){    int fd = (size_t)h->priv_data;    return read(fd, buf, size);}static int gm8210_write(DVRContext *h, unsigned char *buf, int size){    int fd = (size_t)h->priv_data;    return write(fd, buf, size);}static int gm8210_close(DVRContext *h){printf("gm8210_close,%s jiu zheyang bei ni close\n",h->dvrname);    int fd = (size_t)h->priv_data;    return close(fd);}DVRProduct gm8210_dvr ={    "gm8210",gm8210_open,gm8210_read,gm8210_write,gm8210_close,};//8287static int gm8287_open(DVRContext *h, const char *filename, int flags){printf("gm8287_open,%s jiu zheyang bei ni open\n",h->dvrname);    int access;    int fd;access = O_CREAT | O_TRUNC | O_RDWR;fd = open(filename, access, 0666);    if (fd < 0)    {    return  - ENOENT;    }    h->priv_data = (void*)(size_t)fd;    return 0;}static int gm8287_close(DVRContext *h){printf("gm8287_close,%s jiu zheyang bei ni close\n",h->dvrname);    int fd = (size_t)h->priv_data;    return close(fd);}DVRProduct gm8287_dvr ={    "gm8287",gm8287_open,NULL,NULL,gm8287_close,};DVRProduct *first_dvr = NULL;//也可以不创建链表,直接first_dvr = gmxx_dvrint register_product(DVRProduct *pdvr){    DVRProduct **pp;    pp = &first_dvr;    while (*pp != NULL)    {    pp = &(*pp)->next;    }    *pp = pdvr;    pdvr->next = NULL;    return 0;}int gmdvr_open(DVRContext **puc, const char *filename, int flags){    DVRContext *uc;    DVRProduct *up;    const char *p;    int err;    p = filename;    up = first_dvr;    while (up != NULL)    {        if (!strcmp(p, up->name))       {       goto found;//找到对应的        }        up = up->next;    }    err = -ENOENT;    goto fail;found: uc = av_malloc(sizeof(DVRContext) + strlen(filename));    if (!uc)    {        err =  - ENOMEM;        goto fail;    }//抽象/具体关联    strcpy(uc->dvrname, filename);    uc->prot = up;    uc->flags = flags;    uc->max_packet_size = 0; // default: stream file    err = up->dvr_open(uc, filename, flags);//具体的gmxx_dvr.dvr_open    if (err < 0)    {        av_free(uc);        *puc = NULL;        return err;    }    *puc = uc;//带出已确定的上下文(抽象)    return 0;fail:*puc = NULL;    return err;}DVRContext *g_dvrctx = NULL;int gmdvr_getctx(const char *filename){if(!g_dvrctx){return -1;}    const char *p;    p = filename;if (!strcmp(p, g_dvrctx->dvrname))   {   printf("gmdvr_getctx,for %s\n",g_dvrctx->dvrname);return 0;    }else{return -2;}return 0;}int gmdvr_init(const char *filename){    int err;err = gmdvr_open(&g_dvrctx, filename, URL_RDWR);    if (err < 0)    {    return err;    }return 0;}int gmdvr_uninit(const char *filename){    int err;err = gmdvr_getctx(filename);if (err < 0)    {    return err;    }g_dvrctx->prot->dvr_close(g_dvrctx);return 0;} int main(int argc, char* argv[]){//可以全部注册好    register_product(&gm8210_dvr);    register_product(&gm8287_dvr);//char* name/int id来自上层app,或者register && init都可以暴露给上层appgmdvr_init("gm8210");gmdvr_uninit("gm8210");printf("\n#########\n");gmdvr_init("gm8287");gmdvr_uninit("gm8287");return 0;}#ifdef __cplusplusextern "C"}#endif

重新思考了下,感觉应该是这样的

DVRContext  //抽象

DVRProduct //具体



原创粉丝点击