GObject - GObject

GObject
Entwickler Das GNOME-Projekt
Erstveröffentlichung 11. März 2002 ; Vor 19 Jahren  ( 2002-03-11 )
Stabile Version 2,66,7 (11. Februar 2021 ; vor 55 Tagen ) [±]  ( 2021-02-11 )
Geschrieben in C.
Betriebssystem Plattformübergreifend
Verfügbar in Mehrsprachig
Art Softwarebibliothek
Lizenz GNU LGPL
Webseite Entwickler .gnome .org / gobject / stabile /
Da die GNU C-Bibliothek als Wrapper für Linux-Kernel -Systemaufrufe dient , dienen auch die in GLib gebündelten Bibliotheken (GObject, Glib , GModule , GThread und GIO ) als weitere Wrapper für ihre spezifischen Aufgaben.

Das GLib Object System oder GObject ist eine kostenlose Softwarebibliothek, die ein tragbares Objektsystem und eine transparente sprachübergreifende Interoperabilität bietet . GObject wurde sowohl für die direkte Verwendung in C- Programmen zur Bereitstellung objektorientierter C-basierter APIs als auch durch Bindungen an andere Sprachen entwickelt, um eine transparente sprachübergreifende Interoperabilität bereitzustellen , z . B. PyGObject .

GObject Introspection

Geschichte

Abhängig von GLib und libc ist GObject ein Eckpfeiler von GNOME und wird in GTK- , Pango- , ATK- und den meisten übergeordneten GNOME- Bibliotheken wie GStreamer und Anwendungen verwendet. Vor GTK + 2.0 war Code ähnlich wie GObject Teil der GTK-Codebasis. (Der Name "GObject" wurde noch nicht verwendet - die gemeinsame Basisklasse wurde aufgerufen GtkObject .)

Bei der Veröffentlichung von GTK + 2.0 wurde das Objektsystem aufgrund seines allgemeinen Nutzens in eine separate Bibliothek extrahiert. Dabei wurden die meisten nicht GUI- spezifischen Teile der GtkObject Klasse in GObject die neue gemeinsame Basisklasse verschoben. Die GObject-Bibliothek existiert seit dem 11. März 2002 (dem Veröffentlichungsdatum von GTK + 2.0) als separate Bibliothek und wird jetzt von vielen Nicht-GUI-Programmen wie Befehlszeilen- und Serveranwendungen verwendet .

Beziehung zu GLib

Obwohl GObject über einen eigenen Dokumentationssatz verfügt und normalerweise in einer eigenen gemeinsam genutzten Bibliotheksdatei kompiliert wird , befindet sich der Quellcode für GObject im GLib- Quellbaum und wird zusammen mit GLib verteilt. Aus diesem Grund verwendet GObject die GLib-Versionsnummern und wird normalerweise zusammen mit GLib verpackt ( Debian fügt beispielsweise GObject in seine libglib2.0 Paketfamilie ein).

Das Typsystem

Auf der grundlegendsten Ebene des GObject-Frameworks befindet sich ein generisches und dynamisches Typsystem namens GType. Das GType System hält eine Laufzeit Beschreibung aller Objekte ermöglicht Glue Code mehrere Sprachbindungen zu erleichtern. Das Typsystem kann neben nicht klassifizierten Typen wie undurchsichtigen Zeigern , Zeichenfolgen und ganzzahligen Ganzzahlen und Gleitkommazahlen auch jede einfach vererbte Klassenstruktur verarbeiten .

Das Typsystem kann Werte kopieren, zuweisen und zerstören, die zu einem der registrierten Typen gehören. Dies ist für Typen wie Ganzzahlen trivial, aber viele komplexe Objekte werden referenzgezählt , während einige komplex, aber nicht referenzgezählt sind. Wenn das Typsystem ein Objekt mit Referenzzählung „kopiert“, erhöht es normalerweise nur seine Referenzanzahl, während beim Kopieren eines komplexen Objekts ohne Referenzzählung (z. B. einer Zeichenfolge) normalerweise eine tatsächliche Kopie durch Zuweisen erstellt wird Speicher .

Diese grundlegende Funktionalität wird für die Implementierung GValue eines generischen Containertyps verwendet, der Werte aller vom Typsystem bekannten Typen enthalten kann. Solche Container sind besonders nützlich, wenn Sie mit dynamisch typisierten Sprachumgebungen interagieren, in denen sich alle nativen Werte in solchen Typ-Tag- Containern befinden.

