GObject是Glib庫(kù)的一部分,提供了一個(gè)靈活的、可擴(kuò)展的、并且容易映射到其他語(yǔ)言的面向?qū)ο蟮腃語(yǔ)言框架。以下是GObject的一些核心概念和使用方法。
源碼:https://gitlab.gnome.org/GNOME/glib/
教程:https://docs.gtk.org/gobject/index.html
1. GObject的核心概念
動(dòng)態(tài)類型系統(tǒng):GObject允許程序在運(yùn)行時(shí)進(jìn)行類型注冊(cè),這意味著可以使用純C語(yǔ)言設(shè)計(jì)一整套面向?qū)ο蟮?a class="article-link" target="_blank" href="/tag/%E8%BD%AF%E4%BB%B6/">軟件模塊。
內(nèi)存管理:GObject實(shí)現(xiàn)了基于引用計(jì)數(shù)的內(nèi)存管理,這簡(jiǎn)化了內(nèi)存管理的復(fù)雜性。
屬性系統(tǒng):GObject提供了通用的set/get屬性獲取方法,使得屬性管理變得更加簡(jiǎn)單。
信號(hào)機(jī)制:GObject內(nèi)置了簡(jiǎn)單易用的信號(hào)機(jī)制,允許對(duì)象之間進(jìn)行通信。
2. GObject的使用示例
在GObject中,類和實(shí)例是兩個(gè)結(jié)構(gòu)體的組合。類結(jié)構(gòu)體初始化函數(shù)一般被調(diào)用一次,而實(shí)例結(jié)構(gòu)體的初始化函數(shù)的調(diào)用次數(shù)等于對(duì)象實(shí)例化的次數(shù)。所有實(shí)例共享的數(shù)據(jù)保存在類結(jié)構(gòu)體中,而對(duì)象私有的數(shù)據(jù)保存在實(shí)例結(jié)構(gòu)體中。
GObject實(shí)例的結(jié)構(gòu)體定義如下:
typedef?struct?_GObject??GObject;
struct??_GObject
{
??GTypeInstance??g_type_instance;
??
??/*<?private?>*/
??guint??????????ref_count;??/*?(atomic)?*/
??GData?????????*qdata;
};
GObject類的結(jié)構(gòu)體定義如下:
struct??_GObjectClass
{
??GTypeClass???g_type_class;
??/*<?private?>*/
??GSList??????*construct_properties;
??/*<?public?>*/
??/*?seldom?overridden?*/
??GObject*???(*constructor)?????(GType??????????????????type,
?????????????????????????????????guint??????????????????n_construct_properties,
?????????????????????????????????GObjectConstructParam?*construct_properties);
??/*?overridable?methods?*/
??void???????(*set_property)????????(GObject????????*object,
?????????????????????????????????????????guint???????????property_id,
?????????????????????????????????????????const?GValue???*value,
?????????????????????????????????????????GParamSpec?????*pspec);
??void???????(*get_property)????????(GObject????????*object,
?????????????????????????????????????????guint???????????property_id,
?????????????????????????????????????????GValue?????????*value,
?????????????????????????????????????????GParamSpec?????*pspec);
??void???????(*dispose)?????????(GObject????????*object);
??void???????(*finalize)????????(GObject????????*object);
??/*?seldom?overridden?*/
??void???????(*dispatch_properties_changed)?(GObject??????*object,
?????????????????????????guint?????n_pspecs,
?????????????????????????GParamSpec??**pspecs);
??/*?signals?*/
??void???????(*notify)??????????(GObject????*object,
?????????????????????GParamSpec?*pspec);
??/*?called?when?done?constructing?*/
??void???????(*constructed)?????(GObject????*object);
??/*<?private?>*/
??gsize?????flags;
??gsize?????????n_construct_properties;
??gpointer?pspecs;
??gsize?n_pspecs;
??/*?padding?*/
??gpointer??pdummy[3];
};
以下是一個(gè)簡(jiǎn)單的示例,展示了如何創(chuàng)建和使用GObject實(shí)例:
#include?<glib-object.h>
int?main?(int?argc,?char?**argv)?{
????GObject*?instance1,?*instance2;?//?指向?qū)嵗闹羔?
????GObjectClass*?class1,?*class2;??//?指向類的指針
????instance1?=?g_object_new?(G_TYPE_OBJECT,?NULL);
????instance2?=?g_object_new?(G_TYPE_OBJECT,?NULL);
????g_print?("The?address?of?instance1?is?%pn",?instance1);
????g_print?("The?address?of?instance2?is?%pn",?instance2);
????class1?=?G_OBJECT_GET_CLASS?(instance1);
????class2?=?G_OBJECT_GET_CLASS?(instance2);
????g_print?("The?address?of?the?class?of?instance1?is?%pn",?class1);
????g_print?("The?address?of?the?class?of?instance2?is?%pn",?class2);
????g_object_unref?(instance1);
????g_object_unref?(instance2);
????return?0;
}
The?address?of?instance1?is?0x55fb9141ad20
The?address?of?instance2?is?0x55fb9141ad40
The?address?of?the?class?of?instance1?is?0x55fb9141a350
The?address?of?the?class?of?instance2?is?0x55fb9141a350
在這個(gè)示例中,g_object_new
函數(shù)用于創(chuàng)建GObject實(shí)例,并返回指向它的指針。G_TYPE_OBJECT
是GObject基類的類型標(biāo)識(shí)符,所有其他GObject類型都從這個(gè)基類型派生。宏 G_OBJECT_GET_CLASS
返回指向參數(shù)所屬類變量的指針。g_object_unref
用于銷毀實(shí)例變量并釋放內(nèi)存。
實(shí)例1與實(shí)例2的存儲(chǔ)空間是不同的,每個(gè)實(shí)例都有自己的空間。兩個(gè)類的存儲(chǔ)空間是相同的,兩個(gè)GObject實(shí)例共享同一個(gè)類。
3. GObject的信號(hào)機(jī)制
GObject允許定義和使用屬性,以及發(fā)出和連接信號(hào)。這些特性使得GObject非常適合用于構(gòu)建復(fù)雜的軟件系統(tǒng),尤其是在需要組件間通信和屬性管理的場(chǎng)景中。
信號(hào)最基本的用途是實(shí)現(xiàn)事件通知。例如:創(chuàng)建一個(gè)信號(hào),當(dāng)調(diào)用文件寫方法時(shí),觸發(fā)文件變化信號(hào)。
創(chuàng)建信號(hào):
file_signals[CHANGED]?=?
??g_signal_newv?("changed",
?????????????????G_TYPE_FROM_CLASS?(object_class),
?????????????????G_SIGNAL_RUN_LAST?|?G_SIGNAL_NO_RECURSE?|?G_SIGNAL_NO_HOOKS,
?????????????????NULL?/*?closure?*/,
?????????????????NULL?/*?accumulator?*/,
?????????????????NULL?/*?accumulator?data?*/,
?????????????????NULL?/*?C?marshaller?*/,
?????????????????G_TYPE_NONE?/*?return_type?*/,
?????????????????0?????/*?n_params?*/,
?????????????????NULL??/*?param_types?*/);
帶信號(hào)機(jī)制的文件寫方法:
void
viewer_file_write?(ViewerFile???*self,
???????????????????const?guint8?*buffer,
???????????????????gsize?????????size)
{
??g_return_if_fail?(VIEWER_IS_FILE?(self));
??g_return_if_fail?(buffer?!=?NULL?||?size?==?0);
??/*?First?write?data.?*/
??/*?Then,?notify?user?of?data?written.?*/
??g_signal_emit?(self,?file_signals[CHANGED],?0?/*?details?*/);
}
用戶回調(diào)處理函數(shù)連接到信號(hào):
g_signal_connect?(file,?"changed",?(GCallback)?changed_event,?NULL);
4. 跨語(yǔ)言互通性
GObject被設(shè)計(jì)為可以直接使用在C程序中,并且可以封裝至其他語(yǔ)言,如C++、Java、Ruby、Python和.NET/Mono等,這使得GObject具有很好的跨語(yǔ)言互通性。