1 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
2 <!-- saved from url=(0045)http://cscene.org/topics/misc/cs7-04.xml.html -->
3 <HTML><HEAD><TITLE>Callbacks in C++: The OO Way</TITLE>
4 <META content="text/html; charset=iso-8859-1" http-equiv=Content-Type><LINK
5 href="default.css" rel=stylesheet
7 <META content="MSHTML 5.00.2920.0" name=GENERATOR></HEAD>
12 <TD><A href="http://cscene.org/"><IMG alt="cscene logo" border=0
13 class=logo height=52 src="logo.gif"
15 <TD align=middle width="100%"><A
16 href="http://cscene.org/index.html">C-Scene</A> <A
17 href="http://cscene.org/issues.html">Issues 1..9</A> <A
18 href="http://cscene.org/bios.html">Authors</A> <BR><A
19 href="http://cscene.org/topics/algo.xml.html">Algorithms</A> <A
20 href="http://cscene.org/topics/books.xml.html">Books</A> <A
21 href="http://cscene.org/topics/patterns.xml.html">Patterns</A> <A
22 href="http://cscene.org/topics/graphics.xml.html">Graphics</A> <A
23 href="http://cscene.org/topics/misc.xml.html">Miscellaneous</A> <A
24 href="http://cscene.org/topics/unix.xml.html">UNIX</A> <A
25 href="http://cscene.org/topics/web.xml.html">Web & XML</A> <A
26 href="http://cscene.org/topics/windows.xml.html">Windows</A> <BR><A
27 href="http://cscene.org/feedback.html">Feedback</A> <A
28 href="http://cscene.org/faqs.html">FAQs</A> <A
29 href="http://cscene.org/changes.html">Changes</A> <A
30 href="http://cscene.org/submit.html">Submissions</A> </TD>
32 <FORM action=http://www.google.com/search method=get><INPUT name=hl
33 type=hidden value=en><INPUT name=safe type=hidden value=off><INPUT
34 name=domains type=hidden value=cscene.org><INPUT name=sitesearch
35 type=hidden value=cscene.org><INPUT maxLength=256 name=q size=31><INPUT name=btnG type=submit value=Search></FORM></TD></TR></TBODY></TABLE>
36 <H1 class=s1>Callbacks in C++: The OO Way</H1>
38 <H2 class=s2 id=N1698364>Content</H2>
40 <LI><A href="http://cscene.org/topics/misc/cs7-04.xml.html#N7895983">What are
42 <LI><A href="http://cscene.org/topics/misc/cs7-04.xml.html#N310499">A simple
44 <LI><A href="http://cscene.org/topics/misc/cs7-04.xml.html#N7751758">Thread
46 <LI><A href="http://cscene.org/topics/misc/cs7-04.xml.html#N3038356">A real
47 Thread class</A></LI></OL></DIV>
49 <P>by <I>Jürgen Hermann</I><BR>last updated <I>2001/08/02</I> (version
50 <I>1.1.1.1</I>)<BR>also available as <A
51 href="http://cscene.org/topics/misc/cs7-04.xml.txt">XML</A></P>
53 <H2 class=s2 id=N7895983>What are Callbacks?</H2>
54 <P>Many operating systems and other subsystems (like GUI libraries) feature a
55 special type of hook into those systems, named callbacks or callback functions.
56 Upon initialization or by calling an API function you pass pointers to the
57 callback into the subsystem, for later use. The problem with those functions is,
58 since these subsystems are nowadays not yet OO, that they have no notion of what
59 an object is. So if you want to have a <EM>callback object </EM> instead of
60 a mere function, some OO magic is called for.</P>
61 <P>As an example, consider the <CODE>BeginThread</CODE> API that many OSes have
62 in a quite similar form; we assume that it takes a pointer to the function that
63 provides the actual code for the newly created thread plus a <EM>data
64 pointer </EM> that is passed to that function as a startup parameter. Thus,
65 we end up with <CODE>BeginThread (void (*thread_func) (void*), void*
66 startup_data)</CODE>. Now let's make a <CODE>Thread</CODE> class of
69 <H2 class=s2 id=N310499>A simple Thread class</H2>
70 <P>What we want to have is an ABC (abstract base class) that you can inherit
71 from, creating specialized thread classes and in turn thread objects (i.e.
72 actual threads). The code of the thread is located in a <EM>pure
73 virtual </EM> function <CODE>code</CODE> that is provided by the inherited
74 class. <CODE>code</CODE> is then similar to the <CODE>thread_func</CODE>
75 parameter of the <CODE>BeginThread</CODE> call, but is a full-blown member
76 function, not just a C function. So, we get this interface for the
77 <CODE>Thread</CODE> class:</P><PRE class=source>class Thread {
84 virtual void code() = 0;
89 static void dispatch(void* thread_obj);
92 <P>This might seem quite unusual to you (like having a protected constructor),
93 but things will be explained in due course.</P></DIV>
95 <H2 class=s2 id=N7751758>Thread implementation</H2>
96 <P>When we put the thread concept into a class, we have to consider lifetime. A
97 thread exists as long as the thread function does not return, thus the object
98 has to have the same lifetime. Because of this, an <CODE>auto</CODE> thread
99 object does not make much sense; we insure that every thread object exists on
100 the heap by making the ctor protected and providing a static factory method
101 <CODE>create</CODE> for thread objects in each derived class:</P><PRE class=source>Thread::Thread()
106 DerivedThread& DerivedThread::create()
108 return *new DerivedThread;
111 <P><CODE>create</CODE> has to be added to every inherited class, returning an
112 object of that class.</P>
113 <P>Next, we need a <CODE>run</CODE> method that actually starts the thread. This
114 can't be done in the ctor: when <CODE>code</CODE> would be registered as a
115 thread of execution in the <EM>base class </EM> ctor, the superclass would
116 not yet be fully created and calling <CODE>code</CODE> would be quite invalid
117 and dangerous. <CODE>run</CODE> does its job by registering the
118 <CODE>dispatch</CODE> function as a thread, giving that thread the object
119 pointer as a startup parameter; since <CODE>dispatch</CODE> is static, it has a
120 prototype that matches the <CODE>void(*)(void*)</CODE> parameter of
121 <CODE>BeginThread</CODE>.</P><PRE class=source>void Thread::run()
123 // Don't start two threads on the same object
126 // Create an OS thread, using the static callback
127 BeginThread(Thread::dispatch, this);
131 <P>So finally, <CODE>dispatch</CODE> is called and performs the step from a
132 procedural callback to the callback object:</P><PRE class=source>void Thread::dispatch(void* thread_obj)
134 // Call the actual OO thread code
135 ((Thread*)thread_obj)->code();
137 // After code() returns, kill the thread object
138 delete (Thread*)thread_obj;
142 <H2 class=s2 id=N3038356>A real Thread class</H2>
143 <P>A real-world thread class has to consider a few things we have ignored here.
144 These things include: </P>
146 <LI>more access to the thread data, like a method giving the thread ID.
147 <LI>a method for killing the thread, including the deletion of the thread
149 <P>Developed and tested on Windows NT, this is the <A
150 href="../../tests/oo_thread.cpp">source</A> for a little
151 example program that implements the above in the real world. If you run it, you
152 get something similar to the following output:</P><PRE class=source>[\cscene\callback]callback
153 Started thread #80 for dice1
154 Started thread #84 for dice2
190 <P>Have fun!</P></DIV>
191 <P><SMALL><EM>This article is Copyright © 1997-98 by Jürgen Hermann<BR>and
192 Copyright © 1999 by C-Scene. All Rights Reserved. </EM></SMALL></P></DIV>
193 <DIV class=lastwords>
195 Copyright © 1997-2000 by C-Scene. All Rights Reserved.<BR><BR>Part of the
196 graphics and stylesheets used to generate this site are<BR>Copyright © 1999-2000
197 by Apache Software Foundation. </DIV></BODY></HTML>