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?

Интерфейсы GType очень похожи на интерфейсы Java. Они позволяют описывать общий API которого будут придерживаться несколько классов. Представьте кнопки play, pause и stop в hifi-оборудовании - они могут рассматриваться как интерфейс воспроизведения. Как только вы поймёте что они значат, вы сможете управлять вашим cd-player, mp3-player или чем угодно использующим эти символы. Для объявления интерфейса вы должны зарегистрировать неинстанциируемый классифицируемый тип который происходит из . Следующая часть кода объявляет такой интерфейс.

#define MAMAN_IBAZ_TYPE                (maman_ibaz_get_type ())
#define MAMAN_IBAZ(obj)                (G_TYPE_CHECK_INSTANCE_CAST ((obj), MAMAN_IBAZ_TYPE, MamanIbaz))
#define MAMAN_IS_IBAZ(obj)             (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MAMAN_IBAZ_TYPE))
#define MAMAN_IBAZ_GET_INTERFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), MAMAN_IBAZ_TYPE, MamanIbazInterface))

typedef struct _MamanIbaz MamanIbaz; /* dummy object */
typedef struct _MamanIbazInterface MamanIbazInterface;

struct _MamanIbazInterface {
  GTypeInterface parent;

  void (*do_action) (MamanIbaz *self);
};

GType maman_ibaz_get_type (void);

void maman_ibaz_do_action (MamanIbaz *self);

Функция интерфейса, maman_ibaz_do_action реализуется довольно простым способом:

void maman_ibaz_do_action (MamanIbaz *self)
{
  MAMAN_IBAZ_GET_INTERFACE (self)->do_action (self);
}

maman_ibaz_get_type регистрирует тип с именем MamanIBaz который наследует G_TYPE_INTERFACE. Все интерфейсы должны быть дочерними G_TYPE_INTERFACE в дереве иерархии.

static void maman_baz_do_action (MamanIbaz *self)
{
  g_print ("Baz implementation of IBaz interface Action.\n");
}


static void
baz_interface_init (gpointer         g_iface,
                    gpointer         iface_data)
{
  MamanIbazInterface *iface = (MamanIbazInterface *)g_iface;
  iface->do_action = maman_baz_do_action;
}

GType 
maman_baz_get_type (void)
{
  static GType type = 0;
  if (type == 0) {
    static const GTypeInfo info = {
      sizeof (MamanBazInterface),
      NULL,   /* base_init */
      NULL,   /* base_finalize */
      NULL,   /* class_init */
      NULL,   /* class_finalize */
      NULL,   /* class_data */
      sizeof (MamanBaz),
      0,      /* n_preallocs */
      NULL    /* instance_init */
    };
    static const GInterfaceInfo ibaz_info = {
      (GInterfaceInitFunc) baz_interface_init,    /* interface_init */
      NULL,               /* interface_finalize */
      NULL          /* interface_data */
    };
    type = g_type_register_static (G_TYPE_OBJECT,
                                   "MamanBazType",
                                   &info, 0);
    g_type_add_interface_static (type,
                                 MAMAN_IBAZ_TYPE,
                                 &ibaz_info);
  }
  return type;
}

Инициализация интерфейса

Первый буфер памяти распределяется для содержания сструктуры интерфейса. Родительская структура интерфейса копируется поверх новой сструктуры интерфейса (родительский интерфейс уже инициализирован в этой точке). Если нет родителя интерфейса, структура интерфейса инициализируется нулями. Затем инициализируются поля g_type и g_instance_type: g_type устанавливается в значение типа наследуемого интерфейса, а g_instance_type устанавливается в значение типа который реализует этот интерфейс.

Наконец, интерфейс наследует функцию base_init и зтем вызывается функция реализации interface_init. Важно понять, что если есть множество реализаций интерфейса, функции base_init и interface_init будут вызваны один раз для каждой инициализируемой реализиции.

Таким образом функции base_init обычно содержат локальную статическую логическую переменную которая гарантирует что тип интерфейса инициализирован только один раз, даже если есть множество реализаций интерфейса:

struct _GInterfaceInfo
{
  GInterfaceInitFunc     interface_init;
  GInterfaceFinalizeFunc interface_finalize;
  gpointer               interface_data;
};

Если вы находите материал об иерархии интерфейса непостежимым, вы правы: он непостежим, но я ничего не могу с этим сделать. Я могу только суммировать то что вы должны знать об интерфейсах:

Процесс описанный выше может быть резюмирован следующим:

Таблица 2. Инициализация интерфейса

Время вызова

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

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

Ремарка

Интерфейсная функция base_init

В интерфейсной vtable

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

Интерфейсная функция interface_init

В интерфейсной vtable

Инициализирует реализацию интерфейса. То есть, инициализирует указатели метода интерфейса в структуре интерфейса в функции реализации.

Уничтожение интерфейса

Когда последний экземпляр инстанциированного типа, зарегистрированного реализацией интерфейса, уничтожен, реализация интерфейса связанная с типом тоже уничтожается с помощью type_iface_vtable_finalize_Wm (в gtype.c).

type_iface_vtable_finalize_Wm вызывает сначала функцию реализации interface_finalize, а зтем функцию наивысшего наследуемого интерфейса base_finalize.

Выше описанный процесс можно резюмировать следующим:

Таблица 3. Уничтожение интерфейса

Время вызова

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

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

интерфейсная функция interface_finalize

В интерфейсной vtable

интерфейсная функция base_finalize

В интерфейсной vtable

Теперь когда вы прочли этот раздел, вы можете забыть про него. Пожалуйста, забудьте так быстро как только возможно.

Интерфейс определяется только одной структурой которая должна содержать структуру в качестве первого элемента. Структура интерфейса, как ожидается, содержит указатели функции методов интерфейса. Это хороший стиль для определения вспомогательных функций для каждого метода интерфейса который просто называют непосредственно методом интерфейса: maman_ibaz_do_action - один из них.

Как только интерфейсный тип зарегистрирован, вы должны зарегистрировать реализации для этих интерфейсов. Функция с именем maman_baz_get_type регистрируется как новый GType с именем MamanBaz который наследует и реализует интерфейс MamanIBaz.

делает запись в систему типов что данный тип также реализует FooInterface (foo_interface_get_type возвращает тип FooInterface). Структура содержит информацию о реализации интерфейса:struct _GInterfaceInfo { GInterfaceInitFunc interface_init; GInterfaceFinalizeFunc interface_finalize; gpointer interface_data; };

Когда инстанциируемый классифицируемый тип регистрируемый при реализации интерфейса создаётся впервые, его структура класса инициализируется процессом описанным в . Как только структура класса инициализирована, функция type_class_init_Wm (реализована в gtype.c) инициализирует реализацию интерфейса связанного с этим типом вызывая type_iface_vtable_init_Wm для каждого интерфейса.

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

Маловероятно (то есть: я не знаю никого кто использует это) что вам потребуются другие более причудливые вещи которые описаны в следующем разделе ().

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

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

GTypeInterface
GTypeInterface
GObject
g_type_add_interface_static
GInterfaceInfo
раздел “Instantiable classed types: objects”
раздел “Interface Destruction”
разделе “Interface Initialization”
g_type_create_instance
g_type_free_instance