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 cereal 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 RANDOLPH VOORHIES OR SHANE GRANT 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 19200 : static void bind()
56 19200 : { detail::RegisterPolymorphicCaster<Base, Derived>::bind(); }
57 3200 : };
58 3200 : }
59 3200 :
60 3200 : //! Casts a derived class to its non-virtual base class in a way that safely supports abstract classes
61 6400 : /*! This should be used in cases when a derived type needs to serialize its base type. This is better than directly
62 6400 : using static_cast, as it allows for serialization of pure virtual (abstract) base classes.
63 3200 :
64 3200 : This also automatically registers polymorphic relation between the base and derived class, assuming they
65 3200 : are indeed polymorphic. Note this is not the same as polymorphic type registration. For more information
66 3200 : 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 : base_class(Derived const * derived) :
104 : 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 : base_class_detail::RegisterPolymorphicBaseClass<Base, Derived>::bind();
108 : }
109 :
110 : Base * base_ptr;
111 : };
112 6400 :
113 12800 : //! Casts a derived class to its virtual base class in a way that allows cereal to track inheritance
114 6400 : /*! 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 6400 : during serialization.
117 12800 :
118 9600 : It is safe to use virtual_base_class in all circumstances for serializing base classes, even in cases
119 6400 : where virtual inheritance does not take place, though it may be slightly faster to utilize
120 3200 : cereal::base_class<> if you do not need to worry about virtual inheritance.
121 :
122 3200 : This also automatically registers polymorphic relation between the base and derived class, assuming they
123 6400 : are indeed polymorphic. Note this is not the same as polymorphic type registration. For more information
124 4800 : see the documentation on polymorphism. If using a polymorphic class, be sure to include support for
125 3200 : polymorphism (cereal/types/polymorphic.hpp).
126 1600 :
127 : \sa base_class
128 1600 :
129 3200 : @code{.cpp}
130 3200 : struct MyBase
131 3200 : {
132 1600 : int x;
133 :
134 1600 : template <class Archive>
135 3200 : void serialize( Archive & ar )
136 1600 : {
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 : virtual_base_class(Derived const * derived) :
192 : 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 : base_class_detail::RegisterPolymorphicBaseClass<Base, Derived>::bind();
196 : }
197 :
198 : Base * base_ptr;
199 : };
200 :
201 : } // namespace cereal
202 :
203 : #endif // CEREAL_TYPES_BASE_CLASS_HPP_
|