GObject 02: A classed type

Now I am going to create a classed type.

Q: What is a class?
A: I don't know for sure. In object-oriented programming, a class represents a "kind" of data. It specifies what data there is (the members/fields) in each object (instance) and what can be done (the methods) to the object.

Q: What is a "classed" type in GObject?
A: It is a type that has a "class struct".

Each "classed type" has a unique instance of "class structure". Note that IN GOBJECT, THERE IS A DIFFERENCE BETWEEN A "Class" AND AN "Instance". A "Class" IS SOMETHING THAT IS SHARED BY ALL OBJECTS OF A CLASS AND AN "Instance" IS SOMETHING THAT IS SPECIFIC TO EACH OBJECT OF THE CLASS. You can imagine that whatever in a "Class" are like the static members/fields in C++/Java and whatever in an "Instance" are like non-static members/fields.

The code is here:
/* A fundamental type.  It has a class structure, but is not instantiable. */

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

typedef struct {
GTypeClass something_as_boilerplate;
int foo;
char* bar;
void (*baz)();
} myclass_t;

void baz_function() { printf("All your type are belong to us!\n"); }

void my_class_init_func(myclass_t* klass, gpointer data) {
printf("my_class_init_func called!\n");
klass->foo = 42;
klass->bar = "Hello world!";
klass->baz = baz_function;
}

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 */
0, //guint16 instance_size;
0, //guint16 n_preallocs;
NULL, //GInstanceInitFunc instance_init;

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

GTypeFundamentalInfo my_fundamental_info = {
G_TYPE_FLAG_CLASSED
};

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

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

myclass_t *klass = (myclass_t*)g_type_class_ref(my_type_id);

printf("foo: %d\n", klass->foo);
printf("bar: %s\n", klass->bar);
klass->baz();

g_type_class_unref(klass);

return 0;
}


Let's look at the my_type_info struct in the main function. I filled the class_size field to be sizeof(myclass_t) so that the type-system can help me "malloc" my myclass_t struct. I also filled the class_init function so that it will call my my_class_init_func to initialize it.

But I didn't fill the instance_size or instance_init so it is not instantiatable. That is, this type has no instances.

Q: How can it be it useful to have such a type that has no instances?
A: Well... I admit it is not that useful. It may work as something like a "singleton" (a globally unique object). Interfaces (like they are in Java/C#) in GObject are also non-instantiatable types.

Then the my_fundamental_info struct following the my_type_info variable in the main function. I marked this class as "classed".


Let's look at my myclass_t structure.

Q: Why don't you follow the GObject naming convention and name it as MyClass?
A: It is intentional. I am emphasizing that it is not the naming-convention, but the function calls (like g_type_register_fundamental) and its parameters (like GTypeInfo, GTypeFundamentalInfo and so on) that make GObject work. Yeah, you should follow the convention in real-world programming.

typedef struct {
GTypeClass something_as_boilerplate;
int foo; // Not a good idea to store data here.
char* bar;
void (*baz)();
} myclass_t;


The first member is a GTypeClass field. It is required that in GObject type system, all class-structs should begin with a GTypeClass field.

Q: What's inside the GTypeClass?
A: The documentation does not tell me. The source code is:
typedef struct _GTypeClass              GTypeClass;
struct _GTypeClass
{
/*< private >*/
GType g_type;
};


So every class struct starts with a GType field (GType is typedef'ed to be gsize which is then typedef'ed to be unsigned int). This can be queryed at runtime to find the type-id (GType) of a type.

Then there are an int field "foo", a char pointer "bar" and a function pointer "baz" in myclass_t struct. foo and bar are static members of my class. baz, which you may think to be a static member, can also be a virtual method of a class (this will be discussed later).

Let's move on to the my_class_init_func which I filled into the class_init field of the "GTypeInfo my_type_info" struct.
void my_class_init_func(myclass_t* klass, gpointer data) {
printf("my_class_init_func called!\n");
klass->foo = 42;
klass->bar = "Hello world!";
klass->baz = baz_function;
}


It takes two parameters. One of them is a myclass_t pointer pointing to the struct to be initialized. I name it "klass" because "class" is a keyword in C++ and would not work with a C++ compiler. The other is the class_data field provided in the GTypeInfo struct (where I set it to NULL).

I initialized the myclass_t struct here. I filled the foo, bar and baz field.


Now the main function. Here I register my type. And then:
    myclass_t *klass = (myclass_t*)g_type_class_ref(my_type_id);

printf("foo: %d\n", klass->foo);
printf("bar: %s\n", klass->bar);
klass->baz();

g_type_class_unref(klass);

I call the g_type_class_ref function so that my class struct is initialized. Then the members of klass are filled. Finally I call the g_type_class_unref(klass) to unref this class (this may be not necessary here).


Note that it is not a good idea to store static data member into the class struct. It is difficult to get a pointer to the class struct without having an instance of this class. You may wish to access the class member in the main function or in a static function. It is better to use global variables and use naming conventions to show that they belong to a class.
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值