An interface is a class with multiple abstract methods. A class may implement one or more interfaces which means that the class provides all the abstract methods specified in the interfaces. This separates the behavior pattern from the actual implementation.
An interface cannot be instantiated. However, if a class implements an interface, then the interface can be extracted from an instance of that class.
The full code to be ignored for now:
In GObject, you define an interface with a struct containing the abstract methods (represented by function pointers):
as well as the g_type_register_static function and specifys that it is a subclass of GInterface:
A class implements an interface using the g_type_add_interface_static function just after the class type is registered into the GObject library using g_type_register_static. Note that only subclasses of the GObject class may implement interfaces.
The init_my_interface_on_my_class function (that is a GInterfaceInitFunc) is important. It specifies HOW a class implememts an interface. Whenever a class is said to implement an interface, this function is called and a new instance of the interface class struct (that is, "struct myinterface" in this program) is created and passed into this function. This function is supposed to override the abstract methods in this struct by providing the corresponding function pointers that overrides the abstract methods.
You can extract the interface class (struct myinterface) from an instance of myclass. The macro G_TYPE_INSTANCE_GET_INTERFACE gets the specified interface struct fron an instance.
Note that there is no compile-time type-checking on interface implementations. You have to know what class implements what interface. If a class does not implement the interface you specified, G_TYPE_INSTANCE_GET_INTERFACE will return NULL.
.NET languages like C# allows properties and events to appear in interfaces. You can do these too in GObject by utilizing the base_init function in the GTypeInfo struct for the interface type. However, as stated before, there is no compile-time type-checking on properties and signals.
An interface cannot be instantiated. However, if a class implements an interface, then the interface can be extracted from an instance of that class.
The full code to be ignored for now:
/* A subclass of GObject implementing a interface. */
#include <stdio.h>
#include <glib-object.h>
/* My Interface */
typedef struct myinterface myinterface_t;
struct myinterface {
GTypeInterface something_as_boilerplate;
void (*greet)(void *instance);
};
GType get_my_interface_typeid() {
static my_type_id = 0;
if(my_type_id==0) {
GTypeInfo my_type_info = {
sizeof(myinterface_t), //class_size;
NULL, //base_init;
NULL, //base_finalize;
/* classed types, instantiated types */
NULL, //class_init;
NULL, //class_finalize;
NULL, //class_data;
/* instantiated types */
0, //instance_size;
0, //n_preallocs;
NULL, //instance_init;
/* value handling */
NULL, //value_table;
};
my_type_id = g_type_register_static(
G_TYPE_INTERFACE,
"MyInterface",
&my_type_info,
0
);
}
return my_type_id;
}
/* My Class */
typedef struct {
GObject something_as_boilerplate;
char* name;
} myinstance_t;
typedef struct {
GObjectClass something_as_boilerplate;
} myclass_t;
void say_hello(myinstance_t *instance) { // a method of myinstance
printf("Hello, %s!\n",instance->name);
}
void my_instance_init_func(myinstance_t *instance, gpointer data) {
instance->name = "blahblah";
}
void my_class_init_func(myclass_t* klass, gpointer data) {
}
void init_my_interface_on_my_class(myinterface_t* iface, gpointer iface_data) {
iface->greet = say_hello;
}
GType get_my_class_typeid() {
static my_type_id = 0;
if(my_type_id==0) {
GTypeInfo my_type_info = {
sizeof(myclass_t), //class_size;
NULL, //base_init;
NULL, //base_finalize;
/* classed types, instantiated types */
(GClassInitFunc)my_class_init_func, //class_init;
NULL, //class_finalize;
NULL, //class_data;
/* instantiated types */
sizeof(myinstance_t),//instance_size;
0, //n_preallocs;
(GInstanceInitFunc)my_instance_init_func, //instance_init;
/* value handling */
NULL, //value_table;
};
my_type_id = g_type_register_static(
G_TYPE_OBJECT,
"MyClass",
&my_type_info,
0
);
/* Add interface */
GInterfaceInfo my_interface_info = {
(GInterfaceInitFunc)init_my_interface_on_my_class, // interface_init
NULL, // interface_finalize
NULL, // interface_data
};
g_type_add_interface_static(
my_type_id,
get_my_interface_typeid(),
&my_interface_info
);
}
return my_type_id;
}
/* main function */
int main() {
g_type_init();
printf("Class type id: %d\n",get_my_class_typeid());
printf("Class type name: %s\n",g_type_name(get_my_class_typeid()));
printf("Interface type id: %d\n",get_my_interface_typeid());
printf("Interface type name: %s\n",g_type_name(get_my_interface_typeid()));
myinstance_t *instance = (myinstance_t*)g_object_new(
get_my_class_typeid(),NULL);
GObject *obj = g_object_new(g_object_get_type(),NULL);
GObject *objs[2] = {instance,obj};
int i;
for(i=0;i<2;i++) {
myinterface_t *iface = G_TYPE_INSTANCE_GET_INTERFACE(
objs[i],get_my_interface_typeid(),myinterface_t);
if(iface != NULL) {
iface->greet(instance);
} else {
printf("This object does not implement myinterface.\n");
}
}
return 0;
}
In GObject, you define an interface with a struct containing the abstract methods (represented by function pointers):
typedef struct myinterface myinterface_t;
struct myinterface {
GTypeInterface something_as_boilerplate;
void (*greet)(void *instance);
};
as well as the g_type_register_static function and specifys that it is a subclass of GInterface:
GType get_my_interface_typeid() {
static my_type_id = 0;
if(my_type_id==0) {
GTypeInfo my_type_info = {
sizeof(myinterface_t), //class_size;
NULL, //base_init;
NULL, //base_finalize;
/* classed types, instantiated types */
NULL, //class_init;
NULL, //class_finalize;
NULL, //class_data;
/* instantiated types */
0, //instance_size;
0, //n_preallocs;
NULL, //instance_init;
/* value handling */
NULL, //value_table;
};
my_type_id = g_type_register_static(
G_TYPE_INTERFACE,
"MyInterface",
&my_type_info,
0
);
}
return my_type_id;
}
A class implements an interface using the g_type_add_interface_static function just after the class type is registered into the GObject library using g_type_register_static. Note that only subclasses of the GObject class may implement interfaces.
GInterfaceInfo my_interface_info = {
(GInterfaceInitFunc)init_my_interface_on_my_class, // interface_init
NULL, // interface_finalize
NULL, // interface_data
};
g_type_add_interface_static(
my_type_id,
get_my_interface_typeid(),
&my_interface_info
);
}
The init_my_interface_on_my_class function (that is a GInterfaceInitFunc) is important. It specifies HOW a class implememts an interface. Whenever a class is said to implement an interface, this function is called and a new instance of the interface class struct (that is, "struct myinterface" in this program) is created and passed into this function. This function is supposed to override the abstract methods in this struct by providing the corresponding function pointers that overrides the abstract methods.
void init_my_interface_on_my_class(myinterface_t* iface, gpointer iface_data) {
iface->greet = say_hello;
}
You can extract the interface class (struct myinterface) from an instance of myclass. The macro G_TYPE_INSTANCE_GET_INTERFACE gets the specified interface struct fron an instance.
myinstance_t *instance = (myinstance_t*)g_object_new(
get_my_class_typeid(),NULL);
GObject *obj = g_object_new(g_object_get_type(),NULL);
GObject *objs[2] = {instance,obj};
int i;
for(i=0;i<2;i++) {
myinterface_t *iface = G_TYPE_INSTANCE_GET_INTERFACE(
objs[i],get_my_interface_typeid(),myinterface_t);
if(iface != NULL) {
iface->greet(instance);
} else {
printf("This object does not implement myinterface.\n");
}
}
Note that there is no compile-time type-checking on interface implementations. You have to know what class implements what interface. If a class does not implement the interface you specified, G_TYPE_INSTANCE_GET_INTERFACE will return NULL.
.NET languages like C# allows properties and events to appear in interfaces. You can do these too in GObject by utilizing the base_init function in the GTypeInfo struct for the interface type. However, as stated before, there is no compile-time type-checking on properties and signals.