GLib
  • Initial page
  • I. Концепция
    • Background
    • Типы данных и программирование
  • Динамическая система типов Glib
    • Введение
    • Функции копирования
    • Соглашения
    • Неинстанциируемые не классифицированные базовые типы
    • Инстанциируемые классифицируемые типы: объекты
    • Неинстанциированные классифицированные типы: Интерфейсы.
  • Основной класс GObject
    • Введение
    • Инстанциация объекта
    • Объектное управление памятью
    • Свойства объекта
  • Система сообщений GObject
    • Замыкания
    • Сигналы
  • II. Описание API
    • GType
    • GTypePlugin
    • GTypeModule
    • GObject часть 1
    • GObject часть 2
    • Enums and Flags
    • GBoxed
    • Generic Values
    • Parameters and Values часть 1
    • Parameters and Values часть 2
    • Parameters and Values часть 3, ага
    • Value arrays
  • III. Описание инструментов
    • glib-mkenums
    • glib-genmarshal
    • gobject-query
  • IV. Руководство
    • Как определить и реализовать новый GObject?
    • Объектные методы
    • Как определять и реализовывать Интерфейсы?
    • Как создавать и использовать сигналы
    • Как пользователи могут злоупотреблять сигналами (и почему некоторые думают что это хорошо)
  • V. Об инструментах
    • Об инструментах
  • GTK 4
    • GtkApplication и GtkApplicationWindow
    • Widgets
Powered by GitBook
On this page

Was this helpful?

  1. Динамическая система типов Glib

Инстанциируемые классифицируемые типы: объекты

PreviousНеинстанциируемые не классифицированные базовые типыNextНеинстанциированные классифицированные типы: Интерфейсы.

Last updated 6 years ago

Was this helpful?

Типы которые регистрируются с классом и объявляются инстанциированными очень похожи на объекты object. Хотя s (детали в ) самый известный тип инстанциированного классифицированного типа, другие виды подобных объектов используемых как основа иерархии наследования была внешней разработкой и они все основаны на базовых особенностях описанных ниже.

Например, код показанный ниже демонстрирует как вы должны регистрировать такие базовые типовые объекты в системе типов:

typedef struct {
  GObject parent;
  /* instance members */
  int field_a;
} MamanBar;

typedef struct {
  GObjectClass parent;
  /* class members */
  void (*do_action_public_virtual) (MamanBar *self, guint8 i);

  void (*do_action_public_pure_virtual) (MamanBar *self, guint8 i);
} MamanBarClass;

#define MAMAN_BAR_TYPE (maman_bar_get_type ())

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 */
      (GClassInitFunc) foo_class_init,
      NULL,           /* class_finalize */
      NULL,           /* class_data */
      sizeof (MamanBar),
      0,              /* n_preallocs */
      (GInstanceInitFunc) NULL /* instance_init */
    };
    type = g_type_register_static (G_TYPE_OBJECT,
                                   "BarType",
                                   &info, 0);
  }
  return type;
}

После первого вызова maman_bar_get_type, тип с именем BarType будет зарегистрирован в системе типов как наследник типа G_TYPE_OBJECT.

struct _GTypeClass
{
  GType g_type;
};
struct _GTypeInstance
{
  GTypeClass *g_class;
};

Эти ограничения позволяют системе типов удостовериться в том, что каждый экземпляр объекта (идентифицируемый указателем на экземпляр объектной сструктуры) содержит в первом байте указатель на структура класса объекта.

Эти взаимоотношения лучше демонстрируются примером: давайте возьмём объект B который наследуется из объекта A:

/* A definitions */
typedef struct {
  GTypeInstance parent;
  int field_a;
  int field_b;
} A;
typedef struct {
  GTypeClass parent_class;
  void (*method_a) (void);
  void (*method_b) (void);
} AClass;

/* B definitions. */
typedef struct {
  A parent;
  int field_c;
  int field_d;
} B;
typedef struct {
  AClass parent_class;
  void (*method_c) (void);
  void (*method_d) (void);
} BClass;

C стандартом принято что первое поле C сструктуры начинается в первом байте буфера используемого для содержания структурных полей в памяти. Это значит что первое поле экземпляра объекта B - это первое поле A's которое в свою очередь является первым полем GTypeInstance's которая в свою очередь является g_class, указанным в структуре класса B's.

Благодаря этим условиям, возможно определить тип каждого объекта выполнив:

