c实现"对象"

后来看到了此博客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 __cplusplus
extern "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>


#if	1	//来自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,仅demo
static 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,
};


//8287
static 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_dvr
int 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都可以暴露给上层app
	gmdvr_init("gm8210");
	gmdvr_uninit("gm8210");

	printf("\n#########\n");
	gmdvr_init("gm8287");
	gmdvr_uninit("gm8287");
	
	return 0;
}

#ifdef __cplusplus
extern "C"
}
#endif

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

DVRContext  //抽象

DVRProduct //具体



  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值