1 | <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN"> |
---|
2 | <html> |
---|
3 | <head> |
---|
4 | <title>Boost: Base-from-Member Idiom Documentation</title> |
---|
5 | </head> |
---|
6 | |
---|
7 | <body bgcolor="white" link="blue" text="black" vlink="purple" alink="red"> |
---|
8 | <h1><img src="../../boost.png" alt="C++ Boost" align="middle" |
---|
9 | width="277" height="86">Base-from-Member Idiom</h1> |
---|
10 | |
---|
11 | <p>The class template <code>boost::base_from_member</code> provides |
---|
12 | a workaround for a class that needs to initialize a base class with a |
---|
13 | member. The class template is in <cite><a |
---|
14 | href="../../boost/utility/base_from_member.hpp">boost/utility/base_from_member.hpp</a></cite> |
---|
15 | which is included in <i><a href="../../boost/utility.hpp">boost/utility.hpp</a></i>.</p> |
---|
16 | |
---|
17 | <p>There is test/example code in <cite><a |
---|
18 | href="base_from_member_test.cpp">base_from_member_test.cpp</a></cite>.</p> |
---|
19 | |
---|
20 | <h2><a name="contents">Contents</a></h2> |
---|
21 | |
---|
22 | <ul> |
---|
23 | <li><a href="#contents">Contents</a></li> |
---|
24 | <li><a href="#rationale">Rationale</a></li> |
---|
25 | <li><a href="#synopsis">Synopsis</a></li> |
---|
26 | <li><a href="#usage">Usage</a></li> |
---|
27 | <li><a href="#example">Example</a></li> |
---|
28 | <li><a href="#credits">Credits</a> |
---|
29 | <ul> |
---|
30 | <li><a href="#contributors">Contributors</a></li> |
---|
31 | </ul></li> |
---|
32 | </ul> |
---|
33 | |
---|
34 | <h2><a name="rationale">Rationale</a></h2> |
---|
35 | |
---|
36 | <p>When developing a class, sometimes a base class needs to be |
---|
37 | initialized with a member of the current class. As a naïve |
---|
38 | example:</p> |
---|
39 | |
---|
40 | <blockquote><pre> |
---|
41 | #include <streambuf> <i>// for std::streambuf</i> |
---|
42 | #include <ostream> <i>// for std::ostream</i> |
---|
43 | |
---|
44 | class fdoutbuf |
---|
45 | : public std::streambuf |
---|
46 | { |
---|
47 | public: |
---|
48 | explicit fdoutbuf( int fd ); |
---|
49 | //... |
---|
50 | }; |
---|
51 | |
---|
52 | class fdostream |
---|
53 | : public std::ostream |
---|
54 | { |
---|
55 | protected: |
---|
56 | fdoutbuf buf; |
---|
57 | public: |
---|
58 | explicit fdostream( int fd ) |
---|
59 | : buf( fd ), std::ostream( &buf ) |
---|
60 | {} |
---|
61 | //... |
---|
62 | }; |
---|
63 | </pre></blockquote> |
---|
64 | |
---|
65 | <p>This is undefined because C++'s initialization order mandates that |
---|
66 | the base class is initialized before the member it uses. <a |
---|
67 | href="http://www.moocat.org">R. Samuel Klatchko</a> developed a way |
---|
68 | around this by using the initialization order in his favor. Base |
---|
69 | classes are intialized in order of declaration, so moving the desired |
---|
70 | member to another base class, that is initialized before the desired |
---|
71 | base class, can ensure proper initialization.</p> |
---|
72 | |
---|
73 | <p>A custom base class can be made for this idiom:</p> |
---|
74 | |
---|
75 | <blockquote><pre> |
---|
76 | #include <streambuf> <i>// for std::streambuf</i> |
---|
77 | #include <ostream> <i>// for std::ostream</i> |
---|
78 | |
---|
79 | class fdoutbuf |
---|
80 | : public std::streambuf |
---|
81 | { |
---|
82 | public: |
---|
83 | explicit fdoutbuf( int fd ); |
---|
84 | //... |
---|
85 | }; |
---|
86 | |
---|
87 | struct fdostream_pbase |
---|
88 | { |
---|
89 | fdoutbuf sbuffer; |
---|
90 | |
---|
91 | explicit fdostream_pbase( int fd ) |
---|
92 | : sbuffer( fd ) |
---|
93 | {} |
---|
94 | }; |
---|
95 | |
---|
96 | class fdostream |
---|
97 | : private fdostream_pbase |
---|
98 | , public std::ostream |
---|
99 | { |
---|
100 | typedef fdostream_pbase pbase_type; |
---|
101 | typedef std::ostream base_type; |
---|
102 | |
---|
103 | public: |
---|
104 | explicit fdostream( int fd ) |
---|
105 | : pbase_type( fd ), base_type( &sbuffer ) |
---|
106 | {} |
---|
107 | //... |
---|
108 | }; |
---|
109 | </pre></blockquote> |
---|
110 | |
---|
111 | <p>Other projects can use similar custom base classes. The technique |
---|
112 | is basic enough to make a template, with a sample template class in |
---|
113 | this library. The main template parameter is the type of the enclosed |
---|
114 | member. The template class has several (explicit) constructor member |
---|
115 | templates, which implicitly type the constructor arguments and pass them |
---|
116 | to the member. The template class uses implicit copy construction and |
---|
117 | assignment, cancelling them if the enclosed member is non-copyable.</p> |
---|
118 | |
---|
119 | <p>Manually coding a base class may be better if the construction |
---|
120 | and/or copying needs are too complex for the supplied template class, |
---|
121 | or if the compiler is not advanced enough to use it.</p> |
---|
122 | |
---|
123 | <p>Since base classes are unnamed, a class cannot have multiple (direct) |
---|
124 | base classes of the same type. The supplied template class has an |
---|
125 | extra template parameter, an integer, that exists solely to provide type |
---|
126 | differentiation. This parameter has a default value so a single use of a |
---|
127 | particular member type does not need to concern itself with the integer.</p> |
---|
128 | |
---|
129 | <h2><a name="synopsis">Synopsis</a></h2> |
---|
130 | |
---|
131 | <blockquote><pre> |
---|
132 | #ifndef BOOST_BASE_FROM_MEMBER_MAX_ARITY |
---|
133 | #define BOOST_BASE_FROM_MEMBER_MAX_ARITY 10 |
---|
134 | #endif |
---|
135 | |
---|
136 | template < typename MemberType, int UniqueID = 0 > |
---|
137 | class boost::base_from_member |
---|
138 | { |
---|
139 | protected: |
---|
140 | MemberType member; |
---|
141 | |
---|
142 | base_from_member(); |
---|
143 | |
---|
144 | template< typename T1 > |
---|
145 | explicit base_from_member( T1 x1 ); |
---|
146 | |
---|
147 | template< typename T1, typename T2 > |
---|
148 | base_from_member( T1 x1, T2 x2 ); |
---|
149 | |
---|
150 | //... |
---|
151 | |
---|
152 | template< typename T1, typename T2, typename T3, typename T4, |
---|
153 | typename T5, typename T6, typename T7, typename T8, typename T9, |
---|
154 | typename T10 > |
---|
155 | base_from_member( T1 x1, T2 x2, T3 x3, T4 x4, T5 x5, T6 x6, T7 x7, |
---|
156 | T8 x8, T9 x9, T10 x10 ); |
---|
157 | }; |
---|
158 | </pre></blockquote> |
---|
159 | |
---|
160 | <p>The class template has a first template parameter |
---|
161 | <var>MemberType</var> representing the type of the based-member. |
---|
162 | It has a last template parameter <var>UniqueID</var>, that is an |
---|
163 | <code>int</code>, to differentiate between multiple base classes that use |
---|
164 | the same based-member type. The last template parameter has a default |
---|
165 | value of zero if it is omitted. The class template has a protected |
---|
166 | data member called <var>member</var> that the derived class can use |
---|
167 | for later base classes (or itself).</p> |
---|
168 | |
---|
169 | <p>There is a default constructor and several constructor member |
---|
170 | templates. These constructor templates can take as many arguments |
---|
171 | (currently up to ten) as possible and pass them to a constructor of |
---|
172 | the data member. Since C++ does not allow any way to explicitly state |
---|
173 | the template parameters of a templated constructor, make sure that |
---|
174 | the arguments are already close as possible to the actual type used in |
---|
175 | the data member's desired constructor.</p> |
---|
176 | |
---|
177 | <p>The <var>BOOST_BASE_FROM_MEMBER_MAX_ARITY</var> macro constant specifies |
---|
178 | the maximum argument length for the constructor templates. The constant |
---|
179 | may be overridden if more (or less) argument configurations are needed. The |
---|
180 | constant may be read for code that is expandable like the class template and |
---|
181 | needs to maintain the same maximum size. (Example code would be a class that |
---|
182 | uses this class template as a base class for a member with a flexible set of |
---|
183 | constructors.)</p> |
---|
184 | |
---|
185 | <h2><a name="usage">Usage</a></h2> |
---|
186 | |
---|
187 | <p>With the starting example, the <code>fdoutbuf</code> sub-object needs |
---|
188 | to be encapsulated in a base class that is inheirited before |
---|
189 | <code>std::ostream</code>.</p> |
---|
190 | |
---|
191 | <blockquote><pre> |
---|
192 | #include <boost/utility/base_from_member.hpp> |
---|
193 | |
---|
194 | #include <streambuf> <i>// for std::streambuf</i> |
---|
195 | #include <ostream> <i>// for std::ostream</i> |
---|
196 | |
---|
197 | class fdoutbuf |
---|
198 | : public std::streambuf |
---|
199 | { |
---|
200 | public: |
---|
201 | explicit fdoutbuf( int fd ); |
---|
202 | //... |
---|
203 | }; |
---|
204 | |
---|
205 | class fdostream |
---|
206 | : private boost::base_from_member<fdoutbuf> |
---|
207 | , public std::ostream |
---|
208 | { |
---|
209 | // Helper typedef's |
---|
210 | typedef boost::base_from_member<fdoutbuf> pbase_type; |
---|
211 | typedef std::ostream base_type; |
---|
212 | |
---|
213 | public: |
---|
214 | explicit fdostream( int fd ) |
---|
215 | : pbase_type( fd ), base_type( &member ) |
---|
216 | {} |
---|
217 | //... |
---|
218 | }; |
---|
219 | </pre></blockquote> |
---|
220 | |
---|
221 | <p>The base-from-member idiom is an implementation detail, so it |
---|
222 | should not be visible to the clients (or any derived classes) of |
---|
223 | <code>fdostream</code>. Due to the initialization order, the |
---|
224 | <code>fdoutbuf</code> sub-object will get initialized before the |
---|
225 | <code>std::ostream</code> sub-object does, making the former |
---|
226 | sub-object safe to use in the latter sub-object's construction. Since the |
---|
227 | <code>fdoutbuf</code> sub-object of the final type is the only sub-object |
---|
228 | with the name "member," that name can be used |
---|
229 | unqualified within the final class.</p> |
---|
230 | |
---|
231 | <h2><a name="example">Example</a></h2> |
---|
232 | |
---|
233 | <p>The base-from-member class templates should commonly involve |
---|
234 | only one base-from-member sub-object, usually for attaching a |
---|
235 | stream-buffer to an I/O stream. The next example demonstrates how |
---|
236 | to use multiple base-from-member sub-objects and the resulting |
---|
237 | qualification issues.</p> |
---|
238 | |
---|
239 | <blockquote><pre> |
---|
240 | #include <boost/utility/base_from_member.hpp> |
---|
241 | |
---|
242 | #include <cstddef> <i>// for NULL</i> |
---|
243 | |
---|
244 | struct an_int |
---|
245 | { |
---|
246 | int y; |
---|
247 | |
---|
248 | an_int( float yf ); |
---|
249 | }; |
---|
250 | |
---|
251 | class switcher |
---|
252 | { |
---|
253 | public: |
---|
254 | switcher(); |
---|
255 | switcher( double, int * ); |
---|
256 | //... |
---|
257 | }; |
---|
258 | |
---|
259 | class flow_regulator |
---|
260 | { |
---|
261 | public: |
---|
262 | flow_regulator( switcher &, switcher & ); |
---|
263 | //... |
---|
264 | }; |
---|
265 | |
---|
266 | template < unsigned Size > |
---|
267 | class fan |
---|
268 | { |
---|
269 | public: |
---|
270 | explicit fan( switcher ); |
---|
271 | //... |
---|
272 | }; |
---|
273 | |
---|
274 | class system |
---|
275 | : private boost::base_from_member<an_int> |
---|
276 | , private boost::base_from_member<switcher> |
---|
277 | , private boost::base_from_member<switcher, 1> |
---|
278 | , private boost::base_from_member<switcher, 2> |
---|
279 | , protected flow_regulator |
---|
280 | , public fan<6> |
---|
281 | { |
---|
282 | // Helper typedef's |
---|
283 | typedef boost::base_from_member<an_int> pbase0_type; |
---|
284 | typedef boost::base_from_member<switcher> pbase1_type; |
---|
285 | typedef boost::base_from_member<switcher, 1> pbase2_type; |
---|
286 | typedef boost::base_from_member<switcher, 2> pbase3_type; |
---|
287 | |
---|
288 | typedef flow_regulator base1_type; |
---|
289 | typedef fan<6> base2_type; |
---|
290 | |
---|
291 | public: |
---|
292 | system( double x ); |
---|
293 | //... |
---|
294 | }; |
---|
295 | |
---|
296 | system::system( double x ) |
---|
297 | : pbase0_type( 0.2 ) |
---|
298 | , pbase1_type() |
---|
299 | , pbase2_type( -16, &this->pbase0_type::member ) |
---|
300 | , pbase3_type( x, static_cast<int *>(NULL) ) |
---|
301 | , base1_type( pbase3_type::member, pbase1_type::member ) |
---|
302 | , base2_type( pbase2_type::member ) |
---|
303 | { |
---|
304 | //... |
---|
305 | } |
---|
306 | </pre></blockquote> |
---|
307 | |
---|
308 | <p>The final class has multiple sub-objects with the name |
---|
309 | "member," so any use of that name needs qualification by |
---|
310 | a name of the appropriate base type. (Using <code>typedef</code>s |
---|
311 | ease mentioning the base types.) However, the fix introduces a new |
---|
312 | problem when a pointer is needed. Using the address operator with |
---|
313 | a sub-object qualified with its class's name results in a pointer-to-member |
---|
314 | (here, having a type of <code>an_int boost::base_from_member<an_int, |
---|
315 | 0> :: *</code>) instead of a pointer to the member (having a type of |
---|
316 | <code>an_int *</code>). The new problem is fixed by qualifying the |
---|
317 | sub-object with "<code>this-></code>," and is needed just |
---|
318 | for pointers, and not for references or values.</p> |
---|
319 | |
---|
320 | <p>There are some argument conversions in the initialization. The |
---|
321 | constructor argument for <code>pbase0_type</code> is converted from |
---|
322 | <code>double</code> to <code>float</code>. The first constructor |
---|
323 | argument for <code>pbase2_type</code> is converted from <code>int</code> |
---|
324 | to <code>double</code>. The second constructor argument for |
---|
325 | <code>pbase3_type</code> is a special case of necessary conversion; all |
---|
326 | forms of the null-pointer literal in C++ also look like compile-time |
---|
327 | integral expressions, so C++ always interprets such code as an integer |
---|
328 | when it has overloads that can take either an integer or a pointer. The |
---|
329 | last conversion is necessary for the compiler to call a constructor form |
---|
330 | with the exact pointer type used in <code>switcher</code>'s constructor.</p> |
---|
331 | |
---|
332 | <h2><a name="credits">Credits</a></h2> |
---|
333 | |
---|
334 | <h3><a name="contributors">Contributors</a></h3> |
---|
335 | |
---|
336 | <dl> |
---|
337 | <dt><a href="../../people/ed_brey.htm">Ed Brey</a> |
---|
338 | <dd>Suggested some interface changes. |
---|
339 | |
---|
340 | <dt><a href="http://www.moocat.org">R. Samuel Klatchko</a> (<a |
---|
341 | href="mailto:rsk@moocat.org">rsk@moocat.org</a>, <a |
---|
342 | href="mailto:rsk@brightmail.com">rsk@brightmail.com</a>) |
---|
343 | <dd>Invented the idiom of how to use a class member for initializing |
---|
344 | a base class. |
---|
345 | |
---|
346 | <dt><a href="../../people/dietmar_kuehl.htm">Dietmar Kuehl</a> |
---|
347 | <dd>Popularized the base-from-member idiom in his |
---|
348 | <a href="http://www.informatik.uni-konstanz.de/~kuehl/c++/iostream/">IOStream |
---|
349 | example classes</a>. |
---|
350 | |
---|
351 | <dt>Jonathan Turkanis |
---|
352 | <dd>Supplied an implementation of generating the constructor templates that |
---|
353 | can be controlled and automated with macros. The implementation uses |
---|
354 | the <a href="../preprocessor/index.html">Preprocessor library</a>. |
---|
355 | |
---|
356 | <dt><a href="../../people/daryle_walker.html">Daryle Walker</a> |
---|
357 | <dd>Started the library. Contributed the test file <cite><a |
---|
358 | href="base_from_member_test.cpp">base_from_member_test.cpp</a></cite>. |
---|
359 | </dl> |
---|
360 | |
---|
361 | <hr> |
---|
362 | |
---|
363 | <p>Revised: 28 August 2004</p> |
---|
364 | |
---|
365 | <p>Copyright 2001, 2003, 2004 Daryle Walker. Use, modification, and distribution |
---|
366 | are subject to the Boost Software License, Version 1.0. (See accompanying |
---|
367 | file <a href="../../LICENSE_1_0.txt">LICENSE_1_0.txt</a> or a copy at <<a |
---|
368 | href="http://www.boost.org/LICENSE_1_0.txt">http://www.boost.org/LICENSE_1_0.txt</a>>.)</p> |
---|
369 | |
---|
370 | </body> |
---|
371 | </html> |
---|