三、GObject私有属性的查看与设置

本文解析了PMDList类的头文件结构,介绍了如何使用GObject进行类型注册和属性操作,包括宏PM_DLIST的应用、GValue的使用以及GObject的属性设置与获取。涉及了GObjectClass、GParamSpec和GValue的细节以及在主函数中的实践应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.1 类头文件

#ifndef PM_DLIST_H
#define PM_DLIST_H

#include <glib-object.h>

#define PM_TYPE_DLIST (pm_dlist_get_type ())
/* 将基类指针类型转换为PMDList类的指针类型 */
#define PM_DLIST(object) G_TYPE_CHECK_INSTANCE_CAST ((object),\
                                                      PM_TYPE_DLIST, PMDList)

typedef struct _PMDList PMDList;
struct  _PMDList {
        GObject parent_instance;
};

typedef struct _PMDListClass PMDListClass;
struct _PMDListClass {
        GObjectClass parent_class;
};

GType pm_dlist_get_type (void);

#endif

分析
  这章节类头文件唯一改动的地方是加了PM_DLIST(object)宏。该宏的作用是将基类指针类型转换为PMDList类的指针类型。
  下文还会遇见G_OBJECT宏,G_OBJECT_CLASS宏。子类指针转向GObject父类指针。

我的感悟
  参考博客作者认为头文件越简洁越好,C文件去实现头文件简洁背后的繁琐(丑陋)。

1.2 类函数

#include"pm-dlist.h"
/**
 * 此宏的三个功能
 * 1.函数GTyep pm_dlist_get_type()的具体实现,由该宏自动实现
 * 2.注册函数前缀pm_dlish到GObject
 * 3.注册实例结构体名称PMDList到GObject
*/
G_DEFINE_TYPE(PMDList, pm_dlist, G_TYPE_OBJECT);

/* 获得私有成员变量结构体地址 */
#define PM_DLIST_GET_PRIVATE(obj) \
        G_TYPE_INSTANCE_GET_PRIVATE ((obj), PM_TYPE_DLIST, PMDListPrivate)

typedef struct _PMDListPrivate PMDListPrivate;
struct  _PMDListPrivate {
        PMDList *head;
        PMDList *tail;
};

/* 属性对应的ID,真正的属性ID不能为0 */
enum PropertyDlist{
  PROPERTY_DLIST_0,/*占位*/
  PROPERTY_DLIST_HEAD,
  PROPERTY_DLIST_TAIL
};

static void
pm_dlist_set_property(GObject *object, guint property_id,
                      const GValue *value, GParamSpec *pspec){
  /*基类转换成子类指针*/
  PMDList *self = PM_DLIST(object);
  /*通过宏获取唯一私有属性地址*/
  PMDListPrivate *priv = PM_DLIST_GET_PRIVATE(self);

  switch (property_id){
    case PROPERTY_DLIST_HEAD:
            priv->head = g_value_get_pointer (value);
            break;
    case PROPERTY_DLIST_TAIL:
            priv->tail = g_value_get_pointer (value);
            break;
    default:
            G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
            break;
  }
}

static void
pm_dlist_get_property (GObject *object, guint property_id,
                       GValue *value, GParamSpec *pspec)
{
  PMDList *self = PM_DLIST (object);
  PMDListPrivate *priv = PM_DLIST_GET_PRIVATE (self);
  
  switch (property_id) {
  case PROPERTY_DLIST_HEAD:
          g_value_set_pointer (value, priv->head);
          break;
  case PROPERTY_DLIST_TAIL:
          g_value_set_pointer (value, priv->tail);
          break;
  default:
          G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
          break;
  }
}

static void
pm_dlist_class_init(PMDListClass *klass)
{
  /*私有成员添加到类里面*/
  g_type_class_add_private(klass, sizeof(PMDListPrivate));
  
  GObjectClass *base_class = G_OBJECT_CLASS(klass);
  base_class->set_property = pm_dlist_set_property;
  base_class->get_property = pm_dlist_get_property;

  GParamSpec *pspec;
  pspec = g_param_spec_pointer ("head",
                                "Head node",
                                "The head node of the double list",
                                G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT);
  g_object_class_install_property (base_class, PROPERTY_DLIST_HEAD, pspec);
  pspec = g_param_spec_pointer ("tail",
                                "Tail node",
                                "The tail node of the double list",
                                G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT);
  g_object_class_install_property (base_class, PROPERTY_DLIST_TAIL, pspec);

}

