引言
所谓继承就是找出不同对象的共同点,将这些共同点封装成一个基类,而原来的对象变成子类,继承基类。就好比水果有很多种,苹果、梨、橘子、樱桃,这些都可以称之为水果,他们都有颜色,味道,重量,价格等等属性,这时我们可以就抽象出一个水果的基类,这个基类包括颜色,味道,重量,价格等属性,而在声明苹果、梨、橘子、樱桃就没必要重新定义以上属性,只需要继承水果这个基类即可拥有这些属性,这就是所谓的继承。
C语言与继承
而在C语言种没有类这一说法,我们只能使用结构体来代替类,也必须使用结构体来实现继承的操作。
我们可以将基类放到一个struct里面,然后它的子类都包含这个基类,并使用指针强转的方式实现两个结构体之间的转化,因此我们往往将基类结构体放在派生类结构体中的第一个位置,由于地址的偏移都在struct的定义时就清楚了,我们就可以通过指针转化的方式访问父类成员了。
如下:
/*基类定义*/
struct BaseClass {
int data;
};
/*派生类定义*/
struct DerivedClass {
struct BaseClass parent;
int anotherdata;
};
/*从子对象转成父对象*/
int main(int argc, char *argv[]) {
struct DerivedClass son;/*子类定义*/
struct BaseClass *parent = (struct BaseClass *)&son;/*父类指针初始化*/
return 0;
}
如果是基类转化成派生类,很可能会有一些专有操作会被子类重写,比如基类获取子类通常就在虚函数被覆写的时候。
如何获取子类,原理就是地址偏移,如果是单继承的偏移就是0,而多继承的便宜需要计算偏移位置。
/*基类1定义*/
struct BaseClass1 {
int data;
};
/*基类2定义*/
struct BaseClass2 {
int data;
};
/*派生类定义*/
struct DerivedClass{
struct BaseClass1 parent1;
struct BaseClass2 parent2;
int data;
};
int get_data(struct BaseClass2 *parent) {
/******************这里是重点*********************/
struct DerivedClass *son = (struct DerivedClass*)((char *)parent-(char *)(&((struct DerivedClass*)0)->parent2));
return son->data;
}
/*从父对象转成子对象*/
int main(void **argc,void *argv[]) {
struct DerivedClassson;/*子类定义*/
son.data = 3;
/* son 的各种操作*/
struct BaseClass2 *parent = (struct BaseClass *)&son.parent2;/*父类指针初始化*/
parent->data = get_data(parent);
printf("parent data = %d, son data = %d.\n",son.data, parent->data);
return 0;
}