B *b;
b->parent.parent.g_class->g_type

или, намного быстрее:

B *b;
((GTypeInstance*)b)->g_class->g_type

Инициализация и Уничтожение

GTypeInstance* g_type_create_instance (GType          type);
void           g_type_free_instance   (GTypeInstance *instance);

Например, если объект B который происходит из A инстанциирован, GType только вызовет instance_init объекта B, в то время как C++ окружение вызовет конструктор объекта A первым, а зтем типового объекта B. Кроме того, C++ код эквивалентный base_init и class_init callback-функциям GType обычно не необходим, потому что C++ не может создавать типовые объекты во время выполнения.

Процесс инстанциирования/завершения можно резюмировать следующим:

Таблица 1. GType Instantiation/Finalization

Время вызова

Вызываемая функция

Параметры функции

типовая функция base_init

В дереве наследования класса из базового типа для целевого типа. base_init вызывается один раз для каждой структуры класса.

функция целевого типа class_init

В структуре класса целевого типа

функция instance_init целевого типа

В экземпляре объекта

функция class_finalize целевого типа

В структуре класса целевого типа

типовая функция base_finalize

В дереве наследования классов из базового типа в целевой тип. base_finalize вызывается один раз для каждой структуры класса.

Каждый объект должен определяться двумя структурами: структурой класса и структурой объекта. Все сструктуры класса должны содержать в качестве первого члена. Все сструктуры объекта должны содержать структуру в качестве первого члена. Декларация этих C типов, взята из gtype.h, показана ниже:

Инстанциирование этих типов может быть выполнено с помощью :

ищет информационную структуру типа связанную с запрошенным типом. Затем, размер экземпляра и инстанциируемую политику (если поле n_preallocs установлено не в нулевое значение, система типов распределяет экземпляр сструктуры объекта в участок памяти вместо распределения каждого экземпляра) объявленную пользователем используемую для получения буфера содержащего экземпляр объектной сструктуры.

Если это первое инстанциирование создаваемого объекта, система типов должна создать структуру класса: это распределит буфер содержащий структуру объектного класса и инициализирует его. Сначала копируется родительская структура класса поверх этой сструктуры (если нет родителя, инициализируется нулём). Затем вызываются функции base_class_initialization () от самого высшего базового объекта до самого низшего объекта. Объектная функция class_init () вызывается впоследствии, завершая инициализацию сструктуры класса. Наконец, инициализируется интерфейс объекта (позже мы обсудим инициализацию интерфейса более детально). []

Как только система типов получает указатель на инициализированную структуру класса, она устанавливает указатель экземпляра объектного класса в структуру объектного класса и вызывает объектные функции instance_init (), из самого высшего базового типа до самого низшего типа.

Уничтожается объект через очень просто: экземпляр сструктуры возвращается в пул если существует, и если это был последний уничтоженный экземпляр объекта, класс уничтожается.

Уничтожение класса [] (понятие уничтожение иногда описывается как завершение (finalization) в GType) это симметричный процесс инициализации: интерфейсы уничтожаются первыми. Затем, вызывается функция class_finalize (ClassFinalizeFunc). Наконец вызываются функции base_class_finalize () от самого низшего типа до самого высшего базового типа и структура класса освобождается.

Как многие читатели поняли, основы процесса инициализации/завершения очень похожи на парадигму C++ Constructor/Destructor. Практически различия в деталях, хотя это не важно при внешнем сходстве. Обычно, большинству пользователей достаточно знать что C++ constructor (то есть, список методов объекта вызывается в экземпляре объекта один раз для каждого типа иерархии наследования) не существует в GType и должны основываться на предлагаемых особенностях GType. Аналогично, GTypes не имеет механизма деструкции. Ответственность за правильную семантику уничтожения существующего кода GType, лежит на пользователе. (это то что делает GObject. Смотрите )

Первый вызов для целевого типа

инициализация интерфейса, смотрите

Каждый вызов для целевого типа

Последний вызов для целевого типа

уничтожение интерфейса, смотрите

GObject
The GObject base class
GTypeClass
GTypeInstance
g_type_create_instance
g_type_create_instance
GBaseInitFunc
GClassInitFunc
4
GInstanceInitFunc
g_type_free_instance
5
GBaseFinalizeFunc
The GObject base class
g_type_create_instance
раздел с названием “Interface Initialization”
g_type_create_instance
g_type_free_instance
раздел с названием “Interface Destruction”