本文是笔者整理网上资料加上一些自己实践的纪录,本文的主体内容转自如下文章:
源博客网址:http://garfileo.is-programmer.com/categories/6934/posts
以下是本文的所主要学习实践的其中c这个小题目的原文链接。
http://garfileo.is-programmer.com/2011/2/28/data-hiden.24848.html
本节主要是体会数据隐藏的意义和方式方法。
- 头文件之包含了实例结构体和类结构体的声明,不仅简洁,而且有效对开发者屏蔽了所谓的细节信息,但是更重要的是其他开发者在引用了pm-dlist.h之后,只要该头文件不变,即便具体的实现变化,哪怕是在数据结构中增减变量,都不会引发其他程序的重新编译。当然前提是pm-dlist自己形成了动态链接库。为此笔者做了简单的实验:
$ gcc pm-dlist.c $(pkg-config --cflags --libs gobject-2.0) -fPIC -shared libpm-dlist.so
$ gcc main.c $(pkg-config --cflags --libs gobject-2.0) -L./ -lpm-dlist -o test
$ ./test
这样可以复原原作者的实验结果。唯一区别是,没有将所有文件编译在一起。
然后修改pm-dlist.c,比如在PMDListPrivate中添加变量char label。此时,只需要再次重新编译libpm-dlist.so然后再运行test就可以反映出变化。
-
进一步思考的在c++中,private关键字,名义上也是为了实现“数据隐藏”。但是这种隐藏如果明确写在头文件中,那么实际上也没有对别的开发者进行屏蔽。虽然有访问限制,但是,对调用者并非“悄无声息”。特别是,如果出现1所述场景,还会引发问题。针对此,所以就有了所谓“PIMPL idiom”,具体可参考下列链接:
(1). https://stackoverflow.com/questions/60570/why-should-the-pimpl-idiom-be-used
(2). https://cpppatterns.com/patterns/pimpl.html -
作者成文于2011年,所以有些代码稍显老旧,除了GObject学习(一)中所说,本文亦有部分,所以说明如下:
(1). G_TYPE_INSTANCE_GET_PRIVATE已经处于deprecated状态。
G_TYPE_INSTANCE_GET_PRIVATE has been deprecated since version 2.58 and should not be used in newly-written code.Use G_ADD_PRIVATE and the generated your_type_get_instance_private() function instead
从中可以看到,目前官方推荐使用的宏是G_ADD_PRIVATE。
A convenience macro to ease adding private data to instances of a new type in the C section of G_DEFINE_TYPE_WITH_CODE() or G_DEFINE_ABSTRACT_TYPE_WITH_CODE().
笔者采用配合使用的宏就是G_DEFINE_TYPE_WITH_CODE(),注意这个宏是用来定义新“类型”的,其对标的对象是第一节提到的G_DEFINE_TYPE()
G_DEFINE_TYPE_WITH_CODE (PMDList, pm_dlist, G_TYPE_OBJECT, {
G_ADD_PRIVATE(PMDList); \
g_printf("This is in PMDList type add private, %d\n", PMDList_private_offset);});
进一步,就不需要再在_class_init中添加g_type_class_add_private (klass, sizeof (PMDListPrivate));这个函数了。
- G_DEFINE_TYPE()和G_DEFINE_TYPE_WITH_CODE()
#define G_DEFINE_TYPE(TN, t_n, T_P) G_DEFINE_TYPE_EXTENDED (TN, t_n, T_P, 0, {
})
#define G_DEFINE_TYPE_EXTENDED(TN, t_n, T_P, _f_, _C_) _G_DEFINE_TYPE_EXTENDED_BEGIN (TN, t_n, T_P, _f_) {
_C_