Grundtypen

Typen, denen keine Klassen zugeordnet sind, werden als nicht klassifiziert bezeichnet . Diese Typen werden zusammen mit allen Typen, die einer Form der Stammklasse entsprechen , als grundlegende Typen bezeichnet : die Typen, von denen alle anderen Typen abgeleitet sind. Diese bilden eine relativ geschlossene Menge, aber obwohl vom durchschnittlichen Benutzer nicht erwartet wird, dass er seine eigenen grundlegenden Typen erstellt, besteht die Möglichkeit und wurde ausgenutzt, um benutzerdefinierte Klassenhierarchien zu erstellen - dh Klassenhierarchien, die nicht auf der GObject Klasse basieren .

Ab GLib 2.9.2 sind die nicht klassifizierten integrierten Grundtypen:

  • ein leerer Typ, der C's void ( G_TYPE_NONE ) entspricht;
  • Typen C ist und ohne Vorzeichen entspricht char , int , long und 64-Bit - Integer ( G_TYPE_CHAR , G_TYPE_UCHAR , G_TYPE_INT , G_TYPE_UINT , G_TYPE_LONG , G_TYPE_ULONG , G_TYPE_INT64 , und G_TYPE_UINT64 );
  • ein boolescher Typ ( G_TYPE_BOOLEAN );
  • ein Aufzählungstyp und ein "Flags" -Typ, die beide dem enum Typ C entsprechen , sich jedoch darin unterscheiden, dass letzterer nur für Bitfelder ( G_TYPE_ENUM und G_TYPE_FLAGS ) verwendet wird;
  • Typen für IEEE-Floats mit einfacher und doppelter Genauigkeit , entsprechend C float und double ( G_TYPE_FLOAT und G_TYPE_DOUBLE );
  • ein String-Typ, der C's char * ( G_TYPE_STRING ) entspricht;
  • ein undurchsichtiger Zeigertyp, der C's void * ( G_TYPE_POINTER ) entspricht.

Die klassifizierten eingebauten Grundtypen sind:

  • Ein Basisklassentyp für Instanzen von GObject , der Wurzel des Standardklassenvererbungsbaums ( G_TYPE_OBJECT )
  • ein Basis - Schnittstellentyp, die analog zu der Basisklasse Typ , aber die Wurzel des Standard darstellt Schnittstelle Vererbungsbaumes ( G_TYPE_INTERFACE )
  • Ein Typ für Box- Strukturen, mit denen einfache Wertobjekte oder Fremdobjekte in referenzgezählte „Boxen“ ( G_TYPE_BOXED ) eingeschlossen werden.
  • Ein Typ für "Parameter-Spezifikationsobjekte", die in GObject verwendet werden, um Metadaten für Objekteigenschaften ( G_TYPE_PARAM ) zu beschreiben .

Typen, die vom Typsystem automatisch instanziiert werden können, werden als instanziierbar bezeichnet . Ein wichtiges Merkmal dieser Typen ist, dass die ersten Bytes einer Instanz immer einen Zeiger auf die Klassenstruktur (eine Form einer virtuellen Tabelle ) enthalten, die dem Typ der Instanz zugeordnet ist. Aus diesem Grund muss jeder instanziierbare Typ klassifiziert werden. Im Gegensatz dazu darf jeder nicht klassifizierte Typ (wie eine Ganzzahl oder eine Zeichenfolge ) nicht instanziierbar sein. Auf der anderen Seite sind die meisten klassifizierten Typen instanziierbar, einige, wie z. B. Schnittstellentypen, jedoch nicht.

Abgeleitete Typen

Die Typen, die von den integrierten GObject-Grundtypen abgeleitet werden, lassen sich grob in vier Kategorien einteilen:

