--------------------------------------------------------------------------------
标题: 如何使用类的成员方法指针?
作者: 叶飞虎
日期: 2009.03.22
--------------------------------------------------------------------------------
其实,类方法调用原理很简单,若知道如何使用C语言模拟类实现就知道怎么回事了,只
是这个工作由编译器来做罢了。调用方法与调用函数的区别是在调用方法时,编译器把当前
对象的指针当做第一个参数传入,其它参数的传递与函数没有区别,也就说,这为提供回调
事件的方法指针提供一条方便之门。方法指针不能滥用,用好它可以使你的视野更加开阔!
1 /* TObject - 基类 */
2
3 class TObject
4 {
5 };
6
7
8 /* TDemoA - A 类 */
9
10 class TDemoA
11 {
12 public:
13 TDemoA();
14 virtual ~TDemoA();
15
16 void AF1(void* AParam);
17 void AF2(const char* AStr, long AValue);
18
19 // ???
20 };
21
22 /* TDemoB - B 类 */
23
24 class TDemoB
25 {
26 public:
27 TDemoB();
28 virtual ~TDemoB();
29
30 void BF1(void* AParam);
31 void BF2(const char* AStr, long AValue);
32
33 // ???
34 };
35
36 /* TDemoC - C 类 */
37
38 class TDemoC
39 {
40 public:
41 // TOnFunc1 事件类型
42 typedef void (TObject::*TDoFunc1)(void* AParam);
43 typedef struct
44 {
45 TDoFunc1 Method;
46 void* Object;
47 } TOnFunc1;
48
49 // TOnFunc2 事件类型
50 typedef void (TObject::*TDoFunc2)(const char* AStr, long AValue);
51 typedef struct
52 {
53 TDoFunc2 Method;
54 void* Object;
55 } TOnFunc2;
56
57 public:
58 TDemoC();
59 virtual ~TDemoC();
60
61 // Func1
62 void Func1(void* AParam)
63 {
64 if (OnFunc1.Method != NULL)
65 ((TObject*)OnFunc1.Object->*OnFunc1.Method)(AParam);
66 }
67
68 // Func2
69 void Func2(const char* AStr, long AValue)
70 {
71 if (OnFunc2.Method != NULL)
72 ((TObject*)OnFunc2.Object->*OnFunc2.Method)(AStr, AValue);
73 }
74
75 // 事件
76 TOnFunc1 OnFunc1;
77 TOnFunc1 OnFunc2;
78 };
79
80
81 // 例子
82 TDemoA A;
83 TDemoB B;
84 TDemoC C;
85
86 int demo()
87 {
88 // ???
89
90 C.OnFunc1.Object = &B;
91 C.OnFunc1.Method = (TDemoC::TDoFunc1)&TDemoB::BF1;
92
93 C.OnFunc2.Object = &A;
94 C.OnFunc2.Method = (TDemoC::TDoFunc2)&TDemoA::AF2;
95
96 // 调用 C 方法
97 C.Func1(); // <=> B.BF1();
98 C.Func2(); // <=> A.AF2();
99
100 // ???
101
102 C.OnFunc1.Object = &A;
103 C.OnFunc1.Method = (TDemoC::TDoFunc1)&TDemoA::AF1;
104
105 C.OnFunc2.Object = &B;
106 C.OnFunc2.Method = (TDemoC::TDoFunc2)&TDemoB::BF2;
107
108 // 调用 C 方法
109 C.Func1(); // <=> A.AF1();
110 C.Func2(); // <=> B.BF2();
111
112 // ???
113
114 }
115
116 /* TKYFmtMemEvent - 格式化内存项事件类 */
117
118 class TKYFmtMemEvent
119 {
120 public:
121 // TOnFormat 事件类型
122 typedef void (TObject::*TDoFormat)(void* AItem, Word ASize);
123 typedef struct
124 {
125 TDoFormat Method;
126 void* Object;
127 } TOnFormat;
128
129 public:
130 TKYFmtMemEvent() { Clear(); }
131 ~TKYFmtMemEvent() { Clear(); }
132
133 // 清除
134 void Clear();
135
136 // 执行 OnInitialize 事件
137 void DoInitialize(void* AItem, Word ASize)
138 {
139 if (OnInitialize.Method != NULL)
140 ((TObject*)OnInitialize.Object->*OnInitialize.Method)(AItem, ASize);
141 }
142
143 // 执行 OnFinalize 事件
144 void DoFinalize(void* AItem, Word ASize)
145 {
146 if (OnFinalize.Method != NULL)
147 ((TObject*)OnFinalize.Object->*OnFinalize.Method)(AItem, ASize);
148 }
149
150 // 事件
151 TOnFormat OnInitialize;
152 TOnFormat OnFinalize;
153
154 protected:
155 private:
156 };
157
158 // 例子:如何设置事件方法指针
159 void TDemo::SetEvent()
160 {
161 FDemo.OnInitialize.Object = this;
162 FDemo.OnInitialize.Method = (TKYFmtMemEvent::TDoFormat)&TDemo::DoFormat;
163
164 // ???
165 }
166
167 // FDemo 的 OnInitialize 事件方法
168 void TDemo::DoFormat(void* AItem, Word ASize)
169 {
170 // ???
171 }
172
回调事件的方法指针需要C++编译器支持,至少VC的不同版本及GCC编译器都支持。
在VC6和VC2003中设置方法指针相对较宽松,VC2005之后就很严格了,如下:
FDemo.OnInitialize.Method = (TKYFmtMemEvent::TDoFormat)&TDemo::DoFormat;
这行代码都被不同版本VC编译器支持,但如下代码就只能被VC6、VC2003支持:
FDemo.OnInitialize.Method = (TKYFmtMemEvent::TDoFormat)DoFormat;
其实,类方法调用原理很简单,若知道如何使用C语言模拟类实现就知道怎么回事了,只
是这个工作由编译器来做罢了。不过不是什么方法都可以调用的,如:静态方法就只能当做
函数指针来用,而重载方法、虚方法等等是不可靠的,所以最好使用普通的类方法指针。
调用方法与调用函数的区别是在调用方法时,编译器把当前对象的指针当做第一个参数传
入,其它参数的传递与函数没有区别,也就说,这为提供回调事件的方法指针提供一条方便之门。
方法指针不能滥用,用好它可以使你的视野更加开阔!
posted on 2011-05-22 11:01
Kyee Ye 阅读(390)
评论(0) 编辑 收藏 引用 所属分类:
技巧杂集