LINUX.ORG.RU

Расскажите, пожалуйста, про GObject

 


0

2

Первая мысль, которая возникает - неплохо было бы рассмотреть его исходник, это сразу бы многое прояснило.

И уже на первой строчке сталкиваюсь с непонятным, цитирую «Signal Library». Ну, слово Library понятно. А вот сигналы - нет. Это те же самые сигналы, которые имеются в виду в утилите командной строки kill, или это другие сигналы, относящиеся только к потрохам GLib? Что общего между теми и этими сигналами? Имеет ли всё это какое-либо отношение к DBus?

Дальше всё понятно до 20-ой строки. Где прочитать зачем, как и почему делают проверки на непрямое включение? Т.е. понятно, что этими тремя строками рекомендуют в коде писать #include <glib-object.h> вместо #include <gobject.h>. Но неясно, зачем так сделали.

После слова «G_BEGIN_DECLS» желание читать пропадает совсем, совершенно. И возникает желание начать с какой-нибудь книжки-учебника. Но беда в том, что учебники все написаны на уровне бла-бла, без конкретики.

Можно ли сказать, что сигналы это как Event-ы в C# ?

Signals ... are a per-type facility

Чем типы в GLib отличаются от классов в GLib ?

All handlers may prematurely stop a signal emission, and any number of handlers may be connected, disconnected, blocked or unblocked during a signal emission.

Что такое «blocked»/«unblocked»? Вот сложно было авторам статьи вставить гиперссылку?

If you are connecting handlers to signals and using a GObject instance as your signal handler user data

То же самое. Концепция «user data» не объяснена, а читатель должен сам себе вообразить, что же это такое и как это используется. Была бы гиперссылка на отдельную страницу с объяснениями - не было бы вопросов.

Почитаем туториал, как написать наследника GObject.
Доходим до непонятного слова G_BEGIN_DECLS, под ним есть гиперссылка. Ликуем. Переходим. Читаем

Not Found

The requested URL /gobject/glib-Miscellaneous-Macros.html was not found on this server.
Apache/2.2.15 (Red Hat) Server at developer.gnome.org Port 80
Материмся.

Правильно ли я понимаю, что разница между G_DECLARE_FINAL_TYPE и G_DECLARE_DERIVABLE_TYPE на самом деле не в том, static они, final или sealed, а в том, что DERIVABLE есть таблица виртуальных методов, а в FINAL такой таблицы нет?

Поищем эти слова в типовой Gtk-программе:
https://github.com/freeciv/freeciv/search?q=G_DECLARE_FINAL_TYPE
https://github.com/freeciv/freeciv/search?q=G_DECLARE_DERIVABLE_TYPE

Таких слов там нет. Как так?

Доходим до непонятного слова G_BEGIN_DECLS

Используется (наряду с G_END_DECLS) для ограничения (bracket) заголовочных файлов. Если используемый компилятор это C++ компилятор, добавляется extern «C» рядом с заголовком.

http://www.opennet.ru/docs/RUS/glib_api/glib-Miscellaneous-Macros.html (в этой доке ещё много интересного есть).

Но в общем, не совсем честно ожидать от имитации ООП на процедурном языке лёгкой читаемости кода. Нужно что-то более читаемое — добро пожаловать в кресты (можно сразу кутями заправить). Если же нужен именно GObject — просто надо смириться, что «так здесь принято».

hobbit ★★★★★ ()
Последнее исправление: hobbit (всего исправлений: 1)
Ответ на: комментарий от Im_not_a_robot

Элементарно Ватсон: таково может быть требование заказчика/родительского проекта, а задача описывается именно в терминах ООП (оконный GUI, например, именно таков по природе). Может, человеку нужно писать на Си, но работать со строками в стиле strcpy он не хочет.

В случае ТСа, полагаю, лучше спросить его самого :)

hobbit ★★★★★ ()
Ответ на: комментарий от hobbit

Это всё лирика. Почему объектная модель в FreeCiv сделана не на GObject-ах? Ну, всякие там юниты, клетки на карте, города. Из-за этого их нельзя использовать во всяких других языках.

Einstok_Fair ★★ ()
Ответ на: комментарий от akk

Это какие-то самые начала. А нужно ещё продолжение. Про события, про капсулы, про замыкания, про подсчёт ссылок, и всё на простых жизненных примерах.

