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 {
	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宏,用于定义抽象类型对象。抽象类型不能被实例化。
这个宏扩展为:

  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);
	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);
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

barbyQAQ

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值