How to define and implement interfaces

How to define an interface

The bulk of interface definition has already been shown in the section called “Non-instantiable classed types: interfaces” but I feel it is needed to show exactly how to create an interface.

As above, the first step is to get the header right. This interface defines two methods:

#ifndef __MAMAN_IBAZ_H__
#define __MAMAN_IBAZ_H__

#include <glib-object.h>

#define MAMAN_TYPE_IBAZ                 (maman_ibaz_get_type ())
#define MAMAN_IBAZ(obj)                 (G_TYPE_CHECK_INSTANCE_CAST ((obj), MAMAN_TYPE_IBAZ, MamanIbaz))
#define MAMAN_IS_IBAZ(obj)              (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MAMAN_TYPE_IBAZ))
#define MAMAN_IBAZ_GET_INTERFACE(inst)  (G_TYPE_INSTANCE_GET_INTERFACE ((inst), MAMAN_TYPE_IBAZ, MamanIbazInterface))


typedef struct _MamanIbaz               MamanIbaz; /* dummy object */
typedef struct _MamanIbazInterface      MamanIbazInterface;

struct _MamanIbazInterface
{
  GTypeInterface parent_iface;

  void (*do_action) (MamanIbaz *self);
  void (*do_something) (MamanIbaz *self);
};

GType maman_ibaz_get_type (void);

void maman_ibaz_do_action    (MamanIbaz *self);
void maman_ibaz_do_something (MamanIbaz *self);

#endif /* __MAMAN_IBAZ_H__ */

This code is the same as the code for a normal GType which derives from a GObject except for a few details:

  • The _GET_CLASS macro is called _GET_INTERFACE and not implemented with G_TYPE_INSTANCE_GET_CLASS but with G_TYPE_INSTANCE_GET_INTERFACE.

  • The instance type, MamanIbaz is not fully defined: it is used merely as an abstract type which represents an instance of whatever object which implements the interface.

  • The parent of the MamanIbazInterface is not GObjectClass but GTypeInterface.

The implementation of the MamanIbaz type itself is trivial:

  • G_DEFINE_INTERFACE creates a maman_ibaz_get_type function which registers the type in the type system. The third argument is used to define a prerequisite interface (which we'll talk about more later). Just pass 0 for this argument when an interface has no prerequisite.

  • maman_ibaz_default_init is expected to register the interface's signals if there are any (we will see a bit later how to use them).

  • The interface methods maman_ibaz_do_action and maman_ibaz_do_something dereference the interface structure to access its associated interface function and call it.

G_DEFINE_INTERFACE (MamanIbaz, maman_ibaz, 0);

static void
maman_ibaz_default_init (gpointer g_class)
{
    /* add properties and signals to the interface here */
}

void
maman_ibaz_do_action (MamanIbaz *self)
{
  g_return_if_fail (MAMAN_IS_IBAZ (self));

  MAMAN_IBAZ_GET_INTERFACE (self)->do_action (self);
}

void
maman_ibaz_do_something (MamanIbaz *self)
{
  g_return_if_fail (MAMAN_IS_IBAZ (self));

  MAMAN_IBAZ_GET_INTERFACE (self)->do_something (self);
}