Line data Source code
1 : /*! \file base_class.hpp 2 : \brief Support for base classes (virtual and non-virtual) 3 : \ingroup OtherTypes */ 4 : /* 5 : Copyright (c) 2014, Randolph Voorhies, Shane Grant 6 : All rights reserved. 7 : 8 : Redistribution and use in source and binary forms, with or without 9 : modification, are permitted provided that the following conditions are met: 10 : * Redistributions of source code must retain the above copyright 11 : notice, this list of conditions and the following disclaimer. 12 : * Redistributions in binary form must reproduce the above copyright 13 : notice, this list of conditions and the following disclaimer in the 14 : documentation and/or other materials provided with the distribution. 15 : * Neither the name of the copyright holder nor the 16 : names of its contributors may be used to endorse or promote products 17 : derived from this software without specific prior written permission. 18 : 19 : THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 20 : ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 : WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 : DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY 23 : DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 : (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 : LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 26 : ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 : (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 : SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 : */ 30 : #ifndef CEREAL_TYPES_BASE_CLASS_HPP_ 31 : #define CEREAL_TYPES_BASE_CLASS_HPP_ 32 : 33 : #include "cereal/details/traits.hpp" 34 : #include "cereal/details/polymorphic_impl_fwd.hpp" 35 : 36 : namespace cereal 37 : { 38 : namespace base_class_detail 39 : { 40 : //! Used to register polymorphic relations and avoid the need to include 41 : //! polymorphic.hpp when no polymorphism is used 42 : /*! @internal */ 43 : template <class Base, class Derived, bool IsPolymorphic = std::is_polymorphic<Base>::value> 44 : struct RegisterPolymorphicBaseClass 45 : { 46 : static void bind() 47 : { } 48 : }; 49 : 50 : //! Polymorphic version 51 : /*! @internal */ 52 : template <class Base, class Derived> 53 : struct RegisterPolymorphicBaseClass<Base, Derived, true> 54 : { 55 9600 : static void bind() 56 9600 : { detail::RegisterPolymorphicCaster<Base, Derived>::bind(); } 57 : }; 58 : } 59 : 60 : //! Casts a derived class to its non-virtual base class in a way that safely supports abstract classes 61 : /*! This should be used in cases when a derived type needs to serialize its base type. This is better than directly 62 : using static_cast, as it allows for serialization of pure virtual (abstract) base classes. 63 : 64 : This also automatically registers polymorphic relation between the base and derived class, assuming they 65 : are indeed polymorphic. Note this is not the same as polymorphic type registration. For more information 66 : see the documentation on polymorphism. If using a polymorphic class, be sure to include support for 67 : polymorphism (cereal/types/polymorphic.hpp). 68 : 69 : \sa virtual_base_class 70 : 71 : @code{.cpp} 72 : struct MyBase 73 : { 74 : int x; 75 : 76 : virtual void foo() = 0; 77 : 78 : template <class Archive> 79 : void serialize( Archive & ar ) 80 : { 81 : ar( x ); 82 : } 83 : }; 84 : 85 : struct MyDerived : public MyBase //<-- Note non-virtual inheritance 86 : { 87 : int y; 88 : 89 : virtual void foo() {}; 90 : 91 : template <class Archive> 92 : void serialize( Archive & ar ) 93 : { 94 : ar( cereal::base_class<MyBase>(this) ); 95 : ar( y ); 96 : } 97 : }; 98 : @endcode */ 99 : template<class Base> 100 : struct base_class : private traits::detail::BaseCastBase 101 : { 102 : template<class Derived> 103 6400 : base_class(Derived const * derived) : 104 6400 : base_ptr(const_cast<Base*>(static_cast<Base const *>(derived))) 105 : { 106 : static_assert( std::is_base_of<Base, Derived>::value, "Can only use base_class on a valid base class" ); 107 6400 : base_class_detail::RegisterPolymorphicBaseClass<Base, Derived>::bind(); 108 6400 : } 109 : 110 : Base * base_ptr; 111 : }; 112 : 113 : //! Casts a derived class to its virtual base class in a way that allows cereal to track inheritance 114 : /*! This should be used in cases when a derived type features virtual inheritance from some 115 : base type. This allows cereal to track the inheritance and to avoid making duplicate copies 116 : during serialization. 117 : 118 : It is safe to use virtual_base_class in all circumstances for serializing base classes, even in cases 119 : where virtual inheritance does not take place, though it may be slightly faster to utilize 120 : cereal::base_class<> if you do not need to worry about virtual inheritance. 121 : 122 : This also automatically registers polymorphic relation between the base and derived class, assuming they 123 : are indeed polymorphic. Note this is not the same as polymorphic type registration. For more information 124 : see the documentation on polymorphism. If using a polymorphic class, be sure to include support for 125 : polymorphism (cereal/types/polymorphic.hpp). 126 : 127 : \sa base_class 128 : 129 : @code{.cpp} 130 : struct MyBase 131 : { 132 : int x; 133 : 134 : template <class Archive> 135 : void serialize( Archive & ar ) 136 : { 137 : ar( x ); 138 : } 139 : }; 140 : 141 : struct MyLeft : virtual MyBase //<-- Note the virtual inheritance 142 : { 143 : int y; 144 : 145 : template <class Archive> 146 : void serialize( Archive & ar ) 147 : { 148 : ar( cereal::virtual_base_class<MyBase>( this ) ); 149 : ar( y ); 150 : } 151 : }; 152 : 153 : struct MyRight : virtual MyBase 154 : { 155 : int z; 156 : 157 : template <class Archive> 158 : void serialize( Archive & ar ) 159 : { 160 : ar( cereal::virtual_base_clas<MyBase>( this ) ); 161 : ar( z ); 162 : } 163 : }; 164 : 165 : // diamond virtual inheritance; contains one copy of each base class 166 : struct MyDerived : virtual MyLeft, virtual MyRight 167 : { 168 : int a; 169 : 170 : template <class Archive> 171 : void serialize( Archive & ar ) 172 : { 173 : ar( cereal::virtual_base_class<MyLeft>( this ) ); // safely serialize data members in MyLeft 174 : ar( cereal::virtual_base_class<MyRight>( this ) ); // safely serialize data members in MyRight 175 : ar( a ); 176 : 177 : // Because we used virtual_base_class, cereal will ensure that only one instance of MyBase is 178 : // serialized as we traverse the inheritance heirarchy. This means that there will be one copy 179 : // each of the variables x, y, z, and a 180 : 181 : // If we had chosen to use static_cast<> instead, cereal would perform no tracking and 182 : // assume that every base class should be serialized (in this case leading to a duplicate 183 : // serialization of MyBase due to diamond inheritance 184 : }; 185 : } 186 : @endcode */ 187 : template<class Base> 188 : struct virtual_base_class : private traits::detail::BaseCastBase 189 : { 190 : template<class Derived> 191 3200 : virtual_base_class(Derived const * derived) : 192 3200 : base_ptr(const_cast<Base*>(static_cast<Base const *>(derived))) 193 : { 194 : static_assert( std::is_base_of<Base, Derived>::value, "Can only use virtual_base_class on a valid base class" ); 195 3200 : base_class_detail::RegisterPolymorphicBaseClass<Base, Derived>::bind(); 196 3200 : } 197 : 198 : Base * base_ptr; 199 : }; 200 : 201 : } // namespace cereal 202 : 203 : #endif // CEREAL_TYPES_BASE_CLASS_HPP_