Примеры 14.25 и 14.26 иллюстрируют также двойственную роль оператора &
: он действует как оператор <<
при сериализации объекта и как оператор >>
при десериализации объекта. Это удобно, потому что позволяет реализовать сериализацию и десериализацию одной функцией. Однако в некоторых случаях неудобно использовать одну функцию для сериализации и десериализации; для этого в Boost.Serialization предусмотрен механизм разделения метода serialize()
на два отдельных метода, load()
и save()
. Если вам необходимо воспользоваться преимуществами этой возможности, обратитесь к документации Boost.Serialization.
В примерах 14.25, 14.26 и 14.27 я использую функцию boost::serialization::make_nvp
для конструирования пар вида «имя-значение». В Boost.Serialization предусмотрен также макрос BOOST_SERIALIZATION_NVP
, который позволяет выполнять сериализацию переменной, указывая ее имя. Первый компонент пары будет сконструирован автоматически препроцессором, используя оператор «стрингизации» (stringizing) #
для преобразования макропараметров в строковые константы.
// То же самое, что и ar & make_nvp("name_", name_);
ar & BOOST_SERIALIZATION_NVP(name_);
В этих примерах я использую make_nvp
вместо BOOST_SERIALIZATION_NVP
для лучшего контроля имен тегов, чтобы содержимое архива XML легче читалось.
В документации Boost.Serialization рекомендуется объявлять метод serialize()
как закрытый ( private
) для уменьшения ошибок пользователя, когда добавляется поддержка сериализации в классы, производные от других сериализуемых классов. Для того чтобы библиотека Boost.Serialization могла вызвать метод serialize()
вашего класса, вам необходимо объявить дружественным класс boost:: serialization::access
.
Наконец второй параметр метода serialize()
в примерах 14.25 и 14.26 относится к той части Boost.Serialization, которая поддерживает управление версиями классов (class versioning) . Когда объект определенного класса первый раз сохраняется в архиве, вместе с ним сохраняется также его версия; когда выполняется десериализация экземпляра класса. Boost.Serialization передает сохраненную версию методу serialize
в качестве второго аргумента. Эта информация может использоваться для специализации десериализации; например, serialize
мог бы загружать переменную-член только в том случае, если записанная в архив версия класса, по крайней мере, не меньше версии класса, первым объявившим эту переменную. По умолчанию класс имеет версию 0. Для задания версии класса вызовите макрос BOOST_CLASS_VERSION
, который определен в заголовочном файле boost/serialization/version.hpp , передавая в качестве аргументов имя и версию класса.
В этой главе рассматриваются некоторые аспекты C++, которые плохо вписываются в тематику любой другой главы: указатели функций и членов, константные переменные и функции- члены, независимые операторы (т.е. не члены класса) и несколько других тем.
15.1. Применение указателей функций для их обратного вызова
Проблема
Планируется использование некоторой функции func1
, которая на этапе выполнения должна вызывать другую функцию func2
. Однако по той или иной причине нельзя внутри функции func1
жестко закодировать имя функции func2
. Возможно, имя функции func2
неизвестно на этапе компиляции, или func1
относится к программному интерфейсу независимого разработчика, и она не может быть изменена и перекомпилирована В любом случае вам придется воспользоваться функцией обратного вызова (callback function) .
Решение
При использовании указанных выше функций объявите func1
с указателем на функцию в качестве своего аргумента и передайте ей адрес func2
на этапе выполнения. Используйте typedef
, чтобы программа легче читалась и отлаживалась. Пример 15.1 показывает, как можно реализовать функцию обратного вызова, используя указатель на функцию.
Пример 15.1. Функция обратного вызова
#include
// Пример функции обратного вызова
bool updateProgress(int pct) {
std::cout << pct << "% complete...\n";
return(true);
}
// Этот typedef делает программный код более понятным
typedef bool (*FuncPtrBoolInt)(int);
// Функция, которая выполняется достаточно длительное время
void longOperation(FuncPtrBoolInt f) {
for (long l=0; l < 100000000; l++)
if (l % 10000000 == 0)
f(l/1000000);
}
int main() {
longOperation(updateProgress); // нормально
Читать дальше