Aufzählungstypen und "Flags" -Typen
Im Allgemeinen sollte jeder Aufzählungstyp und jeder ganzzahlige Bitfeldtyp (dh jeder enum Typ), den man in irgendeiner Weise verwenden möchte, die mit dem Objektsystem zusammenhängt - beispielsweise als Typ einer Objekteigenschaft - registriert werden das Typsystem. Normalerweise wird der Initialisierungscode, der sich um die Registrierung dieser Typen kümmert, von einem automatisierten Tool generiert, das aufgerufen glib-mkenums und in einer separaten Datei gespeichert wird.
Boxed Typen
Einige Datenstrukturen, die zu einfach sind, um zu vollwertigen Klassentypen zu werden (mit dem gesamten anfallenden Overhead), müssen möglicherweise noch beim Typsystem registriert werden. Beispielsweise könnten wir eine Klasse haben, zu der wir eine background-color Eigenschaft hinzufügen möchten , deren Werte Instanzen einer Struktur sein sollten, die aussieht . Um zu vermeiden, dass eine Unterklasse erstellt werden muss , können wir einen Box-Typ erstellen , um diese Struktur darzustellen, und Funktionen zum Kopieren und Freigeben bereitstellen. GObject wird mit einer Handvoll Boxed-Typen geliefert, die einfache GLib-Datentypen einschließen. Eine andere Verwendung für Typen mit Boxen besteht darin, Fremdkörper in einen mit Tags versehenen Container zu verpacken, den das Typsystem identifizieren kann und der kopieren und freigeben kann. struct color { int r, g, b; }GObject
Undurchsichtige Zeigertypen
Manchmal ist für Objekte, die weder kopiert noch referenzgezählt oder freigegeben werden müssen, sogar ein Box-Typ übertrieben . Während solche Objekte in GObject verwendet werden können, indem sie einfach als undurchsichtige Zeiger ( G_TYPE_POINTER ) behandelt werden, ist es oft eine gute Idee, einen abgeleiteten Zeigertyp zu erstellen, der die Tatsache dokumentiert, dass die Zeiger auf eine bestimmte Art von Objekt verweisen sollten, obwohl dies nichts anderes ist sagte darüber.
Klassen- und Schnittstellentypen
Die meisten Typen in einer GObject-Anwendung sind Klassen - im normalen objektorientierten Sinne des Wortes -, die direkt oder indirekt von der Stammklasse abgeleitet sind GObject . Darüber hinaus gibt es Schnittstellen, die im Gegensatz zu klassischen Java -Stil Schnittstellen implementiert Methoden enthalten. GObject-Schnittstellen können daher als Mixins bezeichnet werden .

Messaging-System

Das GObject-Nachrichtensystem besteht aus zwei sich ergänzenden Teilen: Verschlüssen und Signalen .

Verschlüsse
Ein GObject-Abschluss ist eine verallgemeinerte Version eines Rückrufs . Es werden Verschlüsse unterstützt, die in C und C ++ geschrieben wurden, sowie beliebige Sprachen (wenn Bindungen bereitgestellt werden). Auf diese Weise kann in (beispielsweise) Python und Java geschriebener Code über einen GObject-Abschluss aufgerufen werden.
Signale
Signale sind der Hauptmechanismus, durch den Schließungen aufgerufen werden. Objekte registrieren Signal-Listener beim Typsystem und geben eine Zuordnung zwischen einem bestimmten Signal und einem bestimmten Abschluss an. Bei der Ausgabe eines registrierten Signals wird das Schließen dieses Signals aufgerufen. In GTK können alle nativen GUI-Ereignisse (wie Mausbewegungen und Tastaturaktionen) GObject-Signale generieren, auf die Hörer möglicherweise reagieren können.

Klassenimplementierung

Jede GObject-Klasse wird durch mindestens zwei Strukturen implementiert: die Klassenstruktur und die Instanzstruktur .

Die Klassenstruktur
Die Klassenstruktur entspricht der vtable einer C ++ - Klasse. Es muss mit der Klassenstruktur der Oberklasse beginnen. Anschließend enthält es eine Reihe von Funktionszeigern - einen für jede virtuelle Methode der Klasse. Klassenspezifische Variablen können verwendet werden, um Klassenmitglieder zu emulieren.
Die Instanzstruktur
Die Instanzstruktur, die in einer Kopie pro Objektinstanz vorhanden ist, muss mit der Instanzstruktur der Oberklasse beginnen (dies stellt sicher, dass alle Instanzen mit einem Zeiger auf die Klassenstruktur beginnen, da alle grundlegenden instanziierbaren Typen diese Eigenschaft gemeinsam haben). Nach den zur Oberklasse gehörenden Daten kann die Struktur beliebige instanzspezifische Variablen enthalten, die C ++ - Mitgliedsvariablen entsprechen.

