Справочное описание GObject |
---|
Тип, которым манипулирует система типов Glib, намного более общий, чем тот который обычно подразумевается как объектный тип (Object type). Это лучше всего демонстрирует ниже показанная структура и функции используемые для регистрации типа в системе типов.
typedef struct _GTypeInfo GTypeInfo;
struct _GTypeInfo
{
/* interface types, classed types, instantiated types */
guint16 class_size;
GBaseInitFunc base_init;
GBaseFinalizeFunc base_finalize;
/* classed types, instantiated types */
GClassInitFunc class_init;
GClassFinalizeFunc class_finalize;
gconstpointer class_data;
/* instantiated types */
guint16 instance_size;
guint16 n_preallocs;
GInstanceInitFunc instance_init;
/* value handling */
const GTypeValueTable *value_table;
};
GType g_type_register_static (GType parent_type,
const gchar *type_name,
const GTypeInfo *info,
GTypeFlags flags);
GType g_type_register_fundamental (GType type_id,
const gchar *type_name,
const GTypeInfo *info,
const GTypeFundamentalInfo *finfo,
GTypeFlags flags);
g_type_register_static
и
g_type_register_fundamental
являются C функциями, определёнными в gtype.h
и реализованными в gtype.c
которые вы должны использовать для регистрации новых GType
в программной системе типов.
Маловероятно что вам потребуется использовать
g_type_register_fundamental
(вы должны бить Tim Janik, чтобы делать это) но если вам это нужно, последний раздел разъясняет как создаются новые
базовые типы данных.
[2]
Базовые типы данных являются высшим уровнем типов которые не происходят от других типов
в то время как обычные типы происходят из других типов.
После инициализации g_type_init
,
система типов не только инициализирует внутренние сструктуры данных, но и регистрирует множество основных типов:
некоторые из них являются базовыми типами данных. Остальные являются типами полученными из этих базовых типов.
Базовые и небазовые типы данных определяют:
размер класса: поле class_size в GTypeInfo.
функции инициализации класса (C++ конструктор): поля base_init и class_init в GTypeInfo.
функции уничтожения класса (C++ деструктор): поля base_finalize и class_finalize в GTypeInfo.
размер экземпляра (C++ параметр нового): поле instance_size в GTypeInfo.
instanciation policy (C++ тип нового оператора): поле n_preallocs в GTypeInfo.
функции копирования (C++ операторы копирования): поле value_table в GTypeInfo.
флаги характеризующие тип: GTypeFlags.
Базовые типы данных определяются так же набором
GTypeFundamentalFlags
которые хранятся в GTypeFundamentalInfo.
Небазовые типы кроме всего прочего определяются их родителем, который помещается как параметр parent_type в
g_type_register_static
и g_type_register_dynamic
.
Основным обобщением между всеми glib типами (базовыми и небазовыми, классофицированными и неклассофицированными, instantiable и non-instantiable) является то, что ими можно манипулировать через единственный API для копирования и создания типов.
Структура GValue используется как абстрактный контейнер
для всех этих типов. Её упрощенный API (определён в gobject/gvalue.h
) может использоваться для
вызова value_table функций в течение регистрации типа: например
g_value_copy
для копирования содержимого
GValue в другой
GValue. Это подобно назначению в C++,
когда вызывается оператор копирования C++, чтобы по умолчанию побитно модифицировать копию семантики C++/C структур/классов.
Следующий код демонстрирует как можно копировать 64 битное целочисленное,
так же как экземпляр указателя GObject
(код этого примера находится в исходном пакете этой документации в sample/gtype/test.c
):
static void test_int (void)
{
GValue a_value = {0, };
GValue b_value = {0, };
guint64 a, b;
a = 0xdeadbeaf;
g_value_init (&a_value, G_TYPE_UINT64);
g_value_set_uint64 (&a_value, a);
g_value_init (&b_value, G_TYPE_UINT64);
g_value_copy (&a_value, &b_value);
b = g_value_get_uint64 (&b_value);
if (a == b) {
g_print ("Yay !! 10 lines of code to copy around a uint64.\n");
} else {
g_print ("Are you sure this is not a Z80 ?\n");
}
}
static void test_object (void)
{
GObject *obj;
GValue obj_vala = {0, };
GValue obj_valb = {0, };
obj = g_object_new (MAMAN_BAR_TYPE, NULL);
g_value_init (&obj_vala, MAMAN_BAR_TYPE);
g_value_set_object (&obj_vala, obj);
g_value_init (&obj_valb, G_TYPE_OBJECT);
/* g_value_copy's semantics for G_TYPE_OBJECT types is to copy the reference.
This function thus calls g_object_ref.
It is interesting to note that the assignment works here because
MAMAN_BAR_TYPE is a G_TYPE_OBJECT.
*/
g_value_copy (&obj_vala, &obj_valb);
g_object_unref (G_OBJECT (obj));
g_object_unref (G_OBJECT (obj));
}
Важно в выше представленном коде то, что точная семантика вызова копирования не определена так как зависит от реализации функции копирования. Определённые функции копирования могут решить распределить новый участок памяти и зтем скопировать данные из источника в адресат. Другие могут просто увеличить количество ссылок на экземпляр и скопировать ссылку в новый GValue.
value_table определённый в gtype.h
используется
для определения этих функций и полностью описан в документации API поставляемой с
GObject (for once ;-) это объясняет почему мы не будем детализировать точную семантику.
typedef struct _GTypeValueTable GTypeValueTable;
struct _GTypeValueTable
{
void (*value_init) (GValue *value);
void (*value_free) (GValue *value);
void (*value_copy) (const GValue *src_value,
GValue *dest_value);
/* varargs functionality (optional) */
gpointer (*value_peek_pointer) (const GValue *value);
gchar *collect_format;
gchar* (*collect_value) (GValue *value,
guint n_collect_values,
GTypeCValue *collect_values,
guint collect_flags);
gchar *lcopy_format;
gchar* (*lcopy_value) (const GValue *value,
guint n_collect_values,
GTypeCValue *collect_values,
guint collect_flags);
};
Маловероятно что вы будете когда либо определять value_table в процессе регистрации типа потому что value_tables наследуется из родительского типа для небазовых типов, это значит что если вы хотите создать базовый тип (не очень хорошая идея!), вам не потребуется обеспечить новый value_table так как вы унаследуете структуру value_table из родителя вашего типа.
[2]
Пожалуйста помните что есть другие функции регистрации:
g_type_register_dynamic
.
Мы не будем обсуждать эту функцию здесь, так как её использование очень похоже на версию _static
.