## Object methods

Just as with C++, there are many different ways to define object methods and extend them: the following list and sections draw on C++ vocabulary. (Readers are expected to know basic C++ concepts. Those who have not had to write C++ code recently can refer to e.g. http://www.cplusplus.com/doc/tutorial/ to refresh their memories.)

- non-virtual public methods,

- virtual public methods and

- virtual private methods

### Non-virtual public methods

These are the simplest, providing a simple method which acts on the object. Provide a function prototype in the header and an implementation of that prototype in the source file.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    /* declaration in the header. */
    void maman_bar_do_action (MamanBar *self, /* parameters */);

    /* implementation in the source file */
    void
    maman_bar_do_action (MamanBar *self, /* parameters */)
    {
      g_return_if_fail (MAMAN_IS_BAR (self));

      /* do stuff here. */
    }

### Virtual public methods

This is the preferred way to create GObjects with overridable methods:

- Define the common method and its virtual function in the class structure in the public header

- Define the common method in the header file and implement it in the source file

- Implement a base version of the virtual function in the source file and initialize the virtual function pointer to this implementation in the object’s `class_init` function; or leave it as `NULL` for a ‘pure virtual’ method which must be overridden by derived classes

- Re-implement the virtual function in each derived class which needs to override it

Note that virtual functions can only be defined if the class is derivable, declared using `G_DECLARE_DERIVABLE_TYPE` so the class structure can be defined.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    /* declaration in maman-bar.h. */
    #define MAMAN_TYPE_BAR maman_bar_get_type ()
    G_DECLARE_DERIVABLE_TYPE (MamanBar, maman_bar, MAMAN, BAR, GObject)

    struct _MamanBarClass
    {
      GObjectClass parent_class;

      /* stuff */
      void (*do_action) (MamanBar *self, /* parameters */);

      /* Padding to allow adding up to 12 new virtual functions without
       * breaking ABI. */
      gpointer padding[12];
    };

    void maman_bar_do_action (MamanBar *self, /* parameters */);

    /* implementation in maman-bar.c */
    void
    maman_bar_do_action (MamanBar *self, /* parameters */)
    {
      MamanBarClass *klass;

      g_return_if_fail (MAMAN_IS_BAR (self));

      klass = MAMAN_BAR_GET_CLASS (self);
      g_return_if_fail (klass->do_action != NULL);

      klass->do_action (self, /* parameters */);
    }

The code above simply redirects the `do_action` call to the relevant virtual function.

It is possible to provide a default implementation for this class method in the object's `class_init` function: initialize the `klass->do_action` field to a pointer to the actual implementation. By default, class methods that are not inherited are initialized to `NULL`, and thus are to be considered "pure virtual".

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    static void
    maman_bar_real_do_action_two (MamanBar *self, /* parameters */)
    {
      /* Default implementation for the virtual method. */
    }

    static void
    maman_bar_class_init (MamanBarClass *klass)
    {
      /* this is not necessary, except for demonstration purposes.
       *
       * pure virtual method: mandates implementation in children.
       */
      klass->do_action_one = NULL;

      /* merely virtual method. */
      klass->do_action_two = maman_bar_real_do_action_two;
    }

    void
    maman_bar_do_action_one (MamanBar *self, /* parameters */)
    {
      MamanBarClass *klass;

      g_return_if_fail (MAMAN_IS_BAR (self));

      klass = MAMAN_BAR_GET_CLASS (self);

      /* if the method is purely virtual, then it is a good idea to
       * check that it has been overridden before calling it, and,
       * depending on the intent of the class, either ignore it silently
       * or warn the user.
       */
      g_return_if_fail (klass->do_action != NULL);
      klass->do_action_one (self, /* parameters */);
    }

    void
    maman_bar_do_action_two (MamanBar *self, /* parameters */)
    {
      MamanBarClass *klass;

      g_return_if_fail (MAMAN_IS_BAR (self));

      klass = MAMAN_BAR_GET_CLASS (self);
      if (klass->do_action_two != NULL)
        klass->do_action_two (self, /* parameters */);
    }

### Virtual private Methods

These are very similar to virtual public methods. They just don't have a public function to call directly. The header file contains only a declaration of the virtual function:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    /* declaration in maman-bar.h. */
    struct _MamanBarClass
    {
      GObjectClass parent;

      /* stuff */
      void (* helper_do_specific_action) (MamanBar *self, /* parameters */);

      /* Padding to allow adding up to 12 new virtual functions without
       * breaking ABI. */
      gpointer padding[12];
    };

    void maman_bar_do_any_action (MamanBar *self, /* parameters */);

These virtual functions are often used to delegate part of the job to child classes:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    /* this accessor function is static: it is not exported outside of this file. */
    static void
    maman_bar_do_specific_action (MamanBar *self, /* parameters */)
    {
      MAMAN_BAR_GET_CLASS (self)->do_specific_action (self, /* parameters */);
    }

    void
    maman_bar_do_any_action (MamanBar *self, /* parameters */)
    {
      g_return_if_fail (MAMAN_IS_BAR (self));

      /* random code here */

      /*
       * Try to execute the requested action. Maybe the requested action
       * cannot be implemented here. So, we delegate its implementation
       * to the child class:
       */
      maman_bar_do_specific_action (self, /* parameters */);

      /* other random code here */
    }

Again, it is possible to provide a default implementation for this private virtual function:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    static void
    maman_bar_class_init (MamanBarClass *klass)
    {
      /* pure virtual method: mandates implementation in children. */
      klass->do_specific_action_one = NULL;

      /* merely virtual method. */
      klass->do_specific_action_two = maman_bar_real_do_specific_action_two;
    }

Children can then implement the subclass with code such as:

    1
    2
    3
    4
    5
    6
    7
    8
    static void
    maman_bar_subtype_class_init (MamanBarSubTypeClass *klass)
    {
      MamanBarClass *bar_class = MAMAN_BAR_CLASS (klass);

      /* implement pure virtual function. */
      bar_class->do_specific_action_one = maman_bar_subtype_do_specific_action_one;
    }