如何定义和实现新的GObject之代码实现

本章重点介绍了GObject子类的实现,例如创建自定义继承类,或者实现GTK +窗口类的子类。
在整个章节中,使用文件查看器程序的作为示例,其具有用于表示单个文件查看的ViewerFile类,以及具有特殊功能的不同类型的文件(例如音频文件)的各种派生类。 示例应用程序还支持通过使用ViewerEditable接口编辑文件(例如,调整正在查看的照片)。
1、头文件实现

编写GObject代码之前的第一步是编写类型的头文件,其中包含所需的类型,函数和宏定义。 这些元素中的每一个都只是GObject所有用户遵循的约定,并且在多年的开发基于GObject的代码的经验中进行了改进。 如果你正在写一个库,那么遵守这些约定是尤为重要的; 您的用户将会假定你已经遵循这些约定。 即使你不是在写库,遵守这些约定也会帮助其他想要在你的项目上工作的人。
为您的标题和源代码选择一个约定的名称,并坚持下去:
(1)使用破折号将前缀与typename分开:viewer-file.h和viewer-file.c(这是Nautilus和大多数GNOME库使用的约定)。

(2)使用下划线将前缀与typename分开:viewer_file.h和viewer_file.c。

(3)不要将前缀与typename:viewerfile.h和viewerfile.c分开。 (这是GTK +使用的惯例)

有些人喜欢前两种方法:它使阅读文件名更为容易。
任何GType的基本约定在“约定”一节中描述。
如果要在命名空间'viewer'中声明一个名为'file'的类型,请命名实例类型为ViewerFile,类类型命名为ViewerFileClass(名称区分大小写)。 约定的方法是根据类型是基类还是派生类型的不同而不同。
Final types类型不能进一步子类化,并且应该是新类型的默认选择 - 将Final types更改为可继承的类型始终是与现有代码使用兼容的更改,但相反的往往会导致问题。 Final types使用G_DECLARE_FINAL_TYPE声明,并且要求在源代码(而不是头文件)中声明的实例结构体。

/*
 * Copyright/Licensing information.
 */

/* inclusion guard */
#ifndef __VIEWER_FILE_H__
#define __VIEWER_FILE_H__

#include <glib-object.h>
/*
 * Potentially, include other headers on which this header depends.
 */

G_BEGIN_DECLS

/*
 * Type declaration.
 */
#define VIEWER_TYPE_FILE viewer_file_get_type ()
G_DECLARE_FINAL_TYPE (ViewerFile, viewer_file, VIEWER, FILE, GObject)

/*
 * Method definitions.
 */
ViewerFile *viewer_file_new (void);

G_END_DECLS

#endif /* __VIEWER_FILE_H__ */
继承类可以被子类化,其类和实例结构构成公共API的一部分,如果API稳定性关注,则不能更改。 它们使用G_DECLARE_DERIVABLE_TYPE声明:

/*
 * Copyright/Licensing information.
 */

/* inclusion guard */
#ifndef __VIEWER_FILE_H__
#define __VIEWER_FILE_H__

#include <glib-object.h>
/*
 * Potentially, include other headers on which this header depends.
 */

G_BEGIN_DECLS

/*
 * Type declaration.
 */
#define VIEWER_TYPE_FILE viewer_file_get_type ()
G_DECLARE_DERIVABLE_TYPE (ViewerFile, viewer_file, VIEWER, FILE, GObject)

struct _ViewerFileClass
{
  GObjectClass parent_class;

  /* Class virtual function fields. */
  void (* open) (ViewerFile  *file,
                 GError     **error);

  /* Padding to allow adding up to 12 new virtual functions without
   * breaking ABI. */
  gpointer padding[12];
};

/*
 * Method definitions.
 */
ViewerFile *viewer_file_new (void);

G_END_DECLS

#endif /* __VIEWER_FILE_H__ */
头文件的约定是将最少的头文件#include到需要编译该头文件的顶部。 这允许客户端代码简单地#include“viewer-file.h”,而不需要知道viewer-file.h的先决条件。
2、源代码实现

在源码里面第一步应该先#include需要的头文件

/*
 * Copyright information
 */

#include "viewer-file.h"

/* Private structure definition. */
typedef struct {
  gchar *filename;
  /* stuff */
} ViewerFilePrivate;

/* 
 * forward definitions
 */
如果这个类使用G_DECLARE_FINAL_TYPE声明为不可继承的final types,那么他的实例结构体应当定义在.c文件中。

struct _ViewerFile
{
  GObject parent_instance;

  /* Other members, including private data. */
}

调用G_DEFINE_TYPE宏(或G_DEFINE_TYPE_WITH_PRIVATE如果您的类需要私有数据 - final types不需要私有数据),使用类型名称,函数前缀和父类GType来减少所需的代码数量。这个宏将做如下操作:
(1)实现viewer_file_get_type函数
(2)定义可以从整个.c文件访问的父类指针
(3)将私有实例数据添加到该类型(如果使用G_DEFINE_TYPE_WITH_PRIVATE)
如果使用G_DECLARE_FINAL_TYPE(参见“Boilerplate头代码”一节)将类声明为final,那么私有数据应该放在实例结构中,应该使用ViewerFile和G_DEFINE_TYPE替代G_DEFINE_TYPE_WITH_PRIVATE。final类型的实例结构不会公开暴露,也不会嵌入到任何派生类的实例结构中(因为该类是final);所以它的大小可以变化,而不会导致使用该类的代码不兼容。相反,可继承类的私有数据必须包含在私有结构中,必须使用G_DEFINE_TYPE_WITH_PRIVATE。

G_DEFINE_TYPE (ViewerFile, viewer_file, G_TYPE_OBJECT)

或者

G_DEFINE_TYPE_WITH_PRIVATE (ViewerFile, viewer_file, G_TYPE_OBJECT)

也可以使用G_DEFINE_TYPE_WITH_CODE宏来控制get_type函数实现-例如,添加一个调用G_IMPLEMENT_INTERFACE宏来实现一个接口。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值