Объектная система GLib или GObject — это библиотека свободного программного обеспечения , обеспечивающая переносимую объектную систему и прозрачную межъязыковую совместимость. GObject предназначен для использования как непосредственно в программах C для предоставления объектно-ориентированных API на основе C, так и через привязки к другим языкам для обеспечения прозрачного межъязыкового взаимодействия, например PyGObject .
В зависимости только от GLib и libc , GObject является краеугольным камнем GNOME и используется в GTK , Pango , ATK и большинстве библиотек GNOME более высокого уровня, таких как GStreamer и приложения. До GTK+ 2.0 код, похожий на GObject, был частью кодовой базы GTK. (Имя «GObject» еще не использовалось — назывался общий базовый класс GtkObject
.)
В выпуске GTK+ 2.0 объектная система была выделена в отдельную библиотеку из-за ее общей полезности. В процессе большинство частей класса, не связанных с графическим интерфейсомGtkObject
, были перенесены в GObject
новый общий базовый класс. Существуя как отдельная библиотека с 11 марта 2002 г. (дата выпуска GTK+ 2.0), библиотека GObject теперь используется многими программами без графического интерфейса, такими как приложения командной строки и серверные приложения.
Хотя GObject имеет свой собственный отдельный набор документации [1] и обычно компилируется в собственный файл общей библиотеки , исходный код GObject находится в дереве исходного кода GLib и распространяется вместе с GLib. По этой причине GObject использует номера версий GLib и обычно упаковывается вместе с GLib (например, Debian помещает GObject в свое libglib2.0
семейство пакетов).
На самом базовом уровне инфраструктуры GObject лежит универсальная и динамическая система типов, называемая GType. Система GType содержит описание всех объектов во время выполнения, что позволяет связующему коду облегчить привязку нескольких языков. Система типов может обрабатывать любую структуру классов , унаследованную отдельно , в дополнение к неклассифицированным типам, таким как непрозрачные указатели , строки , а также целые числа различного размера и числа с плавающей запятой .
Система типов умеет копировать, присваивать и уничтожать значения, принадлежащие любому из зарегистрированных типов. Это тривиально для таких типов, как целые числа, но многие сложные объекты имеют подсчет ссылок , а некоторые являются сложными, но без подсчета ссылок. Когда система типов «копирует» объект с подсчетом ссылок, она обычно просто увеличивает его счетчик ссылок, тогда как при копировании сложного объекта без подсчета ссылок (например, строки) она обычно создает фактическую копию, выделяя Память .
Эта базовая функциональность используется для реализации GValue
типа универсального контейнера, который может хранить значения любого типа, известного в системе типов. Такие контейнеры особенно полезны при взаимодействии с динамически типизированными языковыми средами, в которых все собственные значения находятся в таких контейнерах с тегами типа .
Типы, не имеющие связанных классов , называются неклассифицированными . Эти типы вместе со всеми типами, которые соответствуют той или иной форме корневого класса, известны как фундаментальные типы : типы, от которых произошли все остальные типы. Они составляют относительно закрытый набор, но хотя среднестатистический пользователь не должен создавать свои собственные фундаментальные типы, возможность существует и используется для создания пользовательских иерархий классов , то есть иерархий классов, не основанных на GObject
классе.
Начиная с GLib 2.9.2, [ 2 ] неклассифицированными встроенными фундаментальными типами являются:
void
( G_TYPE_NONE
);char
, int
, long
и 64-битным целым числам C ( G_TYPE_CHAR
, G_TYPE_UCHAR
, G_TYPE_INT
, G_TYPE_UINT
, G_TYPE_LONG
, G_TYPE_ULONG
, G_TYPE_INT64
, и G_TYPE_UINT64
);G_TYPE_BOOLEAN
);enum
, но отличающиеся тем, что последний используется только для битовых полей ( G_TYPE_ENUM
и G_TYPE_FLAGS
);float
и double
( G_TYPE_FLOAT
и G_TYPE_DOUBLE
);char *
( G_TYPE_STRING
);void *
( G_TYPE_POINTER
).Классифицированные встроенные фундаментальные типы:
GObject
, корень стандартного дерева наследования классов ( G_TYPE_OBJECT
)G_TYPE_INTERFACE
( )G_TYPE_BOXED
).G_TYPE_PARAM
).Типы, экземпляры которых могут быть созданы автоматически системой типов, называются экземплярами . Важной характеристикой этих типов является то, что первые байты любого экземпляра всегда содержат указатель на структуру класса (форму виртуальной таблицы ), связанную с типом экземпляра. По этой причине любой экземпляр типа должен быть классифицирован. И наоборот, любой неклассифицированный тип (например, целое число или строка ) не должен создавать экземпляры. С другой стороны, большинство классифицированных типов являются экземплярами, а некоторые, например типы интерфейсов, — нет.
Типы, производные от встроенных фундаментальных типов GObject, делятся примерно на четыре категории:
enum
тип), который нужно использовать каким-либо образом, связанным с объектной системой — например, как тип свойства объекта — должен быть зарегистрирован с помощью система типов. Обычно код инициализации, который отвечает за регистрацию этих типов, генерируется автоматизированным инструментом под названием glib-mkenums
[3] и сохраняется в отдельном файле.background-color
свойство, значения которого должны быть экземплярами структуры, похожей на . Чтобы избежать создания подкласса , мы можем создать коробочный тип для представления этой структуры и предоставить функции для копирования и освобождения. GObject поставляется с несколькими коробочными типами, обертывающими простые типы данных GLib. Другое использование коробочных типов — это способ обернуть посторонние объекты в контейнер с тегами, который система типов может идентифицировать и знать, как скопировать и освободить.struct color { int r, g, b; }
GObject
G_TYPE_POINTER
), часто бывает хорошей идеей создать производный тип указателя, документирующий тот факт, что указатели должны ссылаться на объект определенного типа, даже если ничего другого не требуется. сказал об этом.GObject
. Существуют также интерфейсы, которые, в отличие от классических интерфейсов в стиле Java , могут содержать реализованные методы. Таким образом, интерфейсы GObject можно описать как миксины .Система обмена сообщениями GObject состоит из двух взаимодополняющих частей: замыканий и сигналов .
Каждый класс GObject реализуется как минимум двумя структурами: структурой класса и структурой экземпляра .
Определение класса в среде GObject является сложным процессом, требующим большого количества стандартного кода, такого как ручное определение макросов приведения типов и непонятные заклинания регистрации типов. Кроме того, поскольку структура C не может иметь модификаторы доступа, такие как «public», «protected» или «private», необходимо использовать обходные пути для обеспечения инкапсуляции . Один из подходов заключается во включении указателя на частные данные (условно называемые _priv
) в структуру экземпляра. Частная структура может быть объявлена в общедоступном заголовочном файле, но определена только в файле реализации, в результате чего частные данные непрозрачны для пользователей, но прозрачны для разработчика. Если частная структура зарегистрирована в GType, она будет автоматически выделена объектной системой. Действительно, даже нет необходимости включать _priv
указатель, если кто-то готов использовать заклинание G_TYPE_INSTANCE_GET_PRIVATE
каждый раз, когда необходимы личные данные.
Чтобы решить некоторые из этих сложностей, существует несколько языков более высокого уровня, которые компилируются из исходного кода в GObject на C. Язык программирования Vala использует синтаксис в стиле C# и предварительно преобразуется в стандартный код C. GObject Builder, или GOB2, предлагает синтаксис шаблонов, напоминающий Java .
Комбинация C и GObject используется во многих успешных проектах бесплатного программного обеспечения , таких как рабочий стол GNOME , набор инструментов GTK и программа манипулирования изображениями GIMP .
Хотя многие приложения GObject полностью написаны на C, система GObject хорошо сопоставляется с собственными объектными системами многих других языков, таких как C++ , Java , Ruby , Python , Common Lisp и .NET / Mono . В результате обычно сравнительно безболезненно создавать языковые привязки для хорошо написанных библиотек, использующих инфраструктуру GObject.
Однако написание кода GObject на C является относительно многословным. Изучение библиотеки требует много времени, и программисты с опытом работы с объектно-ориентированными языками высокого уровня часто находят несколько утомительным работать с GObject в C. Например, создание подкласса (даже просто подкласса GObject
) может потребовать написание и/или копирование большого количества шаблонного кода . [5] Однако использование Vala , языка, который предназначен в первую очередь для работы с GObject и который преобразуется в C, вероятно, улучшит работу с GObject или написание библиотек на основе GObject.
Хотя на самом деле они не являются первоклассными объектами (в GType нет реальных метатипов), такие метаобъекты , как классы и интерфейсы, создаются приложениями GObject во время выполнения и обеспечивают хорошую поддержку самоанализа . Интроспективные возможности используются языковыми привязками и приложениями для разработки пользовательского интерфейса, такими как Glade , чтобы позволить выполнять такие действия, как загрузка общей библиотеки , предоставляющей класс GObject (обычно какой-то виджет , в случае Glade), а затем получать список всех свойств. класса, дополненный информацией о типе и строками документации.
Поскольку GObject предоставляет практически полную объектную систему для C , его можно рассматривать как альтернативу языкам, производным от C, таким как C ++ и Objective-C . (Хотя оба они также предлагают множество других функций, помимо соответствующих объектных систем.) Легко заметить разницу между C++ и GObject заключается в том, что GObject (как и Java) не поддерживает множественное наследование . [6]
Использование GObject функции выделения памяти g_malloc() из GLib приведет к безоговорочному завершению работы программы при исчерпании памяти, в отличие от malloc () библиотеки C , new C++ и других распространенных распределителей памяти, которые позволяют программе справиться с ней или даже полностью восстановиться. из ситуаций нехватки памяти без простого сбоя. [7] Это, как правило, препятствует включению GObject в программное обеспечение, где важна устойчивость к ограниченной памяти или где обычно обрабатывается очень много или очень больших объектов. g_try_new() можно использовать, когда выделение памяти с большей вероятностью завершится неудачно (например, для большого объекта), но это не может гарантировать, что выделение не завершится неудачно в другом месте кода. [8]
Еще одно важное отличие заключается в том, что, хотя C++ и Objective-C являются отдельными языками, GObject является строго библиотекой и, как таковой, не вводит никакого нового синтаксиса или интеллектуальных возможностей компилятора. Например, при написании кода C на основе GObject часто необходимо выполнить явное повышающее приведение . [ нужна цитация ] Следовательно, «C с GObject», также называемый «C со вкусом glib», рассматриваемый как язык, отдельный от простого C, является строгим расширенным набором простого C — как Objective C, но в отличие от C ++.
На платформах, где нет стандартного ABI , работающего во всех компиляторах C++ (что обычно не так, поскольку обычно используются либо Itanium ABI, либо Microsoft ABI), библиотека, скомпилированная с помощью одного компилятора C++, не всегда может вызвать библиотека, скомпилированная с другой. [ нужна цитация ] Если требуется такая совместимость, методы C++ должны быть экспортированы как простые функции C, что частично противоречит цели объектной системы C++. [ нужна цитация ] Проблема возникает отчасти потому, что разные компиляторы C++ используют разные виды искажения имен , чтобы гарантировать уникальность всех экспортируемых символов. (Это необходимо, поскольку, например, два разных класса могут иметь функции-члены с одинаковыми именами, одно имя функции может быть перегружено несколько раз или функции с одинаковыми именами могут появляться в разных пространствах имен , но в объектном коде такие перекрытия не допускаются.) [ необходима цитация ] Напротив, поскольку C не поддерживает какую-либо форму перегрузки или пространства имен, авторы библиотек C обычно используют явные префиксы, чтобы гарантировать глобальную уникальность своих экспортируемых имен. [ нужна цитация ] Следовательно, несмотря на объектно-ориентированность, библиотека на основе GObject, написанная на C, всегда будет использовать одни и те же имена внешних символов независимо от того, какой компилятор используется.
Возможно, самым глубоким отличием является акцент GObject на сигналах (в других языках называемых событиями ). [ нужна цитация ] Этот акцент обусловлен тем фактом, что GObject был специально разработан для удовлетворения потребностей набора инструментов GUI. Хотя для большинства объектно-ориентированных языков существуют библиотеки сигналов, в случае GObject они встроены в объектную систему. По этой причине типичное приложение GObject будет иметь тенденцию использовать сигналы в гораздо большей степени, чем приложение, не использующее GObject, что делает компоненты GObject гораздо более инкапсулированными и пригодными для повторного использования, чем те, которые используют простой C++ или Java. [ нужна цитата ] [ по мнению кого? ] При использовании glibmm/ gtkmm , официальных оболочек C++ для Glib/GTK соответственно, родственный проект libsigc++ позволяет легко использовать базовые сигналы GObject с использованием стандарта C++. Конечно, практически на всех платформах доступны и другие реализации сигналов, хотя иногда требуется дополнительная библиотека, например Boost.Signals2 для C++.