Gtk组件使用C语言实现了面向对象设计。也就是说,子组件可以调用父组件定义的函数(通过类型强制转换),大大减少代码量,实现代码复用。下面是部分组件间的继承关系。
GObject
├── GInitiallyUnowned
│ ├── GtkWidget
│ │ ├── GtkContainer
│ │ │ ├── GtkBin
│ │ │ │ ├── GtkWindow
│ │ │ │ │ ├── GtkDialog
...
下面通过一个简单的例子体会一下C语言如何实现类似继承的特性:
#include <stdio.h>
#include <stdlib.h>
struct base {
int m_a;
};
struct derive {
struct base m_base;
int m_a;
};
struct derive *new_derive(struct base *base) {
struct derive *derive = calloc(1, sizeof(struct derive));
derive->m_base = *base;
return derive;
}
void print_base(struct base *base) {
printf("I am base, m_a = %d\n", base->m_a);
}
void print_derive(struct derive *derive) {
printf("I am derive, m_a = %d\n", derive->m_a);
}
int main(void) {
struct base base = {
.m_a = 1,
};
struct derive *derive = new_derive(&base);
derive->m_a = 2;
print_derive(derive);
print_base((struct base*)derive);
free(derive);
return 0;
}
输出:
I am derive, m_a = 2
I am base, m_a = 1
代码比较简单就不解释了。C实现面向对象类似继承特性的关键是:
- C是一个弱类型的语言,得益于类型强制转换,可以对类型进行任何操作,
指鹿为马也不为过。C语言给我的感觉更像是一个基于内存编程的语言。就是给你一片内存,以类型作为辅助,想怎么操作就怎么操作,我说你是啥你就是啥,编译能够顺利编译过去,就是运行时可能segmentfault。 - 编译器保证结构体成员的顺序不会被重排,成员排序可能不是最省内存的,但成员顺序是可预测的,在某些方面也会带来便利或能实现一些dark magic。