好吧,又一种C++事件回调封装以及相关的零碎讨论
事件回调机制的实现可能是C++领域里最大众化的代码游戏之一。
一方面,C++并没有这个机制的语法层支持,这导致了众多商业和开源框架各自实现了风格迥异的事件回调。尤其是GUI方面,MFC提供了一层薄薄的消息映射;ATL用了一个thunk技术(不熟悉的可以google一下),简单的说就是偷偷的把this放到栈上;VCL够凶悍,直接扩充了编译器,提供了一个__closure关键字各种成员函数的指针通吃;QT的signal/slot很俏丽,也够强大……
另一方面,如果做一个调查,当一个C++使用者比较熟悉C++的一些特性,亲手写过一些程序之后,想亲手封装一些东西,那么他会封装什么?我想stream IO包括socket)、配置文件、日志、内存池、线程、简单的容器以及本次说的事件回调绝对是高频选项。
比如这里, 这里, 这里,以及 这里
……
如果这些还没让你厌倦,你可以尝试看看下面这个:
1
struct
BaseObject
2 {
3 virtual ~BaseObject(){}
4} ;
2 {
3 virtual ~BaseObject(){}
4} ;
1
struct
ISupportReceiveDestroyMessage :
public
virtual
Interface
2 {
3 virtual ~ISupportReceiveDestroyMessage(){}
4 virtual void receiveDestroyMessage(BaseObject *pNotifier) = 0;
5} ;
6
2 {
3 virtual ~ISupportReceiveDestroyMessage(){}
4 virtual void receiveDestroyMessage(BaseObject *pNotifier) = 0;
5} ;
6
struct
ISupportRelationship :
public
virtual
Interface
{
virtual ~ISupportRelationship(){}
virtual void regRelationship(ISupportReceiveDestroyMessage *pRelate) = 0;
virtual void unregRelationship(ISupportReceiveDestroyMessage *pRelate) = 0;
}
{
virtual ~ISupportRelationship(){}
virtual void regRelationship(ISupportReceiveDestroyMessage *pRelate) = 0;
virtual void unregRelationship(ISupportReceiveDestroyMessage *pRelate) = 0;
}
1
class
CanUseTrigger :
public
BaseObject,
2 public virtual ISupportReceiveDestroyMessage,
3 public virtual ISupportRelationship
4 {
5public:
6 virtual ~CanUseTrigger()
7 {
8 for(std::vector<ISupportReceiveDestroyMessage *>::iterator it = m_vRelateList.begin();
9 it != m_vRelateList.end();
10 it++)
11 {
12 (*it)->receiveDestroyMessage(this);
13 }
14 }
15
16 virtual void regRelationship(ISupportReceiveDestroyMessage *pRelate)
17 {
18 std::vector<ISupportReceiveDestroyMessage *>::iterator it =
19 std::find(m_vRelateList.begin(), m_vRelateList.end(), pRelate);
20
21 if (it == m_vRelateList.end())
22 {
23 m_vRelateList.push_back(pRelate);
24 }
25 }
26
27 virtual void unregRelationship(ISupportReceiveDestroyMessage *pRelate)
28 {
29 m_vRelateList.erase(std::remove(m_vRelateList.begin(), m_vRelateList.end(), pRelate),
30 m_vRelateList.end());
31 }
32
33 virtual void receiveDestroyMessage(BaseObject *pNotifier)
34 {
35 ISupportReceiveDestroyMessage *pTmp = dynamic_cast<ISupportReceiveDestroyMessage *>(pNotifier);
36 if (pTmp)
37 {
38 unregRelationship(pTmp);
39 }
40 }
41
42private:
43 std::vector<ISupportReceiveDestroyMessage *> m_vRelateList;
44} ;
45
46 class TriggerBase : public BaseObject,
47 public virtual ISupportReceiveDestroyMessage
48 {
49public:
50 virtual ~TriggerBase()
51 {
52 for (std::vector<Relationship>::iterator it = m_vRelationships.begin();
53 it != m_vRelationships.end();
54 it++)
55 {
56 it->pOther->receiveDestroyMessage(this);
57 }
58 }
59
60 virtual void receiveDestroyMessage(BaseObject *pNotifier)
61 {
62 CanUseTrigger *pTmp = dynamic_cast<CanUseTrigger *>(pNotifier);
63 if (!pTmp)
64 {
65 return;
66 }
67
68 m_vRelationships.erase(std::remove(m_vRelationships.begin(), m_vRelationships.end(), Relationship(pTmp)),
69 m_vRelationships.end());
70 }
71
72protected:
73 void regToUser(CanUseTrigger *pUser)
74 {
75 std::vector<Relationship>::iterator itUser
76 = std::find(m_vRelationships.begin(), m_vRelationships.end(), Relationship(pUser));
77
78 if (m_vRelationships.end() != itUser)
79 {
80 ++(itUser->RefCount);
81 }
82 else
83 {
84 m_vRelationships.push_back(Relationship(pUser));
85 m_vRelationships[m_vRelationships.size() - 1].RefCount++;
86 pUser->regRelationship(this);
87 }
88 }
89
90 void unregFormUser(CanUseTrigger *pUser)
91 {
92 std::vector<Relationship>::iterator itUser
93 = std::find(m_vRelationships.begin(), m_vRelationships.end(), Relationship(pUser));
94
95 if (m_vRelationships.end() != itUser)
96 {
97 --(itUser->RefCount);
98 if(itUser->RefCount < 1)
99 {
100 m_vRelationships.erase(itUser);
101 pUser->unregRelationship(this);
102 }
103 }
104 }
105
106 struct Relationship
107 {
108 CanUseTrigger *pOther;
109 i32_t RefCount;
110 Relationship(CanUseTrigger *pUser) : pOther(pUser), RefCount(0){}
111
112 Relationship &operator=(const Relationship &rhs)
113 {
114 pOther = rhs.pOther;
115 RefCount = rhs.RefCount;
116
117 return *this;
118 }
119 bool operator==(const Relationship &rhs)
120 {
121 return pOther == rhs.pOther;
122 }
123 bool operator==(const CanUseTrigger *rhs)
124 {
125 return pOther == rhs;
126 }
127 };
128
129 template <class P>
130 struct Channel1Base
131 {
132 typedef struct{} is_member_t;
133 typedef struct{} is_not_member_t;
134
135 virtual ~Channel1Base(){}
136 virtual void invoke(P p) = 0;
137 virtual bool equal(Channel1Base<P> *pOther) = 0;
138 virtual bool isOwner(CanUseTrigger *pCandidate) = 0;
139 };
140
141 template <class P1, class P2>
142 struct Channel2Base
143 {
144 typedef struct{} is_member_t;
145 typedef struct{} is_not_member_t;
146
147 virtual ~Channel2Base(){}
148 virtual void invoke(P1 p1, P2 p2) = 0;
149 virtual bool equal(Channel2Base<P1, P2> *pOther) = 0;
150 virtual bool isOwner(CanUseTrigger *pCandidate) = 0;
151 };
152
153 template <class P>
154 struct NakedChannel1 : public Channel1Base<P>
155 {
156 typedef Channel1Base<P>::is_not_member_t member_spec_t;
157 typedef void (* method_t)(P);
158
159 NakedChannel1(method_t pMethod) : m_pMethod(pMethod){}
160 ~NakedChannel1(){}
161 virtual void invoke(P p)
162 {
163 if (m_pMethod)
164 {
165 m_pMethod(p);
166 }
167 }
168
169 virtual bool equal(Channel1Base<P> *pOther)
170 {
171 NakedChannel1<P> *pTmp = dynamic_cast<NakedChannel1<P> *>(pOther);
172 if (!pTmp)
173 {
174 return false;
175 }
176
177 return m_pMethod == pTmp->m_pMethod;
178 }
179
180 virtual bool isOwner(CanUseTrigger *pCandidate)
181 {
182 return false;
183 }
184
185 method_t m_pMethod;
186 };
187
188 template <class T, class P>
189 struct MemberChannel1 : public Channel1Base<P>
190 {
191 typedef Channel1Base<P>::is_member_t member_spec_t;
192 typedef void (T:: *method_t)(P);
193
194 MemberChannel1(T *pUser, method_t pMethod) : m_pOwner(pUser), m_pMethod(pMethod){}
195 ~MemberChannel1(){}
196 virtual void invoke(P p)
197 {
198 if (m_pOwner && m_pMethod)
199 {
200 (m_pOwner->* m_pMethod)(p);
201 }
202 }
203
204 virtual bool equal(Channel1Base<P> *pOther)
205 {
206 MemberChannel1<T, P> *pTmp = dynamic_cast<MemberChannel1<T, P> *>(pOther);
207 if(!pTmp)
208 {
209 return false;
210 }
211
212 return (m_pOwner == pTmp->m_pOwner) && (m_pMethod == pTmp->m_pMethod);
213 }
214
215 virtual bool isOwner(CanUseTrigger *pCandidate)
216 {
217 return m_pOwner == pCandidate;
218 }
219
220 T *m_pOwner;
221 method_t m_pMethod;
222 };
223
224 template <class P1, class P2>
225 struct NakedChannel2 : public Channel2Base<P1, P2>
226 {
227 typedef Channel2Base<P1, P2>::is_not_member_t member_spec_t;
228 typedef void (* method_t)(P1, P2);
229
230 NakedChannel2(method_t pMethod) : m_pMethod(pMethod){}
231 ~NakedChannel2(){}
232 virtual void invoke(P1 p1, P2 p2)
233 {
234 if (m_pMethod)
235 {
236 m_pMethod(p1, p2);
237 }
238 }
239
240 virtual bool equal(Channel2Base<P1, P2> *pOther)
241 {
242 NakedChannel2<P1, P2> *pTmp = dynamic_cast<NakedChannel2<P1, P2> *>(pOther);
243 if (!pTmp)
244 {
245 return false;
246 }
247
248 return m_pMethod == pTmp->m_pMethod;
249 }
250
251 virtual bool isOwner(CanUseTrigger *pCandidate)
252 {
253 return false;
254 }
255
256 method_t m_pMethod;
257 };
258
259 template <class T, class P1, class P2>
260 struct MemberChannel2 : public Channel2Base<P1, P2>
261 {
262 typedef Channel2Base<P1, P2>::is_member_t member_spec_t;
263 typedef void (T:: *method_t)(P1, P2);
264
265 MemberChannel2(T *pUser, method_t pMethod) : m_pOwner(pUser), m_pMethod(pMethod){}
266 ~MemberChannel2(){}
267 virtual void invoke(P1 p1, P2 p2)
268 {
269 if (m_pOwner && m_pMethod)
270 {
271 (m_pOwner->* m_pMethod)(p1, p2);
272 }
273 }
274
275 virtual bool equal(Channel2Base<P1, P2> *pOther)
276 {
277 MemberChannel2<T, P1, P2> *pTmp = dynamic_cast<MemberChannel2<T, P1, P2> *>(pOther);
278 if (!pTmp)
279 {
280 return false;
281 }
282
283 return (m_pOwner == pTmp->m_pOwner) && (m_pMethod == pTmp->m_pMethod);
284 }
285
286 virtual bool isOwner(CanUseTrigger *pCandidate)
287 {
288 return m_pOwner == pCandidate;
289 }
290
291 T *m_pOwner;
292 method_t m_pMethod;
293 };
294
295private:
296 std::vector<Relationship> m_vRelationships;
297} ;
298
299 template < class Param >
300 class Trigger1 : public TriggerBase
301 {
302public:
303 ~Trigger1()
304 {
305 for (std::vector<Channel1Base<Param> *>::iterator it = m_vChannels.begin();
306 it != m_vChannels.end();
307 it++)
308 {
309 delete (*it);
310 }
311 }
312
313 virtual void receiveDestroyMessage(BaseObject *pNotifier)
314 {
315 CanUseTrigger *pTmp = dynamic_cast<CanUseTrigger *>(pNotifier);
316 if (!pTmp)
317 {
318 return;
319 }
320
321 for (std::vector<Channel1Base<Param> *>::iterator it = m_vChannels.begin();
322 it != m_vChannels.end();
323 )
324 {
325 CanUseTrigger *pTmp = dynamic_cast<CanUseTrigger *>(pNotifier);
326 if (pTmp && (*it)->isOwner(pTmp))
327 {
328 it = m_vChannels.erase(it);
329 }
330 else
331 {
332 ++it;
333 }
334 }
335
336 TriggerBase::receiveDestroyMessage(pNotifier);
337 }
338
339 void fire(Param p)
340 {
341 for (std::vector<Channel1Base<Param> *>::iterator it = m_vChannels.begin();
342 it != m_vChannels.end();
343 it++)
344 {
345 (*it)->invoke(p);
346 }
347 }
348
349 void add(void (* pMethod)(Param))
350 {
351 Channel1Base<Param> *pChannel = new NakedChannel1<Param>(pMethod);
352 std::vector<Channel1Base<Param> *>::iterator it = m_vChannels.begin();
353
354 for (; it != m_vChannels.end(); it++)
355 {
356 if ((*it)->equal(pChannel))
357 {
358 break;
359 }
360 }
361
362 if (it != m_vChannels.end())
363 {
364 m_vChannels.push_back(pChannel);
365 }
366 }
367
368 template <class TUser>
369 void add(TUser *pUser, void (TUser:: *pMethod)(Param))
370 {
371 //assert(dynamic_cast<CanUseTrigger *>(pUser));
372
373 Channel1Base<Param> *pChannel = new MemberChannel1<TUser, Param>(pUser, pMethod);
374 std::vector<Channel1Base<Param> *>::iterator it = m_vChannels.begin();
375
376 for (; it != m_vChannels.end(); it++)
377 {
378 if ((*it)->equal(pChannel))
379 {
380 break;
381 }
382 }
383
384 if (it == m_vChannels.end())
385 {
386 m_vChannels.push_back(pChannel);
387 regToUser(pUser);
388 }
389 }
390
391 void dec(void (* pMethod)(Param))
392 {
393 NakedChannel1<Param> TempChannel(pMethod);
394 std::vector<Channel1Base<Param> *>::iterator it = m_vChannels.begin();
395
396 for (; it != m_vChannels.end(); it++)
397 {
398 if ((*it)->equal(&TempChannel))
399 {
400 break;
401 }
402 }
403
404 if (it != m_vChannels.end())
405 {
406 m_vChannels.erase(it);
407 }
408 }
409
410 template <class TUser>
411 void dec(TUser *pUser, void (TUser:: *pMethod)(Param))
412 {
413 std::assert(dynamic_cast<CanUseTrigger *>(pUser));
414
415 MemberChannel1<TUser, Param> TempChannel(pMethod);
416 std::vector<Channel1Base<Param> *>::iterator it = m_vChannels.begin();
417
418 for (; it != m_vChannels.end(); it++)
419 {
420 if ((*it)->equal(&TempChannel))
421 {
422 break;
423 }
424 }
425
426 if (it != m_vChannels.end())
427 {
428 m_vChannels.erase(it);
429
430 }
431 }
432
433private:
434 std::vector<Channel1Base<Param> *> m_vChannels;
435} ;
436
437 template < class Param1, class Param2 >
438 class Trigger2 : public TriggerBase
439 {
440public:
441 ~Trigger2()
442 {
443 for (std::vector<Channel2Base<Param1, Param2> *>::iterator it = m_vChannels.begin();
444 it != m_vChannels.end();
445 it++)
446 {
447 delete (*it);
448 }
449 }
450
451 virtual void receiveDestroyMessage(BaseObject *pNotifier)
452 {
453 CanUseTrigger *pTmp = dynamic_cast<CanUseTrigger *>(pNotifier);
454 if (!pTmp)
455 {
456 return;
457 }
458
459 for (std::vector<Channel2Base<Param1, Param2> *>::iterator it = m_vChannels.begin();
460 it != m_vChannels.end();
461 )
462 {
463 CanUseTrigger *pTmp = dynamic_cast<CanUseTrigger *>(pNotifier);
464 if (pTmp && (*it)->isOwner(pTmp))
465 {
466 it = m_vChannels.erase(it);
467 }
468 else
469 {
470 ++it;
471 }
472 }
473
474 TriggerBase::receiveDestroyMessage(pNotifier);
475 }
476
477 void fire(Param1 p1, Param2 p2)
478 {
479 for (std::vector<Channel2Base<Param1, Param2> *>::iterator it
480 = m_vChannels.begin();
481 it != m_vChannels.end();
482 it++)
483 {
484 (*it)->invoke(p1, p2);
485 }
486 }
487
488 void add(void (* pMethod)(Param1, Param2))
489 {
490 Channel2Base<Param1, Param2> *pChannel
491 = new NakedChannel2<Param1, Param2>(pMethod);
492 std::vector<Channel2Base<Param1, Param2> *>::iterator it = m_vChannels.begin();
493
494 for (; it != m_vChannels.end(); it++)
495 {
496 if ((*it)->equal(pChannel))
497 {
498 break;
499 }
500 }
501
502 if (it == m_vChannels.end())
503 {
504 m_vChannels.push_back(pChannel);
505 }
506 }
507
508 template <class TUser>
509 void add(TUser *pUser, void (TUser:: *pMethod)(Param1, Param2))
510 {
511 //std::assert(dynamic_cast<CanUseTrigger *>(pUser));
512
513 Channel2Base<Param1, Param2> *pChannel
514 = new MemberChannel2<TUser, Param1, Param2>(pUser, pMethod);
515 std::vector<Channel2Base<Param1, Param2> *>::iterator it = m_vChannels.begin();
516
517 for (; it != m_vChannels.end(); it++)
518 {
519 if ((*it)->equal(pChannel))
520 {
521 break;
522 }
523 }
524
525 if (it == m_vChannels.end())
526 {
527 m_vChannels.push_back(pChannel);
528 regToUser(pUser);
529 }
530 }
531
532 void dec(void (* pMethod)(Param1, Param2))
533 {
534 NakedChannel2<Param1, Param2> TempChannel(pMethod);
535 std::vector<Channel2Base<Param1, Param2> *>::iterator it = m_vChannels.begin();
536
537 for (; it != m_vChannels.end(); it++)
538 {
539 if ((*it)->equal(&TempChannel))
540 {
541 break;
542 }
543 }
544
545 if (it != m_vChannels.end())
546 {
547 m_vChannels.erase(it);
548 }
549 }
550
551 template <class TUser>
552 void dec(TUser *pUser, void (TUser:: *pMethod)(Param1, Param2))
553 {
554 std::assert(dynamic_cast<CanUseTrigger *>(pUser));
555
556 MemberChannel2<TUser, Param1, Param2> TempChannel(pMethod);
557 std::vector<Channel2Base<Param1, Param2> *>::iterator it = m_vChannels.begin();
558
559 for (; it != m_vChannels.end(); it++)
560 {
561 if ((*it)->equal(&TempChannel))
562 {
563 break;
564 }
565 }
566
567 if (it != m_vChannels.end())
568 {
569 m_vChannels.erase(it);
570
571 }
572 }
573
574private:
575 std::vector<Channel2Base<Param1, Param2> *> m_vChannels;
576} ;
577
2 public virtual ISupportReceiveDestroyMessage,
3 public virtual ISupportRelationship
4 {
5public:
6 virtual ~CanUseTrigger()
7 {
8 for(std::vector<ISupportReceiveDestroyMessage *>::iterator it = m_vRelateList.begin();
9 it != m_vRelateList.end();
10 it++)
11 {
12 (*it)->receiveDestroyMessage(this);
13 }
14 }
15
16 virtual void regRelationship(ISupportReceiveDestroyMessage *pRelate)
17 {
18 std::vector<ISupportReceiveDestroyMessage *>::iterator it =
19 std::find(m_vRelateList.begin(), m_vRelateList.end(), pRelate);
20
21 if (it == m_vRelateList.end())
22 {
23 m_vRelateList.push_back(pRelate);
24 }
25 }
26
27 virtual void unregRelationship(ISupportReceiveDestroyMessage *pRelate)
28 {
29 m_vRelateList.erase(std::remove(m_vRelateList.begin(), m_vRelateList.end(), pRelate),
30 m_vRelateList.end());
31 }
32
33 virtual void receiveDestroyMessage(BaseObject *pNotifier)
34 {
35 ISupportReceiveDestroyMessage *pTmp = dynamic_cast<ISupportReceiveDestroyMessage *>(pNotifier);
36 if (pTmp)
37 {
38 unregRelationship(pTmp);
39 }
40 }
41
42private:
43 std::vector<ISupportReceiveDestroyMessage *> m_vRelateList;
44} ;
45
46 class TriggerBase : public BaseObject,
47 public virtual ISupportReceiveDestroyMessage
48 {
49public:
50 virtual ~TriggerBase()
51 {
52 for (std::vector<Relationship>::iterator it = m_vRelationships.begin();
53 it != m_vRelationships.end();
54 it++)
55 {
56 it->pOther->receiveDestroyMessage(this);
57 }
58 }
59
60 virtual void receiveDestroyMessage(BaseObject *pNotifier)
61 {
62 CanUseTrigger *pTmp = dynamic_cast<CanUseTrigger *>(pNotifier);
63 if (!pTmp)
64 {
65 return;
66 }
67
68 m_vRelationships.erase(std::remove(m_vRelationships.begin(), m_vRelationships.end(), Relationship(pTmp)),
69 m_vRelationships.end());
70 }
71
72protected:
73 void regToUser(CanUseTrigger *pUser)
74 {
75 std::vector<Relationship>::iterator itUser
76 = std::find(m_vRelationships.begin(), m_vRelationships.end(), Relationship(pUser));
77
78 if (m_vRelationships.end() != itUser)
79 {
80 ++(itUser->RefCount);
81 }
82 else
83 {
84 m_vRelationships.push_back(Relationship(pUser));
85 m_vRelationships[m_vRelationships.size() - 1].RefCount++;
86 pUser->regRelationship(this);
87 }
88 }
89
90 void unregFormUser(CanUseTrigger *pUser)
91 {
92 std::vector<Relationship>::iterator itUser
93 = std::find(m_vRelationships.begin(), m_vRelationships.end(), Relationship(pUser));
94
95 if (m_vRelationships.end() != itUser)
96 {
97 --(itUser->RefCount);
98 if(itUser->RefCount < 1)
99 {
100 m_vRelationships.erase(itUser);
101 pUser->unregRelationship(this);
102 }
103 }
104 }
105
106 struct Relationship
107 {
108 CanUseTrigger *pOther;
109 i32_t RefCount;
110 Relationship(CanUseTrigger *pUser) : pOther(pUser), RefCount(0){}
111
112 Relationship &operator=(const Relationship &rhs)
113 {
114 pOther = rhs.pOther;
115 RefCount = rhs.RefCount;
116
117 return *this;
118 }
119 bool operator==(const Relationship &rhs)
120 {
121 return pOther == rhs.pOther;
122 }
123 bool operator==(const CanUseTrigger *rhs)
124 {
125 return pOther == rhs;
126 }
127 };
128
129 template <class P>
130 struct Channel1Base
131 {
132 typedef struct{} is_member_t;
133 typedef struct{} is_not_member_t;
134
135 virtual ~Channel1Base(){}
136 virtual void invoke(P p) = 0;
137 virtual bool equal(Channel1Base<P> *pOther) = 0;
138 virtual bool isOwner(CanUseTrigger *pCandidate) = 0;
139 };
140
141 template <class P1, class P2>
142 struct Channel2Base
143 {
144 typedef struct{} is_member_t;
145 typedef struct{} is_not_member_t;
146
147 virtual ~Channel2Base(){}
148 virtual void invoke(P1 p1, P2 p2) = 0;
149 virtual bool equal(Channel2Base<P1, P2> *pOther) = 0;
150 virtual bool isOwner(CanUseTrigger *pCandidate) = 0;
151 };
152
153 template <class P>
154 struct NakedChannel1 : public Channel1Base<P>
155 {
156 typedef Channel1Base<P>::is_not_member_t member_spec_t;
157 typedef void (* method_t)(P);
158
159 NakedChannel1(method_t pMethod) : m_pMethod(pMethod){}
160 ~NakedChannel1(){}
161 virtual void invoke(P p)
162 {
163 if (m_pMethod)
164 {
165 m_pMethod(p);
166 }
167 }
168
169 virtual bool equal(Channel1Base<P> *pOther)
170 {
171 NakedChannel1<P> *pTmp = dynamic_cast<NakedChannel1<P> *>(pOther);
172 if (!pTmp)
173 {
174 return false;
175 }
176
177 return m_pMethod == pTmp->m_pMethod;
178 }
179
180 virtual bool isOwner(CanUseTrigger *pCandidate)
181 {
182 return false;
183 }
184
185 method_t m_pMethod;
186 };
187
188 template <class T, class P>
189 struct MemberChannel1 : public Channel1Base<P>
190 {
191 typedef Channel1Base<P>::is_member_t member_spec_t;
192 typedef void (T:: *method_t)(P);
193
194 MemberChannel1(T *pUser, method_t pMethod) : m_pOwner(pUser), m_pMethod(pMethod){}
195 ~MemberChannel1(){}
196 virtual void invoke(P p)
197 {
198 if (m_pOwner && m_pMethod)
199 {
200 (m_pOwner->* m_pMethod)(p);
201 }
202 }
203
204 virtual bool equal(Channel1Base<P> *pOther)
205 {
206 MemberChannel1<T, P> *pTmp = dynamic_cast<MemberChannel1<T, P> *>(pOther);
207 if(!pTmp)
208 {
209 return false;
210 }
211
212 return (m_pOwner == pTmp->m_pOwner) && (m_pMethod == pTmp->m_pMethod);
213 }
214
215 virtual bool isOwner(CanUseTrigger *pCandidate)
216 {
217 return m_pOwner == pCandidate;
218 }
219
220 T *m_pOwner;
221 method_t m_pMethod;
222 };
223
224 template <class P1, class P2>
225 struct NakedChannel2 : public Channel2Base<P1, P2>
226 {
227 typedef Channel2Base<P1, P2>::is_not_member_t member_spec_t;
228 typedef void (* method_t)(P1, P2);
229
230 NakedChannel2(method_t pMethod) : m_pMethod(pMethod){}
231 ~NakedChannel2(){}
232 virtual void invoke(P1 p1, P2 p2)
233 {
234 if (m_pMethod)
235 {
236 m_pMethod(p1, p2);
237 }
238 }
239
240 virtual bool equal(Channel2Base<P1, P2> *pOther)
241 {
242 NakedChannel2<P1, P2> *pTmp = dynamic_cast<NakedChannel2<P1, P2> *>(pOther);
243 if (!pTmp)
244 {
245 return false;
246 }
247
248 return m_pMethod == pTmp->m_pMethod;
249 }
250
251 virtual bool isOwner(CanUseTrigger *pCandidate)
252 {
253 return false;
254 }
255
256 method_t m_pMethod;
257 };
258
259 template <class T, class P1, class P2>
260 struct MemberChannel2 : public Channel2Base<P1, P2>
261 {
262 typedef Channel2Base<P1, P2>::is_member_t member_spec_t;
263 typedef void (T:: *method_t)(P1, P2);
264
265 MemberChannel2(T *pUser, method_t pMethod) : m_pOwner(pUser), m_pMethod(pMethod){}
266 ~MemberChannel2(){}
267 virtual void invoke(P1 p1, P2 p2)
268 {
269 if (m_pOwner && m_pMethod)
270 {
271 (m_pOwner->* m_pMethod)(p1, p2);
272 }
273 }
274
275 virtual bool equal(Channel2Base<P1, P2> *pOther)
276 {
277 MemberChannel2<T, P1, P2> *pTmp = dynamic_cast<MemberChannel2<T, P1, P2> *>(pOther);
278 if (!pTmp)
279 {
280 return false;
281 }
282
283 return (m_pOwner == pTmp->m_pOwner) && (m_pMethod == pTmp->m_pMethod);
284 }
285
286 virtual bool isOwner(CanUseTrigger *pCandidate)
287 {
288 return m_pOwner == pCandidate;
289 }
290
291 T *m_pOwner;
292 method_t m_pMethod;
293 };
294
295private:
296 std::vector<Relationship> m_vRelationships;
297} ;
298
299 template < class Param >
300 class Trigger1 : public TriggerBase
301 {
302public:
303 ~Trigger1()
304 {
305 for (std::vector<Channel1Base<Param> *>::iterator it = m_vChannels.begin();
306 it != m_vChannels.end();
307 it++)
308 {
309 delete (*it);
310 }
311 }
312
313 virtual void receiveDestroyMessage(BaseObject *pNotifier)
314 {
315 CanUseTrigger *pTmp = dynamic_cast<CanUseTrigger *>(pNotifier);
316 if (!pTmp)
317 {
318 return;
319 }
320
321 for (std::vector<Channel1Base<Param> *>::iterator it = m_vChannels.begin();
322 it != m_vChannels.end();
323 )
324 {
325 CanUseTrigger *pTmp = dynamic_cast<CanUseTrigger *>(pNotifier);
326 if (pTmp && (*it)->isOwner(pTmp))
327 {
328 it = m_vChannels.erase(it);
329 }
330 else
331 {
332 ++it;
333 }
334 }
335
336 TriggerBase::receiveDestroyMessage(pNotifier);
337 }
338
339 void fire(Param p)
340 {
341 for (std::vector<Channel1Base<Param> *>::iterator it = m_vChannels.begin();
342 it != m_vChannels.end();
343 it++)
344 {
345 (*it)->invoke(p);
346 }
347 }
348
349 void add(void (* pMethod)(Param))
350 {
351 Channel1Base<Param> *pChannel = new NakedChannel1<Param>(pMethod);
352 std::vector<Channel1Base<Param> *>::iterator it = m_vChannels.begin();
353
354 for (; it != m_vChannels.end(); it++)
355 {
356 if ((*it)->equal(pChannel))
357 {
358 break;
359 }
360 }
361
362 if (it != m_vChannels.end())
363 {
364 m_vChannels.push_back(pChannel);
365 }
366 }
367
368 template <class TUser>
369 void add(TUser *pUser, void (TUser:: *pMethod)(Param))
370 {
371 //assert(dynamic_cast<CanUseTrigger *>(pUser));
372
373 Channel1Base<Param> *pChannel = new MemberChannel1<TUser, Param>(pUser, pMethod);
374 std::vector<Channel1Base<Param> *>::iterator it = m_vChannels.begin();
375
376 for (; it != m_vChannels.end(); it++)
377 {
378 if ((*it)->equal(pChannel))
379 {
380 break;
381 }
382 }
383
384 if (it == m_vChannels.end())
385 {
386 m_vChannels.push_back(pChannel);
387 regToUser(pUser);
388 }
389 }
390
391 void dec(void (* pMethod)(Param))
392 {
393 NakedChannel1<Param> TempChannel(pMethod);
394 std::vector<Channel1Base<Param> *>::iterator it = m_vChannels.begin();
395
396 for (; it != m_vChannels.end(); it++)
397 {
398 if ((*it)->equal(&TempChannel))
399 {
400 break;
401 }
402 }
403
404 if (it != m_vChannels.end())
405 {
406 m_vChannels.erase(it);
407 }
408 }
409
410 template <class TUser>
411 void dec(TUser *pUser, void (TUser:: *pMethod)(Param))
412 {
413 std::assert(dynamic_cast<CanUseTrigger *>(pUser));
414
415 MemberChannel1<TUser, Param> TempChannel(pMethod);
416 std::vector<Channel1Base<Param> *>::iterator it = m_vChannels.begin();
417
418 for (; it != m_vChannels.end(); it++)
419 {
420 if ((*it)->equal(&TempChannel))
421 {
422 break;
423 }
424 }
425
426 if (it != m_vChannels.end())
427 {
428 m_vChannels.erase(it);
429
430 }
431 }
432
433private:
434 std::vector<Channel1Base<Param> *> m_vChannels;
435} ;
436
437 template < class Param1, class Param2 >
438 class Trigger2 : public TriggerBase
439 {
440public:
441 ~Trigger2()
442 {
443 for (std::vector<Channel2Base<Param1, Param2> *>::iterator it = m_vChannels.begin();
444 it != m_vChannels.end();
445 it++)
446 {
447 delete (*it);
448 }
449 }
450
451 virtual void receiveDestroyMessage(BaseObject *pNotifier)
452 {
453 CanUseTrigger *pTmp = dynamic_cast<CanUseTrigger *>(pNotifier);
454 if (!pTmp)
455 {
456 return;
457 }
458
459 for (std::vector<Channel2Base<Param1, Param2> *>::iterator it = m_vChannels.begin();
460 it != m_vChannels.end();
461 )
462 {
463 CanUseTrigger *pTmp = dynamic_cast<CanUseTrigger *>(pNotifier);
464 if (pTmp && (*it)->isOwner(pTmp))
465 {
466 it = m_vChannels.erase(it);
467 }
468 else
469 {
470 ++it;
471 }
472 }
473
474 TriggerBase::receiveDestroyMessage(pNotifier);
475 }
476
477 void fire(Param1 p1, Param2 p2)
478 {
479 for (std::vector<Channel2Base<Param1, Param2> *>::iterator it
480 = m_vChannels.begin();
481 it != m_vChannels.end();
482 it++)
483 {
484 (*it)->invoke(p1, p2);
485 }
486 }
487
488 void add(void (* pMethod)(Param1, Param2))
489 {
490 Channel2Base<Param1, Param2> *pChannel
491 = new NakedChannel2<Param1, Param2>(pMethod);
492 std::vector<Channel2Base<Param1, Param2> *>::iterator it = m_vChannels.begin();
493
494 for (; it != m_vChannels.end(); it++)
495 {
496 if ((*it)->equal(pChannel))
497 {
498 break;
499 }
500 }
501
502 if (it == m_vChannels.end())
503 {
504 m_vChannels.push_back(pChannel);
505 }
506 }
507
508 template <class TUser>
509 void add(TUser *pUser, void (TUser:: *pMethod)(Param1, Param2))
510 {
511 //std::assert(dynamic_cast<CanUseTrigger *>(pUser));
512
513 Channel2Base<Param1, Param2> *pChannel
514 = new MemberChannel2<TUser, Param1, Param2>(pUser, pMethod);
515 std::vector<Channel2Base<Param1, Param2> *>::iterator it = m_vChannels.begin();
516
517 for (; it != m_vChannels.end(); it++)
518 {
519 if ((*it)->equal(pChannel))
520 {
521 break;
522 }
523 }
524
525 if (it == m_vChannels.end())
526 {
527 m_vChannels.push_back(pChannel);
528 regToUser(pUser);
529 }
530 }
531
532 void dec(void (* pMethod)(Param1, Param2))
533 {
534 NakedChannel2<Param1, Param2> TempChannel(pMethod);
535 std::vector<Channel2Base<Param1, Param2> *>::iterator it = m_vChannels.begin();
536
537 for (; it != m_vChannels.end(); it++)
538 {
539 if ((*it)->equal(&TempChannel))
540 {
541 break;
542 }
543 }
544
545 if (it != m_vChannels.end())
546 {
547 m_vChannels.erase(it);
548 }
549 }
550
551 template <class TUser>
552 void dec(TUser *pUser, void (TUser:: *pMethod)(Param1, Param2))
553 {
554 std::assert(dynamic_cast<CanUseTrigger *>(pUser));
555
556 MemberChannel2<TUser, Param1, Param2> TempChannel(pMethod);
557 std::vector<Channel2Base<Param1, Param2> *>::iterator it = m_vChannels.begin();
558
559 for (; it != m_vChannels.end(); it++)
560 {
561 if ((*it)->equal(&TempChannel))
562 {
563 break;
564 }
565 }
566
567 if (it != m_vChannels.end())
568 {
569 m_vChannels.erase(it);
570
571 }
572 }
573
574private:
575 std::vector<Channel2Base<Param1, Param2> *> m_vChannels;
576} ;
577
一些讨论:
1. 为了防止对象析构后其方法被调用,我采用了一个公用的基类实现析构之前的互相通知,这要求相关的类都要继承自CanUseTrigger类,这显然是个“不情之请”,人家本来就有公用基类怎么办?
2. 使用这个机制的代码大概是这样:
class Foo : public CanUseTrigger
{
public:
void doSomething(int i){/*...*/}
};
class Bar
{
public:
Trigger<int> OnSomeEvent;
void someEvent()
{
this->OnSomeEvent.fire(0);
}
};
int main()
{
Foo f;
Bar b;
b.OnSomeEvent.add(&f, &Foo::doSomething);
b.someEvent();
}
注意绿色的那行,我要是不知道f的类型怎么办?这种情况在OO编程中太常见了。事实上大部分基于模板的解决方式(至少是我见过的)都存在这个问题。怎么解决?我也不知道,maybe, We need typeof.
4. 真实世界中的事件回调,还有一个强大的boost::slot,连仿函数都封装进去了。
5. 各种C++事件回调机制中,VCL的方法可能是最方便的,但是只有borland的编译器才能识别__closure关键字。MFC的(其实就是windows的)方法可能是最灵活的,你可以轻松的实现一个线程到另一个线程的回调,这有时候非常有用,尤其是需要将现成的库中异步调用转换成同步调用时。
posted on 2009-07-26 22:59 欲三更 阅读(1881) 评论(11) 编辑 收藏 引用
评论
# re: 好吧,又一种C++事件回调封装以及相关的零碎讨论[未登录] 2009-07-27 12:18 Chen Jiecao
这种折叠式的代码怎么搞?
不知道cppblog该怎么设置 回复 更多评论
# re: 好吧,又一种C++事件回调封装以及相关的零碎讨论 2009-07-27 13:56 欲三更
@Chen Jiecao
不是有“插入代码”那个按钮吗? 回复 更多评论
# re: 好吧,又一种C++事件回调封装以及相关的零碎讨论 2009-07-27 21:00 CY
你提到的第1点,在你代码中,是不是由那个CanUseTrigger类里面提到的 m_vRelateList进行管理的,是一个静态成员对象,放了所有绑定的内容列表?然后有对象析构时,就自动检查列表的内容? 回复 更多评论
# re: 好吧,又一种C++事件回调封装以及相关的零碎讨论 2009-07-28 04:47 欲三更
@CY
哪有static对象啊?是std::,看花眼了吧?
回复 更多评论
# re: 好吧,又一种C++事件回调封装以及相关的零碎讨论 2009-07-28 04:49 欲三更
@CY
简单的说就是Trigger和CanUseTrigger都保存着与它发生关系的对象列表,然后析构时就通知对方,就是这样。 回复 更多评论
# re: 好吧,又一种C++事件回调封装以及相关的零碎讨论 2009-07-28 10:21 CY
哦,明白了。
之前想过要自动解除绑定,就需要一种管理类,管理类不要被使用者看到,就实现在基类中,用一个静态容器。
看你代码到看到一点这样的迹象,以为和我想的一样就没有继续看了~ 回复 更多评论
# re: 好吧,又一种C++事件回调封装以及相关的零碎讨论 2009-07-28 16:17 没意思
VC里面可以用__hook关键字,委托在编译器层面就是很容易实现的事情
建议看看fastdelegate和functor,楼主这个版本,额。。。 回复 更多评论
# re: 好吧,又一种C++事件回调封装以及相关的零碎讨论 2009-07-28 20:28 欲三更
@没意思
我看过fastdelegate,包括作者那篇文章。
这方面各种各样的实现有,从boost的大一统封装,到跟C++基本上已经没有关系的thunk技术。我写这个东西的出发点主要就是不用高级复杂的技术和编译器特性,尽量在直白简单的层次上实现这个功能,至于成品的成色...我工作中用C++ Builder,有__closure关键字可用。
而且就纯C++内部来说,我倾向于“委托”这个东西接收的应该是个完成特定功能的接口指针而不是符合某种签名函数。 回复 更多评论
# re: 好吧,又一种C++事件回调封装以及相关的零碎讨论 2009-07-29 17:26 DraZet
崩溃了,这么长的代码一行注释都没有,看得难受,建议把注释加上去,方便大家理解 回复 更多评论
# re: 好吧,又一种C++事件回调封装以及相关的零碎讨论 2009-07-31 16:56 yisa
恩 做法还是蛮通用的
建议:
1. del监听代价太大, 应该用双向链表来自动提供节点解除
2. 可以强化Channel的设计, 减少消息发送者的内容
比如:
Struct CallbackNode
{
~CallbackNode(){Detach();}
void Detach(){...自动从自己挂接的地方(一个双向链表)中移除...}
virtural void Exec()= 0;
Callee* _callee;
Func _callbackFunc;
额外信息: 需要记录自己在双向链表中的前后节点
}
typedef doubleList<CallbackNode> _DList;
class ViCaller
{
void Invoke();
DList _channel;
}
每个CallbackNode可以交给每个监听者callee去管理,
如果 caller先析构, DList 可以自动解掉DList 的Node
如果 监听者callee先析构, Node需要被析构, 这样自动从DList 解除, 自然更不会发生回调
在下愚见
QQ 348360855 yisa
回复 更多评论
# re: 好吧,又一种C++事件回调封装以及相关的零碎讨论[未登录] 2009-08-03 14:32 欲三更
@yisa
嗯,这个做法确实避免了“关系”的冗余。 回复 更多评论