Gobject tutorial 三

2024-06-15 19:36
文章标签 tutorial gobject

本文主要是介绍Gobject tutorial 三,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Derivable type and abstract type

Derivable type

在GLib中,类型可以分为两种。一种是可以被继承的(derivable),一种是不能被继承的(final)。二者的主要区别是,final 类型对象的类结构中,除了其父类外,再无其他成员。而derivable类型对象的类结构中会存在其他成员, 且derivable类型的类对其衍生类是可见的。对于上篇我们的例子TDouble,就是一个final类。我们在注册时使用的是G_DEFINE_TYPE,实际上还可以使用G_DECLARE_FINAL_TYPE。

Abstract type

abstract type 属于derivable type,只是abstract type 不会生成实例,但其衍生对象可以使用其函数和信号。

对于abstract type,我们将会创建TNumber类型来进行说明。上篇我们说TDouble 代表了浮点数,那么,更抽象一层,TNumber则表示全体数。TNumber是TDouble 的父类,由于TNumber属于abstract type,因此不能按照我们实例化TDouble那样进行实例化。毕竟不存在能够对数字进行统一表示的方式。int 类型的5.0,与double类型的5.0,虽然绝对值是一样的,但是int类型的5.0相对于double类型的5.0,其实是丧失精度的,因此两者并不相同。但任何包含TDouble的对象在实例化时,也意味着TNumber也被实例化了。例如,当TDouble中value为5.0,我们可以说5.0就是TDouble的实例,同时,5.0首先是个数字,因此,5.0也是TNumber的实例化。

TNumber class

G_DECLARE_DERIVABLE_TYPE (TNumber, t_number, T, NUMBER, GObject)struct _TNumberClass {GObjectClass parent_class;TNumber* (*add) (TNumber *self, TNumber *other);TNumber* (*sub) (TNumber *self, TNumber *other);TNumber* (*mul) (TNumber *self, TNumber *other);TNumber* (*div) (TNumber *self, TNumber *other);TNumber* (*uminus) (TNumber *self);char * (*to_s) (TNumber *self);/* signal */void (*div_by_zero) (TNumber *self);
};

 在glib 2.78.2中,宏G_DECLARE_DERIVABLE_TYPE的定义如下:

#define G_DECLARE_DERIVABLE_TYPE(ModuleObjName, module_obj_name, MODULE, OBJ_NAME, ParentName) \GType module_obj_name##_get_type (void);                                                               \G_GNUC_BEGIN_IGNORE_DEPRECATIONS                                                                       \typedef struct _##ModuleObjName ModuleObjName;                                                         \typedef struct _##ModuleObjName##Class ModuleObjName##Class;                                           \struct _##ModuleObjName { ParentName parent_instance; };                                               \\_GLIB_DEFINE_AUTOPTR_CHAINUP (ModuleObjName, ParentName)                                               \G_DEFINE_AUTOPTR_CLEANUP_FUNC (ModuleObjName##Class, g_type_class_unref)                               \\G_GNUC_UNUSED static inline ModuleObjName * MODULE##_##OBJ_NAME (gpointer ptr) {                       \return G_TYPE_CHECK_INSTANCE_CAST (ptr, module_obj_name##_get_type (), ModuleObjName); }             \G_GNUC_UNUSED static inline ModuleObjName##Class * MODULE##_##OBJ_NAME##_CLASS (gpointer ptr) {        \return G_TYPE_CHECK_CLASS_CAST (ptr, module_obj_name##_get_type (), ModuleObjName##Class); }         \G_GNUC_UNUSED static inline gboolean MODULE##_IS_##OBJ_NAME (gpointer ptr) {                           \return G_TYPE_CHECK_INSTANCE_TYPE (ptr, module_obj_name##_get_type ()); }                            \G_GNUC_UNUSED static inline gboolean MODULE##_IS_##OBJ_NAME##_CLASS (gpointer ptr) {                   \return G_TYPE_CHECK_CLASS_TYPE (ptr, module_obj_name##_get_type ()); }                               \G_GNUC_UNUSED static inline ModuleObjName##Class * MODULE##_##OBJ_NAME##_GET_CLASS (gpointer ptr) {    \return G_TYPE_INSTANCE_GET_CLASS (ptr, module_obj_name##_get_type (), ModuleObjName##Class); }       \G_GNUC_END_IGNORE_DEPRECATIONS

 对于TNumber对象来说,G_DECLARE_DERIVABLE_TYPE宏的作用如下:

  • 声明函数t_number_get_type()。
  • 定义TNumber数据结构,此数据结构的成员只有其父实例。
  • 声明TNumberClass数据结构,具体定义需要用户实现。
  • 定义宏T_NUMBER(cast to instance)、T_NUMBER_CLASS(cast to class)、T_IS_NUMBER(instance check)、T_IS_NUMBER_CLASS(class check)、T_NUMBER_GET_CLASS.
  • g_autoptr()。

 struct _TNumber中的函数指针称为类方法或者虚拟函数,他们会被TNumber的衍生对象重写。