static void
pm_dlist_init (PMDList *self)
{
}

分析
  这一部分新增函数目的就是,外部可以查看和设置私有成员变量。其实这一部分,也可以执行某些函数,不一定只查看或者设置变量。

1.enum PropertyDlist 枚举先为属性编号。
2.编写pm_dlist_set_property和pm_dlist_get_property函数
3.父类留有的set_property和get_property指针指向第二步编写的函数。
4.g_object_class_install_property函数注册属性到子类。

g_param_spec_pointer ("head",
                      "Head node",
                      "The head node of the double list",
                      G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT);

  g_param_spec_pointer可以将 ” 属性名:属性值 “参数打包为GParamSpec类型变量。其中Param 1:键名,Param 2:键名的昵称,Param 3:对这个键值对的详细描述,Param 4:用于表示键值的访问权限,G_PARAM_READABLE | G_PARAM_WRITABLE 是指定属性即可读又可写,G_PARAM_CONSTRUCT 是设定属性可以在对象实例化之时(g_object_new)被设置。

g_object_class_install_property (base_class, \
                                 PROPERTY_DLIST_TAIL, pspec);

  g_object_class_install_property 函数用于将 GParamSpec 类型变量所包含的数据插入到 GObject 子类中,其中的细节可以忽略,只需要知道该函数的第一个参数为 GObject 子类的类结构体,第二个参数是 GParamSpec 对应的属性 ID。GObject 子类的属性 ID 在前文已经提及,它是 GObject 子类设计者定义的宏或枚举类型。第三个参数是要安装值向 GObject 子类中的 GParamSpec 类型的变量指针。
  一定要注意,g_object_class_install_property 函数的第二个参数值不能为 0。

1.3 主函数

#include "pm-dlist.h"

int
main (void)
{
  GValue list1_tail = {0};
  GValue list2_head = {0};

  /* GObject 库的类型管理系统的初始化 */
  g_type_init ();

  PMDList *list1, *list2;
  gpointer *head, *tail;
  list1 = g_object_new (PM_TYPE_DLIST,
                        "head", NULL,
                        "tail", NULL,
                        NULL);
  list2 = g_object_new (PM_TYPE_DLIST,
                        "head", NULL,
                        "tail", NULL,
                        NULL);

  g_value_init(&list1_tail, G_TYPE_POINTER);
  g_value_init(&list2_head, G_TYPE_POINTER);

  g_value_set_pointer(&list1_tail, list1);
  g_value_set_pointer(&list2_head, list2);

  g_object_set_property(G_OBJECT(list2), "head", &list1_tail);
  g_object_set_property(G_OBJECT(list1), "tail", &list2_head);

  g_object_get(list1, "head", &head, "tail", &tail, NULL);

  g_printf("%p\n", head);
  g_printf("%p\n", tail);
  
  g_object_set(list1, "head", 0x22, "tail", 0x33, NULL);
  g_object_get(list1, "head", &head, "tail", &tail, NULL);

  //g_printf("%p\n", g_value_get_pointer(&list1_tail));
  g_printf("%p\n", head);
  g_printf("%p\n", tail);

  g_value_unset(&list1_tail);
  g_value_unset(&list2_head);

  g_object_unref (list1);
  g_object_unref (list2);

  return 0;
}

分析

  1. g_object_set_property和g_object_get_property。参数是GObject类和GValue容器。一次只能设置和查询一次属性。
  2. g_object_set和g_object_get。参数是gpointer指针和属性对应变量类型即可。可同时查看和设置多个属性,最后NULL结尾。

感悟
  DeeepStream项目中是不是可以修改和设置属性。从而实现不同码流的设置,sink属性的开关???

GValue
  在C语言里,通用类型我们一般是用void *以表示任何类型的数据。但GObject的设计初衷是为了解决多语言交互问题,所以必须设计出一可以容纳任何数据类型的通用数据类型。以便在不同的编程语言之间进行数据转换操作。这个数据类型就是GValue。因此GValue就是一个变量容器,可以存放各种变量的值,例如整形数、指针、GObject子类等等,本章节GValue存放指针变量的值。更多GValue的理解,我会另写一篇文章记录。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值