> 文章列表 > 3.派生类和抽象类

3.派生类和抽象类

3.派生类和抽象类

参考资料:https://github.com/ToshioCP/Gobject-tutorial/blob/main/gfm/sec6.md

抽象类型没有任何实例

G_DECLARE_DERIVABLE_TYPE宏用来声明抽象类。这类似于G_DECLARE_FINAL_TYPE宏。

比如面的例子,MNuber是抽象类,G_DECLARE_DERIVABLE_TYPE扩展为:

  1. 函数声明m_number_get_type(),你需要定义它。你可以用G_DEFINE_TYPE等宏定义它。
  2. MNumber实例的定义,它的成员仅仅有它的父类。
  3. MNumberClass的声明。你需要在头文件后面定义它。
  4. 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宏。
  5. 提供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 {GObject 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宏,用于定义抽象类型对象。抽象类型不能被实例化。
这个宏扩展为:

  1. m_number_init()函数声明。
  2. m_number_class_init()函数声明。
  3. m_number_get_tyoe()函数定义
  4. 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);elseG_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);elseG_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);elseG_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);elseG_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);
}