1 G_DEFINE_XX_TYPE

学习GStreamer过程中,代码中用到了一些其他的 G_DEFINE_XX_TYPE ,我在这里补充总结一下。

  • 普通对象 G_DEFINE_TYPE:普通的GObject继承对象。

  • 抽象对象 G_DEFINE_ABSTRACT_TYPE:抽象对象不能创建实例。它只能被继承。

  • 最终对象 G_DEFINE_FINAL_TYPE:最终对象,没有自己的类结构体成员。

  • 接口对象 G_DEFINE_INTERFACE:接口对象可以当做一个抽象类来看待(注册该类型的时候也就仅仅注册了类,并没有注册实例结构体),但是与抽象类不同的是,虚函数可以由任意对象实现。

  • 结构体封装对象 G_DEFINE_BOXED_TYPE:对自定义结构体进行封装,封装成可以注册类型GTYPE系统的对象。跟标准GObject对象不同,没有GObject对象的引用,信号,属性等特性。

  • POINTER对象 G_DEFINE_POINTER_TYPE:跟BOXED定义的对象类似,只是在类型系统注册该类型对象。没有标准GObject的类,实例初始化,引用,信号等特性。BOXED类型一般会自己定义一个初始化函数,还有相关的拷贝和释放函数。POINTER定义的对象什么都没有。

1.1 普通对象


#define G_DEFINE_TYPE(TN, t_n, T_P)			    G_DEFINE_TYPE_EXTENDED (TN, t_n, T_P, 0, {})

#define G_DEFINE_TYPE_WITH_CODE(TN, t_n, T_P, _C_)	    _G_DEFINE_TYPE_EXTENDED_BEGIN (TN, t_n, T_P, 0) {_C_;} _G_DEFINE_TYPE_EXTENDED_END()

#define G_DEFINE_TYPE_WITH_PRIVATE(TN, t_n, T_P)            G_DEFINE_TYPE_EXTENDED (TN, t_n, T_P, 0, G_ADD_PRIVATE (TN))

/* XX_WITH_CODE的宏其实和直接定义、有私有结构体定义都一样 */
#define G_DEFINE_TYPE_EXTENDED(TN, t_n, T_P, _f_, _C_)	    _G_DEFINE_TYPE_EXTENDED_BEGIN (TN, t_n, T_P, _f_) {_C_;} _G_DEFINE_TYPE_EXTENDED_END()

1.1.1 G_DEFINE_TYPE

G_DEFINE_TYPE 宏展开参考代码 /assets/GObjectStudy/202311/10_GObject/example4_G_DEFINE_TYPE.i

具体展开和定义那些函数可以参考 6 G_DEFINE_TYPE 宏

  1. 声明实例初始化函数;

  2. 声明类初始化函数;

  3. 定义t_double_get_type函数(t_double_class_intern_init、t_double_get_type_once函数都是被t_double_get_type函数调用,所有可以把他们合到一起)

  4. 定义t_double_get_instance_private函数(使用G_DEFINE_TYPE宏,_get_instance_private该函数内部的TDouble_private_offset变量并没有被赋值)

    只有在 G_DEFINE_TYPE_WITH_PRIVATE 宏时候使用。

1.1.2 G_DEFINE_TYPE_WITH_CODE

G_DEFINE_TYPE 宏展开参考代码 /assets/GObjectStudy/202311/10_GObject/example4_G_DEFINE_TYPE_WITH_CODE.i

  两个声明和两个定义都和 G_DEFINE_TYPE 宏一样

  唯一不一样的地方就是,t_double_get_type 调用的 t_double_get_type_once 内部可以插入用户自定义要执行的代码。

__attribute__ ((__noinline__)) static GType 
t_double_get_type_once (void) { 
  GType g_define_type_id = g_type_register_static_simple (((GType) ((20) << (2))), 
                                                          g_intern_static_string ("TDouble"), 
                                                          sizeof (TDoubleClass), 
                                                          (GClassInitFunc)(void (*)(void)) t_double_class_intern_init, 
                                                          sizeof (TDouble), 
                                                          (GInstanceInitFunc)(void (*)(void)) t_double_init, 
                                                          (GTypeFlags) 0); 
  
  { {add();} }  /* 用户自定义插入的代码 */
  
  return g_define_type_id; 
}

