想将GTK+-2.0的信号、回调处理映射成类成员函数,然后我们就可以很简单的
将一个个GTK+2.0中的构件映射成类了,其实就是避开GTKMM那么复杂的东东。
2 #define __BASE_OBJECT_CLASS__
3
4 #include <glib.h>
5 #include <glib- object.h>
6
7 #if 0
8 // 函数指针转换,可以把一种类型的数据直接转换成第二种类型的数据
9 template < class FuncPt1, class FuncPt2>
10 inline FuncPt1 Func_Cast(FuncPt2 pt1)
11 {
12 union __TranPt1ToPt2
13 {
14 FuncPt2 pointer2;
15 FuncPt1 pointer1;
16 } __Tran = {pt1};
17 return __Tran.pointer1;
18 }
19 #endif
20
21 #ifndef __GNUC__
22 #define SIGNAL_CALLBACK __cdcel
23 #else
24 #define SIGNAL_CALLBACK __attribute__((cdecl))
25 #endif
26
27 class BaseObject
28 {
29 public:
30 BaseObject();
31 virtual ~BaseObject();
32
33 /* 创建对象并绑定信号的接口 */
34 virtual gulong setupObject() = 0;
35
36 protected:
37 typedef gulong (BaseObject::*CommonCallback)(GObject*instance, ...);
38
39 typedef struct tagOBJ_CALLBACK
40 {
41 BaseObject* x_pThis;
42 CommonCallback x_pCallback;
43 GObject* x_pWidget;
44 } ObjectCallbackInfo;
45
46 GObject* x_pObject;
47
48 gulong ConnectSignal(gpointer instance, const gchar *detailed_signal, CommonCallback c_handler);
49
50 private:
51 GSList* x_pObjectList;
52
53 static gulong SignalProc( const ObjectCallbackInfo* lpObject, ...);
54 };
55
56 #endif
2 #include <stdarg.h>
3 #include <stdio.h>
4
5 BaseObject::BaseObject():x_pObject(NULL),x_pObjectList(NULL)
6 {
7 }
8
9 BaseObject::~BaseObject()
10 {
11 /* 释放所有分配的ObjectToMemFunc空间 */
12 gpointer lpObj;
13 GSList* lpTempList = x_pObjectList;
14 while (NULL != lpTempList)
15 {
16 /* 如果非空 */
17 lpObj = g_slist_nth_data(lpTempList, 0);
18 if (NULL != lpObj)
19 {
20 g_free(lpObj);
21 }
22
23 lpTempList = g_slist_next(lpTempList);
24 }
25 /* 删除列表 */
26 if (NULL != x_pObjectList)
27 {
28 g_slist_free(x_pObjectList);
29 }
30 }
31
32 gulong BaseObject::ConnectSignal(gpointer instance,
33 const gchar *detailed_signal,
34 CommonCallback c_handler)
35 {
36 /* 分配存放回调指针的空间 */
37 ObjectCallbackInfo* lpObject = (ObjectCallbackInfo*)g_malloc( sizeof(ObjectCallbackInfo));
38 if (NULL == lpObject)
39 {
40 return 0;
41 }
42 lpObject->x_pThis = this;
43 lpObject->x_pCallback = c_handler;
44 lpObject->x_pWidget = (GObject*)instance;
45 /* 将信息保存在slist中 */
46 x_pObjectList = g_slist_append(x_pObjectList, lpObject);
47
48 /* 注册信号回调 */
49 return g_signal_connect_swapped(instance, detailed_signal,
50 (GCallback)&(BaseObject::SignalProc), (gpointer)lpObject);
51 }
52
53 gulong BaseObject::SignalProc( const ObjectCallbackInfo* lpObject, ...)
54 {
55 va_list pArgList;
56 gulong ulRetcode;
57 struct reserve_arg { gulong ulReserver[ 20];} *pstTemp;
58 BaseObject* lpThis;
59 CommonCallback pCallBack;
60
61 /* 收到信号时,先判断指针 */
62 if ( (NULL == lpObject) || (NULL == lpObject->x_pCallback ) || (NULL == lpObject->x_pWidget))
63 {
64 return 0;
65 }
66 /* 取出this指针及成员函数指针 */
67 va_start(pArgList, lpObject);
68 pstTemp = ( struct reserve_arg*)pArgList;
69 lpThis = lpObject->x_pThis;
70 pCallBack = lpObject->x_pCallback;
71
72 /* 调用成员函数 */
73 ulRetcode = (lpThis ->*pCallBack)(lpObject->x_pWidget, *pstTemp);
74
75 va_end(pArgList);
76
77 return ulRetcode;
78 }
使用几个关键技术点:
1.将对象指针、对象的成员函数指针及构件指针保存到对象的成员:一个简单列表中
2.静态成员函数指针作为实际的信号处理接口设置到GTK+-2.0的信号处理中
3.GTK+-2.0的信号处理设置采用g_signal_connect_swapped接口,则静态成员函数第一个参数就是第1步保存的列表指针数据
4.调用成员函数指针时,不考虑成员函数的参数个数,采用默认有20个UINT32的参数作为成员函数的参数,这里要求成员函数必须
是遵守C语言调用规范的,即必须是cdecl,因此声明函数必须为__cdecl
5.使用基类的成员函数指针来调用派生类的成员函数,这种行为已经在标准中声明是未定义的。
6.对于5,单一继承、多继承经验证,在GCC/VC上都通过了。但对于虚拟继承,无法支持,根因还在于虚拟继承的成员函数指针调用
方式完全不相同。
7.对于虚拟继承的成员函数指针调用,实现起来其实也应该不复杂,将BaseObject类进行拆分成Object与BaseObject,然后BaseObject
虚拟继承自Object,那么在生成调用代码时,应该就是能够支持虚拟继承的成员函数指针调用 -- 未验证