代码之家  ›  专栏  ›  技术社区  ›  faceclean

在Gobject中,如何覆盖属于接口的父类的方法?

  •  5
  • faceclean  · 技术社区  · 17 年前

    GObject类A实现接口IA,B是A的派生类。B如何重写作为接口IA一部分的A的方法?

    或者,这在GObject中可能吗?

    我知道如何重写父类方法,但当继承遇到接口时,事情似乎更复杂。

    谢谢!

    2 回复  |  直到 13 年前
        1
  •  5
  •   Ruslan PiotrNycz    11 年前

    是的,这是可能的:只需重新实现界面,因为它是第一次,使用 G_IMPLEMENT_INTERFACE() 或者在您的应用程序中手动初始化它 get_type() 作用

    g_type_interface_peek_parent 获取上一个接口类。

    下面是一个测试用例:

    /* 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;
    }
    
        2
  •  5
  •   Ruslan PiotrNycz    11 年前

    #include <glib-object.h>
    #include "fooable.h"
    
    typedef struct {GObject parent;} A;
    typedef struct {
        GObjectClass parent;
        gint (*foo) (Fooable *self, gdouble quux);
    } AClass;
    
    #define TYPE_A           (a_get_type())
    #define A_CLASS(cls)     (G_TYPE_CHECK_CLASS_CAST((cls), TYPE_A, AClass))
    #define A_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), TYPE_A, AClass))
    
    gint a_foo_real (Fooable *self, gdouble quux) {
        g_print("a_foo_real(%g)\n", quux);
        return 5;
    }
    
    gint a_foo (Fooable *self, gdouble quux) {
        return A_GET_CLASS(self)->foo(self, quux);
    }
    
    void implement_fooable (FooableIface *iface) {iface->foo = a_foo;}
    void a_class_init      (AClass *cls)         {cls->foo = a_foo_real;}
    void a_init            (A *self)             {}
    
    G_DEFINE_TYPE_WITH_CODE(A, a, G_TYPE_OBJECT,
        G_IMPLEMENT_INTERFACE(TYPE_FOOABLE, implement_fooable));
    
    /* derive class B from A  */
    typedef struct {A parent;} B;
    typedef struct {AClass parent;} BClass;
    
    #define TYPE_B (b_get_type())
    
    gint b_foo_real (Fooable *self, gdouble quux) {
        g_print("b_foo_real(%g)\n", quux);
        return 55;
    }
    
    void b_class_init (BClass *cls) {A_CLASS(cls)->foo = b_foo_real;}
    void b_init       (B *self)     {}
    
    G_DEFINE_TYPE(B, b, TYPE_A);
    
    int main () {
        g_type_init();
        A *a = g_object_new(TYPE_A, NULL);
        B *b = g_object_new(TYPE_B, NULL);
        fooable_foo(FOOABLE(a), 87.0); // a_foo_real(87.0) and returns 5
        fooable_foo(FOOABLE(b), 32.0); // b_foo_real(32.0) and returns 55
        return 0;
    }
    

    这是一个尽可能简短的例子。当你打电话的时候 fooable_foo() 该函数将查看其vtable,以查找在实现以下接口时定义的函数: a_foo() 它查看类的vtable以确定实际调用哪个函数。B类定义覆盖了类的 a_foo_real() 用它自己的。如果你需要B级的 b_foo_real 要连锁,这是一个很容易(使用) A_CLASS(b_parent_class)->foo() 在G_DEFINE_TYPE宏中为您定义的)