1.1.3 G_DEFINE_TYPE_WITH_PRIVATE

G_DEFINE_TYPE 宏展开参考代码 /assets/GObjectStudy/202311/10_GObject/example4_G_DEFINE_TYPE_WITH_PRIVATE.i

  两个声明和两个定义都和 G_DEFINE_TYPE 宏一样

  唯一不一样的地方就是,t_double_get_type调用的 t_double_get_type_once 内部插入了 G_ADD_PRIVATE(TDouble),该宏展开代码如下:

__attribute__ ((__noinline__)) static GType 
t_double_get_type_once (void) { 
  GType g_define_type_id = g_type_register_static_simple (((GType) ((20) << (2))),
                                                          g_intern_static_string ("TDouble"), 
                                                          sizeof (TDoubleClass), (GClassInitFunc)(void (*)(void)) 
                                                          t_double_class_intern_init, 
                                                          sizeof (TDouble), 
                                                          (GInstanceInitFunc)(void (*)(void)) t_double_init, 
                                                          (GTypeFlags) 0); { 
    
    TDouble_private_offset = g_type_add_instance_private (g_define_type_id, sizeof (TDoublePrivate)); 
    
    } 
    
    return g_define_type_id; 
    
}

  其实跟 G_DEFINE_TYPE_WITH_CODE 一样,只不过 _WITH_CODE宏是用户自己插入代码,而 _WITH_PRIVATE 宏是插入 G_ADD_PRIVATE(TDouble)

1.2 抽象对象

普通对象定义讲明白之后,抽象对象定义也很容易理解。

抽象对象不能创建实例,展开抽象对象定义宏后,与 G_DEFINE_TYPE 唯一不同的地方就是 t_double_get_type_once 函数中的 GTypeFlags变量的参数是 G_TYPE_FLAG_ABSTRACT

typedef enum    /*< skip >*/
{
  G_TYPE_FLAG_NONE GOBJECT_AVAILABLE_ENUMERATOR_IN_2_74 = 0,
  G_TYPE_FLAG_ABSTRACT = (1 << 4),
  G_TYPE_FLAG_VALUE_ABSTRACT = (1 << 5),
  G_TYPE_FLAG_FINAL GOBJECT_AVAILABLE_ENUMERATOR_IN_2_70 = (1 << 6),
  G_TYPE_FLAG_DEPRECATED GOBJECT_AVAILABLE_ENUMERATOR_IN_2_76 = (1 << 7)
} GTypeFlags;

例如:抽象对象一般作为一个基类(比如实现 整形数字对象、小数数学对象,可以把数字作为一个抽象对象)

1.2.1 G_DEFINE_ABSTRACT_TYPE

#define G_DEFINE_TYPE(TN, t_n, T_P)			    G_DEFINE_TYPE_EXTENDED (TN, t_n, T_P, 0, {})

#define G_DEFINE_ABSTRACT_TYPE(TN, t_n, T_P)		    G_DEFINE_TYPE_EXTENDED (TN, t_n, T_P, G_TYPE_FLAG_ABSTRACT, {})

前面已经讲过了 G_DEFINE_TYPE 的展开,这里可以通过两个宏的第一次展开,可以看到仅仅flag不一样

__attribute__ ((__noinline__)) static GType 
t_double_get_type_once (void) { 
  GType g_define_type_id = g_type_register_static_simple (((GType) ((20) << (2))), 
                                                          g_intern_static_string ("TDouble"), 
                                                          sizeof (TDoubleClass), 
                                                          (GClassInitFunc)(void (*)(void)) t_double_class_intern_init, 
                                                          sizeof (TDouble), 
                                                          (GInstanceInitFunc)(void (*)(void)) t_double_init, 
                                                          (GTypeFlags) G_TYPE_FLAG_ABSTRACT); 
  
  { { {}; } }  /* 用户自定义插入的代码地方,也就是宏最后那一对花括号 */
  
  return g_define_type_id; 
}

1.2.2 G_DEFINE_ABSTRACT_TYPE_WITH_CODE

#define G_DEFINE_TYPE_WITH_CODE(TN, t_n, T_P, _C_)	    _G_DEFINE_TYPE_EXTENDED_BEGIN (TN, t_n, T_P, 0) {_C_;} _G_DEFINE_TYPE_EXTENDED_END()

