GObject類A實現了接口IA,B是一個派生類A.如何B可以覆蓋A的方法,它是接口IA的一部分?在Gobject中,如何覆蓋父類的方法屬於一個接口?
或者,這是GObject中可能的嗎?
我知道如何覆蓋父類方法,但是當繼承遇到接口時,事情似乎更復雜。
非常感謝!
GObject類A實現了接口IA,B是一個派生類A.如何B可以覆蓋A的方法,它是接口IA的一部分?在Gobject中,如何覆蓋父類的方法屬於一個接口?
或者,這是GObject中可能的嗎?
我知道如何覆蓋父類方法,但是當繼承遇到接口時,事情似乎更復雜。
非常感謝!
是的,這是可能的:只需重新實現接口,因爲它是第一次使用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;
}
我認爲一個更好的解決辦法是使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宏中爲你定義的)
我建議把這個問題標記爲GObject,因爲它比GTK +更相關。 – ntd 2009-10-22 15:09:58
回想2年後,我真的很幸運,我不需要再與這個廢話作鬥爭。 – ablmf 2011-01-16 04:37:19
廢話?這是GOBJEEECT! – ntd 2011-06-02 17:20:05