1.1 PMDList类头文件

/*  file name : pm-dlist.h */
#ifndef PM_DLIST_H
#define PM_DLIST_H

#include <glib-object.h>

/**
  *   通过该宏指向的pm_dlist_get_type函数
  * 可以获得PMDList类结构体信息和初始化函数
  * pm_dlist_get_type函数内部的实现由G_DEFINE_TYPE宏实现
  */
#define PM_TYPE_DLIST (pm_dlist_get_type ())
  
typedef struct _PMDList PMDList;
struct  _PMDList {
        GObject parent_instance;
};
  
typedef struct _PMDListClass PMDListClass;
struct _PMDListClass {
        GObjectClass parent_class;
};
  
GType pm_dlist_get_type (void);
  
#endif

分析

typedef struct _PMDList PMDList;
struct  _PMDList {
        GObject parent_instance;
};

  只保留了父类成员,其他变量移到C文件中,可以数据隐藏。这本章节加入了私有属性隐藏,其实PMDList类已经是由三个结构体组成的PMDList实例结构体PMDListClass类结构体,下文中马上提到的PMDListPrivate私有属性结构体。至于私有属性结构体,怎样加入到PMDList类中,下文讲到。

1.2 PMDList类函数

/* file name : pm-dlist.c */
#include "pm-dlist.h"

G_DEFINE_TYPE (PMDList, pm_dlist, G_TYPE_OBJECT);
#define PM_DLIST_GET_PRIVATE(obj) (\
        G_TYPE_INSTANCE_GET_PRIVATE ((obj), PM_TYPE_DLIST, PMDListPrivate))

typedef struct _PMDListNode PMDListNode;
struct  _PMDListNode {
        PMDListNode *prev;
        PMDListNode *next;
        void *data;
};

typedef struct _PMDListPrivate PMDListPrivate;
struct  _PMDListPrivate {
        PMDListNode *head;
        PMDListNode *tail;
};

static void
pm_dlist_class_init (PMDListClass *klass)
{
        g_type_class_add_private (klass, sizeof (PMDListPrivate));
}
 
static void
pm_dlist_init (PMDList *self)
{
        PMDListPrivate *priv = PM_DLIST_GET_PRIVATE (self);
         
        priv->head = 0x3333;
        priv->tail = 0x2222;
}

分析   私有成员结构体PMDListPrivate可以通过PM_DLIST_GET_PRIVATE(obj)宏获取PMDList对象的head与tail指针。但是,那个PMDListPrivate结构体是怎样被添加到PMDList对象中的呢?答案存在于PMDList类的类结构体初始化函数之中,如下:

static void
pm_dlist_class_init (PMDListClass *klass)
{
   g_type_class_add_private (klass, sizeof (PMDListPrivate));
}

  所以,在类初始化的时候,因为类初始化函数只会运行一次且,比pm_dlist_init函数先运行。g_object_new函数调用,GObject库的类型管理系统可以从pm_dlist_clss_init函数中获知PMDListPrivate结构体所占用的存储空间,便会多分出一部分以容纳PMDListPrivate结构体,这样便相当于将一个PMDListPrivate结构体挂到PMDList对象之中。   GObject 库对私有属性所占用的存储空间是由限制的。一个 GObject 子类对象,它的私有属性及其父类对象的私有属性累加起来不能超过 64 KB。

1.3 MAIC函数

#include "pm-dlist.h"
  
int
main (void)
{
        /* GObject 库的类型管理系统的初始化 */
        g_type_init ();
     
        PMDList *list;
 
        list = g_object_new (PM_TYPE_DLIST, NULL);
        g_object_unref (list);
          
        return 0;
}

总结

  1. 类头文件的实例结构体私有成员,隐藏在类C文件中,重新命令一个新的私有属性结构体。该私有属性结构体成员可以通过宏PM_DLIST_GET_PRIVATE(obj)构建PMDList和 PMDListPrivate的联系。即可以通过该宏访问私有属性内部成员。
  2. PMDListPrivate是由类初始化函数添加到PMDList类,并在此时分配内存空间。我们可以通过PM_DLIST_GET_PRIVATE获得该内存空间地址,修改成员变量。
  3. 如果在类C文件下面创建函数,都是可以访问私有熟悉成员的。

上述的子对象私有属性,私有属性是添加到的是类对象,所以创建两个PMList对象,两个的PMList私有结构体地址是相同的

#include "pm-dlist.h"
  
int
main (void) {
        PMDList *list1, *list2;

        list1 = g_object_new (PM_TYPE_DLIST, NULL);
        list2 = g_object_new (PM_TYPE_DLIST, NULL);


        PMDListPrivate *list1_priv = PM_DLIST_GET_PRIVATE (list1);
        PMDListPrivate *list2_priv = PM_DLIST_GET_PRIVATE (list1);

        g_print ("list1_priv address = %p\n", list1_priv);
        g_print ("list2_priv address = %p\n", list2_priv);

        g_object_unref (list1);
        g_object_unref (list2);
        
        return 0;
}

输出结果如下

list1_priv address = 0x56203f502800
list2_priv address = 0x56203f502800

补充(Oct-26-2023)

  • g_type_class_add_private在2.58版本以后不赞成使用。

  • 推荐使用G_DEFINE_TYPE_WITH_PRIVATE宏(给实例添加私有成员)。