#define G_DEFINE_ABSTRACT_TYPE_WITH_CODE(TN, t_n, T_P, _C_) _G_DEFINE_TYPE_EXTENDED_BEGIN (TN, t_n, T_P, G_TYPE_FLAG_ABSTRACT) {_C_;} _G_DEFINE_TYPE_EXTENDED_END()

1.2.3 G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE


#define G_DEFINE_TYPE_WITH_PRIVATE(TN, t_n, T_P)            G_DEFINE_TYPE_EXTENDED (TN, t_n, T_P, 0, G_ADD_PRIVATE (TN))

#define G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE(TN, t_n, T_P)   G_DEFINE_TYPE_EXTENDED (TN, t_n, T_P, G_TYPE_FLAG_ABSTRACT, G_ADD_PRIVATE (TN))

1.3 最终对象

最终对象不能被继承,展开最终对象定义宏后,与 G_DEFINE_TYPE 唯一不同的地方就是 t_double_get_type_once 函数中的 GTypeFlags变量的参数是 G_TYPE_FLAG_FINAL

一个final类型对象不需要有自己的类结构体成员。

1.3.1 G_DEFINE_FINAL_TYPE

#define G_DEFINE_FINAL_TYPE(TN, t_n, T_P)    G_DEFINE_TYPE_EXTENDED (TN, t_n, T_P, G_TYPE_FLAG_FINAL, {}) GOBJECT_AVAILABLE_MACRO_IN_2_70

1.3.2 G_DEFINE_FINAL_TYPE_WITH_CODE

#define G_DEFINE_FINAL_TYPE_WITH_CODE(TN, t_n, T_P, _C_)  _G_DEFINE_TYPE_EXTENDED_BEGIN (TN, t_n, T_P, G_TYPE_FLAG_FINAL) {_C_;} _G_DEFINE_TYPE_EXTENDED_END() GOBJECT_AVAILABLE_MACRO_IN_2_70

1.3.3 G_DEFINE_FINAL_TYPE_WITH_PRIVATE

#define G_DEFINE_FINAL_TYPE_WITH_PRIVATE(TN, t_n, T_P)  G_DEFINE_TYPE_EXTENDED (TN, t_n, T_P, G_TYPE_FLAG_FINAL, G_ADD_PRIVATE (TN)) GOBJECT_AVAILABLE_MACRO_IN_2_70

1.4 接口对象

接口对象可以当做一个抽象类来看待(注册该类型的时候也就仅仅注册了类,并没有注册实例结构体),但是与抽象类不同的是,虚函数可以由任意对象实现。

  1. 声明 接口初始化函数;

    static void t_comparable_default_init (TComparableInterface *klass);

  2. 定义t_t_comparable_get_type函数。(没有实例结构体及其实例初始化函数)

     GType g_define_type_id = g_type_register_static_simple (((GType) ((2) << (2))), 
                                                               g_intern_static_string ("TComparable"), 
                                                               sizeof (TComparableInterface), 
                                                               (GClassInitFunc)(void (*)(void)) t_comparable_default_init, 
                                                               0,  /*没有实例结构体*/
                                                               (GInstanceInitFunc) ((void *)0), /* 没有实例初始化函数 */
                                                               (GTypeFlags) 0); 
    

1.4.1 G_DEFINE_INTERFACE

#define G_DEFINE_INTERFACE(TN, t_n, T_P)		    G_DEFINE_INTERFACE_WITH_CODE(TN, t_n, T_P, ;)

1.4.2 G_DEFINE_INTERFACE_WITH_CODE

#define G_DEFINE_INTERFACE_WITH_CODE(TN, t_n, T_P, _C_)     _G_DEFINE_INTERFACE_EXTENDED_BEGIN(TN, t_n, T_P) {_C_;} _G_DEFINE_INTERFACE_EXTENDED_END()

1.5 结构体封装对象

G_DEFINE_BOXED_TYPE` 在 GObject 系统中是一个宏,用于定义新的 “boxed type” 。GObject 的 boxed types 用于处理纯旧数据(POD)结构,这些数据类型如结构体或联合体,并使其与 GObject 类型系统兼容。

定义了 boxed type 后,你可以在 GObject 系统中,例如在 GValue 或信号中,使用这些类型。

  1. 这类型对象没有信号,属性,引用计数等GObject具有的特性。

  2. GBoxed不区分实例和类结构体,只有一个结构体定义

  3. 这类型不会自动注释到类型系统(需要调用my_struct_get_type()函数),不能使用g_object_new。

G_DEFINE_BOXED_TYPE宏展开后,关键函数如下:

alt text

g_boxed_type_register_static` 函数定义如下,可以看见没有类和实例结构体、标准初始化函数的参数传入。

