C语言也能面向对象(二)——new和delete

Technorati 标签: c, c语言, 面向对象, oo, object-oriented

本文版权所有,转载请注明出处和作者联系方式。
作者:孙华明
联系方式: 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呢?这就是下篇我们将要介绍的内容。

你可能感兴趣的:(C语言也能面向对象(二)——new和delete)