对照上篇所说的G_DEFINE_TYPE宏的工作,对于abstract type,有个同样功能的宏G_DEFINE_ABSTRACT。

TInt object

介绍完Derivable type和Abstract type,现在我们来介绍其应用。我们使用新类型TInt来说明。

/*tint.h*/
#pragma once#include <glib-object.h>#define T_TYPE_INT  (t_int_get_type ())
G_DECLARE_FINAL_TYPE (TInt, t_int, T, INT, TNumber)/* create a new TInt instance */
TInt *
t_int_new_with_value (int value);TInt *
t_int_new (void);
/*tint.c*/
#include "tnumber.h"
#include "tint.h"
#include "tdouble.h"#define PROP_INT 1
static GParamSpec *int_property = NULL;struct _TInt {TNumber parent;int value;
};G_DEFINE_TYPE (TInt, t_int, T_TYPE_NUMBER)static void
t_int_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) {TInt *self = T_INT (object);if (property_id == PROP_INT)self->value = g_value_get_int (value);elseG_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}static void
t_int_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec) {TInt *self = T_INT (object);if (property_id == PROP_INT)g_value_set_int (value, self->value);elseG_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}static void
t_int_init (TInt *self) {
}/* arithmetic operator */
/* These operators create a new instance and return a pointer to it. */
#define t_int_binary_op(op) \int i; \double d; \if (T_IS_INT (other)) { \g_object_get (T_INT (other), "value", &i, NULL); \return  T_NUMBER (t_int_new_with_value (T_INT(self)->value op i)); \} else { \g_object_get (T_DOUBLE (other), "value", &d, NULL); \return  T_NUMBER (t_int_new_with_value (T_INT(self)->value op (int) d)); \}static TNumber *
t_int_add (TNumber *self, TNumber *other) {g_return_val_if_fail (T_IS_INT (self), NULL);t_int_binary_op (+)
}static TNumber *
t_int_sub (TNumber *self, TNumber *other) {g_return_val_if_fail (T_IS_INT (self), NULL);t_int_binary_op (-)
}static TNumber *
t_int_mul (TNumber *self, TNumber *other) {g_return_val_if_fail (T_IS_INT (self), NULL);t_int_binary_op (*)
}static TNumber *
t_int_div (TNumber *self, TNumber *other) {g_return_val_if_fail (T_IS_INT (self), NULL);int i;double d;if (T_IS_INT (other)) {g_object_get (T_INT (other), "value", &i, NULL);if (i == 0) {g_signal_emit_by_name (self, "div-by-zero");return NULL;} elsereturn  T_NUMBER (t_int_new_with_value (T_INT(self)->value / i));} else {g_object_get (T_DOUBLE (other), "value", &d, NULL);if (d == 0) {g_signal_emit_by_name (self, "div-by-zero");return NULL;} elsereturn  T_NUMBER (t_int_new_with_value (T_INT(self)->value / (int)  d));}
}static TNumber *
t_int_uminus (TNumber *self) {g_return_val_if_fail (T_IS_INT (self), NULL);return T_NUMBER (t_int_new_with_value (- T_INT(self)->value));
}static char *
t_int_to_s (TNumber *self) {g_return_val_if_fail (T_IS_INT (self), NULL);int i;g_object_get (T_INT (self), "value", &i, NULL); return g_strdup_printf ("%d", i);
}static void
t_int_class_init (TIntClass *class) {TNumberClass *tnumber_class = T_NUMBER_CLASS (class);GObjectClass *gobject_class = G_OBJECT_CLASS (class);/* override virtual functions */tnumber_class->add = t_int_add;tnumber_class->sub = t_int_sub;tnumber_class->mul = t_int_mul;tnumber_class->div = t_int_div;tnumber_class->uminus = t_int_uminus;tnumber_class->to_s = t_int_to_s;gobject_class->set_property = t_int_set_property;gobject_class->get_property = t_int_get_property;int_property = g_param_spec_int ("value", "val", "Integer value", G_MININT, G_MAXINT, 0, G_PARAM_READWRITE);g_object_class_install_property (gobject_class, PROP_INT, int_property);
}TInt *
t_int_new_with_value (int value) {TInt *i;i = g_object_new (T_TYPE_INT, "value", value, NULL);return i;
}TInt *
t_int_new (void) {TInt *i;i = g_object_new (T_TYPE_INT, NULL);return i;
}

