Added base_class to complement virtual_base_class

This commit is contained in:
Randolph Voorhies
2013-07-01 16:12:43 -07:00
parent 8ec6ded75c
commit adcc87cc1f
4 changed files with 104 additions and 14 deletions

View File

@@ -34,7 +34,7 @@
#include <cstdint> #include <cstdint>
#include <cereal/details/traits.hpp> #include <cereal/details/traits.hpp>
#include <cereal/types/virtual_base_class.hpp> #include <cereal/types/base_class.hpp>
#include <cereal/types/common.hpp> #include <cereal/types/common.hpp>
namespace cereal namespace cereal
@@ -284,6 +284,15 @@ namespace cereal
return *self; return *self;
} }
//! Serialization of a base_class wrapper
/*! \sa base_class */
template <class T> inline
ArchiveType & processImpl(base_class<T> b)
{
self->processImpl( *b.base_ptr );
return *self;
}
//! Member serialization //! Member serialization
template <class T> inline template <class T> inline
typename std::enable_if<traits::is_specialized_member_serialize<T, ArchiveType>() || typename std::enable_if<traits::is_specialized_member_serialize<T, ArchiveType>() ||
@@ -495,6 +504,16 @@ namespace cereal
return *self; return *self;
} }
//! Serialization of a base_class wrapper
/*! \sa base_class */
template <class T> inline
ArchiveType & processImpl(base_class<T> b)
{
self->processImpl( *b.base_ptr );
return *self;
}
//! Member serialization //! Member serialization
template <class T> inline template <class T> inline
typename std::enable_if<traits::is_specialized_member_serialize<T, ArchiveType>() || typename std::enable_if<traits::is_specialized_member_serialize<T, ArchiveType>() ||

View File

