GObject 和继承

GObject and inheritance

我在 Glib 上做一些严肃的软件。我意识到有些话题我并不真正理解。 IRC 也没有帮助所以...

我们在做继承的时候,可以有两个类。第一个A直接继承了GObject,B继承了A。然后我就得出这个:

https://developer.gnome.org/gobject/stable/chapter-gobject.html

static void
viewer_file_constructed (GObject *obj)
{
  /* update the object state depending on constructor properties */

  /* Always chain up to the parent constructed function to complete object
   * initialisation. */
  G_OBJECT_CLASS (viewer_file_parent_class)->constructed (obj);
}

static void
viewer_file_class_init (ViewerFileClass *klass)
{
  GObjectClass *object_class = G_OBJECT_CLASS (klass);

  object_class->constructed = viewer_file_constructed;
}

但是当你有这种安排的时候。 child class 这样做: object_class->constructed = viewer_file_constructed;在 B 重写实际上是构造的唯一内存地址。所以表示G_OBJECT_CLASS(viewer_file_parent_class)->constructed(obj);将递归调用 B->constructed 。这不是我们想要的。

可能我没看懂,但我猜想B中的内存结构是这样的:

struct _B
{
  A parent_instance;

  /* instance members */
};

内部表示应该是这样的:

[   Gobject struct memory ]
[                         ]
[   Gobject variables     ]
[   A struct memory       ]
[   A variables           ] 
[                         ]
[   B struct memory       ]
[   B variables           ] 

因此在 B 中转换时的 GObject 内存由 B 和 A classing 共享。并且所有地址在同一个 i...

这是正确的吗? 因此,如果我想覆盖构造的......我是否必须保存之前的指针,然后用我的指针在 init 中覆盖它?这样我处理完之后就可以调用原来的了?

这同样适用于属性。因为 A 通过枚举定义它的属性,所以可以从 0 到 N。

所以我认为 B 属性应该从 N 开始,而不是 0。否则 A 的属性由 B 处理,并且可能具有不同的数据结构和名称。

检查这个: https://developer.gnome.org/gobject/stable/gobject-properties.html

enum
{
  PROP_FILENAME = 1,
  PROP_ZOOM_LEVEL,
  N_PROPERTIES
};

如果两个类都定义了索引为 1 的 属性。那里会有问题,因为 glib 不知道应该由谁来处理。我想 child class B 会处理它但不正确,因为 B 可能正在等待,比如 PROP_DIRECTORY,但因为索引是相同的。 glib 能够发送到正确的实例吗?

我只能说,如果在寄存器上 glib 会根据层次结构级别添加一些偏移量,它就会起作用。有人可以解释这是如何工作的吗?我找不到任何包含所需技术细节的文档。

The internal representation should be something like:

不完全是。 GObjectGObjectClass 结构之间存在差异。每个对象实例有一个 GObject 结构实例,但整个 class.

只有一个 GObjectClass 实例

如果您有一个从 GObject 派生的 class FooBarFooBarClass 结构将类似于:

typedef struct
{
  GObjectClass parent_class;

  /* Virtual methods for FooBar instances: */
  void (*vfunc) (FooBar *self);
} FooBarClass;

堆上会有一个FooBarClass的实例。由于它包含整个 GObjectClass 结构作为其 parent_class 成员,这意味着它有自己的 finalizedisposeget_property 等虚拟方法指针。

单独在堆中,有一个 GObjectClass 的 GObject 类型的实例。它包含另一组finalizedispose等虚方法指针。

由于 FooBar 派生自 GObjectfoo_bar_parent_class 将被设置为指向 GObjectClass 实例。这就是允许链接的原因。

因此,如果你想实现 constructed 虚方法并向上链接(你 必须 向上链接 constructed),只需按照 example code in the documentation you linked to does。没错。


The same applies with the properties. Because A defines it's properties by an enum, that can go from 0 to N.

不正确。当使用 g_object_class_install_properties() 向 class 注册 属性 时,属性 索引与 class 结构内的 GObjectClass 实例相关联class。它们与 GObject 类型的独立 GObjectClass 结构无关。这个和上面的原理是一样的。

换句话说,没有 属性 索引的全局注册:它们都是按 class 完成的。因此,您可以(并且应该)为每个 classes 从 1 开始对属性进行索引。他们不会冲突。

请注意,如 g_object_class_install_properties() 的文档中所述,属性 索引 0 是特殊的,不得使用。您必须从 1 开始 属性 索引。


正如 ptomato 所说,这远远超出了文档的详细程度。你应该阅读源代码。