You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

309 lines
8.3 KiB

  1. /* /////////////////////////////////////////////////////////////////////////
  2. * File: stlsoft/conversion/ptr_cast.hpp
  3. *
  4. * Purpose: A cast that throws bad_cast for dynamic pointer casting, as well
  5. * as references.
  6. *
  7. * Created: 28th December 2002
  8. * Updated: 10th August 2009
  9. *
  10. * Home: http://stlsoft.org/
  11. *
  12. * Copyright (c) 2002-2009, Matthew Wilson and Synesis Software
  13. * All rights reserved.
  14. *
  15. * Redistribution and use in source and binary forms, with or without
  16. * modification, are permitted provided that the following conditions are met:
  17. *
  18. * - Redistributions of source code must retain the above copyright notice, this
  19. * list of conditions and the following disclaimer.
  20. * - Redistributions in binary form must reproduce the above copyright notice,
  21. * this list of conditions and the following disclaimer in the documentation
  22. * and/or other materials provided with the distribution.
  23. * - Neither the name(s) of Matthew Wilson and Synesis Software nor the names of
  24. * any contributors may be used to endorse or promote products derived from
  25. * this software without specific prior written permission.
  26. *
  27. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  28. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  29. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  30. * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  31. * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  32. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  33. * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  34. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  35. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  36. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  37. * POSSIBILITY OF SUCH DAMAGE.
  38. *
  39. * ////////////////////////////////////////////////////////////////////// */
  40. /** \file stlsoft/conversion/ptr_cast.hpp
  41. *
  42. * \brief [C++ only] Definition of the stlsoft::ptr_cast cast class
  43. * (\ref group__library__conversion "Conversion" Library).
  44. */
  45. #ifndef STLSOFT_INCL_STLSOFT_CONVERSION_HPP_PTR_CAST
  46. #define STLSOFT_INCL_STLSOFT_CONVERSION_HPP_PTR_CAST
  47. #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
  48. # define STLSOFT_VER_STLSOFT_CONVERSION_HPP_PTR_CAST_MAJOR 4
  49. # define STLSOFT_VER_STLSOFT_CONVERSION_HPP_PTR_CAST_MINOR 0
  50. # define STLSOFT_VER_STLSOFT_CONVERSION_HPP_PTR_CAST_REVISION 8
  51. # define STLSOFT_VER_STLSOFT_CONVERSION_HPP_PTR_CAST_EDIT 38
  52. #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */
  53. /* /////////////////////////////////////////////////////////////////////////
  54. * Compatibility
  55. */
  56. /*
  57. [Incompatibilies-start]
  58. STLSOFT_COMPILER_IS_INTEL: _MSC_VER<1310
  59. STLSOFT_COMPILER_IS_MSVC: _MSC_VER<1310
  60. STLSOFT_COMPILER_IS_WATCOM:
  61. [Incompatibilies-end]
  62. */
  63. /* /////////////////////////////////////////////////////////////////////////
  64. * Includes
  65. */
  66. #ifndef STLSOFT_INCL_STLSOFT_H_STLSOFT
  67. # include <stlsoft/stlsoft.h>
  68. #endif /* !STLSOFT_INCL_STLSOFT_H_STLSOFT */
  69. #ifndef STLSOFT_INCL_STLSOFT_META_HPP_BASE_TYPE_TRAITS
  70. # include <stlsoft/meta/base_type_traits.hpp>
  71. #endif /* !STLSOFT_INCL_STLSOFT_META_HPP_BASE_TYPE_TRAITS */
  72. #ifndef STLSOFT_INCL_TYPEINFO
  73. # define STLSOFT_INCL_TYPEINFO
  74. # include <typeinfo>
  75. #endif /* !STLSOFT_INCL_TYPEINFO */
  76. /* /////////////////////////////////////////////////////////////////////////
  77. * Namespace
  78. */
  79. #ifndef _STLSOFT_NO_NAMESPACE
  80. namespace stlsoft
  81. {
  82. #endif /* _STLSOFT_NO_NAMESPACE */
  83. /* /////////////////////////////////////////////////////////////////////////
  84. * Classes
  85. */
  86. /** \brief A cast that throws bad_cast for pointer cast failures, as well as
  87. * for reference casts.
  88. *
  89. * \ingroup group__library__conversion
  90. *
  91. * Assume the following class hierarchy, and variables:
  92. \code
  93. class Parent
  94. {
  95. public:
  96. virtual ~Parent();
  97. };
  98. class A
  99. : public Parent
  100. {
  101. public:
  102. ~A();
  103. };
  104. class B
  105. : public Parent
  106. {
  107. public:
  108. ~B();
  109. };
  110. . . .
  111. A a;
  112. B b;
  113. \endcode
  114. *
  115. * The following code segments illustrate the similarities and differences
  116. * between dynamic_cast and ptr_cast:
  117. *
  118. * (i) dynamic cast of reference that succeeds
  119. \code
  120. A &ra1 = dynamic_cast<A&>(a);
  121. A &ra2 = stlsoft::ptr_cast<A&>(a);
  122. assert(&ra1 == &ra2);
  123. \endcode
  124. *
  125. * (ii) dynamic cast of pointer that succeeds
  126. \code
  127. A *pa = dynamic_cast<A*>(&a);
  128. assert(NULL != pa);
  129. assert(stlsoft::ptr_cast<A*>(&a) == pa);
  130. \endcode
  131. *
  132. * (iii) dynamic cast of reference that fails
  133. \code
  134. bool bCastFailed1 = false;
  135. try
  136. {
  137. B &b1 = dynamic_cast<B&>(a);
  138. . . . // Will never get here
  139. }
  140. catch(std::bad_cast &)
  141. {
  142. bCastFailed1 = true;
  143. }
  144. assert(bCastFailed1);
  145. bool bCastFailed2 = false;
  146. try
  147. {
  148. B &rb = stlsoft::ptr_cast<B&>(a);
  149. . . . // Will never get here
  150. }
  151. catch(std::bad_cast &)
  152. {
  153. bCastFailed2 = true;
  154. }
  155. assert(bCastFailed2);
  156. \endcode
  157. *
  158. * (iv) dynamic cast of pointer that fails
  159. \code
  160. assert(NULL == dynamic_cast<B*>(&a));
  161. bool bCastFailed = false;
  162. try
  163. {
  164. B &rb = stlsoft::ptr_cast<B&>(&a);
  165. . . . // Will never get here
  166. }
  167. catch(std::bad_cast &)
  168. {
  169. bCastFailed = true;
  170. }
  171. assert(bCastFailed);
  172. \endcode
  173. *
  174. * \note This is described in detail in chapter 19 of
  175. * <a href = "http://www.imperfectcplusplus.com/">Imperfect C++</a>.
  176. */
  177. template <ss_typename_param_k Target>
  178. struct ptr_cast
  179. {
  180. public:
  181. /// The target type
  182. typedef Target target_type;
  183. /// The current instantiation of the type
  184. typedef ptr_cast<Target> class_type;
  185. /// The target base type
  186. typedef ss_typename_type_k stlsoft::base_type_traits<Target>::cv_type target_base_type;
  187. /// The reference type
  188. typedef target_base_type& reference_type;
  189. /// The pointer type
  190. typedef target_base_type* pointer_type;
  191. private:
  192. typedef ss_typename_type_k stlsoft::base_type_traits<Target>::base_type target_base_type_;
  193. static target_base_type_* manage_const(target_base_type_* p)
  194. {
  195. return p;
  196. }
  197. #if defined(STLSOFT_COMPILER_IS_BORLAND)
  198. static target_base_type_* manage_const(target_base_type_ const* p)
  199. {
  200. return const_cast<target_base_type_*>(p);
  201. }
  202. #else /* ? compiler */
  203. static target_base_type_ const* manage_const(target_base_type_ const* p)
  204. {
  205. return p;
  206. }
  207. #endif /* compiler */
  208. public:
  209. /// Constructor used when casting a reference
  210. template <ss_typename_param_k Source>
  211. ptr_cast(Source &s)
  212. : m_p(manage_const(&dynamic_cast<Target>(s)))
  213. {
  214. // Nothing to do: dynamic_cast throws for reference types
  215. }
  216. /// Constructor used when casting a pointer
  217. template <ss_typename_param_k Source>
  218. #if defined(STLSOFT_COMPILER_IS_BORLAND) || \
  219. defined(STLSOFT_COMPILER_IS_GCC) || \
  220. defined(STLSOFT_COMPILER_IS_MWERKS)
  221. ptr_cast(Source*& s)
  222. #else /* ? compiler */
  223. ptr_cast(Source* s)
  224. #endif /* compiler */
  225. : m_p(manage_const(dynamic_cast<Target>(s)))
  226. {
  227. if(NULL == m_p)
  228. {
  229. STLSOFT_THROW_X(stlsoft_ns_qual_std(bad_cast)());
  230. }
  231. }
  232. #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
  233. ptr_cast(pointer_type pt)
  234. : m_p(pt)
  235. {}
  236. ptr_cast(reference_type t)
  237. : m_p(&t)
  238. {}
  239. #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */
  240. public:
  241. /// Converts an instance of the cast class to a reference
  242. operator reference_type () const
  243. {
  244. return const_cast<reference_type>(*m_p);
  245. }
  246. /// Converts an instance of the cast class to a pointer
  247. operator pointer_type () const
  248. {
  249. return const_cast<pointer_type>(m_p);
  250. }
  251. private:
  252. pointer_type m_p;
  253. // Not to be implemented
  254. private:
  255. ptr_cast(class_type const&);
  256. };
  257. ////////////////////////////////////////////////////////////////////////////
  258. // Unit-testing
  259. #ifdef STLSOFT_UNITTEST
  260. # include "./unittest/ptr_cast_unittest_.h"
  261. #endif /* STLSOFT_UNITTEST */
  262. /* ////////////////////////////////////////////////////////////////////// */
  263. #ifndef _STLSOFT_NO_NAMESPACE
  264. } // namespace stlsoft
  265. #endif /* _STLSOFT_NO_NAMESPACE */
  266. /* ////////////////////////////////////////////////////////////////////// */
  267. #endif /* !STLSOFT_INCL_STLSOFT_CONVERSION_HPP_PTR_CAST */
  268. /* ///////////////////////////// end of file //////////////////////////// */