@@ -24,53 +24,118 @@
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#ifndef CEREAL_TYPES_VIRTUAL_BASE_CLASS_HPP_ #ifndef CEREAL_TYPES_BASE_CLASS_HPP_
#define CEREAL_TYPES_VIRTUAL_BASE_CLASS_HPP_ #define CEREAL_TYPES_BASE_CLASS_HPP_
namespace cereal namespace cereal
{ {
//! Casts a derived class to its base class in a way that allows cereal to track inheritance //! Casts a derived class to its non-virtual base class in a way that safely supports abstract classes
/*! This should be used in cases when a derived type needs to serialize its base type. This is better than directly
using static_cast, as it allows for serialization of pure virtual (abstract) base classes.
\sa virtual_base_class
@code{.cpp}
struct MyBase
{
int x;
virtual void foo() = 0;
template <class Archive>
void serialize( Archive & ar )
{
ar( x );
}
};
struct MyDerived : public MyBase //<-- Note non-virtual inheritance
{
int y;
virtual void foo() {};
template <class Archive>
void serialize( Archive & ar )
{
ar( cereal::base_class<MyBase>(this) );
ar( y );
}
};
@endcode */
template<class Base>
struct base_class
{
template<class Derived>
base_class(Derived const * derived) :
base_ptr(const_cast<Base*>(static_cast<Base const *>(derived)))
{ }
Base * base_ptr;
};
//! Casts a derived class to its virtual base class in a way that allows cereal to track inheritance
/*! This should be used in cases when a derived type features virtual inheritance from some /*! This should be used in cases when a derived type features virtual inheritance from some
base type. This allows cereal to track the inheritance and to avoid making duplicate copies base type. This allows cereal to track the inheritance and to avoid making duplicate copies
during serialization. during serialization.
It is safe to use virtual_base_class in all circumstances for serializing base classes, even in cases It is safe to use virtual_base_class in all circumstances for serializing base classes, even in cases
where virtual inheritance does not take place, though it may be slightly faster to utilize where virtual inheritance does not take place, though it may be slightly faster to utilize
static_cast<> if you do not need to worry about virtual inheritance cereal::base_class<> if you do not need to worry about virtual inheritance.
\sa base_class
@code{.cpp} @code{.cpp}
struct MyBase struct MyBase
{ }; {
int x;
struct MyLeft : virtual MyBase
{
template <class Archive> template <class Archive>
void serialize( Archive & ar ) void serialize( Archive & ar )
{ {
ar( cereal::base_clas<MyBase>( this ) ); ar( x );
}
};
struct MyLeft : virtual MyBase //<-- Note the virtual inheritance
{
int y;
template <class Archive>
void serialize( Archive & ar )
{
ar( cereal::virtual_base_class<MyBase>( this ) );
ar( y );
} }
}; };
struct MyRight : virtual MyBase struct MyRight : virtual MyBase
{ {
int z;
template <class Archive> template <class Archive>
void serialize( Archive & ar ) void serialize( Archive & ar )
{ {
ar( cereal::base_clas<MyBase>( this ) ); ar( cereal::virtual_base_clas<MyBase>( this ) );
ar( z );
} }
}; };
// diamond virtual inheritance; contains one copy if each base class // diamond virtual inheritance; contains one copy of each base class
struct MyDerived : virtual MyLeft, virtual MyRight struct MyDerived : virtual MyLeft, virtual MyRight
{ {
int a;
template <class Archive> template <class Archive>
void serialize( Archive & ar ) void serialize( Archive & ar )
{ {
ar( cereal::virtual_base_class<MyLeft>( this ) ); // safely serialize data members in MyLeft ar( cereal::virtual_base_class<MyLeft>( this ) ); // safely serialize data members in MyLeft
ar( cereal::virtual_base_class<MyRight>( this ) ); // safely serialize data members in MyRight ar( cereal::virtual_base_class<MyRight>( this ) ); // safely serialize data members in MyRight
ar( a );
// Because we used virtual_base_class, cereal will ensure that only one instance of MyBase is // Because we used virtual_base_class, cereal will ensure that only one instance of MyBase is
// serialized as we traverse the inheritance heirarchy. // serialized as we traverse the inheritance heirarchy. This means that there will be one copy
// each of the variables x, y, z, and a
// If we had chosen to use static_cast<> instead, cereal would perform no tracking and // If we had chosen to use static_cast<> instead, cereal would perform no tracking and
// assume that every base class should be serialized (in this case leading to a duplicate // assume that every base class should be serialized (in this case leading to a duplicate
@@ -86,5 +151,6 @@ namespace cereal
Base * base_ptr; Base * base_ptr;
}; };
} // namespace cereal } // namespace cereal
#endif // CEREAL_TYPES_VIRTUAL_BASE_CLASS_HPP_ #endif // CEREAL_TYPES_BASE_CLASS_HPP_

View File

@@ -32,7 +32,7 @@
#include <cereal/types/memory.hpp> #include <cereal/types/memory.hpp>
#include <cereal/types/complex.hpp> #include <cereal/types/complex.hpp>
#include <cereal/types/boost_variant.hpp> #include <cereal/types/boost_variant.hpp>
#include <cereal/types/virtual_base_class.hpp> #include <cereal/types/base_class.hpp>
#include <cxxabi.h> #include <cxxabi.h>
#include <sstream> #include <sstream>

View File

@@ -34,18 +34,21 @@
struct Base struct Base
{ {
int y;
virtual void foo() = 0; virtual void foo() = 0;
template<class Archive> template<class Archive>
void save(Archive & ar) const void save(Archive & ar) const
{ {
std::cout << "Saving Base" << std::endl; std::cout << "Saving Base" << std::endl;
ar( y );
} }
template<class Archive> template<class Archive>
void load(Archive & ar) void load(Archive & ar)
{ {
std::cout << "Loading Base" << std::endl; std::cout << "Loading Base" << std::endl;
ar( y );
} }
}; };
@@ -59,12 +62,14 @@ struct MyType : public Base
void save(Archive & ar) const void save(Archive & ar) const
{ {
std::cout << "Saving MyType" << std::endl; std::cout << "Saving MyType" << std::endl;
ar( cereal::virtual_base_class<Base>( this ) );
} }
template<class Archive> template<class Archive>
void load(Archive & ar) void load(Archive & ar)
{ {
std::cout << "Loading MyType" << std::endl; std::cout << "Loading MyType" << std::endl;
ar( cereal::base_class<Base>( this ) );
} }
}; };
CEREAL_REGISTER_TYPE(MyType); CEREAL_REGISTER_TYPE(MyType);