分享

GObject 09: An Interface

 Tornador 2014-06-19
     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:
C代码  收藏代码
  1. /* A subclass of GObject implementing a interface. */  
  2.   
  3. #include <stdio.h>  
  4. #include <glib-object.h>  
  5.   
  6. /* My Interface */  
  7. typedef struct myinterface myinterface_t;  
  8. struct myinterface {  
  9.     GTypeInterface something_as_boilerplate;  
  10.   
  11.     void (*greet)(void *instance);  
  12. };  
  13.   
  14. GType get_my_interface_typeid() {  
  15.     static my_type_id = 0;  
  16.     if(my_type_id==0) {  
  17.         GTypeInfo my_type_info = {  
  18.             sizeof(myinterface_t),  //class_size;  
  19.   
  20.             NULL,               //base_init;  
  21.             NULL,               //base_finalize;  
  22.   
  23.             /* classed types, instantiated types */  
  24.             NULL,               //class_init;  
  25.             NULL,               //class_finalize;  
  26.             NULL,               //class_data;  
  27.   
  28.             /* instantiated types */  
  29.             0,                  //instance_size;  
  30.             0,                  //n_preallocs;  
  31.             NULL,               //instance_init;  
  32.   
  33.             /* value handling */  
  34.             NULL,               //value_table;  
  35.         };  
  36.   
  37.         my_type_id = g_type_register_static(  
  38.                 G_TYPE_INTERFACE,  
  39.                 "MyInterface",  
  40.                 &my_type_info,  
  41.                 0  
  42.                 );  
  43.     }  
  44.     return my_type_id;  
  45. }  
  46.   
  47. /* My Class */  
  48. typedef struct {  
  49.     GObject something_as_boilerplate;  
  50.     char* name;  
  51. } myinstance_t;  
  52.   
  53. typedef struct {  
  54.     GObjectClass something_as_boilerplate;  
  55. } myclass_t;  
  56.   
  57. void say_hello(myinstance_t *instance) { // a method of myinstance  
  58.     printf("Hello, %s!\n",instance->name);  
  59. }  
  60.   
  61. void my_instance_init_func(myinstance_t *instance, gpointer data) {  
  62.     instance->name = "blahblah";  
  63. }  
  64.   
  65. void my_class_init_func(myclass_t* klass, gpointer data) {  
  66. }  
  67.   
  68. void init_my_interface_on_my_class(myinterface_t* iface, gpointer iface_data) {  
  69.     iface->greet = say_hello;  
  70. }  
  71.   
  72. GType get_my_class_typeid() {  
  73.     static my_type_id = 0;  
  74.     if(my_type_id==0) {  
  75.         GTypeInfo my_type_info = {  
  76.             sizeof(myclass_t),  //class_size;  
  77.   
  78.             NULL,               //base_init;  
  79.             NULL,               //base_finalize;  
  80.   
  81.             /* classed types, instantiated types */  
  82.             (GClassInitFunc)my_class_init_func, //class_init;  
  83.             NULL,               //class_finalize;  
  84.             NULL,               //class_data;  
  85.   
  86.             /* instantiated types */  
  87.             sizeof(myinstance_t),//instance_size;  
  88.             0,                  //n_preallocs;  
  89.             (GInstanceInitFunc)my_instance_init_func, //instance_init;  
  90.   
  91.             /* value handling */  
  92.             NULL,               //value_table;  
  93.         };  
  94.   
  95.         my_type_id = g_type_register_static(  
  96.                 G_TYPE_OBJECT,  
  97.                 "MyClass",  
  98.                 &my_type_info,  
  99.                 0  
  100.                 );  
  101.   
  102.         /* Add interface */  
  103.   
  104.         GInterfaceInfo my_interface_info = {  
  105.             (GInterfaceInitFunc)init_my_interface_on_my_class, // interface_init  
  106.             NULL,   // interface_finalize  
  107.             NULL,   // interface_data  
  108.         };  
  109.   
  110.         g_type_add_interface_static(  
  111.                 my_type_id,  
  112.                 get_my_interface_typeid(),  
  113.                 &my_interface_info  
  114.                 );  
  115.     }  
  116.   
  117.     return my_type_id;  
  118. }  
  119.   
  120.   
  121. /* main function */  
  122.   
  123. int main() {  
  124.     g_type_init();  
  125.   
  126.     printf("Class type id: %d\n",get_my_class_typeid());  
  127.     printf("Class type name: %s\n",g_type_name(get_my_class_typeid()));  
  128.     printf("Interface type id: %d\n",get_my_interface_typeid());  
  129.     printf("Interface type name: %s\n",g_type_name(get_my_interface_typeid()));  
  130.   
  131.     myinstance_t *instance = (myinstance_t*)g_object_new(  
  132.             get_my_class_typeid(),NULL);  
  133.   
  134.     GObject *obj = g_object_new(g_object_get_type(),NULL);  
  135.   
  136.     GObject *objs[2] = {instance,obj};  
  137.   
  138.     int i;  
  139.     for(i=0;i<2;i++) {  
  140.         myinterface_t *iface = G_TYPE_INSTANCE_GET_INTERFACE(  
  141.                 objs[i],get_my_interface_typeid(),myinterface_t);  
  142.   
  143.         if(iface != NULL) {  
  144.             iface->greet(instance);  
  145.         } else {  
  146.             printf("This object does not implement myinterface.\n");  
  147.         }  
  148.     }  
  149.   
  150.     return 0;  
  151. }  