TDouble object

我们对TDouble进行重构,以增加其功能,使TDouble类型的数据能够使用TNumber的函数进行基础运算。

/*tdouble.h*/
#pragma once#include <glib-object.h>#define T_TYPE_DOUBLE  (t_double_get_type ())
G_DECLARE_FINAL_TYPE (TDouble, t_double, T, DOUBLE, TNumber)/* create a new TDouble instance */
TDouble *
t_double_new_with_value (double value);TDouble *
t_double_new (void);
/*tdouble.c*/
#include "tnumber.h"
#include "tdouble.h"
#include "tint.h"#define PROP_DOUBLE 1
static GParamSpec *double_property = NULL;struct _TDouble {TNumber parent;double value;
};G_DEFINE_TYPE (TDouble, t_double, T_TYPE_NUMBER)static void
t_double_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) {TDouble *self = T_DOUBLE (object);if (property_id == PROP_DOUBLE) {self->value = g_value_get_double (value);} elseG_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}static void
t_double_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec) {TDouble *self = T_DOUBLE (object);if (property_id == PROP_DOUBLE)g_value_set_double (value, self->value);elseG_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}static void
t_double_init (TDouble *self) {
}/* arithmetic operator */
/* These operators create a new instance and return a pointer to it. */
#define t_double_binary_op(op) \int i; \double d; \if (T_IS_INT (other)) { \g_object_get (T_INT (other), "value", &i, NULL); \return  T_NUMBER (t_double_new_with_value (T_DOUBLE(self)->value op (double) i)); \} else { \g_object_get (T_DOUBLE (other), "value", &d, NULL); \return  T_NUMBER (t_double_new_with_value (T_DOUBLE(self)->value op d)); \}static TNumber *
t_double_add (TNumber *self, TNumber *other) {g_return_val_if_fail (T_IS_DOUBLE (self), NULL);t_double_binary_op (+)
}static TNumber *
t_double_sub (TNumber *self, TNumber *other) {g_return_val_if_fail (T_IS_DOUBLE (self), NULL);t_double_binary_op (-)
}static TNumber *
t_double_mul (TNumber *self, TNumber *other) {g_return_val_if_fail (T_IS_DOUBLE (self), NULL);t_double_binary_op (*)
}static TNumber *
t_double_div (TNumber *self, TNumber *other) {g_return_val_if_fail (T_IS_DOUBLE (self), NULL);int i;double d;if (T_IS_INT (other)) {g_object_get (T_INT (other), "value", &i, NULL);if (i == 0) {g_signal_emit_by_name (self, "div-by-zero");return NULL;} elsereturn  T_NUMBER (t_double_new_with_value (T_DOUBLE(self)->value / (double) i));} else {g_object_get (T_DOUBLE (other), "value", &d, NULL);if (d == 0) {g_signal_emit_by_name (self, "div-by-zero");return NULL;} elsereturn  T_NUMBER (t_double_new_with_value (T_DOUBLE(self)->value / d));}
}static TNumber *
t_double_uminus (TNumber *self) {g_return_val_if_fail (T_IS_DOUBLE (self), NULL);return T_NUMBER (t_double_new_with_value (- T_DOUBLE(self)->value));
}static char *
t_double_to_s (TNumber *self) {g_return_val_if_fail (T_IS_DOUBLE (self), NULL);double d;g_object_get (T_DOUBLE (self), "value", &d, NULL);return g_strdup_printf ("%lf", d);
}static void
t_double_class_init (TDoubleClass *class) {TNumberClass *tnumber_class = T_NUMBER_CLASS (class);GObjectClass *gobject_class = G_OBJECT_CLASS (class);/* override virtual functions */tnumber_class->add = t_double_add;tnumber_class->sub = t_double_sub;tnumber_class->mul = t_double_mul;tnumber_class->div = t_double_div;tnumber_class->uminus = t_double_uminus;tnumber_class->to_s = t_double_to_s;gobject_class->set_property = t_double_set_property;gobject_class->get_property = t_double_get_property;double_property = g_param_spec_double ("value", "val", "Double value", -G_MAXDOUBLE, G_MAXDOUBLE, 0, G_PARAM_READWRITE);g_object_class_install_property (gobject_class, PROP_DOUBLE, double_property);
}TDouble *
t_double_new_with_value (double value) {TDouble *d;d = g_object_new (T_TYPE_DOUBLE, "value", value, NULL);return d;
}TDouble *
t_double_new (void) {TDouble *d;d = g_object_new (T_TYPE_DOUBLE, NULL);return d;
}

