| |
Справочное описание GObject |
---|
В двух предыдущих разделах обсуждались детали Динамической системы типов Glib и её система управления сигналами. Библиотека GObject так же содержит реализацию основного базового типа называемого GObject.
GObject это базовый классифицируемый инстанциируемый тип. Он осуществляет:
Управление памятью с подсчётом ссылок
Создание/уничтожение интерфейсов
Основные свойства объекта с установкой/получением функциональных пар
Лёгкое использование сигналов
Все библиотеки GNOME которые используют систему типов GLib (такие как Gtk+ и GStreamer) наследуют GObject который важно изучить, чтобы понять детально как это работает.
Семейство функций g_object_new
могут использоваться для инстанциации любого GType который наследует основной тип GObject. Все эти функции проверяют класс
и экземпляр сструктуры на правильную инициализацию в системе типов glib и вызывают один за другим метод конструктора класса,
который используется для:
Распределение и очистка памяти с помощью
g_type_create_instance
,
Инициализацию экземпляра объекта с созданными свойствами.
Хотя можно устанавливать класс и члены объекта (кроме полей указывающих на родителей) в нули, некоторые считают хорошей практикой установку явных значений для них.
Объекты которые наследуют GObject позволяют переписывать этот метод создания класса: однако перед этим, они должны привязываться к их родительскому методу конструктора:
GObject* (*constructor) (GType type, guint n_construct_properties, GObjectConstructParam *construct_properties);
Например ниже показано как MamanBar перезаписывает родительский конструктор:
#define MAMAN_TYPE_BAR (maman_bar_get_type ()) #define MAMAN_BAR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MAMAN_TYPE_BAR, MamanBar)) #define MAMAN_BAR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MAMAN_TYPE_BAR, MamanBarClass)) #define MAMAN_IS_BAR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MAMAN_TYPE_BAR)) #define MAMAN_IS_BAR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MAMAN_TYPE_BAR)) #define MAMAN_BAR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MAMAN_TYPE_BAR, MamanBarClass)) typedef struct _MamanBar MamanBar; typedef struct _MamanBarClass MamanBarClass; struct _MamanBar { GObject parent; /* instance members */ }; struct _MamanBarClass { GObjectClass parent; /* class members */ }; /* used by MAMAN_TYPE_BAR */ GType maman_bar_get_type (void); static GObject * maman_bar_constructor (GType type, guint n_construct_properties, GObjectConstructParam *construct_properties) { GObject *obj; { /* Invoke parent constructor. */ MamanBarClass *klass; GObjectClass *parent_class; klass = MAMAN_BAR_CLASS (g_type_class_peek (MAMAN_TYPE_BAR)); parent_class = G_OBJECT_CLASS (g_type_class_peek_parent (klass)); obj = parent_class->constructor (type, n_construct_properties, construct_properties); } /* do stuff. */ return obj; } static void maman_bar_instance_init (GTypeInstance *instance, gpointer g_class) { MamanBar *self = (MamanBar *)instance; /* do stuff */ } static void maman_bar_class_init (gpointer g_class, gpointer g_class_data) { GObjectClass *gobject_class = G_OBJECT_CLASS (g_class); MamanBarClass *klass = MAMAN_BAR_CLASS (g_class); gobject_class->constructor = maman_bar_constructor; } GType maman_bar_get_type (void) { static GType type = 0; if (type == 0) { static const GTypeInfo info = { sizeof (MamanBarClass), NULL, /* base_init */ NULL, /* base_finalize */ maman_bar_class_init, /* class_init */ NULL, /* class_finalize */ NULL, /* class_data */ sizeof (MamanBar), 0, /* n_preallocs */ maman_bar_instance_init /* instance_init */ }; type = g_type_register_static (G_TYPE_OBJECT, "MamanBarType", &info, 0); } return type; }
Если пользователь инстанциирует объект MamanBar с помощью:
MamanBar *bar = g_object_new (MAMAN_TYPE_BAR, NULL);
Если это первая инстанциация такого объекта, функция maman_b_class_init
будет вызвана после любой функции maman_b_base_class_init
.
Это позволит убедиться в том, что структура класса этого нового объекта правильно инициализирована.
Здесь maman_bar_class_init
как ожидается отменит объектные методы класса
и установит собственные. В примере выше, метод конструктора единственный отменённый метод:
он устанавливается в maman_bar_constructor
.
Как только g_object_new
получила ссылку на инициализированную структуру класса, она вызывает свой метод конструктора для создания экземпляра нового объекта.
Затем она просто отменяет maman_bar_class_init
в maman_bar_constructor
, вызывая её позже, потому что была реализована правильно,
она связывается со своим родительским конструктором. Проблема заключается в поиске родительского конструктора.
Метод (используемый в исходном коде GTK+) состоит в том, чтобы сохранить оригинальный конструктор в статической переменной
в maman_bar_class_init
и зтем многократно использовать её из
maman_bar_constructor
. Это вполне возможно и очень просто, но это не очень хороший метод,
предпочтительней использовать функции
g_type_class_peek
и
g_type_class_peek_parent
.
Наконец, попорядку, g_object_constructor
вызывается последней в цепочке.
Эта функция распределяет инстанциированный объектный буфер через
g_type_create_instance
это значит в этой точке вызывается функция instance_init если она зарегистрирована.
После выполнения instance_init, объект полностью инициализирован и должен быть готов ответить на любой пользовательский запрос.
Когда g_type_create_instance
выполнена, g_object_constructor
устанавливает свойства конструкции
(то есть: свойства полученные в g_object_new
)
и возвращается в пользовательский конструктор которому позволяет выполнить подходящую инициализацию экземпляра...
Процессс описанный выше может показаться немного сложным (он действительно усложнён по моему..) но он может быть
резюмирован таблицей ниже, которая описывает
g_object_new
и порядок её вызова.
Таблица 4. g_object_new
Время вызова | Вызываемая функция | Параметры функции | Ремарка |
---|---|---|---|
Первый вызов g_object_new для целевого типа |
функция base_init целевого типа | В дереве иерархии классов из базового типа в целевой тип. base_init вызывается один раз для каждой сструктуры класса. | У меня нет идей как это может использоваться. Если вы знаете хороший работающий пример как используется base_init класса, пожалуйста, сообщите мне. |
Функция class_init целевого типа | В структуре класса целевого типа | Здесь вы должны убедиться что инициализировали или отменили методы класса (то есть, указатели функций связанные с каждым методом класса) и создать сигналы и свойства связанные с вашим объектом. | |
Интерфейсная функция base_init | В интерфейсной vtable | ||
интерфейсная функция interface_init | В интерфейсной vtable | ||
Каждый вызов g_object_new для целевого типа |
Метод конструктора класса целевого типа: GObjectClass->constructor | В экземпляре объекта | Если вам нужно завершить инициализацию объекта после того как все свойства конструкции установлены, отмените метод конструктора и проверьте цепочку объектного родительского класса перед выполнением вашей собственной инициализации. Если сомневаетесь, не переписывайте метод конструктора. |
типовая функция instance_init | В дереве иерархии классов из базового типа в целевой тип. instance_init обеспечивается для каждого типа вызывая для каждого экземпляра сструктуры. | Обеспечьте функцию instance_init для инициализации вашего объекта перед установкой конструкционных свойств. Это предпочтительный способ инициализации экземпляра GObject. Эта функция эквивалентна конструкторам C++. |
Читатели могут быть смущены некоторым обстоятельством в порядке вызова функций:
в то время как, технически, метод классового конструктора вызывается перед
GType функцией instance_init (так как
g_type_create_instance
которая вызывает instance_init вызывается g_object_constructor
которая находится на верхнем уровне
классового метода конструктора и к которому привязываются пользователи), пользовательский код который выполняется в обеспеченном
пользователем конструкторе будет всегда выполняться после
GType функции instance_init, так как конструктор обеспеченный пользователем
должен (вы были предкпреждены) привязываться перед
выполнением чего-либо полезного.
Закладки на сайте Проследить за страницей |
Created 1996-2024 by Maxim Chirkov Добавить, Поддержать, Вебмастеру |