GObject和继承

时间:2018-01-17 16:48:32

标签: inheritance glib gobject

我在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;
}

但是当你有这种安排时。子类执行此操作:object_class-> construct = viewer_file_constructed;在B中实际上覆盖了构造的唯一内存地址。所以它意味着G_OBJECT_CLASS(viewer_file_parent_class) - > construct(obj);将以递归方式调用B->。而这不是我们想要的。

也许我不明白,但我认为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分类共享的。并且所有地址都是相同的...

  • G_OBJECT_CLASS(B) - >构建
  • G_OBJECT_CLASS(A) - >构建

这是对的吗? 所以,如果我想覆盖构造...我是否必须保存之前的指针,然后在我的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
};

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

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

1 个答案:

答案 0 :(得分:6)

  

内部表示应该是这样的:

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

如果您的某个类FooBar派生自GObject,那么FooBarClass结构将类似于:

typedef struct
{
  GObjectClass parent_class;

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

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

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

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

因此,如果您要实施constructed虚拟方法并进行链接(必须链接constructed),请执行example code in the documentation you linked to does。这是对的。

  

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

不正确的。使用g_object_class_install_properties()向类注册属性时,属性索引与该类的类结构中的GObjectClass实例相关联。它们与GObject类型的独立GObjectClass结构无关。这与上述原理相同。

换句话说,没有属性指数的全球注册表:它都是按类进行的。因此,您可以(并且应该)为每个类启动1的属性索引。他们不会发生冲突。

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

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