Das Definieren einer Klasse im GObject-Framework ist komplex und erfordert große Mengen an Boilerplate- Code, z. B. manuelle Definitionen von Typumwandlungsmakros und obskure Beschwörungsformeln für die Typregistrierung. Da eine C-Struktur keine Zugriffsmodifikatoren wie "öffentlich", "geschützt" oder "privat" haben kann, müssen Problemumgehungen verwendet werden, um die Kapselung bereitzustellen . Ein Ansatz besteht darin, einen Zeiger auf die üblicherweise als privat bezeichneten privaten Daten _priv in die Instanzstruktur aufzunehmen. Die private Struktur kann in der öffentlichen Header-Datei deklariert, jedoch nur in der Implementierungsdatei definiert werden, sodass die privaten Daten für Benutzer undurchsichtig, für den Implementierer jedoch transparent sind. Wenn die private Struktur bei GType registriert ist, wird sie vom Objektsystem automatisch zugewiesen. In der Tat ist es nicht einmal notwendig, den _priv Zeiger einzuschließen, wenn man bereit ist, die Beschwörung G_TYPE_INSTANCE_GET_PRIVATE jedes Mal zu verwenden, wenn die privaten Daten benötigt werden.

Um einige dieser Komplexitäten zu beheben, gibt es mehrere übergeordnete Sprachen, die von Quelle zu Quelle in C zu GObject kompiliert werden . Die Programmiersprache Vala verwendet eine Syntax im C # -Stil und wird in Vanille- C-Code vorverarbeitet . Der GObject Builder oder GOB2 bietet eine Vorlagensyntax, die an Java erinnert .

Verwendung

Die Kombination von C und GObject wird in vielen erfolgreichen freien Softwareprojekten wie dem GNOME- Desktop, dem GTK- Toolkit und dem GIMP- Bildbearbeitungsprogramm verwendet.

Obwohl viele GObject-Anwendungen vollständig in C geschrieben sind, lässt sich das GObject-System gut in die nativen Objektsysteme vieler anderer Sprachen wie C ++ , Java , Ruby , Python , Common Lisp und .NET / Mono abbilden . Daher ist es normalerweise relativ einfach, Sprachbindungen für gut geschriebene Bibliotheken zu erstellen , die das GObject-Framework verwenden.

Das Schreiben von GObject-Code in C ist jedoch relativ ausführlich. Die Bibliothek nimmt ziemlich viel Zeit zu lernen, und Programmierer mit Erfahrung in der High-Level - objektorientierte Sprachen finden es oft etwas mühsam Arbeit mit GObject in C. Um zum Beispiel eine Unterklasse zu schaffen (auch nur eine Unterklasse von GObject ) kann verlangen Schreiben und / oder Kopieren großer Mengen von Boilerplate-Code . Die Verwendung von Vala , einer Sprache, die hauptsächlich für die Arbeit mit GObject entwickelt wurde und in C konvertiert wird, dürfte jedoch die Arbeit mit GObject oder das Schreiben von GObject-basierten Bibliotheken erleichtern.

Obwohl es sich nicht wirklich um erstklassige Objekte handelt (es gibt keine tatsächlichen Metatypen in GType), werden Metaobjekte wie Klassen und Schnittstellen zur Laufzeit von GObject-Anwendungen erstellt und bieten eine gute Unterstützung für die Selbstbeobachtung . Die introspektiven Funktionen werden von Sprachbindungen und Anwendungen zum Entwerfen von Benutzeroberflächen wie Glade verwendet , um beispielsweise eine gemeinsam genutzte Bibliothek zu laden , die eine GObject-Klasse bereitstellt - im Fall von Glade normalerweise eine Art Widget - und anschließend eine Liste aller Eigenschaften abzurufen der Klasse, komplett mit Typinformationen und Dokumentationszeichenfolgen.

Vergleiche mit anderen Objektsystemen

Da GObject ein größtenteils vollständiges Objektsystem für C bereitstellt, kann es als Alternative zu C-abgeleiteten Sprachen wie C ++ und Objective-C angesehen werden . (Beide bieten jedoch auch viele andere Funktionen, die über ihre jeweiligen Objektsysteme hinausgehen.) Ein leicht zu beobachtender Unterschied zwischen C ++ und GObject besteht darin, dass GObject (wie Java) keine Mehrfachvererbung unterstützt .

