`
cloverprince
  • 浏览: 129824 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

GObject 04: A class with private members

阅读更多
A private member is a member that is only accessible by other methods of the class.

Q: Why private?  It is inconvenient, isn't it?
A: Exposing all details may offer some convenience, but it is almost always undesirable.

Q: Why?
A: You may allow your users to directly access your private data and you suddenly changed the internal structure of your class and the user code no longer work.

The practical way is to introduce "private data".  Private data are stored separately from the public data so that changing the private data does not affect the interface of the class.  Other code using this class will stay working as long as the public data are not changed.

See the Bridge Pattern, a famous design pattern.


GObject provide mechanism to add "private struct" to a class.

This is the full code which you can safely skip.
/* A fundamental type.  Instantiatable.  Has private struct. */

#include <stdio.h>
#include <glib-object.h>

typedef struct {
    GTypeClass something_as_boilerplate;
} myclass_t;

typedef struct {
    GTypeInstance something_as_boilerplate;
    int an_instance_member;
} myinstance_t;

typedef struct {
    int a_private_instance_member;
} myinstance_private_t;

void my_class_init_func(myclass_t* klass, gpointer data) {
    g_type_class_add_private(klass,sizeof(myinstance_private_t));
}

void my_instance_init_func(myinstance_t *instance, gpointer data) {
    myinstance_private_t *priv;
    priv = G_TYPE_INSTANCE_GET_PRIVATE(instance,G_TYPE_FROM_INSTANCE(instance),myinstance_private_t);
    priv->a_private_instance_member = 81;
}

int main() {
    g_type_init();

    GTypeInfo my_type_info = {
        sizeof(myclass_t),  //guint16                class_size;

        NULL,               //GBaseInitFunc          base_init;
        NULL,               //GBaseFinalizeFunc      base_finalize;

        /* classed types, instantiated types */
        (GClassInitFunc)my_class_init_func, //GClassInitFunc         class_init;
        NULL,               //GClassFinalizeFunc     class_finalize;
        NULL,               //gconstpointer          class_data;

        /* instantiated types */
        sizeof(myinstance_t),//guint16               instance_size;
        0,                  //guint16                n_preallocs;
        (GInstanceInitFunc)my_instance_init_func, //GInstanceInitFunc      instance_init;

        /* value handling */
        NULL,               //const GTypeValueTable *value_table;
    };

    GTypeFundamentalInfo my_fundamental_info = {
        G_TYPE_FLAG_CLASSED | G_TYPE_FLAG_INSTANTIATABLE
    };

    GType my_type_id = g_type_register_fundamental(
            g_type_fundamental_next(),
            "MyTypeWithPrivate",
            &my_type_info,
            &my_fundamental_info,
            0
            );

    printf("%d\n",my_type_id);
    printf("%s\n",g_type_name(my_type_id));

    myinstance_t *inst = (myinstance_t*)g_type_create_instance(my_type_id);

    myinstance_private_t *priv = G_TYPE_INSTANCE_GET_PRIVATE(inst,my_type_id,myinstance_private_t);

    printf("%d\n",priv->a_private_instance_member);
    priv->a_private_instance_member = 90;
    printf("%d\n",priv->a_private_instance_member);

    g_type_free_instance((GTypeInstance*)inst);

    return 0;
}


First let's see the structs.
typedef struct {
    GTypeClass something_as_boilerplate;
} myclass_t;

typedef struct {
    GTypeInstance something_as_boilerplate;
    int an_instance_member;
} myinstance_t;

typedef struct {
    int a_private_instance_member;
} myinstance_private_t;

There is only one class, which has three separate structs now.
  • myinstance_t, the instance struct, stores public data.
  • myinstance_private_t, the private data struct, stores private data.


Now let's tell GObject about the existance of such a class.  You may skip this.
    GTypeInfo my_type_info = {
        sizeof(myclass_t),  //guint16                class_size;

        NULL,               //GBaseInitFunc          base_init;
        NULL,               //GBaseFinalizeFunc      base_finalize;

        /* classed types, instantiated types */
        (GClassInitFunc)my_class_init_func, //GClassInitFunc         class_init;
        NULL,               //GClassFinalizeFunc     class_finalize;
        NULL,               //gconstpointer          class_data;

        /* instantiated types */
        sizeof(myinstance_t),//guint16               instance_size;
        0,                  //guint16                n_preallocs;
        (GInstanceInitFunc)my_instance_init_func, //GInstanceInitFunc      instance_init;

        /* value handling */
        NULL,               //const GTypeValueTable *value_table;
    };

    GTypeFundamentalInfo my_fundamental_info = {
        G_TYPE_FLAG_CLASSED | G_TYPE_FLAG_INSTANTIATABLE
    };

    GType my_type_id = g_type_register_fundamental(
            g_type_fundamental_next(),
            "MyTypeWithPrivate",
            &my_type_info,
            &my_fundamental_info,
            0
            );

Nothing special.

The secret lies in the class init function.
void my_class_init_func(myclass_t* klass, gpointer data) {
    g_type_class_add_private(klass,sizeof(myinstance_private_t));
}

So simple!  Just tell GObject that there is a private struct for my class and pass in its size as an argument as well.  Then the private struct will be allocated together with each instance.

Q: How to access the private struct?
A: see:
void my_instance_init_func(myinstance_t *instance, gpointer data) {
    myinstance_private_t *priv;
    priv = G_TYPE_INSTANCE_GET_PRIVATE(instance,G_TYPE_FROM_INSTANCE(instance),myinstance_private_t);
    priv->a_private_instance_member = 81;
}

Use the G_TYPE_INSTANCE_GET_PRIVATE macro to extract the private struct from an instance.

That's it.


Note that you can call G_TYPE_INSTANCE_GET_PRIVATE anywhere in your program, even outside any methods of the class.  Since the C language does not understand "class" or "private", it makes no different what is "inside" a class or "outside" a class.  That's to say, your private struct is accessible anywhere.

To further keeping the user from messing up with your private struct, you can provide the definition of the public struct in the header file (*.h) and keep the definition of the private struct in the implement file (*.c) and keep the private struct undocumented so that the users do not know what is inside the private struct.

This still does not stop the users if they copy your source code if your program is open-sourced, but their programs may break at any time since you can change the private struct without a warning.  It is not your fault.  It relies on the good habit of programmers to write good programs.

分享到:
评论
2 楼 cloverprince 2011-04-25  
xjtusehcy 写道
I think we should not use G_TYPE_FROM_INSTANCE to get the type of the instance in G_TYPE_INSTANCE_GET_PRIVATE. If this class has derived class, and the instance is an instance of its derived class, G_TYPE_FROM_INSTANCE will return the derived class type. Then, we will get the derived class's private data from G_TYPE_INSTANCE_GET_PRIVATE, not the class's.


Agreed.  So we'd better hard-code the name of the class whenever we need the private struct.
1 楼 xjtusehcy 2011-04-24  
I think we should not use G_TYPE_FROM_INSTANCE to get the type of the instance in G_TYPE_INSTANCE_GET_PRIVATE. If this class has derived class, and the instance is an instance of its derived class, G_TYPE_FROM_INSTANCE will return the derived class type. Then, we will get the derived class's private data from G_TYPE_INSTANCE_GET_PRIVATE, not the class's.

相关推荐

    Giveda_GObject_c++11_v1.5

    利用本软件,c++开发者可以在不依赖c++编译器之外的任何工具的前提下,实现c++中类与类之间的解耦合(class A对象与class B对象之间的解耦合)。 本软件支持c++11并向后兼容(支持c++11及其后续版本)。 开发环境为...

    gobject_create_class_demo.tar.gz

    本示例用于演示GObject创建新类,类的继承与重载。代码实现了shape和square类,继承关系为: square -&gt; shape -&gt;gobject 其中,square重载了shape类的info接口。

    GObject Reference Manual

    The GObject base class Object instanciation Object memory management Reference count Weak References Reference counts and cycles Object properties Accessing multiple properties at once The ...

    Gobject 离线API手册

    GObject是GTK+库的核心组件,它为C语言提供了一种面向对象的编程模型。在GTK+和Gnome开发中,GObject系统是构建复杂、可扩展软件的基础。这个离线API手册包含了GObject框架的详细信息,对于理解并利用GObject进行...

    Gobject Reference Manual

    《GObject参考手册》是针对GLib库中的核心组件GObject进行详细解释的重要参考资料,尤其对深入理解并熟练使用GObject系统至关重要。GLib是GNOME桌面环境的基础库,广泛应用于各种C语言开发的跨平台项目。GObject是...

    gobject-snippets:UltiSnips C 片段有助于编写 GObject 代码

    UltiSnips C 片段有助于编写 GObject 代码 安装 这些片段使用 UltiSnips ( ) 所以你应该先安装和配置它。 我使用 Vundle ( ) 来管理 vim 插件,但这不是强制性的。 如果你使用 Vundle,你可以添加到你的 ~/.vimrc ...

    crystal-gobject:Crystal的gobject-introspection

    crystal-gobject:Crystal的gobject-introspection

    Gobject 资料,全面介绍

    Gobject 资料,全面介绍Gobject 资料,全面介绍Gobject 资料,全面介绍Gobject 资料,全面介绍Gobject 资料,全面介绍Gobject 资料,全面介绍Gobject 资料,全面介绍

    groonga-gobject:Groonga的GObject包装器

    Groonga GObject 描述 Groonga的GObject包装器。 去做... 安装 Debian GNU / Linux 。 运行以下命令: % sudo apt-get install -V -y gir1.2-groonga libgroonga-gobject0 的Ubuntu 。 运行以下命令: % ...

    gobject_setup_property_demo.zip

    在IT领域,特别是软件开发中,GObject是一个关键的概念,它是GTK+库中的基础对象模型。GObject系统为C语言提供了面向对象编程的支持,而这个"gobject_setup_property_demo.zip"压缩包显然提供了一个关于如何使用...

    gobject:适用于PHP的静态Gobject绑定

    gtkforphp gobject扩展为GObject功能提供了语言绑定。 有关该库的文档和信息可以在找到 现在,这只不过是一个占位符。 您可以发送评论,补丁,问题 这仍然是实验性的扩展。 安装/配置 此扩展需要gtkforphp / glib...

    yard-gobject-introspection:YARD插件,用于从GObject Introspection数据检索文档

    码-对象反省码插件,用于基于GObject-Intropection构建库文档。要求Ruby / GObject-Introspection尝试一下 git clone ...

    gobject对象系统

    ### gobject对象系统详解 #### 一、简介 GObject是一种强大的对象系统,它为C语言提供了一套灵活且易于扩展的对象模型。虽然C语言本身不是面向对象的语言,但通过GObject,开发者能够构建出类似面向对象编程的功能...

    cairo-gobject-1.15.12-3.el7.x86_64.rpm

    离线安装包,亲测可用

    GObject对象系统

    ### GObject对象系统详解 #### 前言与概述 GObject是GLib库中的一个核心组件,它提供了一个用于C语言的面向对象编程框架。尽管C语言本身并不具备内置的对象和类型系统,但通过GObject,开发人员可以利用类似于其他...

    gir_ffi, 在运行时使用 FFI,为基于GObject的库自动生成绑定.zip

    gir_ffi, 在运行时使用 FFI,为基于GObject的库自动生成绑定 GirFFI由 Matijs van Zuijlen描述使用GObject内省存储库的GNOME的ruby 绑定。状态 特性为基于任何gobject的库创建绑定。在运行时生成绑定。为选定方法...

    lgi:使用GObject-Introspection将动态Lua绑定到GObject库

    液化天然气LGI是基于gobject内省的动态Lua绑定到基于GObject的库。 它允许直接从Lua使用基于GObject的库。 已获得许可的许可,请参见LICENSE文件全文。 该项目的主页位于。 LGI经过测试,并与标准Lua 5.1,Lua 5.2,...

    python3-pygobject3:GObject库的Python 3绑定

    **Python3-pygobject3: GObject库的Python 3绑定** `python3-pygobject3` 是一个Python 3版本的绑定库,它允许Python程序员能够利用GObject库的功能,这是GNOME桌面环境的核心组件之一。GObject库是C语言编写的一个...

    avahi-gobject-0.6.25-11.el6.i686.rpm

    avahi-gobject-0.6.25-11.el6.i686.rpm是centos工具包。

    python-gobject-3.22.0-1.el7_4.1.x86_64.rpm

    离线安装包,亲测可用

Global site tag (gtag.js) - Google Analytics