GObject 03: An Instantiatable Class
2011年08月01日
Most of the time classes are instantiatable. It can create "instances", which have their own data and share common methods of the class.
So a CLASS is shared by many INSTANCEs.
In GObject, we need two structs. One for the class and one for the instance.
/* A fundamental type. Instantiatable. */ #include #include typedef struct { GTypeClass something_as_boilerplate; } myclass_t; int a_class_member_of_myclass; typedef struct { GTypeInstance something_as_boilerplate; int an_instance_member; } myinstance_t; void my_class_method() { printf("The class member is %d\n", a_class_member_of_myclass); } void my_instance_method(myinstance_t *instance, int a_parameter) { printf("The member is %d\n",instance->an_instance_member); printf("The parameter is %d\n",a_parameter); } void my_class_init_func(myclass_t* klass, gpointer data) { printf("my_class_init_func called!\n"); a_class_member_of_myclass = 42; } void my_instance_init_func(myinstance_t *instance, gpointer data) { printf("my_instance_init_func called!\n"); instance->an_instance_member = 65; } 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(), "MyInstantiatableFundamentalType", &my_type_info, &my_fundamental_info, 0 ); printf("%d\n",my_type_id); printf("%s\n",g_type_name(my_type_id)); myinstance_t *instance = (myinstance_t*)g_type_create_instance(my_type_id); my_instance_method(instance,78); my_class_method(); printf("Is instance of class? %s\n", G_TYPE_CHECK_INSTANCE_TYPE(instance, my_type_id)?"yes":"no"); printf("Is instance of class? %s\n", G_TYPE_CHECK_INSTANCE_TYPE(instance, G_TYPE_INT)?"yes":"no"); return 0; }
And focus in here:
typedef struct { GTypeClass something_as_boilerplate; } myclass_t; int a_class_member_of_myclass; typedef struct { GTypeInstance something_as_boilerplate; int an_instance_member; } myinstance_t;
Q: What are the something_as_boilerplate things?
A: As every other classes in GObject, all class structs start with a GTypeClass field and all instance structs start with a GTypeInstance field.
Q: What do they contain?
A: GTypeClass contains a GType which shows its type. GTypeInstance contains a pointer to its class struct so every instance knows its class. See the source code to make sure.
Q: Where are their members/fields?
A: Non-static members (such as an_instance_member) are in the instance struct, after the GTypeInstace. Static members (such as a_class_member_of_myclass) are usually global and are usually not in the class struct(see the previous article).
Q: How do you figure out if it is a member or a global variable?
A: You say "let it be a member" and it is a member. The concepts "object-oriented programming", "class", "instance" and "member" are all man-made so it is a member if you treat it like a member.
And the functions:
void my_class_method() { printf("The class member is %d\n", a_class_member_of_myclass); } void my_instance_method(myinstance_t *instance, int a_parameter) { printf("The member is %d\n",instance->an_instance_member); printf("The parameter is %d\n",a_parameter); }
Q: What are methods like?
A: Methods are simply functions. Non-static methods always take a pointer to an instance struct as their first parameter. Static methods are ordinary functions.
Q: How do you figure out if it is a member or a global variable?
A: You say "let it be a method" and it is a method. The concept "method" is man-made so it is a method if you treat it like a method.
Now we ask GLib to recognize my class as a type.
Code from the main() function:
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(), "MyInstantiatableFundamentalType", &my_type_info, &my_fundamental_info, 0 );
Again we use the g_type_register_fundamental() function to make the library think myclass is a class whose instance is myinstance.
We provide one GTypeInfo struct. class_size and instance_size are filled so that the library can automatically malloc a myclass_t struct and some myinstance_t structs. class_init and instance_init are also provided so that the library can help me initialize the class/instance struct when they are created.
In GTypeFundamentalInfo, mark my class as CLASSED and INSTANTIATABLE.
Register it with g_type_register_fundamental and then it becomes a type.
And the init functions:
void my_class_init_func(myclass_t* klass, gpointer data) { printf("my_class_init_func called!\n"); a_class_member_of_myclass = 42; } void my_instance_init_func(myinstance_t *instance, gpointer data) { printf("my_instance_init_func called!\n"); instance->an_instance_member = 65; }
They initialize the class and the instance, respectively on creating. You can omit them if they are not necessary.
Now the main() function:
printf("%d\n",my_type_id); printf("%s\n",g_type_name(my_type_id)); myinstance_t *instance = (myinstance_t*)g_type_create_instance(my_type_id); my_instance_method(instance,78); my_class_method(); printf("Is instance of class? %s\n", G_TYPE_CHECK_INSTANCE_TYPE(instance, my_type_id)?"yes":"no"); printf("Is instance of class? %s\n", G_TYPE_CHECK_INSTANCE_TYPE(instance, G_TYPE_INT)?"yes":"no");
g_type_name querys the string representation of the name of the type.
When first creating an instance using g_type_create_instance, the class struct is automatically allocated and initialized.
In order to call a instance method, just call the function with the first argument filled as the instance pointer.
G_TYPE_CHECK_INSTANCE_TYPE checks the type of an instance.
Q: How can it know the type of the instance by merely a pointer to the instance?
A: Recall that the first field of myinstance_t (that is GTypeInstance) contains a pointer which points to its class struct (myclass_t) which begins with a GTypeClass which has a GType field which identifies its type.
This means GObject provides runtime type information (RTTI) support which C++ classes do not usually have. Note that you need to #include in C++ in order to use RTTI.
2011年08月01日
Most of the time classes are instantiatable. It can create "instances", which have their own data and share common methods of the class.
So a CLASS is shared by many INSTANCEs.
In GObject, we need two structs. One for the class and one for the instance.
/* A fundamental type. Instantiatable. */ #include #include typedef struct { GTypeClass something_as_boilerplate; } myclass_t; int a_class_member_of_myclass; typedef struct { GTypeInstance something_as_boilerplate; int an_instance_member; } myinstance_t; void my_class_method() { printf("The class member is %d\n", a_class_member_of_myclass); } void my_instance_method(myinstance_t *instance, int a_parameter) { printf("The member is %d\n",instance->an_instance_member); printf("The parameter is %d\n",a_parameter); } void my_class_init_func(myclass_t* klass, gpointer data) { printf("my_class_init_func called!\n"); a_class_member_of_myclass = 42; } void my_instance_init_func(myinstance_t *instance, gpointer data) { printf("my_instance_init_func called!\n"); instance->an_instance_member = 65; } 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(), "MyInstantiatableFundamentalType", &my_type_info, &my_fundamental_info, 0 ); printf("%d\n",my_type_id); printf("%s\n",g_type_name(my_type_id)); myinstance_t *instance = (myinstance_t*)g_type_create_instance(my_type_id); my_instance_method(instance,78); my_class_method(); printf("Is instance of class? %s\n", G_TYPE_CHECK_INSTANCE_TYPE(instance, my_type_id)?"yes":"no"); printf("Is instance of class? %s\n", G_TYPE_CHECK_INSTANCE_TYPE(instance, G_TYPE_INT)?"yes":"no"); return 0; }
And focus in here:
typedef struct { GTypeClass something_as_boilerplate; } myclass_t; int a_class_member_of_myclass; typedef struct { GTypeInstance something_as_boilerplate; int an_instance_member; } myinstance_t;
Q: What are the something_as_boilerplate things?
A: As every other classes in GObject, all class structs start with a GTypeClass field and all instance structs start with a GTypeInstance field.
Q: What do they contain?
A: GTypeClass contains a GType which shows its type. GTypeInstance contains a pointer to its class struct so every instance knows its class. See the source code to make sure.
Q: Where are their members/fields?
A: Non-static members (such as an_instance_member) are in the instance struct, after the GTypeInstace. Static members (such as a_class_member_of_myclass) are usually global and are usually not in the class struct(see the previous article).
Q: How do you figure out if it is a member or a global variable?
A: You say "let it be a member" and it is a member. The concepts "object-oriented programming", "class", "instance" and "member" are all man-made so it is a member if you treat it like a member.
And the functions:
void my_class_method() { printf("The class member is %d\n", a_class_member_of_myclass); } void my_instance_method(myinstance_t *instance, int a_parameter) { printf("The member is %d\n",instance->an_instance_member); printf("The parameter is %d\n",a_parameter); }
Q: What are methods like?
A: Methods are simply functions. Non-static methods always take a pointer to an instance struct as their first parameter. Static methods are ordinary functions.
Q: How do you figure out if it is a member or a global variable?
A: You say "let it be a method" and it is a method. The concept "method" is man-made so it is a method if you treat it like a method.
Now we ask GLib to recognize my class as a type.
Code from the main() function:
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(), "MyInstantiatableFundamentalType", &my_type_info, &my_fundamental_info, 0 );
Again we use the g_type_register_fundamental() function to make the library think myclass is a class whose instance is myinstance.
We provide one GTypeInfo struct. class_size and instance_size are filled so that the library can automatically malloc a myclass_t struct and some myinstance_t structs. class_init and instance_init are also provided so that the library can help me initialize the class/instance struct when they are created.
In GTypeFundamentalInfo, mark my class as CLASSED and INSTANTIATABLE.
Register it with g_type_register_fundamental and then it becomes a type.
And the init functions:
void my_class_init_func(myclass_t* klass, gpointer data) { printf("my_class_init_func called!\n"); a_class_member_of_myclass = 42; } void my_instance_init_func(myinstance_t *instance, gpointer data) { printf("my_instance_init_func called!\n"); instance->an_instance_member = 65; }
They initialize the class and the instance, respectively on creating. You can omit them if they are not necessary.
Now the main() function:
printf("%d\n",my_type_id); printf("%s\n",g_type_name(my_type_id)); myinstance_t *instance = (myinstance_t*)g_type_create_instance(my_type_id); my_instance_method(instance,78); my_class_method(); printf("Is instance of class? %s\n", G_TYPE_CHECK_INSTANCE_TYPE(instance, my_type_id)?"yes":"no"); printf("Is instance of class? %s\n", G_TYPE_CHECK_INSTANCE_TYPE(instance, G_TYPE_INT)?"yes":"no");
g_type_name querys the string representation of the name of the type.
When first creating an instance using g_type_create_instance, the class struct is automatically allocated and initialized.
In order to call a instance method, just call the function with the first argument filled as the instance pointer.
G_TYPE_CHECK_INSTANCE_TYPE checks the type of an instance.
Q: How can it know the type of the instance by merely a pointer to the instance?
A: Recall that the first field of myinstance_t (that is GTypeInstance) contains a pointer which points to its class struct (myclass_t) which begins with a GTypeClass which has a GType field which identifies its type.
This means GObject provides runtime type information (RTTI) support which C++ classes do not usually have. Note that you need to #include in C++ in order to use RTTI.