El sistema de objetos GLib , o GObject , es una biblioteca de software libre que proporciona un sistema de objetos portátil e interoperabilidad transparente entre lenguajes. GObject está diseñado para usarse tanto directamente en programas C para proporcionar API basadas en C orientadas a objetos como a través de enlaces a otros lenguajes para proporcionar interoperabilidad transparente entre lenguajes, por ejemplo, PyGObject .
Historia
GObject, que depende únicamente de GLib y libc , es un componente fundamental de GNOME y se utiliza en GTK , Pango , ATK y la mayoría de las bibliotecas de alto nivel de GNOME, como GStreamer y las aplicaciones. Antes de GTK+ 2.0, existía código similar a GObject en el código fuente de GTK. (El nombre "GObject" aún no se utilizaba ; la clase base común se llamaba GtkObject).
Con el lanzamiento de GTK+ 2.0, el sistema de objetos se extrajo a una biblioteca independiente debido a su utilidad general. En este proceso, la mayoría de las partes de la clase que no eran específicas de la interfaz gráfica de usuario (GUI)GtkObject se trasladaron a GObjectla nueva clase base común. Habiendo existido como una biblioteca independiente desde el 11 de marzo de 2002 (fecha de lanzamiento de GTK+ 2.0), la biblioteca GObject ahora es utilizada por muchos programas sin interfaz gráfica de usuario, como aplicaciones de línea de comandos y de servidor .
Relación con GLib
Aunque GObject tiene su propia documentación [ 2 ] y suele compilarse en su propio archivo de biblioteca compartida , el código fuente de GObject reside en el árbol de código fuente de GLib y se distribuye junto con GLib. Por esta razón, GObject utiliza los números de versión de GLib y normalmente se empaqueta junto con GLib (por ejemplo, Debian incluye GObject en su libglib2.0familia de paquetes).
El sistema de tipos
En el nivel más básico del marco GObject se encuentra un sistema de tipos genérico y dinámico llamado GType. El sistema GType contiene una descripción en tiempo de ejecución de todos los objetos, lo que permite que el código de enlace facilite la integración con múltiples lenguajes. El sistema de tipos puede manejar cualquier estructura de clase de herencia simple , además de tipos no clasificados como punteros opacos , cadenas y números enteros y de punto flotante de diversos tamaños .
El sistema de tipos sabe cómo copiar, asignar y destruir valores pertenecientes a cualquiera de los tipos registrados. Esto es trivial para tipos como los enteros, pero muchos objetos complejos utilizan un contador de referencias , mientras que otros son complejos pero no lo utilizan. Cuando el sistema de tipos "copia" un objeto con contador de referencias, normalmente solo incrementa su contador, mientras que al copiar un objeto complejo sin contador de referencias (como una cadena), normalmente crea una copia real asignando memoria .
Esta funcionalidad básica se utiliza para implementar GValueun tipo de contenedor genérico que puede almacenar valores de cualquier tipo conocido por el sistema de tipos. Estos contenedores son particularmente útiles al interactuar con entornos de lenguajes de tipado dinámico, donde todos los valores nativos residen en contenedores con etiquetas de tipo .
Tipos fundamentales
Los tipos que no tienen clases asociadas se denominan tipos sin clase . Estos tipos, junto con todos los tipos que corresponden a alguna forma de clase raíz, se conocen como tipos fundamentales : los tipos de los que se derivan todos los demás. Estos conforman un conjunto relativamente cerrado, pero aunque no se espera que el usuario promedio cree sus propios tipos fundamentales, la posibilidad existe y se ha aprovechado para crear jerarquías de clases personalizadas , es decir, jerarquías de clases que no se basan en la GObjectclase.
A partir de GLib 2.9.2, [ 3 ] los tipos fundamentales integrados no clasificados son:
- un tipo vacío , correspondiente a C
void(G_TYPE_NONE); - tipos correspondientes a los enteros con signo y sin signo de C
char,int,long, y enteros de 64 bits (G_TYPE_CHAR,G_TYPE_UCHAR,G_TYPE_INT,G_TYPE_UINT,G_TYPE_LONG,G_TYPE_ULONG,G_TYPE_INT64, yG_TYPE_UINT64); - un tipo booleano (
G_TYPE_BOOLEAN); - un tipo de enumeración y un tipo de "banderas", ambos correspondientes al tipo de C
enum, pero que difieren en que este último solo se utiliza para campos de bits (G_TYPE_ENUMyG_TYPE_FLAGS); - tipos para números de coma flotante IEEE de precisión simple y doble , correspondientes a los de C
floatydouble(G_TYPE_FLOATyG_TYPE_DOUBLE); - un tipo de cadena , correspondiente a
char *(G_TYPE_STRING); de C - un tipo de puntero opaco , correspondiente al de C
void *(G_TYPE_POINTER).
Los tipos fundamentales integrados clasificados son:
- un tipo de clase base para instancias de
GObject, la raíz del árbol de herencia de clases estándar (G_TYPE_OBJECT) - un tipo de interfaz base , análogo al tipo de clase base pero que representa la raíz del árbol de herencia de interfaz
G_TYPE_INTERFACEestándar ( ) - un tipo para estructuras encapsuladas , que se utilizan para encapsular objetos de valor simples u objetos externos en "cajas" con conteo de referencias (
G_TYPE_BOXED) - un tipo para "objetos de especificación de parámetros", que se utilizan en GObject para describir metadatos para propiedades de objetos (
G_TYPE_PARAM).
Los tipos que el sistema de tipos puede instanciar automáticamente se denominan instanciables . Una característica importante de estos tipos es que los primeros bytes de cualquier instancia siempre contienen un puntero a la estructura de clase (una forma de tabla virtual ) asociada al tipo de la instancia. Por esta razón, cualquier tipo instanciable debe ser una clase. Por el contrario, cualquier tipo no clasificado (como entero o cadena ) no debe ser instanciable. En cambio, la mayoría de los tipos clasificados son instanciables, pero algunos, como los tipos de interfaz, no lo son.
Tipos derivados
Los tipos que se derivan de los tipos fundamentales integrados de GObject se dividen aproximadamente en cuatro categorías:
- Tipos enumerados y tipos de "banderas"
- En general, todo tipo enumerado y todo tipo de campo de bits basado en enteros (es decir, todo tipo
enum) que se desee utilizar de alguna manera relacionada con el sistema de objetos —por ejemplo, como el tipo de una propiedad de objeto— debe registrarse en el sistema de tipos. Normalmente, el código de inicialización que se encarga de registrar estos tipos se genera mediante una herramienta automatizada llamada [ 4 ] y se almacena en un archivo aparte.glib-mkenums - Tipos en caja
- Algunas estructuras de datos que son demasiado simples para ser convertidas en tipos de clase completos (con toda la sobrecarga que esto implica) aún pueden necesitar ser registradas en el sistema de tipos. Por ejemplo, podríamos tener una clase a la que queremos agregar una
background-colorpropiedad, cuyos valores deberían ser instancias de una estructura que se ve como . Para evitar tener que crear una subclase de , podemos crear un tipo encapsulado para representar esta estructura y proporcionar funciones para copiar y liberar. GObject incluye un puñado de tipos encapsulados que encapsulan tipos de datos simples de GLib. Otro uso para los tipos encapsulados es como una forma de encapsular objetos externos en un contenedor etiquetado que el sistema de tipos puede identificar y sabrá cómo copiar y liberar.structcolor{intr,g,b;}GObject - Tipos de puntero opacos
- En ocasiones, para objetos que no necesitan ser copiados, ni contar referencias ni liberarse, incluso un tipo encapsulado sería excesivo. Si bien estos objetos pueden usarse en GObject simplemente tratándolos como punteros opacos (
G_TYPE_POINTER), a menudo es buena idea crear un tipo de puntero derivado, documentando el hecho de que los punteros deben hacer referencia a un tipo particular de objeto, aunque no se indique nada más al respecto. - Tipos de clase e interfaz
- La mayoría de los tipos en una aplicación GObject serán clases —en el sentido normal de la palabra orientado a objetos— derivadas directa o indirectamente de la clase raíz
GObject. También hay interfaces que, a diferencia de las interfaces clásicas de estilo Java , pueden contener métodos implementados. Por lo tanto, las interfaces de GObject pueden describirse como mixins .
Sistema de mensajería
El sistema de mensajería GObject consta de dos partes complementarias: cierres y señales .
- Cierres
- Un cierre de GObject es una versión generalizada de una función de devolución de llamada . Se admiten cierres escritos en C y C++, así como en lenguajes arbitrarios (cuando se proporcionan enlaces). Esto permite invocar código escrito en (por ejemplo) Python y Java mediante un cierre de GObject.
- Señales
- Las señales son el mecanismo principal mediante el cual se invocan los cierres. Los objetos registran oyentes de señales en el sistema de tipos, especificando una correspondencia entre una señal y un cierre determinados. Al emitirse una señal registrada, se invoca el cierre correspondiente. En GTK, todos los eventos nativos de la interfaz gráfica de usuario (como el movimiento del ratón y las acciones del teclado) pueden generar señales GObject que los oyentes pueden procesar.
Implementación de clase
Cada clase GObject se implementa mediante al menos dos estructuras: la estructura de clase y la estructura de instancia .
- La estructura de clases
- La estructura de la clase corresponde a la tabla virtual (vtable) de una clase de C++. Debe comenzar con la estructura de la superclase. A continuación, contendrá un conjunto de punteros a funciones , uno por cada método virtual de la clase. Se pueden usar variables específicas de la clase para emular sus miembros.
- La estructura de instancia
- La estructura de instancia, que existirá en una copia por cada instancia de objeto, debe comenzar con la estructura de instancia de la superclase (esto garantiza que todas las instancias comiencen con un puntero a la estructura de la clase, ya que todos los tipos instanciables fundamentales comparten esta propiedad). Después de los datos pertenecientes a la superclase, la estructura puede contener cualquier variable específica de la instancia, correspondiente a las variables miembro de C++.
Definir una clase en el framework GObject es complejo, ya que requiere una gran cantidad de código repetitivo , como definiciones manuales de macros de conversión de tipos e invocaciones de registro de tipos poco claras. Además, dado que una estructura C no puede tener modificadores de acceso como "public", "protected" o "private", se deben usar soluciones alternativas para proporcionar encapsulación . Un enfoque consiste en incluir un puntero a los datos privados ( conocidos convencionalmente como `GType` _priv) en la estructura de instancia. La estructura privada puede declararse en el archivo de encabezado público, pero definirse solo en el archivo de implementación, de modo que los datos privados sean opacos para los usuarios, pero transparentes para el implementador. Si la estructura privada se registra con GType, el sistema de objetos la asignará automáticamente. De hecho, ni siquiera es necesario incluir el _privpuntero si se está dispuesto a usar la invocación G_TYPE_INSTANCE_GET_PRIVATEcada vez que se necesiten los datos privados.
Para abordar algunas de estas complejidades, existen varios lenguajes de alto nivel que compilan de fuente a fuente a GObject en C. El lenguaje de programación Vala utiliza una sintaxis al estilo de C# y se preprocesa en código C estándar . GObject Builder, o GOB2 , ofrece una sintaxis de plantillas que recuerda a Java .
Introspección del objeto
- La introspección de GObject (abreviada GIR [ 5 ] ) es una capa de middleware de interfaz de funciones externas entre las bibliotecas C (que utilizan GObject) y los enlaces de lenguaje, cf. Lista de enlaces de lenguaje para GTK .
Uso
La combinación de C y GObject se utiliza en muchos proyectos de software libre de éxito , como el entorno de escritorio GNOME , el conjunto de herramientas GTK y el programa de manipulación de imágenes GIMP .
Aunque muchas aplicaciones GObject están escritas completamente en C, el sistema GObject se integra perfectamente con los sistemas de objetos nativos de muchos otros lenguajes, como C++ , Java , Ruby , Python , Common Lisp y .NET / Mono . Por lo tanto, suele ser relativamente sencillo crear enlaces de lenguaje para bibliotecas bien escritas que utilizan el framework GObject.
Por ejemplo, muchos programas de Python utilizan bibliotecas escritas en C que usan el marco de trabajo GObject mediante el enlace de lenguaje PyGObject . (Algunos de ellos se enumeran en la categoría: Software que usa PyGObject ).
Escribir código GObject en C es, en primer lugar, bastante laborioso. Aprender la biblioteca lleva bastante tiempo, y a los programadores con experiencia en lenguajes orientados a objetos de alto nivel a menudo les resulta algo tedioso trabajar con GObject en C. Por ejemplo, crear una subclase (incluso una simple subclase de GObject) puede requerir escribir o copiar grandes cantidades de código repetitivo . [ 6 ] Sin embargo, usar Vala , un lenguaje diseñado principalmente para trabajar con GObject y que se convierte a C, probablemente hará que trabajar con GObject o escribir bibliotecas basadas en GObject sea más agradable.
Aunque no son objetos de primera clase (no existen metatipos propiamente dichos en GType), los metaobjetos como clases e interfaces son creados por aplicaciones GObject en tiempo de ejecución y ofrecen un buen soporte para la introspección . Las capacidades de introspección son utilizadas por las bibliotecas de lenguaje y las aplicaciones de diseño de interfaces de usuario, como Glade, para permitir acciones como cargar una biblioteca compartida que proporciona una clase GObject (generalmente algún tipo de widget , en el caso de Glade) y luego obtener una lista de todas las propiedades de la clase, con información de tipo y cadenas de documentación.
Comparaciones con otros sistemas de objetos
Dado que GObject proporciona un sistema de objetos prácticamente completo para C , puede considerarse una alternativa a lenguajes derivados de C como C++ y Objective-C , aunque ambos también ofrecen muchas otras características más allá de sus respectivos sistemas de objetos. Una diferencia fácilmente observable entre C++ y GObject es que GObject (al igual que Java) no admite la herencia múltiple . [ 7 ]
El uso que hace GObject de la función de asignación de memoria g_malloc() de GLib provoca que el programa finalice incondicionalmente al agotarse la memoria, a diferencia de malloc () de la biblioteca C, new de C++ y otros asignadores de memoria comunes que permiten que un programa gestione o incluso se recupere completamente de situaciones de falta de memoria sin simplemente bloquearse. [ 8 ] Esto suele ser un inconveniente para incluir GObject en software donde la resiliencia ante la memoria limitada es importante, o donde se manejan comúnmente muchos objetos o objetos muy grandes. g_try_new() se puede usar cuando es más probable que falle una asignación de memoria (para un objeto grande, por ejemplo), pero esto no garantiza que la asignación no falle en otra parte del código. [ 9 ]
Otra diferencia importante es que, si bien C++ y Objective-C son lenguajes distintos, GObject es estrictamente una biblioteca y, como tal, no introduce ninguna sintaxis nueva ni inteligencia de compilación. Por ejemplo, al escribir código C basado en GObject, suele ser necesario realizar conversiones de tipo explícitas . Por lo tanto, "C con GObject", también llamado "C con sabor a glib", considerado un lenguaje separado del C estándar, es un superconjunto estricto de este último, al igual que Objective-C, pero a diferencia de C++.
En plataformas donde no existe una ABI estándar que funcione en todos los compiladores de C++ (lo cual no suele ser el caso, ya que normalmente se siguen la ABI de Itanium o la de Microsoft), una biblioteca compilada con un compilador de C++ no siempre puede llamar a una biblioteca compilada con otro. Si se requiere dicha compatibilidad, los métodos de C++ deben exportarse como funciones C simples, lo que en parte anula el propósito del sistema de objetos de C++. El problema surge, en parte, porque los distintos compiladores de C++ utilizan diferentes tipos de modificación de nombres para garantizar la unicidad de todos los símbolos exportados. (Esto es necesario porque, por ejemplo, dos clases diferentes pueden tener funciones miembro con el mismo nombre, un nombre de función puede sobrecargarse varias veces o funciones con el mismo nombre pueden aparecer en diferentes espacios de nombres ; sin embargo, en el código objeto, estas superposiciones no están permitidas). En cambio, dado que C no admite ninguna forma de sobrecarga ni de espacios de nombres, los autores de bibliotecas de C suelen utilizar prefijos explícitos para garantizar la unicidad global de sus nombres exportados. Por lo tanto, a pesar de ser orientada a objetos, una biblioteca basada en GObject escrita en C siempre utilizará los mismos nombres de símbolos externos, independientemente del compilador que se utilice.
Quizás la diferencia más profunda radica en el énfasis que GObject pone en las señales (denominadas eventos en otros lenguajes). Este énfasis se debe a que GObject fue diseñado específicamente para satisfacer las necesidades de un kit de herramientas de interfaz gráfica de usuario (GUI). Si bien existen bibliotecas de señales para la mayoría de los lenguajes orientados a objetos, en el caso de GObject, estas están integradas en el sistema de objetos. Por ello, una aplicación típica de GObject tenderá a utilizar señales en mucha mayor medida que una aplicación que no las utilice, lo que hace que los componentes de GObject sean mucho más encapsulados y reutilizables que los que utilizan C++ o Java estándar. Si se utiliza glibmm / gtkmm , las bibliotecas oficiales de C++ para Glib/GTK respectivamente, el proyecto hermano libsigc++ permite un uso sencillo de las señales subyacentes de GObject mediante C++ estándar. Por supuesto, existen otras implementaciones de señales disponibles en casi todas las plataformas, aunque a veces se necesita una biblioteca adicional, como Boost.Signals2 para C++.
Véase también
- Vala : un lenguaje de programación basado en GObject con sintaxis similar a C#. Compilador de código fuente a código fuente para C.
Referencias
- ↑ "2.87.0 · GNOME / GLib · GitLab" . Consultado el 25 de noviembre de 2025 .
- ↑ "Manual de referencia de GObject" .
- ↑ "Manual de referencia de GObject - Estable" .
- ↑ "glib-mkenums, Manual de referencia de GObject" .
- ↑ "Introspección, Resumen" . Gnome Developer, Directrices de programación - Instrucciones específicas . Consultado el 9 de agosto de 2020 .
- ↑ "Cómo definir e implementar un nuevo GObject" . gnome.org . Consultado el 27 de julio de 2013 .
- ↑ "c++ - ¿Por qué se creó el sistema GObject?" . Stack Overflow . Consultado el 16/11/2019 .
- ↑ "Asignación de memoria: Manual de referencia de GLib" . developer.gnome.org . Consultado el 16 de noviembre de 2019 .
- ↑ "Asignación de memoria: Manual de referencia de GLib" . developer.gnome.org . Consultado el 17 de noviembre de 2019 .
Enlaces externos
- Manual de referencia de GObject (y tutorial)
- Tutorial de GObject, agosto de 2004
- GOB2 — el Generador de objetos GObject
- Página principal de Vala
- Bibliotecas de C (lenguaje de programación)
- Bibliotecas informáticas gratuitas
- Software libre programado en C
- Freedesktop.org
- Bibliotecas de GNOME
- GTK