关于c语言面向对象继承的一些杂谈
我们知道面向对象和语言无关,c语言也能实现面向对象。在工作中我经常接触gtk+的代码,而gtk+正好是用c语言实现的面向对象的库。再加上之前研究安卓内核时,hal层的代码以及linux内核代码,算是对c语言实现面向对象有了一定的了解。
但是有一点当时我一直没有搞明白,很多资料里都说
在设计C语言继承性的时候, 我们需要做的就是把基础数据放在继承的结构的首位
置即可。 这样, 不管是数据的访问、 数据的强转、 数据的访问都不会有什么问题。
而我当时非常不解,为什么必须放在数据结构首位呢,放在别的地方不一样可以访问吗?
事实上,放在别的位置确实也可以访问,但是这样一来,我们是没有办法直接访问父类的成员的,必须以子类->父类->父类成员
的形式来访问。如果仅仅只要做到这样,那么父类的结构体放在子类的任何位置都是没问题的。
那么,把父类放到子类结构体的第一个位置有什么作用呢?答案就是当我们使用结构体类型强制转换时,我们把子类转换成父类时就可以直接访问父类的成员了。即((子类)转换成父类)->父类成员
。下面用一段代码来解释。
#include <stdio.h>
#include <string.h>
typedef struct Father {
int father1;
int father2;
}Father;
typedef struct Son {
Father father;
int son1;
int son2;
}Son;
int main() {
Son s;
s.father.father1 = 1;
s.father.father2 = 2;
printf("s.father.son1=%d\ns.father.son2=%d\n", s.father.father1, s.father.father2);
Father *f = (Father*)(&s);
printf("f->father1=%d\nf->father2=%d\n", f->father1, f->father2);
return 0;
}
输出结果
如果把父类放到其他位置,例如
typedef struct Son {
int son1;
int son2;
Father father;
}Son;
输出结果
为什么会产生这种结果呢,其实这涉及到结构体在内存里的存储方式,具体的存储方式比较复杂,不过大体上来说编译器按成员列表的顺序一个一个给每个成员分配内存,指针所指的正好是它的起始位置,故而如果把父类放在首位,强制转换类型后其实访问的就是那个父类的结构体。
这个特点在c语言实现面向对象时是一个很有用的特性。