1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162
|
<!doctype HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<!--
(C) Copyright 2002-4 Robert Ramey - http://www.rrsd.com .
Use, modification and distribution is subject to the Boost Software
License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
http://www.boost.org/LICENSE_1_0.txt)
-->
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<link rel="stylesheet" type="text/css" href="../../../boost.css">
<link rel="stylesheet" type="text/css" href="style.css">
<title>Serialization - Derivation from an Existing Archive</title>
</head>
<body link="#0000ff" vlink="#800080">
<table border="0" cellpadding="7" cellspacing="0" width="100%" summary="header">
<tr>
<td valign="top" width="300">
<h3><a href="../../../index.htm"><img height="86" width="277" alt="C++ Boost" src="../../../boost.png" border="0"></a></h3>
</td>
<td valign="top">
<h1 align="center">Serialization</h1>
<h2 align="center">Derivation from an Existing Archive</h2>
</td>
</tr>
</table>
<hr>
<dl class="page-index">
<dt><a target="detail" href="#portable_archives">Portable Binary Archives</a>
<dt><a target="detail" href="#fast_archives">Fast Binary Archives</a>
</dl>
<a name=portable_archives>
<h3>Portable Binary Archives</h3>
It may happen that one wants to create a new archive class by derivation from one
of the included ones. Included is a sample program that shows how to derive a
new archive from one of the ones included with the library. The first example is
<a href="../example/demo_portable_archive.cpp" target="demo_portable_archive_cpp">demo_portable_archive.cpp</a>.
This binary archive save/loads integers in a portable format. To this end
it is derived from the native binary archive and the save/load functions for
integers are overridden with special versions which convert to big endian
format if necessary. It also implements an exception for the case where an
integer saved on one platform is too large for the platform which is loading
the archive. This example doesn't address floating point types.
This examples illustrates several issues that have to be addressed when doing
something like this. The discussion below refers to the output archive only but it
applies equally to input archives as well.
<ol>
<li><i>It is derived from</i> <code style="white-space: normal">binary_oarchive_impl<portable_binary_oarchive></code>
<b>NOT</b> <code style="white-space: normal">binary_oarchive</code> <br>
As described in the comments in
<a href="../../../boost/archive/binary_oarchive.hpp" target="binary_oarchive_hpp">binary_oarchive.hpp</a>.
<code style="white-space: normal">binary_oarchive</code> really a shorthand name for
<code style="white-space: normal">binary_oarchive_impl<binary_oarchive></code>. So we should derive
from <code style="white-space: normal">binary_oarchive_impl<portable_binary_oarchive></code> rather
than <code style="white-space: normal">binary_oarchive</code>.
<pre><code>
class portable_binary_oarchive :
// don't derive from binary_oarchive !!!
public binary_oarchive_impl<portable_binary_oarchive>
{
...
</code></pre>
<li><i>Note the</i> <code style="white-space: normal">portable_binary_oarchive</code> <i>between the</i> <>
This is required so that base classes can downcast their <code style="white-space: normal">this</code> pointer
to the most derived class. This is referred to as <b>C</b>uriously <b>R</b>ecurring
<b>T</b>emplate <b>P</b>attern (<b>CRTP</b>) <a href="bibliography.html#11">[11]</a>.
It is used to implement static polymorphism.
<li><i>Base classes need to be explicitly given access to the derived class.</i>
This can be done by making members public or by including friend declarations for
the base classes.
<pre><code>
typedef portable_binary_oarchive derived_t;
friend class detail::common_oarchive<derived_t>;
friend class basic_binary_oarchive<derived_t>;
friend class basic_binary_oprimitive<
derived_t,
std::ostream::char_type,
std::ostream::traits_type
>;
friend class boost::serialization::save_access;
</code></pre>
<li><i>Base class functions will usually need to be explicitly invoked</i>
We commonly overload the function name <code style="white-space: normal">save</code> for saving primitives.
This is very convenient. Usage of a function name in a derived class
"hides" similarly named functions of the base class. That is,
function name overloading doesn't automatically
include base classes. To address this, we can use:
<pre><code>
using binary_oarchive_impl<derived_t>::save;
void save(const unsigned int t);
...
</code></pre>
which should work on conforming compilers. However, I have found
that the following equivalent works on more compilers.
<pre><code>
// default fall through for any types not specified here
template<class T>
void save(const T & t){
binary_oarchive_impl<derived_t>::save(t);
}
void save(const unsigned int t);
...
</code></pre>
so it's what I use.
<li><i>Template definitions of base classes may have to be included.</i>
The demo includes
<pre><code>
// explicitly instantiate for this type of binary stream
#include <boost/archive/basic_binary_oprimitive.ipp>
</code></pre>
for just this purpose. Failure to include required template definitions
will result in undefined symbol errors when the program is linked.
<li><i>Without alteration, this class cannot be further derived from</i><br>
Base classes using <b>CRTP</b> must be templates with a parameter corresponding to
the most derived class. As presented here, this class doesn't qualify, so
it cannot be used as a base class. In order to derive further from this class,
it would have to be reorganized along the lines of the original <code style="white-space: normal">binary_oarchive</code>.
Specifically, it would look something like:
<pre><code>
template<class Archive>
class portable_binary_oarchive_impl :
// don't derive from binary_oarchive !!!
public binary_oarchive_impl<Archive>
{
...
);
// do not derived from this class !!!
class portable_binary_oarchive :
public portable_binary_oarchive_impl<portable_binary_oarchive>
{
public:
portable_binary_oarchive(std::ostream & os, unsigned int flags = 0) :
portable_binary_oarchive_impl<binary_oarchive>(os, flags)
{}
};
</code></pre>
</ol>
<a name=fast_archives>
<h3>Fast Binary Archives</h3>
The second example
<a href="../example/demo_fast_archive.cpp" target="demo_fast_archive_cpp">demo_fast_archive.cpp</a>.
is similar to the first one. The difference is that it intercepts the serialization before
the default serialization is invoked. In this case we want to replace the default
serialization of C arrays of integers with a faster one. The default version
will invoke serialization of each element of the array. If its an array of
integers, and we're not concerned with the archive being portable to another platform
we can just save/load the whole array as a binary string of bytes. This should
be faster than the default element by element method.
<p>
The same considerations that applied when overriding the the save/load of primitives
above apply here, and the code is very similar.
<hr>
<p><i>© Copyright <a href="http://www.rrsd.com">Robert Ramey</a> 2002-2004.
Distributed under the Boost Software License, Version 1.0. (See
accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
</i></p>
</body>
</html>
|