GObject der Nutzung von GLib ‚s g_malloc () Speicherzuordnungsfunktion bewirkt , dass das Programm zu beenden bedingungslos auf Speicher Erschöpfung, im Gegensatz zu der der C - Bibliothek malloc (), C ++‘ s neue und andere gängigen Speicherverteilern , die ein Programm ermöglichen , mit fertig zu werden oder sogar vollständig zu erholen aus Situationen, in denen nicht genügend Speicher vorhanden ist, ohne einfach abzustürzen. Dies wirkt tendenziell der Aufnahme von GObject in Software entgegen, bei der die Ausfallsicherheit angesichts des begrenzten Speichers wichtig ist oder bei der häufig sehr viele oder sehr große Objekte gehandhabt werden. G_try_new () kann verwendet werden, wenn eine Speicherzuweisung mit größerer Wahrscheinlichkeit fehlschlägt (z. B. für ein großes Objekt). Dies kann jedoch nicht gewährleisten, dass die Zuweisung an keiner anderen Stelle im Code fehlschlägt.

Ein weiterer wichtiger Unterschied besteht darin, dass C ++ und Objective-C zwar getrennte Sprachen sind, GObject jedoch ausschließlich eine Bibliothek ist und daher keine neue Syntax oder Compiler-Intelligenz einführt. Wenn Sie beispielsweise GObject-basierten C-Code schreiben, ist es häufig erforderlich, ein explizites Upcasting durchzuführen . Daher ist „C mit GObject“, eine Sprache, die von einfachem C getrennt ist, eine strikte Obermenge von einfachem C - wie Ziel C, aber im Gegensatz zu C ++.

Auf Plattformen, auf denen es kein Standard- ABI gibt , das für alle C ++ - Compiler geeignet ist (was normalerweise nicht der Fall ist, da normalerweise entweder das Itanium-ABI oder das Microsoft-ABI befolgt werden), kann eine mit einem C ++ - Compiler kompilierte Bibliothek nicht immer a aufrufen Bibliothek mit einer anderen kompiliert. Wenn eine solche Kompatibilität erforderlich ist, müssen die C ++ - Methoden als einfache C-Funktionen exportiert werden, was den Zweck des C ++ - Objektsystems teilweise zunichte macht. Das Problem tritt teilweise auf, weil verschiedene C ++ - Compiler unterschiedliche Arten der Namensverknüpfung verwenden , um die Eindeutigkeit aller exportierten Symbole sicherzustellen. (Dies ist erforderlich, weil beispielsweise zwei verschiedene Klassen identisch benannte Elementfunktionen haben können, ein Funktionsname mehrfach überladen sein kann oder identisch benannte Funktionen in unterschiedlichen Namespaces erscheinen können , aber im Objektcode sind diese Überlappungen nicht zulässig.) In Da C keine Form von Überladung oder Namespace unterstützt, verwenden Autoren von C-Bibliotheken normalerweise explizite Präfixe, um die globale Eindeutigkeit ihrer exportierten Namen sicherzustellen. Daher verwendet eine in C geschriebene GObject-basierte Bibliothek, obwohl sie objektorientiert ist, immer dieselben externen Symbolnamen, unabhängig davon, welcher Compiler verwendet wird.

Der vielleicht tiefgreifendste Unterschied ist die Betonung von Signalen durch GObject ( Ereignisse in anderen Sprachen genannt). Diese Betonung ergibt sich aus der Tatsache, dass GObject speziell für die Anforderungen eines GUI-Toolkits entwickelt wurde. Während es für die meisten objektorientierten Sprachen Signalbibliotheken gibt, ist diese im Fall von GObject in das Objektsystem integriert. Aus diesem Grund verwendet eine typische GObject-Anwendung Signale in viel größerem Umfang als eine Nicht-GObject-Anwendung, wodurch GObject- Komponenten viel gekapselter und wiederverwendbarer sind als solche, die einfaches C ++ oder Java verwenden. Wenn Sie glibmm / gtkmm verwenden , die offiziellen C ++ - Wrapper für Glib / GTK, ermöglicht das Geschwisterprojekt libsigc ++ die einfache Verwendung der zugrunde liegenden GObject-Signale unter Verwendung von Standard-C ++. Natürlich sind andere Implementierungen von Signalen auf fast allen Plattformen verfügbar, obwohl manchmal eine zusätzliche Bibliothek erforderlich ist, wie z. B. Boost.Signals2 für C ++.

Siehe auch


Verweise

Externe Links