Seitenleiste

Grundlegende Deklaration im Header

Willkommen zum kleinen Tutorial zu GObject. Ganz nach den klassischen Tutorials zu objektorientierter Programmierung (OOP) werden wir eine Klasse Tier erstellen.

Hinweis: Dies ist kein OOP-Tutorial. Grundlagen zur objektorientierten Programmierung werden vorausgesetzt!

Vorarbeiten

Deklaration und Implementierung einer Klasse werden bei der Arbeit mit GObject auf zwei Dateien aufgeteilt (wie es ohne OOP in C auch ist):

  • tutorial-tier.h
  • tutorial-tier.c

Bitte achtet bei Code-Beispielen immer darauf, in welcher dieser beiden Dateien dieser steht!

Namensrichtlinien

Mit der Zeit haben sich bei den Entwicklern, die mit GObject zu tun hatten, bestimmte Richtlinien entwickelt, an die wir uns auch halten sollten. Das wichtigste für uns grob zusammengefasst:

  • Um Namenskonflikte zu vermeiden, bekommt jede Klasse ein Präfix. Üblicherweise ist das der Name der Library oder der Anwendung.
  • Jede Memberfunktion folgt dem Namensprinzip: <präfix>_<name der klasse>_<name der methode>

Zum Nachlesen: Conventions

Das Grundgerüst

tutorial-tier.h
/*
 * Copyright- und Lizenzinformationen
 */
 
/*
 * Header guard
 */
#ifndef __TUTORIAL_TIER_H__
#define __TUTORIAL_TIER_H__
 
#include <glib.h>
 
/*
 * GType Makros
 */
#define TUTORIAL_TYPE_TIER              (tutorial_tier_get_type())
#define TUTORIAL_TIER(obj)              (G_TYPE_CHECK_INSTANCE_CAST ((obj), TUTORIAL_TYPE_TIER, TutorialTier))
#define TUTORIAL_IS_TIER(obj)           (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TUTORIAL_TYPE_TIER))
#define TUTORIAL_TIER_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass), TUTORIAL_TYPE_TIER, TutorialTierClass))
#define TUTORIAL_IS_TIER_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), TUTORIAL_TYPE_TIER))
#define TUTORIAL_TIER_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj), TUTORIAL_TYPE_TIER, TutorialTierClass))
 
typedef struct _TutorialTier        TutorialTier;
typedef struct _TutorialTierClass   TutorialTierClass;
 
struct _TutorialTier
{
    GObject parent_instance;
};
 
struct _TutorialTierClass
{
    GObjectClass parent_class;
};
 
GType tutorial_tier_get_type(void);
 
/*
 * Platz für Methoden.
 */
 
#endif


Hinweis: Kein Bezeichner sollte class heißen, da dies ein C++ Schlüsselwort ist!

Wie zu sehen, bedarf es bei der Deklaration einer Klasse ein wenig mehr Aufwand als bei objektorientierten Sprachen wie C++ oder Java.

Die Makros

Am seltsamsten mögen euch vielleicht die sechs Makros zu Beginn des Headers scheinen:

MakroFunktion
TUTORIAL_TYPE_TIERLiefert den GType der Klasse wieder.
TUTORIAL_TIERCast für Instanzen, um innerhalb der Vererbungshierarchie auf Member zuzugreifen.
TUTORIAL_IS_TIERTypüberprüfung für Instanzen.
TUTORIAL_TIER_CLASSCast für Klassenbeschreibung, um innerhalb der Vererbungshierarchie auf Klasseneigenschaften (z.B. Properties) zuzugreifen
TUTORIAL_IS_TIER_CLASSTypüberprüfung Klassenbeschreibung.
TUTORIAL_TIER_GET_CLASSLiefert die Klassenbeschreibung (TutorialTierClass) einer Instanz (TutorialTier) wieder.

Die Strukturen

Auch müsste euch auffallen, dass wie zwei Structs deklariert haben (und das auch immer tun müssen…):

StructFunktion
TutorialTierInstanz. Eine Variable diesen Typs entspricht einer Instanz einer Klasse. Variablen innerhalb der Struktur entsprechen Memebervariablen (zu privaten Membern siehe unten)
TutorialTierClassKlassenbeschreibung. Diese Struktur speichert Daten zur Klasse, z.B. Properties und Signals.

Private Member

Aus objektorientierten Sprachen dürfte euch wohl das Schlüsselwort private bekannt sein. Für die Umsetzung mit GObject gibt es zwei mögliche Varianten:

Die GTK+ Variante

Diese Variante findet man vorwiegend im Code zu GTK+. Bei ihr werden private Variablen nur durch Kommentare als solche gekennzeichnet:

struct _TutorialTier
{
    GObject parent_instance;
 
    /* < private > */
    gint gehirn_masse;
};

Die Nautilus Variante

Diese Variante kam erstmals im Code zum Dateimanager Nautilus vor. Mittlerweile ist sie mehr oder weniger Standard, aus diesem Grund werden wir diese Methode verwenden.

Hierbei werden alle privaten Variablen in eine eigene Struktur gepackt, die dann später in der .c-Datei definiert wird.

Die Liste der typedefs wird um einen Eintrag ergänzt:

typedef struct _TutorialTierPrivate TutorialTierPrivate;


Und die _TutorialTier-Struktur bekommt eine neue Variable:

struct _TutorialTier
{
    GObject parent_instance;
 
    TutorialTierPrivate* priv;
};


Hinweis: Die Variable sollte nicht private genannt werden, da dies ein C++ Schlüsselwort ist.

Der fertige Header

Mit privaten Feldern sieht unser „nackter“ Header nun so aus:

tutorial-tier.h
#ifndef __TUTORIAL_TIER_H__
#define __TUTORIAL_TIER_H__
 
#include <glib.h>
 
/*
 * GType Makros
 */
#define TUTORIAL_TYPE_TIER              (tutorial_tier_get_type())
#define TUTORIAL_TIER(obj)              (G_TYPE_CHECK_INSTANCE_CAST ((obj), TUTORIAL_TYPE_TIER, TutorialTier))
#define TUTORIAL_IS_TIER(obj)           (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TUTORIAL_TYPE_TIER))
#define TUTORIAL_TIER_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass), TUTORIAL_TYPE_TIER, TutorialTierClass))
#define TUTORIAL_IS_TIER_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), TUTORIAL_TYPE_TIER))
#define TUTORIAL_TIER_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj), TUTORIAL_TYPE_TIER, TutorialTierClass))
 
typedef struct _TutorialTier        TutorialTier;
typedef struct _TutorialTierClass   TutorialTierClass;
typedef struct _TutorialTierPrivate TutorialTierPrivate;
 
struct _TutorialTier
{
    GObject parent_instance;
 
    TutorialTierPrivate* priv;
};
 
struct _TutorialTierClass
{
    GObjectClass parent_class;
};
 
GType tutorial_tier_get_type(void);
 
/*
 * Platz für Methoden.
 */
 
#endif