add ignore pattern for git
[web/konrad/chester.git] / dptr.dox
1 /** \mainpage Chester - d-pointers
2
3 Chester is an implementation of the Cheshire Cat idiom - also known as
4 d-pointer, PImpl (Pointer IMPLementation), or opaqua data pointer.
5 It hides the data of a class behind a "d" pointer.
6
7 This implementation takes away much of the bookkeeping work, like allocating
8 and de-allocating the pointer.
9
10 All the files of Chester are copyrighted under a permissive license:
11  Copying and distribution of this file, with or without modification,
12  are permitted in any medium without royalty provided the copyright
13  notice and this notice are preserved.  This file is offered as-is,
14  without any warranty.
15
16 So, you are free to use this implementation in any project under any kind of
17 license as long as you do not remove my copyright notice.
18
19 Although I do not require it, I would appreciate feedback on problems, bugs,
20 and the occasional code improvement - if you feel like it...
21
22 Different versions of Chester can be mixed for different classes, but the same version must be used both in the header file and in the implementation of the same class.
23
24 \section kinds Kinds of D-Pointers
25
26 Cheshire cats or d-pointers allow you to hide the data members (and if you want some of the implementation) of a class and also allow (within some constraints) to maintain ABI compatibility (ABI=Application Binary Interface) while adding or removing hidden data members.
27
28 Chester defines three different kinds of d-pointers: non-copy, non-shared, and shared. Those three define different access patterns to the d-pointer.
29
30 Non-copy d-pointers cannot be copied directly, if you want to make your main class copyable you have to explicitly create a copy constructor and/or an assignment operator. Those should be used with main classes and data objects that cannot be copied (like Qt's QObject and its subclasses).
31
32 Non-shared d-pointers can be copied - if you copy an instance of the main class, the content of the d-pointer gets copied automatically (at least if you use the automatic copy constructor or call the copy constructor of the d-pointer). Each copy acts independently. This version produces the same behavior as if the data was defined directly in the main class instead of inside the d-pointer.
33
34 Shared d-pointers can also be copied, but copying shares the data between instances of the main class. This can be used to create interface classes in which all copied instances share their data.
35
36 All three kinds share the usage pattern. The header file and class interface declaration is declared like this (this example uses non-shared d-pointers):
37 \code
38 //file: myclass.h
39
40 #include <DPtrBase>
41
42 //declare main class
43 class MyClass
44 {
45   //declare d-pointer
46   DECLARE_DPTR(d)
47   //declare the remainder of the class minus data
48   public:
49     MyClass();
50     void setInt(int);
51     int getInt()const;
52     int getIntPlusOne()const{return getInt()+1;}
53 };
54 \endcode
55
56 As shown above, methods cannot be defined as inlines if the data is hidden behind a d-pointer, since this would require the compiler to know the structure of the d-pointer. However, it is possible to inline any method that does not access the d-pointer directly.
57
58 The actual implementation file then declares and defines the d-pointer class and defines all methods of the main class that need access to the d-pointer:
59 \code
60 //file: myclass.cpp
61
62 #include "myclass.h"
63 #include <DPtr>
64
65 //declare internal d-pointer class
66 class DPTR_CLASS_NAME(MyClass):public DPtr
67 {
68   public:
69     int myint;
70 };
71 //define glue code
72 DEFINE_DPTR(MyClass)
73
74 //constructor
75 MyClass:MyClass()
76 {
77   d->myint = 0;
78 }
79
80 //a setter function (non-const)
81 void MyClass::setInt(int i)
82 {
83   d->myint = i;
84 }
85
86 //a getter function (const)
87 int MyClass::getInt()const
88 {
89   return d->myint;
90   //this code would not compile:
91   //d->myint = 7;
92 }
93
94 //example usage:
95 main()
96 {
97   MyClass myinst;
98   myinst.setInt(1);
99 }
100 \endcode
101
102 Which actual kind of d-pointer behavior is declared is decided by using different macros and base classes for the d-pointer class. The argument to the DECLARE_* macro defines the name of the d-pointer variable, usually this will be "d", but you can chose any other name (except "Private" and "DPrivate", which are used as wrapper class names).
103
104 The DPTR_CLASS_NAME macro returns the class name of the d-pointer class relative to the main class, which is given as argument. The DEFINE_* macro defines the logic that automatically instantiates, deletes and copies the d-pointer when the main class is instantiated, deleted, and copied. The d-pointer class must be derived from one of the DPtr classes, since these implement some functionality complementing the DEFINE_* macro.
105
106 The header file should only include \<DPtrBase> - this file contains the DECLARE_* macros, which is the only thing needed for the header. If you include any other file, this makes mixing versions of Chester impossible in some situations. The implementation file must include one of the d-pointer implementation variants.
107
108 \section table Comparison Table
109
110 The macros, classes, \#include statements above need to be replaced with different ones if you want one of the other kinds of d-pointers:
111
112 <table>
113 <tr>
114  <td><b>Type</b><td><b>Pointer Declaration (1)</b><td><b>Declaration Include (1)</b>
115  <td><b>Base Class(2, 3)</b><td><b>Definition (2)</b><td><b>Implementation Include (2)</b></tr>
116 <tr>
117  <td>Non-Shared, Copyable<td>DECLARE_DPTR(Class)<td>\#include \<\link dptr_base.h DPtrBase \endlink >
118  <td>DPtr<td>DEFINE_DPTR(Class)
119  <td>\#include \<\link dptr.h DPtr \endlink >
120  </tr>
121 <tr>
122  <td>Shared<td>DECLARE_SHARED_DPTR(Class)<td>\#include \<\link dptr_base.h DPtrBase \endlink >
123  <td>SharedDPtr<td>DEFINE_SHARED_DPTR(Class)
124  <td>\#include \<\link dptr_shared.h SharedDPtr \endlink >
125  </tr>
126 <tr>
127  <td>Non-Copyable<td>DECLARE_NONCOPY_DPTR(Class)<td>\#include \<\link dptr_base.h DPtrBase \endlink >
128  <td>NonCopyDPtr<td>DEFINE_NONCOPY_DPTR(Class)
129  <td>\#include \<\link dptr_noncopy.h NonCopyDPtr \endlink >
130  </tr>
131 </table>
132
133 (1) The DECLARE_* macro and declartion include directive are supposed to be used in the header file of the main class.
134
135 (2) The implementation include directive should only be used in the main class'es implementation file - use the DEFINE_* macro to create the glue code that connects the d-pointer class with the main class.
136
137 (3) The base class must be used to derive the d-pointer class in the implementation file. It contains some functionality that the DEFINE_* macro relies on.
138
139 There are three more macros that return default names for d-pointer properties:
140 - DPTR_CLASS_NAME(Class) returns the name of the d-pointer class for a given main class (which may be namespace qualified)
141 - \link ::DPTR_NAME DPTR_NAME \endlink returns the local name of the d-pointer class, and its constructor
142 - \link ::DPTR_WRAPPER_NAME DPTR_WRAPPER_NAME \endlink returns the local name of the wrapper class that contains the glue code to implement the expected d-pointer behavior
143
144 \section nonshare Using Non-Shared D-Pointers
145
146 Using the code above you will get a non-shared d-pointer for your main class. The behavior of your main class will be very similar to the behavior you would get with defining the data inside the main class itself. So this is the normal choice when you transform a normal class into a d-pointer based class. The automatic copy constructor and the automatic assignment operator work exactly as would be expected from a normal class:
147
148 \code
149 MyClass my1;
150 my1.setInt(1);
151 printf("my1 is now %i\n",my1.getInt()); // my1 is now 1
152 //create a copy
153 MyClass my2(my1);
154 printf("my2 is now %i\n",my2.getInt()); // my2 is now 1
155 my1.setInt(2);
156 my2.setInt(3);
157 printf("my1 is now %i\n",my1.getInt()); // my1 is now 2
158 printf("my2 is now %i\n",my2.getInt()); // my2 is now 3
159 \endcode
160
161 If you want to override the copy constructor you have several choices: you can do all the copying yourself in the main class or the d-pointer class, you can use the d-pointers copy constructor or you can use the d-pointers assignment operator:
162 \code
163 //version 1: using the copy constructor
164 MyClass::MyClass(const MyClass&copy)
165   :d(copy.d)
166 {
167 }
168
169 //version 2: using the assignment operator
170 MyClass::MyClass(const MyClass&copy)
171 {
172   d = copy.d;
173 }
174
175 //version 3: doing the copying itself in the main class
176 MyClass::MyClass(const MyClass&copy)
177 {
178   d->myint = copy.d->myint;
179 }
180
181 //version 4: d-pointer class with copy constructor:
182 class DPTR_CLASS_NAME(MyClass):public DPtr
183 {
184   public:
185     DPTR_NAME(const DPTR_NAME&copy)
186     {
187       myint = copy.myint;
188     }
189 }
190 \endcode
191
192 It is recommended to use the copy constructor, since this most closely models the behavior of the automatic copy constructor and may save some unnecessary initialization of members. The manual copying of members is quite error prone, since it may break if you add members to the d-pointer, but forget to add them in the copy constructor of the main class or the d-pointer class.
193
194 The version of a d-pointer class above uses the DPTR_NAME macro to resolve the local name of its constructor and class name. It is also almost identical to the version that the compiler would have created automatically, but as with the custom versions in the main class above you can change some behavior here. However, since the danger exists to forget some members it is not recommended to do this. Instead it is usually much safer to use version 1 above and add custom code in the body of the copy constructor of the main class.
195
196 For the assignment operator you also have the choice of implementing it in the main class or the d-pointer class, but it is recommended to do it in the main class:
197 \code
198 MyClass& MyClass::operator=(const MyClass&copy)
199 {
200   //use the automatic operator from d-pointer
201   d = copy.d;
202   //add custom code here...
203 }
204 \endcode
205
206 This leverages the automatic assignment operator of the d-pointer class, eliminating the risk of forgetting members and still allows some customization.
207
208 \section share Using Shared D-Pointers
209
210 When defining shared d-pointers you have to use different macros and a different base class, but otherwise things stay identical:
211 \code
212 // file: myfile.h
213 #include <DPtrBase>
214 class MyClass
215 {
216   DECLARE_SHARED_DPTR(d)
217   public:
218     ...
219 };
220
221 // file: myfile.cpp
222 #include "myfile.h"
223 #include <SharedDPtr>
224
225 //define d-pointer class
226 class DPTR_CLASS_NAME(MyClass):public SharedDPtr
227 {
228   public:
229     int myint;
230 };
231 //define glue code
232 DEFINE_SHARED_DPTR(MyClass)
233 \endcode
234
235 Instances of shared d-pointers access the same members if they have been assigned from each other:
236 \code
237 MyClass my1;
238 my1.setInt(1);
239 printf("my1 is now %i\n",my1.getInt()); // my1 is now 1
240 //create a copy
241 MyClass my2(my1);
242 printf("my2 is now %i\n",my2.getInt()); // my2 is now 1
243 my1.setInt(2);
244 my2.setInt(3);
245 printf("my1 is now %i\n",my1.getInt()); // my1 is now 3
246 printf("my2 is now %i\n",my2.getInt()); // my2 is now 3
247 MyClass my3;
248 my3.setInt(99);
249 printf("my1 is now %i\n",my1.getInt()); // my1 is now 3
250 printf("my3 is now %i\n",my3.getInt()); // my3 is now 99
251 my3 = my1;
252 printf("my3 is now %i\n",my3.getInt()); // my3 is now 3
253 \endcode
254
255 If instances are never copied or assigned they still are independent, they get linked as soon as assignment happens. Chester keeps a reference counter on the d-pointer automatically allocating and de-allocating it if necessary.
256
257 Even in the case of shared d-pointers it is sometimes desireable to create a "deep copy" - a copy of an instance that is independent from the original. This can be done by implementing a simple clone method:
258 \code
259 MyClass MyClass::deepCopy()const
260 {
261   MyClass ret;
262   ret.d=d.clone();
263   return ret;
264 }
265
266 ...
267 my3 = my1.deepCopy();
268 my3.setInt(100);
269 printf("my1 is now %i\n",my1.getInt()); // my3 is now 3
270 printf("my3 is now %i\n",my3.getInt()); // my3 is now 100
271 \endcode
272
273 Please note that the clone() method of the d-pointer is called with a dot (.), not an arrow (->) - we are using a method of the pointer-wrapper itself here. Please see below for details.
274
275 Under normal circumstances the copy constructor of the d-pointer class is never used in shared d-pointers, the assignment operator is only used when creating deep copies. The rest of the time the pointer is just passed around.
276
277 \section noncopy Non-Copyable D-Pointers
278
279 When defining non-copyable d-pointers you have to use different macros and a different base class, but otherwise things stay identical:
280 \code
281 // file: myfile.h
282 #include <DPtrBase>
283 class MyClass
284 {
285   DECLARE_NONCOPY_DPTR(d)
286   public:
287     ...
288 };
289
290 // file: myfile.cpp
291 #include "myfile.h"
292 #include <NonCopyDPtr>
293
294 //define d-pointer class
295 class DPTR_CLASS_NAME(MyClass):public NonCopyDPtr
296 {
297   public:
298     int myint;
299 };
300 //define glue code
301 DEFINE_NONCOPY_DPTR(MyClass)
302 \endcode
303
304 You can use the non-copyable version of Chesters d-pointers if you want to prevent the user from copying instances of your main class or if you want to explicitly implement the copy constructor and assignment operator yourself. If you do implement them you will have to do this in the main class, since the d-pointer-wrapper itself has a built-in barrier to copying - only its default constructor is usable.
305
306 This version is meant for d-pointers serving classes that are inherently un-copyable, like Qt's widgets.
307
308 \section magic Deep Magic: the Inner Workings of Chester
309
310 The DECLARE_* macro of Chester actually defines two internal classes for its purposes: MyClass::Private and MyClass::DPrivate. The MyClass::Private class is the one you define to contain the data and the one that you access through "d->". The MyClass::DPrivate class contains the wrapper code that automatically instantiates and deletes the instance of MyClass::Private. The member variable "d" is actually an instance of DPrivate - however the "->" operator of that class returns a pointer of Private, so that it appears to be a normal pointer to Private. But since no dereference operator (*) is defined you cannot directly overwrite or delete the instance of Private - this serves as a barrier against accidental deletion or non-deletion of the d-pointer (of course you can still get at the pointer with some fancy casting).
311
312 A simplified version of the expanded DECLARE_* macro would look like this:
313 \code
314 class MyClass
315 {
316   //DECLARE_*DPTR(d):
317   class Private; //forward declaration of Private
318   class DPrivate
319   {
320     public:
321       DPrivate();  //constructor, see below
322       ~DPrivate(); //destructor, see below
323       const Private* operator->()const; //access to the pointer, const
324       Private* operator->();  //access to the pointer, non-const
325     private:
326       Private *inner; //actual pointer
327   };
328   DPrivate d; //instance of the d-pointer-wrapper
329   //end of macro
330   public:
331     MyClass(); //...
332 };
333 \endcode
334
335 The DEFINE_* macro then implements the methods declared above:
336 \code
337 //DEFINE_*DPTR(MyClass):
338 MyClass::DPrivate::DPrivate()
339 {
340   inner = new MyClass::Private;
341 }
342
343 MyClass::DPrivate::~DPrivate()
344 {
345   delete inner;
346 }
347
348 MyClass::Private* MyClass::DPrivate::operator->()
349 {
350   return inner;
351 }
352
353 const MyClass::Private* MyClass::DPrivate::operator->()const
354 {
355   return inner;
356 }
357 \endcode
358
359 So when accessing "d" directly we access the wrapper class (which does not offer much of an interface), and when accessing it through "d->" we access members of the inner member of the wrapper instead of the wrapper itself.
360
361 There are two versions of the "->" operator. The first one without const is used when the d-pointer is written to, the second version with const is used for pure read operations and inside const methods of the main class. Having those two versions ensures that the members of the d-pointer adhere to the const declarations of the main class, otherwise it would be possible to write to members even if it happens inside a const method.
362
363 The differences between the various versions of the macros are in details not shown above - copy constructors, and assignment operators.
364
365 \section abi A Word about ABI
366
367 If you want to use d-pointers to maintain ABI (Application Binary Interface) compatibility over several versions, you also have to adhere to a few more rules. While adding and removing data members is the most obvious cause of ABI incompatibility, some other changes also influence it. For example:
368 - changing inheritance
369 - changing a parent class in an ABI incompatible way
370 - changing of inline status of a method
371 - removing methods
372 - changing a method's signature (changing/adding/removing arguments, access-levels, add/remove const)
373 - changing return types
374 - adding/removing virtual methods
375 - changing the order of virtual methods
376
377 For a more complete article on the topic see for example:
378 http://techbase.kde.org/Policies/Binary_Compatibility_Issues_With_C++
379
380 */