callback.cpp

(plain text)
1
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
/*****
 * How to use a non-static member function as a callback function
 * by Shane Beasley <sbeasley@acm.org>
 *****
 * Scenario: You're using an event-driven library which was written in C -- at
 * least, it was written for use by C programmers. Whenever an event occurs (the
 * mouse moves, a network packet comes off the wire, the user opens the CD-ROM
 * drive, and so on), the library calls a function which you provided to handle
 * the event. If you were writing C, this would be very cut-and-dry; the program
 * expects a function with a certain signature, you provide it, and everyone's
 * happy.
 *
 * The trouble is that you're currently writing object-oriented C++, and instead
 * of a normal callback function, you need the library to call a member function
 * on an object. You try passing a member function to the library, but it doesn't
 * compile, and for good reason -- two reasons, actually. First, C doesn't know
 * anything about member functions, let alone how to call them. Specifically,
 * your average C++ member function requires at least two components, the
 * function itself and an object upon which to call it: C functions are called
 * like f(x, y), but C++ member functions are called x.f(y). Second, C++ member
 * function pointers are generally bigger than conventional member functions --
 * perhaps three times as large -- because of extra information required for
 * resolving virtual function calls at run-time.
 *
 * The solution, then, needs to be able to tell C how to call a C++ member
 * function, and it needs to have a normal-sized function pointer. How about a
 * normal function which calls a C++ member function? :)
 *****/

////////////////////////////////////////////////////////////////////////////////

/* The event-driven C library in question looks something like this: */

typedef void (*callback_function) (int event_code, void *data);
void on_event (callback_function f, void *data);

// The goal is as follows:
// - main() will have an instance of this class.
// - we want to call a member function on this instance when an event occurs.

class EventHandler {
public:
  void handle (int eventCode);
};

// Solution: a callback function which calls the desired member function on the
// given EventHandler object.

void call_member (int eventCode, void *data) {
  static_cast<EventHandler *>(data)->handle(eventCode);
}

// Putting it all together...

int main () {
  EventHandler instance;
  on_event(&call_member, &instance);
}