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