十、声明和定义类型宏总结
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 宏
-
声明实例初始化函数;
-
声明类初始化函数;
-
定义t_double_get_type函数(t_double_class_intern_init、t_double_get_type_once函数都是被t_double_get_type函数调用,所有可以把他们合到一起)
-
定义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 接口对象
接口对象可以当做一个抽象类来看待(注册该类型的时候也就仅仅注册了类,并没有注册实例结构体),但是与抽象类不同的是,虚函数可以由任意对象实现。
-
声明 接口初始化函数;
static void t_comparable_default_init (TComparableInterface *klass);
-
定义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 或信号中,使用这些类型。
-
这类型对象没有信号,属性,引用计数等GObject具有的特性。
-
GBoxed不区分实例和类结构体,只有一个结构体定义
-
这类型不会自动注释到类型系统(需要调用my_struct_get_type()函数),不能使用g_object_new。
G_DEFINE_BOXED_TYPE
宏展开后,关键函数如下:
g_boxed_type_register_static` 函数定义如下,可以看见没有类和实例结构体、标准初始化函数的参数传入。
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)
宏展开后内容如下:
g_pointer_type_register_static
函数定义如下:
下面的两种注册形式区别是:是否包含有用户有注册的时候进行执行的代码。
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
宏。