测试

完成对TInt、TDouble类型的定义,现在,看看这两个类型在应用程序中应该如何使用。

#include <glib-object.h>
#include "tnumber.h"
#include "tint.h"
#include "tdouble.h"static void
notify_cb (GObject *gobject, GParamSpec *pspec, gpointer user_data) {const char *name;int i;double d;name = g_param_spec_get_name (pspec);if (T_IS_INT (gobject) && strcmp (name, "value") == 0) {g_object_get (T_INT (gobject), "value", &i, NULL);g_print ("Property \"%s\" is set to %d.\n", name, i);} else if (T_IS_DOUBLE (gobject) && strcmp (name, "value") == 0) {g_object_get (T_DOUBLE (gobject), "value", &d, NULL);g_print ("Property \"%s\" is set to %lf.\n", name, d);}
}int
main (int argc, char **argv) {TNumber *i, *d, *num;char *si, *sd, *snum;i = T_NUMBER (t_int_new ());d = T_NUMBER (t_double_new ());g_signal_connect (G_OBJECT (i), "notify::value", G_CALLBACK (notify_cb), NULL);g_signal_connect (G_OBJECT (d), "notify::value", G_CALLBACK (notify_cb), NULL);g_object_set (T_INT (i), "value", 100, NULL);g_object_set (T_DOUBLE (d), "value", 12.345, NULL);num = t_number_add (i, d);si = t_number_to_s (i);sd = t_number_to_s (d);snum = t_number_to_s (num);g_print ("%s + %s is %s.\n", si, sd, snum);g_object_unref (num);g_free (snum);num = t_number_add (d, i);snum = t_number_to_s (num);g_print ("%s + %s is %s.\n", sd, si, snum);g_object_unref (num);g_free (sd);g_free (snum);g_object_set (T_DOUBLE (d), "value", 0.0, NULL);sd = t_number_to_s (d);if ((num = t_number_div(i, d)) != NULL) {snum = t_number_to_s (num);g_print ("%s / %s is %s.\n", si, sd, snum);g_object_unref (num);g_free (snum);}g_object_unref (i);g_object_unref (d);g_free (si);g_free (sd);return 0;
}

程序运行结果如下:

Property "value" is set to 100.
Property "value" is set to 12.345000.
100 + 12.345000 is 112.
12.345000 + 100 is 112.345000.
Property "value" is set to 0.000000.Error: division by zero.

有趣的是,两次加法的结果不同。这是为什么呢?TInt与TDouble都对TNumber 的add 函数进行了覆盖,那么当使用两个不同类型的数据调用加法函数时,应该使用哪个类型的add函数呢,这就取决于t_number_add的实现了。

这篇关于Gobject tutorial 三的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1064384

相关文章

A Tutorial on Near-Field XL-MIMO Communications Towards 6G【论文阅读笔记】

