创建一个对象的时候,一个对象包含两部分,类结构体和实例结构体。所以私有结构体也分两种:

  1. 类里面添加私有结构体

  2. 实例里面添加私有结构体

可以参考:GtkWidget对象,该对象即有类私有结构体,也有实例私有结构体

1 类添加私有结构体

/* 1. 结构体定义 */
typedef struct _MyObjectClassPrivate MyObjectClassPrivate;
struct _MyObjectClassPrivate
{
  gint secret_class_count;
};

/* 2. 类型定义 */
/**
 * g_define_type_id是G_DEFINE_TYPE_WITH_CODE宏里面,表示MyObject类型的ID。
*/
G_DEFINE_TYPE_WITH_CODE (MyObject, my_object, G_TYPE_OBJECT,
                         g_type_add_class_private (g_define_type_id, sizeof (MyObjectClassPrivate)) );

alt text

2 实例添加私有结构体

2.1 结构体名称(类型名+Private)

只需要在实例对象名称TypeName后面加(Private)

/* 一定要是 TestObjectPrivate,因为 G_DECLARE_FINAL_TYPE 和 G_DECLARE_DERIVABLE_TYPE 没有 typedef struct _TestObjectPrivate TestObjectPrivate */
typedef struct _TestObjectPrivate TestObjectPrivate;
struct _TestObjectPrivate{
  int dummy_0;
  float dummy_1;
} TestObjectPrivate;

2.2 如何定义

方式一

G_DEFINE_TYPE_WITH_CODE (TestObject, test_object, G_TYPE_OBJECT,
                         G_ADD_PRIVATE (TestObject))

方式二

G_DEFINE_TYPE_WITH_PRIVATE (TestObject, test_object, G_TYPE_OBJECT)

其实核心都是一样,都是调用 g_type_add_instance_private,然后把私有结构体的大小赋值给 private_size

alt text

对象被创建的时候,其实创建的大小等于 instance_size + private_size

alt text

2.3 问题总结

私有结构体能否被继承:

可以被继承,一般不能被访问到(除非定义到同一个源文件里面)。私有结构体一般被定义到源文件里面,还有获取私有结构体的 类型_名称_get_instance_private()函数也是在源文件里面定义的。

alt text

为什么有时候实例结构体定义的时候有私有结构体指针:

为了便于外部找到私有结构体地址,我们以 GApplication 为例:

/* gapplication.h */
struct _GApplication
{
  /*< private >*/
  GObject parent_instance;

  GApplicationPrivate *priv;
};

/* gapplication.c */
static void
g_application_init (GApplication *application)
{
  /* 会把实际的私有结构体地址获取到,赋值给 application->priv */
  application->priv = g_application_get_instance_private (application);

  ...
}