doubango ANSI-C 对象编程的实现方法


doubango 3GPP IMS/LTE Framework v1.0.0

 

Programmer’s Guide


正如你知道的,C语言不是一个面向对象语言今天,OOP面向对象编程)是编写精心设计软件的最好方式

在这份文档中“被定义的对象”是指一个特殊C语言结构体本文的所有功能是tinySAK项目一部分。为了解释如何定义对象及如何使用对象我会使用一个基于对象例子。“人”对象被声明是这样的:

typedef struct person_s
{
	TSK_DECLARE_OBJECT; /* Mandatory */

	char* name;
	struct person_s* girlfriend;
}
person_t;

对象定义可以被视为一个类的定义。该定义包括对象的必须具备(强制性)的功能,对象的大小和一个引用计数器。强制性的功能包括:构造函数,析构函数和比较函数。C结构体通过在其体内的TSK_DECLARE_OBJECT宏#define为对象。

对象定义指针指向一个结构体 tsk_object_def_s

typedef struct tsk_object_def_s
{
	//! The size of the object.
	size_t size;
	//! Pointer to the constructor.
	tsk_object_t*	(* constructor) (tsk_object_t *, va_list *);
	//! Pointer to the destructor.
	tsk_object_t*	(* destructor) (tsk_object_t *);
	//! Pointer to the comparator.
	int		(*comparator) (const tsk_object_t *, const tsk_object_t *);
}
tsk_object_def_t;

创建一个对象分为两个阶段。第一阶段是动态在堆上分配对象; 这就是为什么在对象定义结构内它的大小是强制性的原因。当一个新的对象是在堆上分配,其所有成员(char*,void*,int,long...)将被清零。在第二阶段,将新创建的对象通过调用提供的构造函数初始化。为了执行这两个阶段,你应该调用tsk_object_new()或tsk_object_new_2()。


对象被销毁分两个阶段进行。第一阶段释放其成员(void*,char* ...函数负责这项任务的第二阶段对象本身被销毁。因为对象不能销毁自己使用tsk_object_unreftsk_object_delete执行这两个阶段接下来部分对这两个函数之间差异进行了解释

下面是如何声明一个对象定义的例子:

//(Object defnition)
 static const tsk_object_def_t person_def_t = 
 {
 	sizeof(person_t),
 	person_ctor,
 	person_dtor,
 	person_cmp
}
构造函数是负责初始化,不会分配对象传递给构造方法 对象已经被分配。

下面是一个例子

// (constructor)
static tsk_object_t* person_ctor(tsk_object_t * self, va_list * app)
{
 	person_t *person = self;
 	if(person){
 		person->name = tsk_strdup(va_arg(*app, const char *));
 	}
 	return self;
 }

析构函数会释放对象的成员不会破坏对象本身(第一阶段)析构函数必须返回一个指针允许调用者执行第二阶段

// (destructor)
 static tsk_object_t * person_dtor(tsk_object_t * self)
 { 
 	person_t *person = self;
 	if(person){
 		TSK_FREE(person->name);
		tsk_object_unref(person->girlfriend);
 	}
 	return self;
 }

比较函数是用来比较两个定义的对象比较对象应具有相同的定义或类型

// (comparator)
static int person_cmp(const tsk_object_t *_p1, const tsk_object_t *_p2)
 {
 	const person_t *p1 = _p1;
 	const person_t *p1 = _p2;
	int ret;
	
	// do they have the same name?
	if((ret = tsk_stricmp(p1->name, p2->name))){
		return ret;
	}
	// do they have the same girlfriend?
	if((ret = tsk_object_cmp(p1->girlfriend, p2->girlfriend))){
		return ret;
	}
	
	// they are the same
	return 0;
 }

引用计数用来模拟垃圾收集每个被定义对象包含一个引用计数器字段这表明多少对象对该对象进行引用

一个对象被创建(见下文)计数器的值被初始化为1这是自动完成你不用做任何事情计数器加1当你调用tsk_object_ref递减1调用tsk_object_unref计数器的值达到,然后对象被回收(释放

正如你认为的那样,ANSI-C是不支持继承的。因为任何C结构可以强制转换为它的第一个元素的指针,继承可以这样实现:

#include "tsk.h"
// (a student is a person)
typedef struct student_s
{
struct person_s* person; // Must be the first element
	char* school;
}
student_t;

// (as a student is a person you can do)
student_t* s;
((person_t*)s)->name = tsk_strdup("bob");
因为person_t是个定义的对象,那么student_t也是。
一旦声明了 对象的 定义 以及实现了对象 所有 强制性 功能 ,它可以 这样被使用:

// creates a person: will call the constructor
person_t* bob = tsk_object_new(&person_def_t, "bob");
// creates bob's girlfriend
bob->girlfriend = tsk_object_new(&person_def_t, "alice");
// deletes bob: will delete both bob and bob's girlfriend field by calling their destructors
tsk_object_unref(bob);
由于很难记住构造函数需要哪个参数(As it’s hard to guest which parameters the construct expects),一般我们用宏或函数来帮助。宏定义是这样的:

// create a person
#define PERSON_CREATE(name)	tsk_object_new(&person_def_t, (const char*)name)
由于 函数 有固定 参数 有一个共同的 宏来 销毁所有 定义的对象   TSK_OBJECT_SAFE_FREE ()可用来 销毁 任何对象 只有 对象 引用计数 减1并 等于零时,对象将被释放 在所有 情况 释放或不释放 的指针值 设置为NULL。
上面的例子 可以 写成 这样

#include "tsk.h"

// create a person: will call the constructor
person_t* bob = PERSON_CREATE("bob");
// create bob's girlfriend
bob->girlfriend = PERSON_CREATE("alice");
// delete bob: will delete both bob and bob's girlfriend field by calling their destructors
TSK_OBJECT_SAFE_FREE(bob);
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值