vala 如何允许定义没有默认构造函数的 GObject?

How does vala allow defining GObjects with no default constructor?

Vala tutorial 表明 classes 可以用 GObject 风格或类似于 Java / C# 等风格的构造函数编写。

教程显示这完全独立于 class 是否继承自 Glib.GObject。(编辑:我对教程感到困惑在 Glib.ObjectObject 之间切换。在 Vala 中有一个隐含的 using Glib,所以两者是相同的)。

如果 Glib.GObject subclass 的定义没有默认构造函数(使用 Java/C# 样式),那么我是否认为必须定义隐式默认构造函数?对于 GObject,可能会将所有字段都填充为二进制零(根据 GObject 初始化)?

另见 Initialize a GObject with parameters which are not GObject properties?

让我们用valac -C找出答案。

示例代码:

class MySuper : Object
{
    private int i;
    private int j;

    public MySuper (int i)
    {
        this.i = i;
        j = 1;
    }
}

class MyDerived : MySuper
{
    public MyDerived ()
    {
        base (10);
    }
}

生成的(相关部分)C 代码如下所示:

MySuper* my_super_construct (GType object_type, gint i) {
    MySuper * self = NULL;
    gint _tmp0_ = 0;
    self = (MySuper*) g_object_new (object_type, NULL);
    _tmp0_ = i;
    self->priv->i = _tmp0_;
    self->priv->j = 1;
    return self;
}


MySuper* my_super_new (gint i) {
    return my_super_construct (TYPE_MY_SUPER, i);
}


MyDerived* my_derived_construct (GType object_type) {
    MyDerived * self = NULL;
    self = (MyDerived*) my_super_construct (object_type, 10);
    return self;
}


MyDerived* my_derived_new (void) {
    return my_derived_construct (TYPE_MY_DERIVED);
}

对 valac 生成的内容的一些观察:

  • MySuper 和 MyDerived 都有一个 _construct_new 函数。
  • my_super_construct 只调用 g_object_new.
  • my_derived_construct 仅调用 my_super_construct(后者又调用 g_object_new.

所以一切都被 Vala 编译器很好地链接起来,C#/Java 风格的构造函数被翻译成 GObject 风格的构造。

关于成员的初始化:如果您不在 Vala 代码中提供初始化,生成的构造函数也不会初始化任何东西。

所有这一切都是通过 Vala 在幕后为您完成的。你不应该担心代码生成的细节,但如果你愿意,你总是可以使用 -C ...

Vala 会自动在 C 代码中创建一个构造函数。这遵循 *_new 命名模式。所以最简单的例子:

void main () {
    new ExampleWithoutExplicitConstructor ();
}

class ExampleWithoutExplicitConstructor {
}

如果您使用 valac --ccode example.vala 编译它并查看生成的 C 代码,您将看到 _vala_main 调用 example_without_explicit_constructor_new (),然后调用 example_without_explicit_constructor_construct ()example_without_explicit_constructor_construct () 然后为该类型调用 g_object_new ()。作为 g_object_new 创建类型的一部分,它将调用 example_without_explicit_constructor_instance_init () 可以初始化任何变量的地方。

这是一个更复杂的示例,它继承自 Object,完整的 GObject class 也是如此,它有一个带有默认值的字段和一个带有默认值的 属性默认值:

void main () {
    new ExampleWithoutExplicitConstructor ();
}

class ExampleWithoutExplicitConstructor:Object {
    private string example_field = "default";

    public string an_object_property { get; 
        set; 
        default = "this object properties default string";
        }
}

你会从 C 代码中注意到 _new_constructg_object_new_instance_init 模式是相同的。 Vala 所做的是设置 _instance_init 来初始化字段和属性的默认值。

Public 没有默认值的字段为空。您将看到它们出现在保存实例数据的 struct 的定义中。私有字段类似,但在实例的私有 struct 中保存。您可以通过尝试示例来亲眼看到这一点。