alt text

1.5.1 G_DEFINE_BOXED_TYPE

#define G_DEFINE_BOXED_TYPE(TypeName, type_name, copy_func, free_func) G_DEFINE_BOXED_TYPE_WITH_CODE (TypeName, type_name, copy_func, free_func, {})

1.5.2 G_DEFINE_BOXED_TYPE_WITH_CODE

#define G_DEFINE_BOXED_TYPE_WITH_CODE(TypeName, type_name, copy_func, free_func, _C_) _G_DEFINE_BOXED_TYPE_BEGIN (TypeName, type_name, copy_func, free_func) {_C_;} _G_DEFINE_TYPE_EXTENDED_END()

1.6 POINTER对象定义

G_DEFINE_POINTER_TYPE (GstStaticPadTemplate, gst_static_pad_template)宏展开后内容如下:

alt text

g_pointer_type_register_static 函数定义如下:

alt text

下面的两种注册形式区别是:是否包含有用户有注册的时候进行执行的代码。

1.6.1 G_DEFINE_POINTER_TYPE

#define G_DEFINE_POINTER_TYPE(TypeName, type_name) 
G_DEFINE_POINTER_TYPE_WITH_CODE (TypeName, type_name, {})

1.6.2 G_DEFINE_POINTER_TYPE_WITH_CODE

#define G_DEFINE_POINTER_TYPE_WITH_CODE(TypeName, type_name, _C_) 
_G_DEFINE_POINTER_TYPE_BEGIN (TypeName, type_name) {_C_;} _G_DEFINE_TYPE_EXTENDED_END()

2 G_DECLARE_XX

2.1 G_DECLARE_FINAL_TYPE

一个final类型对象不需要有自己的类结构体成员

G_DECLARE_FINAL_TYPE执行以下主要操作:

  • 声明 GType t_double_get_type (void);

  • 定义 typedef struct _TDouble TDouble;

  • 定义 类结构体。一个final类型对象不需要有自己的类结构体成员。

    typedef struct { 
      GObjectClass parent_class; 
    } TDoubleClass; 
    
  • 定义 T_DOUBLE 宏。例如,如果对象是TDouble,宏就是T_DOUBLE。它将展开为一个函数,将实参转换为指向对象的指针。例如,T_Double (obj)将obj类型强制转换为TDouble *。
  • 定义 T_IS_DOUBLE 宏。例如,如果对象是TDouble,宏就是T_IS_DOUBLE。它将扩展为一个函数,该函数检查参数是否指向TDouble的实例。如果参数指向TDouble的后代,则返回true。

2.2 G_DECLARE_DERIVABLE_TYPE

一个可派生类型实例对象仅有父实例

G_DECLARE_DERIVABLE_TYPE执行以下主要操作:

  • 声明 GType t_double_get_type (void);

  • 定义 typedef struct _TDoubleClass TDoubleClass;

  • 定义 实例结构体。其成员仅为其父实例。

    typedef struct _TDouble TDouble; 
    struct _TDouble { GObject parent_instance; }; 
    
  • 定义 T_DOUBLE 宏。

  • 定义 T_IS_DOUBLE 宏。

  • 定义 T_DOUBLE_CLASS 宏。

  • 定义 T_IS_DOUBLE_CLASS 宏。

  • 定义 T_DOUBLE_GET_CLASS 宏。

2.3 G_DECLARE_INTERFACE

仅仅有一个接口类,没有实例结构体

G_DECLARE_INTERFACE执行以下主要操作:

  • 声明 GType t_comparable_get_type (void);

  • 定义
      /* 感觉没有必要存在,因为注册该类型就不会注册实例结构体 */
    typedef struct _TComparable TComparable;
    
    typedef struct _TComparableInterface TComparableInterface; 
    
  • 定义 T_COMPARABLE 宏。

  • 定义 T_IS_COMPARABLE 宏。

  • 定义 T_COMPARABLE_GET_IFACE 宏。