C语言也能面向对象(四)——继承

原文出处:http://blog.csdn.net/wormsun/archive/2011/05/08/6406252.aspx

 

 

 

 C语言也能面向对象(四)——继承 收藏 此文于2011-05-10被推荐到CSDN首页
如何被推荐?
Technorati 标签: c,c语言,面向对象,oo,object-oriented
本文版权所有,转载请注明出处和作者联系方式。
作者:孙华明
联系方式: wormsun at gmail.com
博客:http://blog.csdn.net/wormsun

在C++中如果一个类有父类,那么这个类的对象中就包含了父类中定义的数据,并且可以使用父类的函数访问或操作该这些数据。在C中如何实现这样的机制呢?

animal类的定义如下:

typedef struct _animal animal;struct _animal{/*class info*/    klass_info* klass;    /*private data*/    char name[256];    int weight;};
现在我们再定义一个dog类,除了包含animal类的属性外,还包括一个age属性,即年龄。如下:

typedef struct _dog dog ;struct _dog {/*class info*/    klass_info* klass;    /*private data*/    char name[256];    int weight;    int age;};
在保持类的对象的内存布局不变的情况下,我们可以将dog类的定义变换为:

typedef struct _dog dog;struct _dog{/*base*/    animal base; /*private data*/    int age;};
两个dog类的定义在内存布局上是完全一致的。因此,只要将dog类对象的指针强制转型为animal类的指针,那么animal类的成员函数就可以访问或操作 dog类对象了,如下:

dog* my_dog = lw_new(dog_klass);animal_set_weight(ANIMAL(my_dog), 40);int weight = animal_get_weight(ANIMAL(my_dog));lw_delete(my_dog);
在C++中创建子类的对象时,要先调用父类的构造函数,然后再调用子类的函数;删除子类对象时,要先调用子类的析构函数,然后再调用父类的析构函数。

animal类是dog类的父类,在定义dog类信息时,要将dog类信息中的super属性初始化为animal类信息的地址,如下:

static klass_info local_dog_klass = {    animal_klass,    "dog_klass",    sizeof(dog),    dog_ctor,    dog_dtor,};
在实现dog的构造函数时,就可以使用类信息的super成员获取其父类的构造函数地址,如下:

static dog* dog_ctor(dog* self){    ((voidf)(klass_of(self)->super->ctor))(self);    self->age = 0;    return self;}
klass_of函数的功能是获取对象的类信息地址。可以看出dog类的构造函数是先调用父类的构造函数,然后再初始化子类的属性。类似,析构函数的实现如下:

static dog* dog_dtor(dog* self){    ((voidf)(klass_of(self)->super->dtor))(self);    return self;}
目前为止,我们都是使用结构体初始化的方式来初始化类信息,这种方式有代码重复、容易犯错,难于维护的缺点,例如,animal类信息的初始化在animal.c中已经实现过,定义dog类时在dog.c中又要再次实现,如果再定义其他继承自animal类的子类,则还要实现。按顺序初始化结构体这种做法本身就很容易犯错,如果这样的代码到处都是,那么维护难度就可想而知了。

所以我们考虑使用类信息初始化函数来初始化类信息,即专门定义一个函数用来初始化类信息,该函数在程序运行后,第一次创建该类的对象时由lw_new函数调用。在类信息结构体中新加入一个属性,即类信息初始化函数的地址,如下:

typedef struct _klass_info klass_info;struct _klass_info{    void* init; /*initialize function*/    klass_info* super;    /*object's klass's super klass*/    char* name; /*object's klass's name*/    size_t size; /*object's size*/    void* ctor; /*object's constructor*/    void* dtor; /*object's destructor*/};
init属性在定义静态类信息结构体对象时初始化,其他属性在init指向的函数中初始化,以animal类为例:

static animal_klass_info local_animal_klass = {animal_init};animal_klass_info* animal_klass = &local_animal_klass; void animal_init(void){    if(animal_klass->init)    {        animal_klass->init = NULL;        animal_klass->super = NULL;        animal_klass->name = "animal_klass";        animal_klass->size = sizeof(animal);        animal_klass->ctor = animal_ctor;        animal_klass->dtor = animal_dtor;    }}
lw_new函数修改如下:

void* lw_new(void* klass){    klass_info* kls = KLASS(klass);    if(kls->init)    {        ((init_fun)kls->init)();    }        void* p = malloc(kls->size);    *((klass_info**)p) = kls;    return ((voidf)(kls->ctor))(p);}
类信息初始化函数中会将类信息结构体的init属性置空,所以该函数只会被调用一次,即第一次创建该类的对象时调用。

子类的类信息初始化函数可以直接调用父类的类信息初始化函数,以dog类为例:

void dog_init(void){    if(dog_klass->init)    {        animal_init();        memcpy(dog_klass, animal_klass, sizeof(animal_klass_info));        dog_klass->super = animal_klass;        dog_klass->name = "dog_klass";        dog_klass->size = sizeof(dog);        dog_klass->ctor = dog_ctor;    }}
至此我们实现了类继承,并使用类信息初始化函数来初始化类信息。

这里是相关代码。

下篇文章我们将讨论多态。

 

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/wormsun/archive/2011/05/08/6406252.aspx

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值