In GObject, you define an interface with a struct containing the abstract methods (represented by function pointers):
C代码  收藏代码
  1. typedef struct myinterface myinterface_t;  
  2. struct myinterface {  
  3.     GTypeInterface something_as_boilerplate;  
  4.   
  5.     void (*greet)(void *instance);  
  6. };  


as well as the g_type_register_static function and specifys that it is a subclass of GInterface:
C代码  收藏代码
  1. GType get_my_interface_typeid() {  
  2.     static my_type_id = 0;  
  3.     if(my_type_id==0) {  
  4.         GTypeInfo my_type_info = {  
  5.             sizeof(myinterface_t),  //class_size;  
  6.   
  7.             NULL,               //base_init;  
  8.             NULL,               //base_finalize;  
  9.   
  10.             /* classed types, instantiated types */  
  11.             NULL,               //class_init;  
  12.             NULL,               //class_finalize;  
  13.             NULL,               //class_data;  
  14.   
  15.             /* instantiated types */  
  16.             0,                  //instance_size;  
  17.             0,                  //n_preallocs;  
  18.             NULL,               //instance_init;  
  19.   
  20.             /* value handling */  
  21.             NULL,               //value_table;  
  22.         };  
  23.   
  24.         my_type_id = g_type_register_static(  
  25.                 G_TYPE_INTERFACE,  
  26.                 "MyInterface",  
  27.                 &my_type_info,  
  28.                 0  
  29.                 );  
  30.     }  
  31.     return my_type_id;  
  32. }  


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.
C代码  收藏代码
  1.     GInterfaceInfo my_interface_info = {  
  2.         (GInterfaceInitFunc)init_my_interface_on_my_class, // interface_init  
  3.         NULL,   // interface_finalize  
  4.         NULL,   // interface_data  
  5.     };  
  6.   
  7.     g_type_add_interface_static(  
  8.             my_type_id,  
  9.             get_my_interface_typeid(),  
  10.             &my_interface_info  
  11.             );  
  12. }  


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.
C代码  收藏代码
  1. void init_my_interface_on_my_class(myinterface_t* iface, gpointer iface_data) {  
  2.     iface->greet = say_hello;  
  3. }  



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.
C代码  收藏代码
  1. myinstance_t *instance = (myinstance_t*)g_object_new(  
  2.         get_my_class_typeid(),NULL);  
  3.   
  4. GObject *obj = g_object_new(g_object_get_type(),NULL);  
  5.   
  6. GObject *objs[2] = {instance,obj};  
  7.   
  8. int i;  
  9. for(i=0;i<2;i++) {  
  10.     myinterface_t *iface = G_TYPE_INSTANCE_GET_INTERFACE(  
  11.             objs[i],get_my_interface_typeid(),myinterface_t);  
  12.   
  13.     if(iface != NULL) {  
  14.         iface->greet(instance);  
  15.     } else {  
  16.         printf("This object does not implement myinterface.\n");  
  17.     }  
  18. }  


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. 

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多