参考资料:https://github.com/ToshioCP/Gobject-tutorial/blob/main/gfm/sec6.md
抽象类型没有任何实例。
G_DECLARE_DERIVABLE_TYPE
宏用来声明抽象类。这类似于G_DECLARE_FINAL_TYPE
宏。
比如面的例子,MNuber
是抽象类,G_DECLARE_DERIVABLE_TYPE
扩展为:
- 函数声明
m_number_get_type()
,你需要定义它。你可以用G_DEFINE_TYPE
等宏定义它。 MNumber
实例的定义,它的成员仅仅有它的父类。MNumberClass
的声明。你需要在头文件后面定义它。M_NUMBER
(cast to instance) 、M_NUMBER_CLASS
(cast to class) 、M_IS_NUMBER
(instance check)、M_IS_MUBER_CLASS
(class check)、M_NUMBER_GET_CLASS
宏。- 提供
g_autoptr()
然后,是定义MNumberClass
结构退。
下来,是初始化函数指针,它们被称为类方法或虚函数。子类对象需要覆盖它们。
然后是一些公开的函数。
1. 抽象类MNumber
m_number.h:
#ifndef M_NUMBER_H
#define M_NUMBER_H
#include <glib-object.h>
#define M_TYPE_NUMBER (m_number_get_type())
G_DECLARE_DERIVABLE_TYPE (MNumber, m_number, M, NUMBER, GObject)
struct _MNumberClass {
GObjectClass base_class;
MNumber * (*add) (MNumber *self, MNumber *other);
MNumber * (*sub) (MNumber *self, MNumber *other);
MNumber * (*mul) (MNumber *self, MNumber *other);
MNumber * (*div) (MNumber *self, MNumber *other);
MNumber * (*uminus) (MNumber *self);
char * (*to_str) (MNumber *self);
};
MNumber *
m_number_add (MNumber *self, MNumber *other);
MNumber *
m_number_sub (MNumber *self, MNumber *other);
MNumber *
m_number_mul (MNumber *self, MNumber *other);
MNumber *
m_number_div (MNumber *self, MNumber *other);
MNumber *
m_number_uminus (MNumber *self);
char *
m_number_to_str (MNumber *self);
#endif // M_NUMBER_H
下面的,G_DEFINE_ABSTRACT_TYPE
宏,用于定义抽象类型对象。抽象类型不能被实例化。
这个宏扩展为:
m_number_init()
函数声明。m_number_class_init()
函数声明。m_number_get_tyoe()
函数定义m_number_parent_class
静态变量的定义,它指向父类。
虚函数指针分配为NULL
,需要让后代覆盖。
m_number_init()
是实例初始化函数,但是抽象对象不被实例化,所以它什么都不做。但是不能省略这个函数定义。
m_number.c:
#include "m_number.h"
G_DEFINE_ABSTRACT_TYPE (MNumber, m_number, G_TYPE_OBJECT)
static void
m_number_class_init (MNumberClass *klass)
{
klass->add = NULL;
klass->sub = NULL;
klass->mul = NULL;
klass->div = NULL;
klass->uminus = NULL;
klass->to_str = NULL;
}
static void
m_number_init (MNumber *inst)
{ }
MNumber *
m_number_add (MNumber *self, MNumber *other)
{
g_return_val_if_fail (M_IS_NUMBER (self), NULL);
g_return_val_if_fail (M_IS_NUMBER (other), NULL);
MNumberClass *class_ = M_NUMBER_GET_CLASS (self);
return class_->add ? class_->add (self, other) : NULL;
}
MNumber *
m_number_sub (MNumber *self, MNumber *other)
{
g_return_val_if_fail (M_IS_NUMBER (self), NULL);
g_return_val_if_fail (M_IS_NUMBER (self), NULL);
MNumberClass *class_ = M_NUMBER_GET_CLASS (self);
return class_->sub ? class_->sub (self, other) : NULL;
}
MNumber *
m_number_mul (MNumber *self, MNumber *other)
{
g_return_val_if_fail (M_IS_NUMBER (self), NULL);
g_return_val_if_fail (M_IS_NUMBER (other), NULL);
MNumberClass *class_ = M_NUMBER_GET_CLASS (self);
return class_->mul ? class_->mul (self, other) : NULL;
}
MNumber *
m_number_div (MNumber *self, MNumber *other)
{
g_return_val_if_fail (M_IS_NUMBER (self), NULL);
g_return_val_if_fail (M_IS_NUMBER (other), NULL);
MNumberClass *class_ = M_NUMBER_GET_CLASS (self);
return class_->div ? class_->div (self, other) : NULL;
}
MNumber *
m_number_uminus (MNumber *self)
{
g_return_val_if_fail (M_IS_NUMBER (self), NULL);
MNumberClass *class_ = M_NUMBER_GET_CLASS (self);
return class_->uminus ? class_->uminus (self) : NULL;
}
char *
m_number_to_str (MNumber *self)
{
g_return_val_if_fail (M_IS_NUMBER (self), NULL);
MNumberClass *class_ = M_NUMBER_GET_CLASS (self);
return class_->to_str ? class_->to_str (self) : NULL;
}
2. 派生类 MInt
m_int.h:
#ifndef M_INT_H
#define M_INT_H
#include <glib-object.h>
#include "m_number.h"
#define M_TYPE_INT (m_int_get_type())
G_DECLARE_FINAL_TYPE (MInt, m_int, M, INT, MNumber)
MInt *
m_int_new_with_value (int value);
MInt *
m_int_new (void);
#endif // M_INT_H
m_int.c:
#include "m_int.h"
#include "m_double.h"
#define PROP_INT 1
static GParamSpec *int_property = NULL;
struct _MInt {
MNumber base_class;
int value;
};
G_DEFINE_TYPE (MInt, m_int, M_TYPE_NUMBER)
static void
m_int_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
MInt *self = M_INT (object);
if (property_id == PROP_INT)
self->value = g_value_get_int (value);
else
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
static void
m_int_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
MInt *self = M_INT (object);
if (property_id == PROP_INT)
g_value_set_int (value, self->value);
else
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
static void
m_int_init (MInt *d)
{ }
#define m_int_binary_op(op)\
int i;\
double d;\
if (M_IS_INT (other)) {\
g_object_get (M_INT (other), "value", &i, NULL);\
return M_NUMBER (m_int_new_with_value (M_INT (self)->value op i));\
} else {\
g_object_get (M_DOUBLE (other), "value", &d, NULL);\
return M_NUMBER (m_int_new_with_value (M_INT (self)->value op (int)d));\
}
static MNumber *
m_int_add (MNumber *self, MNumber *other)
{
g_return_val_if_fail (M_IS_INT (self), NULL);
m_int_binary_op (+)
}
static MNumber *
m_int_sub (MNumber *self, MNumber *other)
{
g_return_val_if_fail (M_IS_INT (self), NULL);
m_int_binary_op (-)
}
static MNumber *
m_int_mul (MNumber *self, MNumber *other)
{
g_return_val_if_fail (M_IS_INT (self), NULL);
m_int_binary_op (*)
}
static MNumber *
m_int_div (MNumber *self, MNumber *other)
{
g_return_val_if_fail (M_IS_INT (self), NULL);
m_int_binary_op ( /)
}
static MNumber *
m_int_uminus (MNumber *self)
{
g_return_val_if_fail (M_IS_INT (self), NULL);
return M_NUMBER (m_int_new_with_value (-M_INT (self)->value));
}
static char *
m_int_to_str (MNumber *self)
{
g_return_val_if_fail (M_IS_INT (self), NULL);
int i;
g_object_get (M_INT (self), "value", &i, NULL);
return g_strdup_printf ("%d", i);
}
static void
m_int_class_init (MIntClass *class_)
{
MNumberClass *mnumber_class = M_NUMBER_CLASS (class_);
GObjectClass *gobject_class = G_OBJECT_CLASS (class_);
mnumber_class->add = m_int_add;
mnumber_class->sub = m_int_sub;
mnumber_class->mul = m_int_mul;
mnumber_class->div = m_int_div;
mnumber_class->uminus = m_int_uminus;
mnumber_class->to_str = m_int_to_str;
gobject_class->set_property = m_int_set_property;
gobject_class->get_property = m_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);
}
MInt *
m_int_new_with_value (int value)
{
return g_object_new (M_TYPE_INT, "value", value, NULL);
}
MInt *
m_int_new (void)
{
return g_object_new (M_TYPE_INT, NULL);
}
3. 派生类MDouble
m_double.h:
#ifndef M_DOUBLE_H
#define M_DOUBLE_H
#include <glib-object.h>
#include "m_number.h"
#define M_TYPE_DOUBLE (m_double_get_type())
G_DECLARE_FINAL_TYPE (MDouble, m_double, M, DOUBLE, MNumber)
MDouble *
m_double_new_with_value (double value);
MDouble *
m_double_new (void);
#endif // M_DOUBLE_H
m_double.c:
#include "m_double.h"
#include "m_int.h"
#define PROP_DOUBLE 1
static GParamSpec *double_property = NULL;
struct _MDouble {
MDouble base_class;
double value;
};
G_DEFINE_TYPE (MDouble, m_double, M_TYPE_NUMBER)
static void
m_double_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
MDouble *self = M_DOUBLE (object);
if (property_id == PROP_DOUBLE)
self->value = g_value_get_double (value);
else
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
static void
m_double_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
MDouble *self = M_DOUBLE (object);
if (property_id == PROP_DOUBLE)
g_value_set_double (value, self->value);
else
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
static void
m__double_init (MDouble *d)
{ }
#define m_double_binary_op(op)\
int i;\
double d;\
if (M_IS_INT (other)) {\
g_object_get (M_INT (other), "value", &i, NULL);\
return M_NUMBER (m_double_new_with_value (M_DOUBLE (self)->value op (double) i));\
} else {\
g_object_get (M_DOUBLE (other), "value", &d, NULL);\
return M_NUMBER (m_double_new_with_value (M_DOUBLE (self)->value op d));\
}
static MNumber *
m_double_add (MNumber *self, MNumber *other)
{
g_return_val_if_fail (M_IS_DOUBLE (self), NULL);
m_double_binary_op (+)
}
static MNumber *
m_double_sub (MNumber *self, MNumber *other)
{
g_return_val_if_fail (M_IS_DOUBLE (self), NULL);
m_double_binary_op (-)
}
static MNumber *
m_double_mul (MNumber *self, MNumber *other)
{
g_return_val_if_fail (M_IS_DOUBLE (self), NULL);
m_double_binary_op (*)
}
static MNumber *
m_double_div (MNumber *self, MNumber *other)
{
g_return_val_if_fail (M_IS_DOUBLE (self), NULL);
m_double_binary_op ( /)
}
static MNumber *
m_double_uminus (MNumber *self)
{
g_return_val_if_fail (M_IS_DOUBLE (self), NULL);
return M_NUMBER (m_double_new_with_value (- M_DOUBLE (self)->value));
}
static MNumber *
m_doube_to_str (MNumber *self)
{
g_return_val_if_fail (M_IS_DOUBLE (self), NULL);
double d;
g_object_get (M_DOUBLE (self), 'value', &d, NULL);
return g_strdup_printf ("%lf", d);
}
static void
m_double_class_init (MDoubleClass *class_)
{
MNumberClass *mnumber_class = M_NUMBER_CLASS (class_);
GObjectClass *gobject_class = G_OBJECT_CLASS (class_);
mnumber_class->add = m_double_add;
mnumber_class->sub = m_double_sub;
mnumber_class->mul = m_double_mul;
mnumber_class->div = m_double_div;
mnumber_class->uminus = m_double_uminus;
mnumber_class->to_str = m_doube_to_str;
gobject_class->set_property = m_double_set_property;
gobject_class->get_property = m_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);
}
MDouble *
m_double_new_with_value (double value)
{
return g_object_new (M_TYPE_DOUBLE, "value", value, NULL);
}
MDouble *
m_double_new (void)
{
return g_object_new (M_TYPE_DOUBLE, NULL);
}