2009-10-22 16 views
5

GObject clase A implementa interfaz IA, B es una clase derivada de A. ¿Cómo puede B anular el método de A que forma parte de la interfaz IA?En Gobject, ¿cómo anular el método de la clase padre pertenece a una interfaz?

O, ¿esto es posible en GObject?

Sé cómo anular los métodos de clase padre, pero cuando la herencia se encuentra con la interfaz, las cosas parecen ser más complicadas.

¡Muchas gracias!

+1

Sugiero etiquetar esta pregunta como GObject, porque está más relacionada con ella que GTK +. – ntd

+0

Mirando hacia atrás 2 años después, realmente me siento afortunado de no tener que pelear más con esta mierda. – ablmf

+0

¿Mierda? ESTO ES GOBJEEECT! – ntd

Respuesta

5

Sí, es posible: simplemente vuelva a implementar la interfaz como era la primera vez, ya sea usando G_IMPLEMENT_INTERFACE() o inicializándola manualmente en su función get_type().

El verdadero problema es si necesita encadenar el método anterior. En este caso, debe jugar con g_type_interface_peek_parent para obtener la clase de interfaz anterior.

Aquí es un caso de prueba:

/* 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

Creo que una mejor solución sería hacer el método de una virtual, en lugar de tener B re-implementar la interfaz A está unido a (esto puede requerir más trabajo que acaba de redefinir una función), que se puede hacer así (ejemplo debería ser otra que la completa definición de interfaz 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; 
} 

que es tan breve de un ejemplo que puedo hacerlo. Cuando llame al fooable_foo(), la función verá su vtable para la función definida cuando implementó la interfaz que es a_foo() que mira el vtable de la clase A para determinar a qué función llamar realmente. La definición de clase B anula la clase A de a_foo_real() con la suya propia. Si necesita el b_foo_real de la clase B para encadenarse, eso es bastante fácil (use A_CLASS(b_parent_class)->foo(), que se define para usted en la macro G_DEFINE_TYPE)

Cuestiones relacionadas