三、使用GObject——私有成员和静态变量

像C++、Java这些面向对象语言中都有访问权限的概念,公有(public)类型的成员别人可以随便访问,保护(protected)类型的成员只能由子类访问,而私有(private)类型的成员只允许自己访问等等.那么在GObject系统中如何实现访问权限呢.公有类型的权限不是问题,在头文件中声明的成员或函数都是公有类型.那么私有类型呢?私有函数很好定义,只要将函数定义在源文件中,声明为static,那别人就不能访问了.难就难在如何定义私有变量.

在GObject中定义私有变量的通用方法则有两种.一种是GTK的做法,定义结构体时通过注释说明那些变量是私有变量.像下面这样:
struct _TestDog
{
GObject parent_instance;
/* < private > */
int age;
};

这就把保护私有变量这个难题抛给了类的使用者.

我们重点介绍另外一种方法,这种方法利用了C语言的一个特性,就是即使在结构体还没有定义的情况下,我们也可以声明结构体的指针,只要不通过该指针访问结 构体的成员就没有问题,如果使用该指针访问结构体的成员,编译器就会报类型未定义的错误.在定义类时,我们可以将类的私有变量都定义到一个Private 结构体中,并且在头文件中定义类的对象部分结构体时,将Private结构体的指针定义为成员,而在源文件中才正式定义这个Private结构体,如下:
/*
                test-dog.h
                */
                
typedef struct _TestDogPrivate TestDogPrivate;
struct _TestDog
{
GObject parent_instance;
TestDogPrivate* priv;
};
/* test-dog.c */
struct _TestDogPrivate
{
int age;
};

这样就只有在test-dog.c中访问TestDogPrivate中的成员才是合法的,在其他文件中访问就会出现编译错误.
至于如何定义保护类型的成员,好像没有什么好方法,向GTK学习吧,加注释.

静态变量是类的变量,是由所有该类型的对象共有的,所以静态变量只能定义在类的类部分结构体中,反过来说定义在类的类部分结构体中变量都是静态变量.
struct _TestDogClass
{
GObjectClass parent_class;
int dog_count;
};

dog_count统计了当前已经生成的TestDog对象的个数.
那么如何定义私有类型的静态变量呢,好像也只能向GTK学习,加注释.

下面是完整的代码:
#ifndef TEST_DOG_H
#define TEST_DOG_H
#include <glib-object.h>
#define TEST_TYPE_DOG (test_dog_get_type())
#define TEST_DOG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TEST_TYPE_DOG, TestDog))
#define TEST_IS_DOG(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), TEST_TYPE_DOG))
#define TEST_DOG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), TEST_TYPE_DOG, TestDogClass))
#define TEST_IS_DOG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), TEST_TYPE_DOG))
#define TEST_DOG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), TEST_TYPE_DOG, TestDogClass))
typedef struct _TestDog TestDog;
typedef struct _TestDogClass TestDogClass;
typedef struct _TestDogPrivate TestDogPrivate;
struct _TestDog
{
GObject parent_instance;
TestDogPrivate* priv;
};
struct _TestDogClass
{
GObjectClass parent_class;
int dog_count;
};
GType test_dog_get_type(void);
int test_dog_get_age(TestDog* self);
void test_dog_set_age(TestDog* self, int age);
int test_dog_get_count(void);
#endif


我们声明了访问和写入私有变量age的函数int test_dog_get_age(TestDog* self)和void test_dog_set_age(TestDog* self, int age),还有访问静态成员dog_count的int test_dog_get_count(void),可以看出访问静态成员的函数不需要TestDog对象的指针作为参数.
#include "
                test-dog.h
                "
                
#include <glib/gprintf.h>
#include <string.h>
#define TEST_DOG_GET_PRIVATE(obj) /
(G_TYPE_INSTANCE_GET_PRIVATE ((obj), TEST_TYPE_DOG, TestDogPrivate))
struct _TestDogPrivate
{
int age;
};
static gpointer test_dog_class = NULL;
static void test_dog_finalize (GObject *gobject)
{
TEST_DOG_CLASS(test_dog_class)->dog_count -= 1;
G_OBJECT_CLASS (g_type_class_peek_parent(test_dog_class))->finalize (gobject);
}
static void test_dog_class_init(gpointer g_class, gpointer g_class_data)
{
TestDogClass* dog_class_pointer = NULL;
test_dog_class = g_class;
dog_class_pointer = TEST_DOG_CLASS(g_class);
dog_class_pointer->dog_count = 0;
G_OBJECT_CLASS(dog_class_pointer)->finalize = test_dog_finalize;
g_type_class_add_private(g_class, sizeof(TestDogPrivate));
}
static void test_dog_instance_init(GTypeInstance *instance, gpointer g_class)
{
TestDog* dog_pointer = TEST_DOG(instance);
dog_pointer->priv = TEST_DOG_GET_PRIVATE(dog_pointer);
dog_pointer->priv->age = 2;
TEST_DOG_CLASS(test_dog_class)->dog_count += 1;
}
GType test_dog_get_type(void)
{
static GType type = 0;
if (type == 0) {
static const GTypeInfo info = {
sizeof (TestDogClass),
NULL, /* base_init */
NULL, /* base_finalize */
(GClassInitFunc) test_dog_class_init,
NULL, /* class_finalize */
NULL, /* class_data */
sizeof (TestDog),
0, /* n_preallocs */
(GInstanceInitFunc) test_dog_instance_init /* instance_init */
};
type = g_type_register_static (G_TYPE_OBJECT,
" TestDogType ",
&info, 0);
}
return type;
}
void test_dog_set_age(TestDog* self, int age)
{
self->priv->age = age;
}
int test_dog_get_age(TestDog* self)
{
return self->priv->age;
}
int test_dog_get_count(void)
{
return TEST_DOG_CLASS(test_dog_class)->dog_count;
}

TEST_DOG_GET_PRIVATE(obj)用来取得对象私用成员的地址,在对象的初始化函数中我们将其赋值给了对象的priv成员.static void test_dog_finalize (GObject *gobject)函数在对象析构时会被调用.

#include <glib.h>
#include <glib/gstdio.h>
#include " test-dog.h "
int main(void)
{
TestDog* dog1 = NULL;
TestDog* dog2 = NULL;
g_type_init();
dog1 = (TestDog*)g_object_new(TEST_TYPE_DOG, NULL);
g_printf(" new dog1, dog's count is %d/n ", test_dog_get_count());
g_printf(" dog1's age is %d/n ", test_dog_get_age(dog1));
dog2 = (TestDog*)g_object_new(TEST_TYPE_DOG, NULL);
g_printf(" new dog2, dog's count is %d/n ", test_dog_get_count());
test_dog_set_age(dog2, 5);
g_printf(" dog2's age is %d/n ", test_dog_get_age(dog2));
g_object_unref(dog1);
g_printf(" unref dog1, dog's count is %d/n ", test_dog_get_count());
g_object_unref(dog2);
g_printf(" unref dog2, dog's count is %d/n ", test_dog_get_count());
}

你可能感兴趣的:(三、使用GObject——私有成员和静态变量)