|  |  |  | Справочное описание 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, так как конструктор обеспеченный пользователем 
      должен (вы были предкпреждены) привязываться перед
      выполнением чего-либо полезного.