如何将GTK+2.0的信号、回调处理映射成类成员函数的调用

想将GTK+-2.0的信号、回调处理映射成类成员函数,然后我们就可以很简单的

将一个个GTK+2.0中的构件映射成类了,其实就是避开GTKMM那么复杂的东东。

 1 #ifndef __BASE_OBJECT_CLASS__
 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
 1 #include "BaseObject.hpp"
 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,那么在生成调用代码时,应该就是能够支持虚拟继承的成员函数指针调用 -- 未验证

原文地址:https://www.cnblogs.com/eaglexmw/p/3054876.html