Неинстанциированные классифицированные типы: Интерфейсы.
Last updated
Was this helpful?
Last updated
Was this helpful?
Интерфейсы GType очень похожи на интерфейсы Java. Они позволяют описывать общий API которого будут придерживаться несколько классов. Представьте кнопки play, pause и stop в hifi-оборудовании - они могут рассматриваться как интерфейс воспроизведения. Как только вы поймёте что они значат, вы сможете управлять вашим cd-player, mp3-player или чем угодно использующим эти символы. Для объявления интерфейса вы должны зарегистрировать неинстанциируемый классифицируемый тип который происходит из . Следующая часть кода объявляет такой интерфейс.
Функция интерфейса, maman_ibaz_do_action
реализуется довольно простым способом:
maman_ibaz_get_type
регистрирует тип с именем MamanIBaz который наследует G_TYPE_INTERFACE. Все интерфейсы должны быть дочерними G_TYPE_INTERFACE в дереве иерархии.
Первый буфер памяти распределяется для содержания сструктуры интерфейса. Родительская структура интерфейса копируется поверх новой сструктуры интерфейса (родительский интерфейс уже инициализирован в этой точке). Если нет родителя интерфейса, структура интерфейса инициализируется нулями. Затем инициализируются поля g_type и g_instance_type: g_type устанавливается в значение типа наследуемого интерфейса, а g_instance_type устанавливается в значение типа который реализует этот интерфейс.
Наконец, интерфейс наследует функцию base_init
и зтем вызывается функция реализации interface_init
. Важно понять, что если есть множество реализаций интерфейса, функции base_init
и interface_init
будут вызваны один раз для каждой инициализируемой реализиции.
Таким образом функции base_init обычно содержат локальную статическую логическую переменную которая гарантирует что тип интерфейса инициализирован только один раз, даже если есть множество реализаций интерфейса:
Если вы находите материал об иерархии интерфейса непостежимым, вы правы: он непостежим, но я ничего не могу с этим сделать. Я могу только суммировать то что вы должны знать об интерфейсах:
Процесс описанный выше может быть резюмирован следующим:
Таблица 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
вызываются только один раз для уничтожения каждой реализации интерфейса. Таким образом, если вы используете одну из этих функций, вы должны использовать статическую целочисленную переменную которая должна считать количество экземпляров реализации интерфейса чтобы класс интерфейса был уничтожен только один раз (когда целочисленная переменная достигает нуля).
Последний вызов для типовой реализации интерфейса