Мне что-то подсказывает, что так не делают из-за эпического объёма кода. Может какие-нибудь компиляторы (транспиляторы) таким занимаются? Ну, из Vala, например.

Einstok_Fair ★★ ()
Последнее исправление: Einstok_Fair (всего исправлений: 1)
Ответ на: комментарий от Im_not_a_robot

Потому что overhead. Си хорош там, где не нужны объекты, потому что количество объектов одного типа(класса) редко превышает одного.

Нет, я считаю что GUI надо писать на крестах исключительно. Потому что как раз всяких кнопочек очень много. Видать поэтому и создали такое убожество в виде GLib, пытаясь насиловать красивый, но неподходящий для GUI, язык.

a1batross ★★★★★ ()
Последнее исправление: a1batross (всего исправлений: 1)

Первая мысль, которая возникает - неплохо было бы рассмотреть его исходник

Боюсь представить, какие мысли тебе придут в голову, когда ты заинтересуешься плюсами. Полагаю, ты первым делом полезешь в исходники libg++.

Ну, слово Library понятно. А вот сигналы - нет. Это те же самые сигналы, которые имеются в виду в утилите командной строки kill, или это другие сигналы, относящиеся только к потрохам GLib?

Нет, общее только название. Это просто удобная возможность для реализации событийно-ориентированной парадигмы:

g_signal_connect(my_button, "clicked", my_func, my_arg);

Теперь при нажатии на my_button будет вызываться функция my_func, которой будет передаваться аргумент my_arg.

Где прочитать зачем, как и почему делают проверки на непрямое включение?

Нигде не надо делать никаких проверок. Просто подключай glib-object.h напрямую, а не какие-то отдельные хёдеры из состава glib, иначе потратишь кучу времени на выяснение, что ещё нужно подключить, чтобы это хотя бы скомпилировалось. Так что в современных версиях glib ввели проверку, которая не позволяет подключать хёдеры по одному, только оптом.

Чем типы в GLib отличаются от классов в GLib ?

Типы - инстанцируемые объекты, классы - их родовые структуры, которые содержат набор виртуальных функций. Ты пользуешься объектами, классы нужны обычно только для наследования от существующих типов и переопределения каких-то виртуальных функций. Для каждого типа, который ты можешь инстанцировать, при создании первого экземпляра создаётся экземпляр его класса. Класс существует в одном экземпляре для всех объектов этого типа.

Концепция «user data» не объяснена, а читатель должен сам себе вообразить, что же это такое и как это используется.

Это просто указатель на произвольные данные, которые можно передать обработчику сигнала. Можно передать NULL.

Доходим до непонятного слова G_BEGIN_DECLS

