Как определять и реализовывать Интерфейсы?
Как определять Интерфейсы?
Большая часть определения интерфейса уже показана “Non-instantiable classed types: Interfaces.” но я чувствую что нужно показать как конкретно создаётся интерфейс. Исходные коды примеров связанных с этим разделом можно найти в исходном пакете документации, в файле sample/interface/maman-ibaz.{h|c}.
Как и раньше, сначала получаем правильный заголовок:
#ifndef MAMAN_IBAZ_H
#define MAMAN_IBAZ_H
#include <glib-object.h>
#define MAMAN_TYPE_IBAZ (maman_ibaz_get_type ())
#define MAMAN_IBAZ(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MAMAN_TYPE_IBAZ, MamanIbaz))
#define MAMAN_IS_IBAZ(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MAMAN_TYPE_IBAZ))
#define MAMAN_IBAZ_GET_INTERFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), MAMAN_TYPE_IBAZ, MamanIbazInterface))
typedef struct _MamanIbaz MamanIbaz; /* макет объекта */
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);
#endif /*MAMAN_IBAZ_H*/Этот код похож на обычную GType которая наследует GObject за исключением некоторых деталей:
_GET_CLASSмакрос называется_GET_INTERFACEи реализуется не с помощьюG_TYPE_INSTANCE_GET_CLASS, а с помощьюG_TYPE_INSTANCE_GET_INTERFACE.Тип экземпляра MamanIbaz определён не полностью: он используется просто как абстрактный тип который представляет экземпляр любого объекта реализующего интерфейс.
Реализация самого типа MamanIbaz тривиальна:
maman_ibaz_get_typeрегистрирует тип в системе типов.maman_ibaz_base_initкак ожидается регистрирует интерфейсные сигналы если они есть (позже мы рассмотрим как их использовать). Убедитесь что используете статичную локальную логическую переменную чтобы не выполнять код инициализации дважды (как описано в “Interface Initialization”,base_initвыполняется один раз для каждой реализованной инстанциации интерфейса)maman_ibaz_do_actionразыменовывает структуру класса для доступа к связанным с ней функциям класса и их вызова.
Как определить реализацию Интерфейса?
Как только интерфейс определён, его реализация довольно тривиальна. Исходный код, показывающий как это делается для определённого интерфейса IBaz в предыдущем разделе, расположен в sample/interface/maman-baz.{h|c}.
Первый шаг - определяем обычную GType. Здесь мы решили использовать GType которая наследует GObject. Её имя MamanBaz:
В этом заголовке нет ничего сверхъестественного или страшного: он не определяет никакого особенного API и не наследует особенный тип.
Второй шаг - реализация maman_baz_get_type:
Эта функция очень похожа на подобные функции рассматриваемые нами ранее. Единственный интерфейсно-специфичный код представленный здесь это вызов g_type_add_interface_static который используется для информирования системы типов что зарегистрированный тип GType также реализует интерфейс MAMAN_TYPE_IBAZ.
baz_interface_init, функция инициализации интерфейса, она тоже очень проста:
baz_interface_init просто инициализирует интерфейсные методы для реализации определённого MamanBaz: maman_baz_do_action не делает ничего полезного но могла бы :)
Предпосылки определения Интерфейса
Для определения что интерфейс требует присутствия других интерфейсов при реализации, GObject вводит понятие предпосылки: возможность связать список необходимых как условие интерфейсов с интерфейсом. Например, если объект A хочет реализовать интерфейс I1, и если интерфейс I1 имеет предпосылку на интерфейс I2, A реализует оба интерфейса I1 и I2.
Механизм описанный выше на практике очень похож на Java, интерфейс I1 дополняется интерфейсом I2. Пример ниже показывает GObject эквивалент:
Код показанный выше добавляет интерфейс MamanIbaz в список предпосылок MamanIbar в то время как код ниже показывает как реализовать оба интерфейса и зарегистрировать их реализацию:
Важно обратить внимание что порядок, в котором реализованные интерфейсы добавляются к основному объекту, не случаен: g_type_add_interface_static должна быть вызвана сначала для интерфейсов которые не имеют никаких предпосылок а зтем для остальных.
Полный исходный код, показывающий как определить интерфейс MamanIbar который требует MamanIbaz и как реализовать интерфейс MamanIbar, расположен в sample/interface/maman-ibar.{h|c} и sample/interface/maman-bar.{h|c}.
Свойства интерфейса
Начиная с версии glib 2.4, GObject интерфейсы могут также иметь свойства. Декларация свойств интерфейса похожа на декларацию свойств обычных типов GObject как показано в“Object properties”, исключая то, что g_object_interface_install_property используется для декларации свойств вместо g_object_class_install_property.
Для включения свойства с именем 'name' типа string в код выше приведённого примера интерфейса maman_ibaz, нам нужно добавить только одну[14] строчку в maman_ibaz_base_init[15] как показано ниже:
Одно замечание - задекларированному свойству не был присвоен целочисленный ID. Причина в том, что целочисленный ID этого свойства используется только внутри методов получения и установки, а так как интерфейс не реализует свойства, нет необходимости привязывать целочисленный ID к свойствам интерфейса.
История для конструкторов интерфейса также весьма тривиальна. Конструктор должен задекларировать и определить свойства обычным способом как описано в the section called “Object properties”, за исключением одной мелочи: он должен задекларировать свойства интерфейса используя g_object_class_override_property вместоg_object_class_install_property. Следующий код демонстрирует изменения необходимые в декларации и реализации MamanBaz показанной выше:
[14] Это действительно одна строка расширенная на шесть для ясности
[15] g_object_interface_install_property может также быть вызвана из class_init но её нельзя вызвать после этой точки.
Last updated
Was this helpful?