ctkPimpl.h 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  1. /**
  2. \class ctkPimpl ctkPimpl
  3. \brief Hide private details of a class
  4. Application code generally doesn't have to be concerned about hiding its
  5. implementation details, but when writing library code it is important to
  6. maintain a constant interface, both source and binary. Maintaining a constant
  7. source interface is easy enough, but keeping the binary interface constant
  8. means moving implementation details into a private class. The PIMPL, or
  9. d-pointer, idiom is a common method of implementing this separation. ctkPimpl
  10. offers a convenient way to connect the public and private sides of your class.
  11. \section start Getting Started
  12. Before you declare the public class, you need to make a forward declaration
  13. of the private class. The private class must have the same name as the public
  14. class, followed by the word Private.
  15. \subsection pub The Public Class
  16. Generally, you shouldn't keep any data members in the public class without a
  17. good reason. Functions that are part of the public interface should be declared
  18. in the public class, and functions that need to be available to subclasses (for
  19. calling or overriding) should be in the protected section of the public class.
  20. To connect the private class to the public class, include the
  21. QCTK_DECLARE_PRIVATE macro in the private section of the public class. In the
  22. example above, the private class is connected as follows:
  23. Additionally, you must include the QCTK_INIT_PRIVATE macro in the public class's
  24. constructor.
  25. \subsection priv The Private Class
  26. As mentioned above, data members should usually be kept in the private class.
  27. This allows the memory layout of the private class to change without breaking
  28. binary compatibility for the public class. Functions that exist only as
  29. implementation details, or functions that need access to private data members,
  30. should be implemented here.
  31. To define the private class, inherit from the template qCTKPrivate class, and
  32. include the QCTK_DECLARE_PUBLIC macro in its public section. The template
  33. parameter should be the name of the public class.
  34. \section cross Accessing Private Members
  35. Use the qctk_d() function (actually a function-like object) from functions in
  36. the public class to access the private class. Similarly, functions in the
  37. private class can invoke functions in the public class by using the qctk_p()
  38. function (this one's actually a function).
  39. */
  40. #ifndef __ctkPimpl_h
  41. #define __ctkPimpl_h
  42. // Qt includes
  43. #include <QtGlobal>
  44. /*! \relates ctkPimpl
  45. * Define a public class constructor with no argument
  46. *
  47. * Also make sure the Pimpl is initalized
  48. */
  49. #define CTK_CONSTRUCTOR_NO_ARG_CXX(PUB) \
  50. PUB::PUB() \
  51. { \
  52. CTK_INIT_PRIVATE(PUB); \
  53. }
  54. /*! \relates ctkPimpl
  55. * Define a public class constructor with one argument
  56. *
  57. * Also make sure the Pimpl is initalized
  58. */
  59. #define CTK_CONSTRUCTOR_1_ARG_CXX(PUB, _ARG1) \
  60. PUB::PUB(_ARG1 _parent) : \
  61. Superclass( _parent ) \
  62. { \
  63. CTK_INIT_PRIVATE(PUB); \
  64. }
  65. /*! \relates ctkPimpl
  66. * Define the setter in the public class.
  67. *
  68. * This should be put in the .cxx file of the public class. The parameter are
  69. * the name of the public class (PUB), the type of the argument to return (_TYPE),
  70. * the name of the getter(_NAME) and the name of the variable in the Private class(_VARNAME).
  71. */
  72. #define CTK_SET_CXX(PUB, _TYPE, _NAME, _VARNAME) \
  73. void PUB::_NAME(_TYPE var) \
  74. { \
  75. ctk_d.ref()._VARNAME = var; \
  76. }
  77. /*! \relates ctkPimpl
  78. * Define the setter in the public class.
  79. *
  80. * This should be put in the .cxx file of the public class. The parameter are
  81. * the name of the public class (PUB), the type of the argument to return (_TYPE),
  82. * the name of the setter(_NAME) and the name of the variable in the Private class(_VARNAME).
  83. */
  84. #define CTK_GET_CXX(PUB, _TYPE, _NAME, _VARNAME) \
  85. _TYPE PUB::_NAME()const \
  86. { \
  87. return ctk_d.ref()._VARNAME; \
  88. }
  89. /*! \relates ctkPimpl
  90. * Declares that a public class has a related private class.
  91. *
  92. * This should be put in the private section of the public class. The parameter is the name of the public class.
  93. * For convenience, this macro also add 'typedef PUB Self;'
  94. */
  95. #define CTK_DECLARE_PRIVATE(PUB) \
  96. friend class PUB##Private; ctkPrivateInterface<PUB, PUB##Private> ctk_d; \
  97. typedef PUB Self;
  98. /*! \relates ctkPimpl
  99. * Declares that a private class has a related public class.
  100. *
  101. * This may be put anywhere in the declaration of the private class. The parameter is the name of the public class.
  102. */
  103. #define CTK_DECLARE_PUBLIC(PUB) friend class PUB;
  104. /*! \relates ctkPimpl
  105. * Initializes resources owned by the private class.
  106. *
  107. * This should be called from the public class's constructor,
  108. * before qctk_d() is used for the first time. The parameter is the name of the public class.
  109. */
  110. #define CTK_INIT_PRIVATE(PUB) ctk_d.setPublic(this)
  111. /*! \relates ctkPimpl
  112. * Returns a pointer (or reference) in the current scope named "d" to the private class.
  113. *
  114. * This function is only available in a class using \a QCTK_DECLARE_PRIVATE.
  115. */
  116. #define CTK_D(PUB) PUB##Private* d = ctk_d()
  117. #define CTK_D_REF(PUB) PUB##Private& d = ctk_d.ref()
  118. /*! \relates ctkPimpl
  119. * Creates a pointer ( or reference) in the current scope named "q" to the public class.
  120. *
  121. * This macro only works in a class using \a CTK_DECLARE_PUBLIC.
  122. */
  123. #define CTK_P(PUB) PUB* p = ctk_p()
  124. #define CTK_P_REF(PUB) PUB& p = ctk_p_ref()
  125. #ifdef CTK_DOXYGEN_RUN
  126. /*! \relates ctkPimpl
  127. * Returns a pointer to the private class.
  128. *
  129. * This function is only available in a class using \a CTK_DECLARE_PRIVATE.
  130. */
  131. ctkPrivate<PUB>* ctk_d();
  132. /*! \relates ctkPimpl
  133. * Returns a const pointer to the private class.
  134. *
  135. * This function is only available in a class using \a CTK_DECLARE_PRIVATE.
  136. * This overload will be automatically used in const functions.
  137. */
  138. const ctkPrivate<PUB>* ctk_d();
  139. /*! \relates ctkPimpl
  140. * Returns a reference or pointer to the public class.
  141. *
  142. * This function is only available in a class using \a CTK_DECLARE_PUBLIC.
  143. */
  144. PUB& ctk_p_ref();
  145. PUB* ctk_p();
  146. /*! \relates ctkPimpl
  147. * Returns a const reference or pointer to the public class.
  148. *
  149. * This function is only available in a class using \a CTK_DECLARE_PUBLIC.
  150. * This overload will be automatically used in const functions.
  151. */
  152. const PUB& ctk_p_ref();
  153. const PUB* ctk_p();
  154. #endif
  155. template <typename PUB>
  156. class ctkPrivate
  157. {
  158. public:
  159. virtual ~ctkPrivate(){}
  160. inline void CTK_setPublic(PUB* pub)
  161. {
  162. Q_ASSERT(pub);
  163. ctk_p_ptr = pub;
  164. }
  165. protected:
  166. inline PUB& ctk_p_ref()
  167. {
  168. Q_ASSERT(this->ctk_p_ptr);
  169. return *this->ctk_p_ptr;
  170. }
  171. inline const PUB& ctk_p_ref() const
  172. {
  173. Q_ASSERT(this->ctk_p_ptr);
  174. return *this->ctk_p_ptr;
  175. }
  176. inline PUB* ctk_p()
  177. {
  178. Q_ASSERT(this->ctk_p_ptr);
  179. return this->ctk_p_ptr;
  180. }
  181. inline const PUB* ctk_p() const
  182. {
  183. Q_ASSERT(this->ctk_p_ptr);
  184. return this->ctk_p_ptr;
  185. }
  186. private:
  187. PUB* ctk_p_ptr;
  188. };
  189. template <typename PUB, typename PVT>
  190. class ctkPrivateInterface
  191. {
  192. friend class ctkPrivate<PUB>;
  193. public:
  194. ctkPrivateInterface()
  195. {
  196. this->pvt = new PVT;
  197. }
  198. ~ctkPrivateInterface()
  199. {
  200. delete this->pvt;
  201. }
  202. inline void setPublic(PUB* pub)
  203. {
  204. Q_ASSERT(pub);
  205. this->pvt->CTK_setPublic(pub);
  206. }
  207. inline PVT& ref()
  208. {
  209. return *static_cast<PVT*>(this->pvt);
  210. }
  211. inline const PVT& ref() const
  212. {
  213. return *static_cast<PVT*>(this->pvt);
  214. }
  215. inline PVT* operator()()
  216. {
  217. return static_cast<PVT*>(this->pvt);
  218. }
  219. inline const PVT* operator()() const
  220. {
  221. return static_cast<PVT*>(this->pvt);
  222. }
  223. private:
  224. ctkPrivate<PUB>* pvt;
  225. };
  226. #endif