好吧,又一种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



4

1
struct
ISupportReceiveDestroyMessage :
public
virtual
Interface
2
{
3
virtual ~ISupportReceiveDestroyMessage()
{}
4
virtual void receiveDestroyMessage(BaseObject *pNotifier) = 0;
5
}
;
6

2



3



4

5

6











1
class
CanUseTrigger :
public
BaseObject,
2
public
virtual
ISupportReceiveDestroyMessage,
3
public
virtual
ISupportRelationship
4
{
5
public:
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
42
private:
43
std::vector<ISupportReceiveDestroyMessage *> m_vRelateList;
44
}
;
45
46
class
TriggerBase :
public
BaseObject,
47
public
virtual
ISupportReceiveDestroyMessage
48
{
49
public:
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
72
protected:
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
295
private:
296
std::vector<Relationship> m_vRelationships;
297
}
;
298
299
template
<
class
Param
>
300
class
Trigger1 :
public
TriggerBase
301
{
302
public:
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
433
private:
434
std::vector<Channel1Base<Param> *> m_vChannels;
435
}
;
436
437
template
<
class
Param1,
class
Param2
>
438
class
Trigger2 :
public
TriggerBase
439
{
440
public:
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
574
private:
575
std::vector<Channel2Base<Param1, Param2> *> m_vChannels;
576
}
;
577

2

3

4



5

6

7



8

9

10

11



12

13

14

15

16

17



18

19

20

21

22



23

24

25

26

27

28



29

30

31

32

33

34



35

36

37



38

39

40

41

42

43

44

45

46

47

48



49

50

51



52

53

54

55



56

57

58

59

60

61



62

63

64



65

66

67

68

69

70

71

72

73

74



75

76

77

78

79



80

81

82

83



84

85

86

87

88

89

90

91



92

93

94

95

96



97

98

99



100

101

102

103

104

105

106

107



108

109

110



111

112

113



114

115

116

117

118

119

120



121

122

123

124



125

126

127

128

129

130

131



132



133



134

135



136

137

138

139

140

141

142

143



144



145



146

147



148

149

150

151

152

153

154

155



156

157

158

159



160



161

162



163

164



165

166

167

168

169

170



171

172

173



174

175

176

177

178

179

180

181



182

183

184

185

186

187

188

189

190



191

192

193

194



195



196

197



198

199



200

201

202

203

204

205



206

207

208



209

210

211

212

213

214

215

216



217

218

219

220

221

222

223

224

225

226



227

228

229

230



231



232

233



234

235



236

237

238

239

240

241



242

243

244



245

246

247

248

249

250

251

252



253

254

255

256

257

258

259

260

261



262

263

264

265



266



267

268



269

270



271

272

273

274

275

276



277

278

279



280

281

282

283

284

285

286

287



288

289

290

291

292

293

294

295

296

297

298

299

300

301



302

303

304



305

306

307

308



309

310

311

312

313

314



315

316

317



318

319

320

321

322

323

324



325

326

327



328

329

330

331



332

333

334

335

336

337

338

339

340



341

342

343

344



345

346

347

348

349

350



351

352

353

354

355



356

357



358

359

360

361

362

363



364

365

366

367

368

369

370



371

372

373

374

375

376

377



378

379



380

381

382

383

384

385



386

387

388

389

390

391

392



393

394

395

396

397



398

399



400

401

402

403

404

405



406

407

408

409

410

411

412



413

414

415

416

417

418

419



420

421



422

423

424

425

426

427



428

429

430

431

432

433

434

435

436

437

438

439



440

441

442



443

444

445

446



447

448

449

450

451

452



453

454

455



456

457

458

459

460

461

462



463

464

465



466

467

468

469



470

471

472

473

474

475

476

477

478



479

480

481

482

483



484

485

486

487

488

489



490

491

492

493

494

495



496

497



498

499

500

501

502

503



504

505

506

507

508

509

510



511

512

513

514

515

516

517

518



519

520



521

522

523

524

525

526



527

528

529

530

531

532

533



534

535

536

537

538



539

540



541

542

543

544

545

546



547

548

549

550

551

552

553



554

555

556

557

558

559

560



561

562



563

564

565

566

567

568



569

570

571

572

573

574

575

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的)方法可能是最灵活的,你可以轻松的实现一个线程到另一个线程的回调,这有时候非常有用,尤其是需要将现成的库中异步调用转换成同步调用时。