Большая часть определения интерфейса уже показана но я чувствую что нужно показать как конкретно создаётся интерфейс. Исходные коды примеров связанных с этим разделом можно найти в исходном пакете документации, в файле sample/interface/maman-ibaz.{h|c}.
Как и раньше, сначала получаем правильный заголовок:
_GET_CLASS макрос называется _GET_INTERFACE и реализуется не с помощью G_TYPE_INSTANCE_GET_CLASS, а с помощью G_TYPE_INSTANCE_GET_INTERFACE.
Тип экземпляра MamanIbaz определён не полностью: он используется просто как абстрактный тип который представляет экземпляр любого объекта реализующего интерфейс.
Реализация самого типа MamanIbaz тривиальна:
maman_ibaz_get_type регистрирует тип в системе типов.
maman_ibaz_do_action разыменовывает структуру класса для доступа к связанным с ней функциям класса и их вызова.
Как только интерфейс определён, его реализация довольно тривиальна. Исходный код, показывающий как это делается для определённого интерфейса IBaz в предыдущем разделе, расположен в sample/interface/maman-baz.{h|c}.
Первый шаг - определяем обычную GType. Здесь мы решили использовать GType которая наследует GObject. Её имя MamanBaz:
baz_interface_init просто инициализирует интерфейсные методы для реализации определённого MamanBaz: maman_baz_do_action не делает ничего полезного но могла бы :)
Предпосылки определения Интерфейса
Для определения что интерфейс требует присутствия других интерфейсов при реализации, GObject вводит понятие предпосылки: возможность связать список необходимых как условие интерфейсов с интерфейсом. Например, если объект A хочет реализовать интерфейс I1, и если интерфейс I1 имеет предпосылку на интерфейс I2, A реализует оба интерфейса I1 и I2.
Механизм описанный выше на практике очень похож на Java, интерфейс I1 дополняется интерфейсом I2. Пример ниже показывает GObject эквивалент:
Код показанный выше добавляет интерфейс MamanIbaz в список предпосылок MamanIbar в то время как код ниже показывает как реализовать оба интерфейса и зарегистрировать их реализацию:
Полный исходный код, показывающий как определить интерфейс MamanIbar который требует MamanIbaz и как реализовать интерфейс MamanIbar, расположен в sample/interface/maman-ibar.{h|c} и sample/interface/maman-bar.{h|c}.
Свойства интерфейса
static void
maman_ibaz_base_init (gpointer g_iface)
{
static gboolean initialized = FALSE;
if (!initialized) {
/* здесь создаём сигналы интерфейса. */
g_object_interface_install_property (g_iface,
g_param_spec_string ("name",
"maman_ibaz_name",
"Name of the MamanIbaz",
"maman",
G_PARAM_READWRITE));
initialized = TRUE;
}
}
Одно замечание - задекларированному свойству не был присвоен целочисленный ID. Причина в том, что целочисленный ID этого свойства используется только внутри методов получения и установки, а так как интерфейс не реализует свойства, нет необходимости привязывать целочисленный ID к свойствам интерфейса.
Этот код похож на обычную которая наследует за исключением некоторых деталей:
maman_ibaz_base_init как ожидается регистрирует интерфейсные сигналы если они есть (позже мы рассмотрим как их использовать). Убедитесь что используете статичную локальную логическую переменную чтобы не выполнять код инициализации дважды (как описано в , base_init выполняется один раз для каждой реализованной инстанциации интерфейса)
Эта функция очень похожа на подобные функции рассматриваемые нами ранее. Единственный интерфейсно-специфичный код представленный здесь это вызов который используется для информирования системы типов что зарегистрированный тип также реализует интерфейс MAMAN_TYPE_IBAZ.
Важно обратить внимание что порядок, в котором реализованные интерфейсы добавляются к основному объекту, не случаен: должна быть вызвана сначала для интерфейсов которые не имеют никаких предпосылок а зтем для остальных.
Начиная с версии glib 2.4, GObject интерфейсы могут также иметь свойства. Декларация свойств интерфейса похожа на декларацию свойств обычных типов GObject как показано в, исключая то, что используется для декларации свойств вместо .
Для включения свойства с именем 'name' типа string в код выше приведённого примера интерфейса maman_ibaz, нам нужно добавить только одну[] строчку в maman_ibaz_base_init[] как показано ниже:
История для конструкторов интерфейса также весьма тривиальна. Конструктор должен задекларировать и определить свойства обычным способом как описано в , за исключением одной мелочи: он должен задекларировать свойства интерфейса используя вместо. Следующий код демонстрирует изменения необходимые в декларации и реализации MamanBaz показанной выше:
[] Это действительно одна строка расширенная на шесть для ясности
[] может также быть вызвана из class_init но её нельзя вызвать после этой точки.