本文版权所有,转载请注明出处和作者联系方式。
作者:孙华明
联系方式: wormsun at gmail.com
上篇我们介绍了如何使用结构体写一个简单的类animal,并使用animal* animal_create(void)和void animal_destroy(animal* self)来创建和删除animal类的对象。
在C++中创建和删除对象时使用的是new和delete操作符,并会自动调用类的构造函数和析构函数初始化和析构对象,那么使用C语言如何实现这样的机制呢?我们可以用函数模拟new和delete,定义两个函数:lw_new和lw_delete("lw"意为light-weight,轻量级的意思)。
使用lw_new创建类的对象时,需要为对象申请内存空间,并且需要初始化该对象,所以lw_new函数至少需要知道该类的对象需要多大的内存空间,以及该类的构造函数是谁。我们可以将这些信息封装到一个结构体中,称之为类信息结构体,如下(以上篇介绍的animal类为例):
typedef struct _animal_klass_info animal_klass_info;
struct _animal_klass_info
{
size_t size; /*animal's size*/
animal* (*ctor)(animal* self); /*constructor*/
};
然后我们创建一个该结构体的对象(称之为类信息),将animal类的内存大小、构造函数等信息存入到对象中,再使用一个全局的指针指向该对象(称之为全局类信息指针),如下:
extern animal_klass_info* animal_klass;
static animal_klass_info local_animal_klass =
{
sizeof(animal),
animal_ctor,
};
animal_klass_info* animal_klass = &local_animal_klass;
这样在创建animal类的对象时,我们只需要将animal类的全局类信息指针animal_klass传入到 lw_new函数中,lw_new函数就能够申请内存空间,并自动调用构造函数初始化对象了,lw_new的实现如下:
animal* lw_new(animal_klass_info* klass)
{
animal* p = ANIMAL(malloc(klass->size));
return klass->ctor(p);
}
现在可以使用lw_new创建animal类的对象了,如下:
animal* animal1 = lw_new(animal_klass);
那么如何使用lw_delete函数删除对象,并自动调用析构函数呢?
在C++中删除对象时,传递给delete操作符的参数只有对象的地址,所以我们传递给lw_delete函数的也只能是对象的地址。使用对象地址我们可以释放对象占用的内存空间,但如何调用对象的析构函数呢?
我们可以将析构函数的地址加入到类信息结构体中,还是以animal类为例,将其类信息结构体修改为:
typedef struct _animal_klass_info animal_klass_info;
struct _animal_klass_info
{
size_t size; /*animal's size*/
animal* (*ctor)(animal* self); /*constructor*/
animal* (*dtor)(animal* self); /*destructor*/
};
在创建类信息时加入析构函数的地址,如下:
static animal_klass_info local_animal_klass =
{
sizeof(animal),
animal_ctor,
animal_dtor,
};
然后在animal类中加入一个类信息结构体的指针,用来保存animal类信息的地址。修改animal类定义如下:
typedef struct _animal animal;
struct _animal
{
/*klass info*/
animal_klass_info* klass;
/*private data*/
char name[256];
int weight;
};
在lw_new函数中初始化animal类的类信息结构体指针,如下:
animal* lw_new(animal_klass_info* klass)
{
animal* p = ANIMAL(malloc(klass->size));
p->klass = klass;
return klass->ctor(p);
}
这样lw_delete函数就能够根据传入的对象的地址,取得相应的类信息地址,进而取得析构函数了,lw_delete实现如下:
void lw_delete(animal* self)
{
if(self)
{
free(self->klass->dtor(self));
}
}
至此,lw_new和lw_delete都已经实现了,我们测试一下吧.
int main(int argc, char* argv)
{
argc;
argv;
animal* animal1 = NULL;
animal* animal2 = NULL;
animal1 = lw_new(animal_klass);
animal_set_name(animal1, "Kitty");
animal_set_weight(animal1, 30);
printf("animal1, name : %s, weight : %d/n",
animal_get_name(animal1),
animal_get_weight(animal1));
lw_delete(animal1);
animal2 = lw_new(animal_klass);
animal_set_name(animal2, "Bib");
animal_set_weight(animal2, 10);
printf("animal2, name : %s, weight : %d/n",
animal_get_name(animal2),
animal_get_weight(animal2));
lw_delete(animal2);
return 0;
}
完整的代码可以在此处下载。
大家可以看出我们目前实现的lw_new和lw_delete只能用于创建和删除animal类的对象。如何实现通用的lw_new和lw_delete呢?这就是下篇我们将要介绍的内容。