GObject

    技术2024-09-29  66

    GObject

    GLib Object System,也叫GObject,是一个免费的库(由LGPL授权)。它提供了一个可移植的对象系统,清晰的跨语言互用性。GObject被设计成既可以直接在C语言中使用,也可以通过绑定,用于其它语言。

    历史

    GObject只依赖于GLib和libc,它是GNOME的基石,被广泛应用于GTK+,Pango,Accessibility Toolkit及大多数高层次GNOME库和应用程序。在GTK+2.0 之前,GObject代码是GTK+代码的一部分。(名字“GObject ” 当时还未使用——共同的基类叫GtkObject)

     

    由于它的通用性,GTK+2.0把这个对象系统给抽取成一个分离的库。 再这个过程中,GtkObject内和GUI无关的部分被移到GObject中,GObject成为新的共同基类。自从2002年3月11日(GTK+2.0发布),GObject作为一个分离开的库已经被很多非GUI的程序所使用,例如命令行和server应用程序。

    和Gilb的关系

    尽管GObject有它自己的文档集,并且通常被编译成它自己的共享文件,但是GObject的源代码位于GLib的源代码树,并且和GLib一起发布。因此,GObject采用GLib的版本号,典型地和Glib打包在一起(例如,Debian把GObject放在libglib2.0包族)。

    类型系统

    GObject框架最基础的一层是一个叫做GType的泛化的动态的类型系统。GType系统保存着所有对象的运行时描述符,这样可以利用“胶水”代码便于多语言绑定。这个类型系统可以处理任何单继承类结构,附加地也可以处理

    非类结构的类型,例如opaque pointers,strings,和各种大小的整型及浮点数。

     

    这个类型系统知道注册的所有类型的值如何复制,赋值,和销毁。对于像整型这样的类型,这是没用的,但是很多复杂类型是引用计数的,也有一些类型不用引用计数但是很复杂。当类型系统“拷贝”一个引用对象时,典型地,它只是简单的增加引用计数的值,而当拷贝一个复杂的,非引用计数(比如string)时,它通常会分配内存,进行真正的拷贝。

     

    这些基本功能实现了GValue,它是一种泛化的容器类型,可以保存任何类型系统知道的类型。这些容器在和动态语言交互的环境下就十分有用,此时,所有自然的值都可以保存在这些被标记了类型的容器中。

     

    基础类型

    不和任何类相关的类型叫做non-classed。这些类型再加上所有以某种形式作为根类的类型叫做基础类型:其他所有类型都是派生于这些类型。这些类型组成了一个相关的封闭的集合,但是尽管大多数用户不被建议创建自己的基础类型,但是这种能力是存在,并且可以用来实现定制的类继承体系——比如一个不是基于GObject的继承体系。

     

    GLib 2.9.2 的non-class内建基础类型有

     

    一个空类型,对应于C语言的void(G_TYPE_NONE) 对应于C语言带符号和不带符号 char,int,long,和 64-bit  整数(G_TYPE_CHAR,G_TYPE_UCHAR,G_TYPE_INT,G_TYPE_UINT,G_TYPE_LONG,G_TYPE_ULONG,G_TYPE_INT64,和G_TYPE_UINT64) 一个布尔类型(G_TYPE_BOOLEAN) 一个枚举类型和一个“flags”类型,这两个都对应于C语言enum类型,但是后者只用于bit fields (G_TYPE_ENUM 和 G_TYPE_FLAGS) IEEE的单精度和双精度浮点数,对应于C语言的float和double(G_TYPE_FLOAT和G_TYPE_DOUBLE) 一个string类型,对应C语言的 char* (G_TYPE_STRING) opaque pointer类型,对应C语言的 void * (G_TYPE_POINTER)

     

     classed的内建基础类型有

    基类GObject,标准的类继承树的根(G_TYPE_OBJECT) 一个基础接口类型,类似于基类除了它代表了标准接口的继承树(G_TYPE_INTERFACE) 一个盒子结构类型,用来把简单的值对象或者外来对象包装成引用计数。(G_TYPE_BOXED) 一个“参数相关的对象”,这个类型被GObject用来描述对象属性的元数据(G_TYPE_PARAM)

    可以由类型系统自动实例化的类型称为可实例化的。这些类型的一个最重要的特点是任何实例的前几个字节永远保存着指向类结构的指针,类结构中保存着这个实例的类型的虚表。因此,任何可实例化的对象都是类类型的。相反的,任何non-classed的类型(比如整数和字符串)必须是不可实例化的。另一方面,大多数类类型是可实例化的,但是另一些,比如说接口类型则不可以实例化。

    派生类型

    从内建的基础类型GObject派生出来的类型可以分成四种:

    枚举类型和“flags”类型

    (···此处略去很多字)

    消息系统

     

    GObject的消息系统由两个互补的部分组成:closures 和 signals

    Closures

    GObject的闭包是一种泛化版的回调函数。对闭包的支持用c和c++写成,同样支持任何语言(当提供了绑定)。这允许(比如说)由python和java写成的代码通过closure调用。

    Signals

    信号是closures被调用的一种主要形式。对象通过指定一个信号到closure的映射,来向系统注册信号接收器。直到一个注册了的信号被发射,信号的closure才被调用。在GTK+中,所有的原始事件(例如鼠标移动,键盘动作)都能产生GObject信号,这些信号潜在地会让监听器有所反应。

    类的实现

    每个GObject类都是通过至少两个结构实现的:class结构和instance结构。

     

    类结构

    类结构对应于c++类的vtable。结构的开始必须是它的父类的类结构。下面是一组函数指针的集合——每个指针代表这个类的一个虚函数。Class-specific variables can be used to emulate class members。

    实例结构体

    实例结构体在每个实例对象中都有一份拷贝,它必须以父类的实例结构体为开始(这确保了所有实例以一个指针开始,这个指针指向类结构,因为所有的基础可实例的类型都有这个特点)在属于父类的数据之后,结构可以保存任何实例相关的变量,这些变量对应于c++的成员变量。

     

    由于c语言没有类似于“public”,“protected”或者“private”的存取修饰符,通常的技术是在实例结构体内包含一个指向私有数据的指针——习惯上叫 _priv。私有结构体可以在公共头文件内声明,但是只在实现文件内定义。这样私有数据对于使用者隐藏,对于实现者透明。如果私有结构已经向GType注册了,它可以被对象系统自动分配空间。实际上,包含_priv指针不是必须的,如果愿意的话在每次需要私有数据的时候,可以使用G_TYPE_INSTANCE_GET_PRIVATE

     

    GObject框架的主要缺点是它的冗长。大量的样板代码,比如手工定义类型装换宏,晦涩的类型注册语句等,这些都是创建一个新类所必须的。GObject Builder 或者 GOB2 就是一个试着补救这些问题的工具,它提供了一种类似Java的语法模板。用GOB2写的代码在编译之前被预处理成朴实的c代码。另一个GObject类型系统的 compiler-to-C 是Vala ,它采用c#风格的语法。

    最新回复(0)