2009-10-22 42 views
5

Lớp GObject Một giao diện thực hiện IA, B là một lớp dẫn xuất của A. Làm sao B có thể ghi đè lên phương thức A là một phần của giao diện IA?Trong Gobject, cách ghi đè lên phương thức của lớp cha thuộc về một giao diện?

Hoặc, điều này có thể xảy ra trong GObject không?

Tôi biết cách ghi đè lên các phương thức lớp cha, nhưng khi thừa kế giao diện, mọi thứ có vẻ phức tạp hơn.

Cảm ơn rất nhiều!

+1

Tôi đề xuất gắn thẻ câu hỏi này là GObject vì nó có liên quan nhiều hơn GTK +. – ntd

+0

Nhìn lại 2 năm sau, tôi thực sự cảm thấy may mắn vì tôi không cần phải chiến đấu với cái crap này nữa. – ablmf

+0

Crap? ĐÂY LÀ GOBJEEECT! – ntd

Trả lời

5

Có, có thể: chỉ cần triển khai lại giao diện vì đây là lần đầu tiên sử dụng G_IMPLEMENT_INTERFACE() hoặc khởi chạy thủ công giao diện trong hàm get_type() của bạn.

Nỗi đau thực sự là nếu bạn cần kết chuỗi phương pháp cũ. Trong trường hợp này, bạn nên chơi với g_type_interface_peek_parent để nhận lớp giao diện trước đó.

Đây là một trường hợp thử nghiệm:

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

Tôi nghĩ rằng một giải pháp tốt hơn sẽ được thực hiện của một phương pháp ảo, chứ không phải có B tái thực hiện các giao diện A được gắn vào (điều này có thể yêu cầu công việc hơn chỉ xác định lại một chức năng), mà bạn có thể làm như thế này (ví dụ nên được hoàn khác với định nghĩa giao diện 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; 
} 

đó là như ngắn gọn về một ví dụ như tôi có thể làm cho nó. Khi bạn gọi hàm fooable_foo(), hàm sẽ xem xét vtable của nó cho hàm được xác định khi bạn triển khai giao diện là a_foo() xem giao diện của lớp A để xác định hàm nào thực sự gọi. Định nghĩa lớp B ghi đè a_foo_real() của lớp A với riêng nó. Nếu bạn cần b_foo_real của lớp B để kết nối, điều đó đủ dễ dàng (sử dụng A_CLASS(b_parent_class)->foo() được xác định cho bạn trong macro G_DEFINE_TYPE)

Các vấn đề liên quan