原文出处: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