2009-10-22 62 views
5

GObject類A實現了接口IA,B是一個派生類A.如何B可以覆蓋A的方法,它是接口IA的一部分?在Gobject中,如何覆蓋父類的方法屬於一個接口?

或者,這是GObject中可能的嗎?

我知道如何覆蓋父類方法,但是當繼承遇到接口時,事情似乎更復雜。

非常感謝!

+1

我建議把這個問題標記爲GObject,因爲它比GTK +更相關。 – ntd 2009-10-22 15:09:58

+0

回想2年後,我真的很幸運,我不需要再與這個廢話作鬥爭。 – ablmf 2011-01-16 04:37:19

+0

廢話?這是GOBJEEECT! – ntd 2011-06-02 17:20:05

回答

5

是的,這是可能的:只需重新實現接口,因爲它是第一次使用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; 
} 
5

我認爲一個更好的解決辦法是使A的方法,虛擬的,而不是具有B-重新實現接口A連接到(這可能需要比更多的工作只是重新定義一個函數),你可以這樣做(例如應該比fooable接口定義完整等):

#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()時,函數將查看它的虛函數表,當你實現接口a_foo()時,它定義了函數,該接口查看A類的vtable來確定實際調用哪個函數。 B類定義用自己的類覆蓋A類的a_foo_real()。如果你需要B類的b_foo_real來鏈接,這很簡單(使用A_CLASS(b_parent_class)->foo(),這是在G_DEFINE_TYPE宏中爲你定義的)