此系列是本人阅读论文过程中的简单笔记,比较随意且具有严重的偏向性(偏向自己研究方向和感兴趣的),随缘分享,共同进步~ 论文主要内容: 建立XL-MIMO模型,考虑NUSW信道和非平稳性; 基于近场信道模型,分析性能(SNR scaling laws,波束聚焦、速率、DoF) XL-MIMO设计问题:信道估计、波束码本、波束训练、DAM XL-MIMO信道特性变化: UPW ➡ NU

beanstalkc Tutorial 中文版

英文原版:https://github.com/earl/beanstalkc/blob/wip-doc-rtfd/doc/tutorial.rst 背景介绍: Beanstalk,一个高性能、轻量级的分布式内存队列系统。而beanstalkc是Beanstalk的一个python客户端库。看题主写的通俗易懂,就直接翻译过来。 开始: 启动服务端beanstalkd进程来监听14711端口,可以

OpenGuass under Ubuntu_22.04 install tutorial

今天开始短学期课程:数据库课程设计。今天9点左右在SL1108开课,听陈老师讲授了本次短学期课程的要求以及任务安排,随后讲解了国产数据库的三层架构的逻辑。配置了大半天才弄好,放一张成功的图片,下面开始记录成功的步骤: My operator system is Ubuntu_22.04. procedures sudo wget https://opengauss.obs.cn-so

Tutorial : Getting Started with Kubernetes on your Windows Laptop with Minikube

https://rominirani.com/tutorial-getting-started-with-kubernetes-on-your-windows-laptop-with-minikube-3269b54a226#.d9lmuvzf2 本文的注意事项: 1, 截止到2017.01.20, window上的kubernetes依然是实验性的, 存在各种不可预知的bug

OpenCV2.4.10之samples_cpp_tutorial-code_learn-----ImgTrans(仿射变换)

本系列学习笔记参考自OpenCV2.4.10之opencv\sources\samples\cpp\tutorial_code和http://www.opencv.org.cn/opencvdoc/2.3.2/html/genindex.html 本博文将继续学习opencv-tutorial-code中的ImgTrans,这里讲主要介绍仿射变换。仿射变换是直角坐标系的一种,描述的是一

OpenCV2.4.10之samples_cpp_tutorial-code_learn-----ImgTrans(图片边框与图片卷积)

本系列学习笔记参考自OpenCV2.4.10之 opencv\sources\samples\cpp\tutorial_code和 http://www.opencv.org.cn/opencvdoc/2.3.2/html/genindex.html 本博文将继续介绍如何给一张图片添加边框以及如何对一张图片进行卷积。核心函数为copyMakeBorder与filter2D 1.co

OpenCV2.4.10之samples_cpp_tutorial-code_learn-----ImgTrans(Canny边缘检测)

本系列学习笔记参考自OpenCV2.4.10之 opencv\sources\samples\cpp\tutorial_code和 http://www.opencv.org.cn/opencvdoc/2.3.2/html/genindex.html 本博文接下来将介绍图像变换相关的Demo,如下图所示: CannyDetector_Demo.cpp(Canny边缘检测)

OpenCV2.4.10之samples_cpp_tutorial-code_learn-----ImgProc(图像处理)

本系列学习笔记参考自OpenCV2.4.10之 opencv\sources\samples\cpp\tutorial_code和 http://www.opencv.org.cn/opencvdoc/2.3.2/html/genindex.html       本博文将继续学习 OpenCV2.4.10中tutorial-code下的ImgProc,还有对于涉及到的知

OpenCV2.4.10之samples_cpp_tutorial-code_learn------安装配置与第一个Opencv程序

本系列学习笔记参考自OpenCV2.4.10之 opencv\sources\samples\cpp\tutorial_code和 http://www.opencv.org.cn/opencvdoc/2.3.2/html/genindex.html opencv作为一个开源的二维图形库,提供了一套完整的二维图像处理等相关算法的C/C++实现。自opencv2.0版

【kaldi】Kaldi tutorial翻译之Prerequisites(前提条件)-kaldi学习前必备梳理

本翻译仅供自己学习使用,不承担任何其他责任。水平有限拒绝转载。欢迎大家指出错误,共同学习。 我们假设本页的读者了解使用HMM-GMM进行语音识别的基础知识。在这里我们需要在线简明介绍的是:M. Gales and S. Young (2007).``The Application of Hidden Markov Models in Speech Recognition."