本文是笔者整理网上资料加上一些自己实践的纪录,本文的主体内容转自如下文章:
源博客网址:http://garfileo.is-programmer.com/categories/6934/posts
以下是本文的所主要学习实践的其中d这个小题目的原文链接。
http://garfileo.is-programmer.com/2011/3/4/accessing-properties-of-gobject-subclass.24952.html#ref-3
该文没有其他好特别说的,主要学习的是对私有数据的“好”的访问方法及其必要性。其实就是get和set方法。只不过Gobject的get和set方法有一定的步骤。
唯一需要特别关注的是,属性的安装是在class_init中完成的。
以下是作者原文转载,放在此处纯属为了自己方便,并防止原文地址丢失。
GObject 子类私有属性的外部访问
之前,写了一篇 GObject 劝学的文章 [1],还有两篇有关 GObject 子类对象数据封装的文章 [2, 3]。
虽然,创建一个 GObject 子类对象需要一些辅助函数和宏的支持,并且它们的内幕也令人费解,但是只要将足够的信任交托给 GObject 开发者,将那些辅助函数和宏当作“语法”糖一样享用,一切还是挺简单的。至于细节,还是等较为全面的掌握 GObject 库的用法之后再去挖掘!
现在,我们基本上知道了如何将数据封装并藏匿于 GObject 子类的实例结构体中。本文打算再向前走一步,关注如何实现在外部比较安全的访问(读写)这些数据。
简单的做法
像下面这样的双向链表数据结构:
typedef struct _PMDListNode PMDListNode;
struct _PMDListNode {
PMDListNode *prev;
PMDListNode *next;
};
typedef struct _PMDList PMDList;
struct _PMDList {
PMDListNode *head;
PMDListNode *tail;
};
现在,我们希望能够安全访问 PMDList 结构题的两个成员,即链表的首结点指针 head 和尾结点指针 tail,以便进行一些操作,例如将两个双向链表 list1 和 list2 链接到一起。
所谓安全访问,意味着不要像下面这样简单粗暴:
/* 将 list1 与 list2 链接在一起 */
list1->tail->next = list2->head;
list2->head->prev = list1->tail;
而应当委婉一些:
PMDListNode *list1_tail, *list2_head;
list1_tail = pm_dlist_get (list1, TAIL);
list2_head = pm_dlist_get (list2, HEAD);
pm_dlist_set (list1, TAIL, NEXT, list2_head);
pm_dlist_set (list2, HEAD, PREV, list1_tail);
这样委婉的访问,有什么好处?答案很简单,可以将数据的变化与程序的功能隔离开,数据的变化不影响程序的功能。
试想,如果有一天,上述 PMDList 结构体的设计者使用 GObject 子类化的方法将双向链表定义为建 PMDList 类的形式,并且将链表的首结点指针 head 与尾结点都隐匿起来,那么上述的那个简单粗暴的数据访问方法便失效了。更糟糕的是,PMDList 类的设计者明知道很多人会受到这种数据变化的影响,对此也毫无办法。
如果 PMDList 结构体的设计者提供了 pm_dlist_set 与 pm_dlist_get 函数,那么即便设计者基于 GObject 子类化的方式定义了 PMDList 类,他只需要修改 pm_dlist_set 和 pm_dlist_get 函数,便可以让上述那种委婉方式访问 PMDList 结构体成员的代码不会受到任何影响。
既然 pm_dlist_set 与 pm_dlist_get 函数这样有用,我们可以像下面这样实现它们。
typedef enum _PM_DLIST_PROPERTY PM_DLIST_PROPERTY
enum _PM_DLIST_PROPERTY {
PM_DLIST_HEAD,
PM_DLIST_TAIL,
PM_DLIST_NODE_PREV,
PM_DLIST_NODE_NEXT
};
PMDListNode *
pm_dlist_get (PMDList *self, PM_DLIST_PROPERTY property)
{
PMDListNode *node = NULL;
switch (property) {
case PM_DLIST_HEAD:
node = self->head;
break;
case PM_DLIST_TAIL:
node = self->tail;
break;
default:
g_print ("对不起,你访问的成员不存在!\n");
}
return node;
}
void
pm_dlist_set (PMDList *self,
PM_DLIST_PROPERTY property,
PM_DLIST_PROPERTY subproperty,
PMDListNode *node)
{
switch (property) {
case PM_DLIST_HEAD:
if (subproperty == PM_DLIST_NODE_PREV)
self->head->prev = node;
else if (subproperty == PM_DLIST_NODE_NEXT)
self->head->next = node;
break;
case PM_DLIST_TAIL: