| |
Справочное описание GObject |
---|
Так же как в C++, есть много разных способов определить методы объекта и дополнить их: следующее описание и разделы используют словарь C++. (Ожидается что читатель знает основные базовые термины C++. Те кто давно не писал код на C++ могут обратиться например к http://www.cplusplus.com/doc/tutorial/ чтобы освежить свою память.)
невиртуальные общие методы (non-virtual public methods),
виртуальные общие методы (virtual public methods) и
виртуальные закрытые методы (virtual private methods)
Они являются самыми простыми: вам нужно обеспечить простой метод который может взаимодействовать с вашим объектом. Всё что вам нужно сделать это обеспечить прототип функции в заголовочном файле и реализовать её прототип в исходном файле.
/* декларация в заголовочном файле. */ void maman_bar_do_action (MamanBar *self, /* parameters */); /* реализация в исходном фале */ void maman_bar_do_action (MamanBar *self, /* parameters */) { /* наполнение. */ }
В этом нет ничего страшного.
Это предпочтительный способ создания полиморфных объектов GObjects. Всё что вам нужно сделать это определить основной метод и его классовую функцию в общем заголовке, реализовать основной метод в исходном файле и перереализовать классовую функцию в каждом объекте который вас интересует.
/* декларация в maman-bar.h. */ struct _MamanBarClass { GObjectClass parent; /* наполнение */ void (*do_action) (MamanBar *self, /* параметры */); }; void maman_bar_do_action (MamanBar *self, /* параметры */); /* реализация в maman-bar.c */ void maman_bar_do_action (MamanBar *self, /* параметры */) { MAMAN_BAR_GET_CLASS (self)->do_action (self, /* параметры */); }
Код выше просто переадресует вызов do_action в подходящую классовую функцию. Некоторые пользователи,
заинтересованные в производительности, не обеспечивают maman_bar_do_action
функцию оболочку и требуют чтобы пользователи самостоятельно разыменовывали классовый указатель. Это не очень
хорошая идея в период инкапсуляции и мешает изменять реализацию объекта в последствие.
Другие пользователи, также заинтересованные в производительности, декларируют maman_bar_do_action
функцию inline в заголовочном файле. Это также мешает изменять реализацию объекта в последствие
(хотя проще чем требование от пользователей непосредственного разыменования классовой функции)
и часто сложно написать переносимым способом (ключевое слово inline
не является частью стандарта C).
Сомневайтесь, пока пользователь не показал вам твёрдые цифры о производительности функционального вызова,
по сравнению с простой maman_bar_do_action
в исходном файле.
Пожалуйста, помните что это возможно обеспечит для вас реализованная по умолчанию объектная функция для этого метода класса: инициализируйте поле klass->do_action указателем на фактическую реализацию. Вы можете так же сделать этот метод класса чисто виртуальным инициализировав поле klass->do_action в значение NULL:
static void maman_bar_real_do_action_two (MamanBar *self, /* параметры */) { /* реализация по умолчанию для виртуального метода. */ } static void maman_bar_class_init (BarClass *klass) { /* чисто виртуальный метод: мандаты реализуются в наследниках (children). */ klass->do_action_one = NULL; /* просто виртуальный метод. */ klass->do_action_two = maman_bar_real_do_action_two; } void maman_bar_do_action_one (MamanBar *self, /* параметры */) { MAMAN_BAR_GET_CLASS (self)->do_action_one (self, /* параметры */); } void maman_bar_do_action_two (MamanBar *self, /* параметры */) { MAMAN_BAR_GET_CLASS (self)->do_action_two (self, /* параметры */); }
Это очень похожие на Virtual Public методы. Просто они не имеют общих функций для непосредственного вызова функции. Заголовочный файл содержит только декларацию классовой функции:
/* декларация в maman-bar.h. */ struct _MamanBarClass { GObjectClass parent; /* наполнение */ void (*helper_do_specific_action) (MamanBar *self, /* параметры */); }; void maman_bar_do_any_action (MamanBar *self, /* параметры */);
Эти классовые функции часто используются для делегирования части работы в дочерние классы:
/* статичная функция аксессор: она не экспортируется за пределы этого файла. */ static void maman_bar_do_specific_action (MamanBar *self, /* параметры */) { MAMAN_BAR_GET_CLASS (self)->do_specific_action (self, /* параметры */); } void maman_bar_do_any_action (MamanBar *self, /* параметры */) { /* здесь произвольный код */ /* * Пробуем выполнить требуемое действие. Возможно требуемое действие не может быть реализовано * здесь. Поэтому мы делегируем его реализацию в дочерний класс: */ maman_bar_do_specific_action (self, /* параметры */); /* здесь другой произвольный код */ }
Снова, возможно обеспечить реализацию по умолчанию для этой закрытой виртуальной классовой функции:
static void maman_bar_class_init (MamanBarClass *klass) { /* чисто виртуальный метод: мандаты реализуются в наследниках (children). */ klass->do_specific_action_one = NULL; /* просто виртуальный метод. */ klass->do_specific_action_two = maman_bar_real_do_specific_action_two; }
Наследники могут реализовать подкласс с помощью похожего кода:
static void maman_bar_subtype_class_init (MamanBarSubTypeClass *klass) { MamanBarClass *bar_class = MAMAN_BAR_CLASS (klass); /* реализуем чисто виртуальную функцию класса. */ bar_class->do_specific_action_one = maman_bar_subtype_do_specific_action_one; }
Закладки на сайте Проследить за страницей |
Created 1996-2024 by Maxim Chirkov Добавить, Поддержать, Вебмастеру |