level 12
#define VIEWER_TYPE_EDITABLE viewer_editable_get_type ()
G_DECLARE_INTERFACE (ViewerEditable, viewer_editable, VIEWER, EDITABLE, GObject)
struct _ViewerEditableInterface {
GTypeInterface parent;
void (*save) (ViewerEditable *self,
GError **error);
};
void viewer_editable_save (ViewerEditable *self,
GError **error);
void
viewer_editable_save (ViewerEditable *self,
GError **error)
{
ViewerEditableinterface *iface;
g_return_if_fail (VIEWER_IS_EDITABLE (self));
g_return_if_fail (error == NULL || *error == NULL);
iface = VIEWER_EDITABLE_GET_IFACE (self);
g_return_if_fail (iface->save != NULL);
iface->save (self);
}
这个例子是官方文档里面的例子。
ViewerEditableinterface是一个接口的结构体。
有谁能够告诉我,这里面的ViewerEditable究竟是一个什么东西吗?
2025年01月09日 17点01分
1
吧务
level 14
感觉这个ViewerEditable的作用是定义了一类控件要实现的功能,比如GtkEntry,GtkSpin等要有文本可编辑的能力,所以这些控件的属性中都有GtkEditable相关的内容了
2025年01月10日 15点01分
3
https://docs.gtk.org/gtk4/iface.Editable.html
2025年01月10日 15点01分
这个是GTK库里面的一个接口,也是基于GObject库里面的接口类型来实现的。但是,我的问题并不是这个。
2025年01月10日 17点01分
level 12
在GLib类型系统中注册一个接口类型,
其实和注册一个类类型是很相似的。
你可以先用G_DECLARE_INTERFACE宏,来声明一些需要的宏。
然后,用G_DEFINE_INTERFACE宏来定义这个接口。
当我们继续分析G_DECLARE_INTERFACE宏时,
可以在源文件里面看到,
typedef struct _##ModuleObjName ModuleObjName;
typedef struct _#
#ModuleObjName#
#Interface ModuleObjName#
#Interface;
这个宏看起来会声明两个结构体。
根据注释里面提供的用法:
#ifndef _my_model_h_ * #define _my_model_h_
#define MY_TYPE_MODEL my_model_get_type ()
GDK_AVAILABLE_IN_3_12
G_DECLARE_INTERFACE (MyModel, my_model, MY, MODEL, GObject)
struct _MyModelInterface
{
GTypeInterface g_iface;
gpointer (* get_item) (MyModel *model);
};
可以看到,
typedef struct _#
#ModuleObjName#
#Interface ModuleObjName#
#Interface;
这是一个继承GTypeInterface的结构体,
可以向其中添加虚函数,用来定义接口的方法。
然而,
typedef struct _##ModuleObjName ModuleObjName;
这又是什么呢?
在类类型的声明中,这个也是一个结构体,实例结构体。
但是,在接口类型的声明中,不明白这是什么?一个结构体吗?
在注释中看不出来。
因为,
iface = VIEWER_EDITABLE_GET_IFACE (self);
会用到ViewerEditable *self指针,
所以,我们继续分析G_DECLARE_INTERFACE宏的源代码,
可以看到,
G_GNUC_UNUSED
static inline ModuleObjName#
#Interface*MODULE#
#_#
#OBJ_NAME#
#_GET_IFACE (gpointer ptr) { return G_TYPE_INSTANCE_GET_INTERFACE (ptr, module_obj_name#
#_get_type (), ModuleObjName#
#Interface); } G_GNUC_END_IGNORE_DEPRECATIONS
看不明白了。
还可以继续追踪这里的G_TYPE_INSTANCE_GET_INTERFACE宏,
最后,会找到一个_G_TYPE_IGI宏,
继续,会找到一个g_type_interface_peek函数。
但是,g_type_interface_peek函数用于查找某一个类类型中的指定接口的GTypeInterface结构体指针。
哎,好复杂,
还是看不懂typedef struct _##ModuleObjName ModuleObjName; 究竟是个啥。
2025年01月10日 17点01分
4
level 12
我现在的唯一解释是:
typedef struct _##ModuleObjName ModuleObjName;
其实只是一个编程技巧,
用来欺骗编译器,
告诉编译器某处定义了_##ModuleObjName这样一个结构体,
以使得
void viewer_editable_save (ViewerEditable *self,GError **error);
这样的函数可以使用。
因为可能不会事先知道哪些类会实现这个接口,
因此,ViewerEditable *self仅仅作为一个占位符。
实际调用此函数时,
传递的其实是实现了此接口的类的实例的指针。
因此,可以在函数内部,用
iface = VIEWER_EDITABLE_GET_IFACE (self);
这样的宏,查找实例的类,最后通过类查找指定的接口的GTypeInterface结构体指针,
并最终调用其中的接口方法。
2025年01月11日 05点01分
5
这么理解的话,一切都能够说得通。而且,接口的方法不能脱离实现接口的类存在,脱离某个类(实例),单独去调用接口的方法是没有意义的。这么一来,一切都能解释了。
2025年01月11日 06点01分
level 12
不得不说,
官方的教程写得太狗血了,
省略了大片大片的东西。
太难搞了。
2025年01月11日 06点01分
6
确实,最开始看官方文档的时候也是因为这个有些地方搞不懂
2025年01月11日 15点01分