G_BEGIN_DECLS раскладывается в банальное extern «C» {. Используется для совместимости с компиляторами C++.

Правильно ли я понимаю, что разница между G_DECLARE_FINAL_TYPE и G_DECLARE_DERIVABLE_TYPE на самом деле не в том, static они, final или sealed, а в том, что DERIVABLE есть таблица виртуальных методов, а в FINAL такой таблицы нет?

Вроде того. FINAL_TYPE - упрощённая реализация, от которой нельзя наследоваться. Поэтому и виртуальные функции она вводить не может, только переопределять существующие в родительском классе.

Поищем эти слова в типовой Gtk-программе

По ссылке не ходил, но эти макросы появились относительно недавно. Они, в свою очередь, раскладываются на кучу кода вида:

#define FOO_BAR(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj), FOO_TYPE_BAR, FooBar))
#define FOO_BAR_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST ((klass), FOO_TYPE_BAR, FooBarClass))
#define FOO_IS_BAR(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj), FOO_TYPE_BAR))
#define FOO_IS_BAR_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), FOO_TYPE_BAR))
#define FOO_BAR_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), FOO_TYPE_BAR, FooBarClass))

typedef struct FooBar_         FooBar;
typedef struct FooBarClass_    FooBarClass;
typedef struct FooBarPrivate_  FooBarPrivate;
В старых программах вручную всю эту лапшу писали. Сейчас в этом нет необходимости.

meliafaro ★★★★ ()
Ответ на: комментарий от Einstok_Fair

Это какие-то самые начала.

Ты точно читал эти статьи? Ты задаешь кучу бестолковых вопросов, которые вообще-то расписаны в документации. Может, стоит начать с «самых начал», тогда и многие вопросы отпадут?

Про события

Это ты где откопал? Нет в GObject специального понятия события. Событие - это просто событие, в самом прямом смысле. На кнопку нажали, окошко закрыли, файл был изменён, и т. д. Соответствующий объект издаёт сигнал, который ты можешь обработать.

про капсулы

Што. Мы точно об одном и том же GObject?

так не делают из-за эпического объёма кода

Какого такого эпического?


/* базовые макросы */
#define FOO_TYPE_BAR (foo_bar_get_type())
G_DECLARE_FINAL_TYPE (FooBar, foo_bar, FOO, BAR, GObject)

/* объявление метода */
foo_bar_my_method(FooBar* self, void* some_data);

/* объявление самой инстанции */
struct _FooBar
{
    GObject parent;
    void* some_incapsulated_data;
}

/* ещё один макрос, обычно в .c-файле с реализацией */
G_DEFINE_TYPE (FooBar, foo_bar, G_TYPE_OBJECT)

/* конструктор */
foo_bar_init(FooBar* self)
{
}

/* реализация метода */
foo_bar_my_method(FooBar* self, void* some_data)
{
}
meliafaro ★★★★ ()
Ответ на: комментарий от hobbit

Но в общем, не совсем честно ожидать от имитации ООП на процедурном языке лёгкой читаемости кода.

Прямо даже не знаю, с чего начать.

от имитации ООП

Полноценного ООП, никакой имитации. С удовольствием поддержу конструктивную полемику на эту тему, разумеется, при наличие у оппонентов внятной аргументации.

на процедурном языке

То есть уже язык определяет парадигму?

лёгкой читаемости кода

Это, я полагаю, стоит интерпретировать как «лёгкой читаемости кода для людей, знакомых лишь с приёмами ООП, типичными для С++-подобных языков»?

Нужно что-то более читаемое — добро пожаловать в кресты (можно сразу кутями заправить)

Зачем так безапелляционно рассуждать на тему, в которой не хватает знания матчасти? В целом подход GObject гораздо более читаемый, чем плюсовый. Я бы сказал, он более многословный и избыточный в плане информативности. Но чаще всего такой код читать проще. Если объект наследуется в седьмом поколении, явное указание типа куда как более читабельно, чем вызов у объекта какого-то метода, неизвестно от какого именно суперкласса унаследованного.

meliafaro ★★★★ ()
Ответ на: комментарий от meliafaro

С удовольствием поддержу конструктивную полемику на эту тему, разумеется, при наличие у оппонентов внятной аргументации.

Ну во-первых, признаю, что со словом «имитация» я несколько погорячился. Да, то полноценное ООП, но поскольку встроенных средств в языке нет, оно действительно выглядит очень многословно.

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

Если объект наследуется в седьмом поколении, явное указание типа куда как более читабельно, чем вызов у объекта какого-то метода, неизвестно от какого именно суперкласса унаследованного.

Вот это весомый аргумент, да.

hobbit ★★★★★ ()

Если не троллишь, то достаточно прочитать https://developer.gnome.org/gobject/2.56/. Там всё подробно объяснено.

Это те же самые сигналы, которые имеются в виду в утилите командной строки kill, или это другие сигналы, относящиеся только к потрохам GLib?

https://developer.gnome.org/gobject/2.56/signal.html : «GObject's signals have nothing to do with standard UNIX signals: they connect arbitrary application-specific events with any number of listeners...»

Чем типы в GLib отличаются от классов в GLib ?

Классы - подмножество типов. https://developer.gnome.org/gobject/2.56/chapter-gtype.html

Правильно ли я понимаю, что разница между G_DECLARE_FINAL_TYPE и G_DECLARE_DERIVABLE_TYPE на самом деле не в том, static они, final или sealed, а в том, что DERIVABLE есть таблица виртуальных методов, а в FINAL такой таблицы нет

Нет своих виртуальных методов. Таблица виртуальных методов совпадает с таковой базового класса.

monk ★★★★★ ()

Тред не читал, но есть glibmm на плюсах. В большинстве случаев, всё на плюсах, но некоторые функции таки приходится дёргать из glib напрямую

UVV ★★★★★ ()