Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In Gobject, how to override parent class's method belong to an interface?

Tags:

glib

gobject

GObject class A implements interface IA, B is a derived class of A. How can B override A's method that is part of the interface IA?

Or, is this possible in GObject?

I know how to override parent class methods, but when inheritance meets interface, things seems to be more complicated.

Thanks a lot!

like image 986
ablmf Avatar asked Oct 22 '09 11:10

ablmf


1 Answers

Yes, it is possible: just reimplement the interface as it was the first time, either using G_IMPLEMENT_INTERFACE() or manual initializing it in your get_type() function.

The real pain is if you need to chain up the old method. In this case, you should play with g_type_interface_peek_parent to get the previous interface class.

Here is a test case:

/* gcc -otest `pkg-config --cflags --libs gobject-2.0` test.c */
#include <glib-object.h>


/* Interface */

#define TYPE_IFACE   (iface_get_type())

typedef void Iface;
typedef struct {
    GTypeInterface parent_class;
    void (*action) (Iface *instance);
} IfaceClass;

GType
iface_get_type(void)
{
    static GType type = 0;

    if (G_UNLIKELY(type == 0)) {
        const GTypeInfo info = {
            sizeof(IfaceClass), 0,
        };

        type = g_type_register_static(G_TYPE_INTERFACE, "Iface", &info, 0);
    }

    return type;
}

void
iface_action(Iface *instance)
{
    G_TYPE_INSTANCE_GET_INTERFACE(instance, TYPE_IFACE, IfaceClass)->
        action(instance);
}


/* Base object */

#define TYPE_BASE    (base_get_type())

typedef GObject        Base;
typedef GObjectClass   BaseClass;

static void
base_action(Iface *instance)
{
    g_print("Running base action on a `%s' instance...\n",
            g_type_name(G_TYPE_FROM_INSTANCE(instance)));
}

static void
base_iface_init(IfaceClass *iface)
{
    iface->action = base_action;
}

G_DEFINE_TYPE_WITH_CODE(Base, base, G_TYPE_OBJECT,
                        G_IMPLEMENT_INTERFACE(TYPE_IFACE, base_iface_init));

static void
base_class_init(BaseClass *klass)
{
}

static void
base_init(Base *instance)
{
}


/* Derived object */

#define TYPE_DERIVED (derived_get_type())

typedef Base      Derived;
typedef BaseClass DerivedClass;

static void
derived_action(Iface *instance)
{
    IfaceClass *iface_class, *old_iface_class;

    iface_class = G_TYPE_INSTANCE_GET_INTERFACE(instance, TYPE_IFACE, IfaceClass);
    old_iface_class = g_type_interface_peek_parent(iface_class);

    g_print("Running derived action on a `%s' instance...\n",
            g_type_name(G_TYPE_FROM_INSTANCE(instance)));

    /* Chain up the old method */
    old_iface_class->action(instance);
}

static void
derived_iface_init(IfaceClass *iface)
{
    iface->action = derived_action;
}

G_DEFINE_TYPE_WITH_CODE(Derived, derived, TYPE_BASE,
                        G_IMPLEMENT_INTERFACE(TYPE_IFACE, derived_iface_init));

static void
derived_class_init(DerivedClass *klass)
{
}

static void
derived_init(Derived *instance)
{
}


int
main()
{
    GObject *object;

    g_type_init();

    object = g_object_new(TYPE_BASE, NULL);
    iface_action((Iface *) object);
    g_object_unref(object);

    object = g_object_new(TYPE_DERIVED, NULL);
    iface_action((Iface *) object);
    g_object_unref(object);

    return 0;
}
like image 164
ntd Avatar answered Sep 21 '22 06:09

ntd