GTK3笔记 - Object Hierarchy

237 阅读1分钟

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。