GValue,GTypeValueTable,GTypeInfo和GParamSpec的目的

Bor*_*kov 7 gtk gnome gobject glib

GObject库真的很有文件记录.很难确定创建实体的目的.也就是说,我不明白的角色GValue,GTypeValueTable,GTypeInfo,GParamSpecTypeData.

简而言之,类型注册的过程如下.每种类型由TypeNode结构表示.有两种TypeNode结构static_fundamental_type_nodes array存储:用于存储TypeNodes静态基本类型和static_type_nodes_ht用于静态非基本类型的哈希表.在基本类型的情况下,每个GType只是TypeNode非基本类型或TypeNodein的索引的对应的存储器地址static_fundamental_type_nodes.动态类型会发生什么 - 我不知道,如果可以,请解释我.相应的代码驻留在gtype_init函数中,负责类型系统的初始化:http://git.gnome.org/browse/glib/tree/gobject/gtype.c#n4323 .

在此输入图像描述

GValue,GParamSpec并且GObjectGTypes自己,所以它们被注册为类型.

GValue 用于通过它注册新类型值,但如何?

GParameters并且GParamSpec似乎需要注册GObject类型(不确定).究竟是怎么做到的?每个人的角色是什么?

最重要的:是什么的角色GTypeValueTable,GTypeInfoTypeDataTypeData被引用TypeNode并包含GTypeValueTable子结构BoxedData,ClassData,IFaceData,InstanceData(为什么Instance,我们不是注册类型?).而且,它们似乎互相复制,导致它们全部包含对base_init/finalize的引用,class_init/finalize具有引用GTypeValueTable.

所以,GObject papas,如果你正在读这篇文章,请自己解释一下!描述您使用的那些结构的目的.

iai*_*ain 17

除非你试图处理一些非常低级的代码,否则你真正需要关心的其中只有两个是GValue和GParamType

我会先说 GParamType

GParamType用于向GObject注册属性.比方说,我有一个名为Person的GObject子类,我希望它有两个属性:Name和Age.在class_init函数中,我会像这样注册这些

{
    GParamSpec *pspec;

    . . .

    pspec = g_param_spec_string ("name", "Name", "The name of the person", "", G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
    g_object_class_install_property (object_class, PROP_NAME, pspec);

    pspec = g_param_spec_int ("age", "Age", "The age of the person", 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
    g_object_class_install_property (object_class, PROP_AGE, spec);

    . . .
}
Run Code Online (Sandbox Code Playgroud)

现在您可以调用g_object_getg_object_set在这些属性上,系统将知道如何处理它

char *name;
int age;
g_object_set (G_OBJECT (person), "name", "Steve", "age", 37, NULL);
g_object_get (G_OBJECT (person), "name", &name, "age", &age, NULL);

g_print ("%s is %d years old\n", name, age);

// And because the type system knows when a property is a string, it knows how to give
// you a copy of the string, so you need to free it once you've finished with it
g_free (name);
Run Code Online (Sandbox Code Playgroud)

这里解释了各种参数:GParamSpec所有标准类型都有GValue类型:字符串,bool,int等,而其他一些库(如GStreamer)将注册自己的自定义类型.

除了在GObjectClass上安装属性之外,您很少需要处理GParamSpec.它们出现的两个主要场合是GObjectClass set/get_property方法和GObject通知信号.在最后一种情况下,通过调用来检测哪个属性已经接收到通知信号是有用的g_param_spec_get_name,但实际上最好使用更具体的通知信号,如下所示:

g_signal_connect (person, "notify::name", G_CALLBACK (name_changed_cb), NULL);
g_signal_connect (person, "notify::age", G_CALLBACK (age_changed_cb), NULL);
Run Code Online (Sandbox Code Playgroud)

而不是

g_signal_connect (person, "notify", G_CALLBACK (something_changed_cb), NULL);
Run Code Online (Sandbox Code Playgroud)

有时您可能想要创建自己的结构并将其用于属性.例如,如果我有

struct _PersonDetails {
    char *name;
    int age;
}
Run Code Online (Sandbox Code Playgroud)

而不是在Person对象上有两个属性,我想要一个名为"details"的东西.GLib类型系统不知道如何处理我的自定义struct _PersonDetails因此我需要为它创建一个盒装类型,以便它知道如何正确地复制/释放结构,因为它在Glib内部传递.这就是GValue进来的地方.

GValue 用于包装不同类型的值,以便可以正确地复制和释放它们(如果需要),以便可以使用通用函数.

例如,GObjectClass方法set_property具有原型

void set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec)
Run Code Online (Sandbox Code Playgroud)

这意味着可以传入任何可以由GValue表示的类型,并且不需要特定的函数,例如set_int_property,set_string_property,set_bool_property.

它还意味着函数g_object_setg_object_get知道如何处理传入的参数,因为它知道属性"name"被注册为字符串类型,并且它具有复制/释放该字符串所需的功能.

有关GValue的更多信息,请点击此处 - 通用值

struct _PersonDetails使用GLib类型系统注册我们的自定义,我们将创建一个自定义Boxed类型,告诉系统如何复制和释放它.详细信息如下:盒装类型

G_DEFINE_BOXED_TYPE (PersonDetails, person_details,
                     person_details_copy,
                     person_details_free)
. . .

static gpointer
person_details_copy (gpointer data)
{
    struct _PersonDetails *details = (struct _PersonDetails *)data;
    struct _PersonDetails *copy = g_new (struct _PersonDetails, 1);

    // We need to copy the string
    copy->name = g_strdup (details->name);
    copy->age = details->age;

    return (gpointer) copy;
}

static void
person_details_free (gpointer data)
{
    struct _PersonDetails *details = (struct _PersonDetails *)data;

    // name was allocated so it needs freed as well
    g_free (details->name);

    g_free (details);
}
Run Code Online (Sandbox Code Playgroud)

现在我们可以使用注册我们的类型

pspec = g_param_spec_boxed ("details", "Details", "The person's details", person_details_get_type (), G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
g_object_class_install_property (object_class, PROP_DETAILS, pspec);
Run Code Online (Sandbox Code Playgroud)